├── .gitignore ├── .tasks ├── LICENSE ├── README.md ├── build.sh ├── czmod.bash ├── czmod.c ├── czmod.fish ├── czmod.zsh └── system ├── imembase.c ├── imembase.h ├── iposix.c └── iposix.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | 54 | czmod 55 | czmod.p 56 | czmod.o 57 | 58 | test*.c 59 | test*.o 60 | test* 61 | 62 | 63 | -------------------------------------------------------------------------------- /.tasks: -------------------------------------------------------------------------------- 1 | # vim: set fenc=utf-8 ft=dosini: 2 | [file-build] 3 | command=musl-gcc -O3 "$(VIM_FILENAME)" -o "$(VIM_FILENOEXT)" -static 4 | cwd=$(VIM_FILEDIR) 5 | save=1 6 | 7 | [project-build] 8 | command=musl-gcc -O3 -o czmod czmod.c system/imembase.c system/iposix.c -static -s 9 | cwd= 10 | save=2 11 | 12 | [project-run] 13 | command=./czmod --test 14 | cwd= 15 | save=2 16 | output=terminal 17 | 18 | [project-test] 19 | command=./czmod -e vim 20 | cwd= 21 | save=2 22 | output=terminal 23 | 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Linwei 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Preface 2 | 3 | [z.lua](https://github.com/skywind3000/z.lua) is fast enough for most cases, the path tracking action will be triggered each time when you change your current directory. 4 | 5 | So I still recommend the pure lua script for portability and flexibility, but for someone who really cares about very high performance, this module can be helpful. 6 | 7 | 8 | ## Features 9 | 10 | - Speeds up `z.lua` for history tracking and matching. 11 | - Easy to install. 12 | 13 | ## Install 14 | 15 | ### Install musl-gcc 16 | 17 | ```bash 18 | sudo apt-get install musl-tools 19 | ``` 20 | 21 | ### Build the binary 22 | 23 | ```Bash 24 | git clone https://github.com/skywind3000/czmod.git ~/github/czmod 25 | cd ~/github/czmod 26 | sh build.sh 27 | ``` 28 | 29 | ### Enable Czmod 30 | 31 | `czmod` must be initialized after `z.lua`: 32 | 33 | bash: 34 | 35 | ```bash 36 | eval "$(lua ~/github/z.lua/z.lua --init bash enhanced once echo)" 37 | source ~/github/czmod/czmod.bash 38 | ``` 39 | 40 | zsh: 41 | 42 | ```bash 43 | eval "$(lua ~/github/z.lua/z.lua --init zsh enhanced once echo)" 44 | source ~/github/czmod/czmod.zsh 45 | ``` 46 | 47 | ## Benchmark 48 | 49 | Average performance: 50 | 51 | | Name | czmod | z.lua | 52 | |-|-|-| 53 | | **Update Time** | 1.6ms | 13.2ms | 54 | | **Query Time** | 1.5ms | 9.8ms | 55 | 56 | ## Credit 57 | 58 | TODO 59 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | CC="$(which musl-gcc 2> /dev/null)" 4 | 5 | if [ ! -x "$CC" ]; then 6 | echo "Error: musl-gcc not find, install it with:" 7 | echo "sudo apt-get install musl-tools" 8 | exit 1 9 | fi 10 | 11 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 12 | 13 | cd "$SCRIPTPATH" 14 | 15 | $CC -O3 -o czmod czmod.c system/imembase.c system/iposix.c -static -s 16 | 17 | if [ "$?" -eq 0 ]; then 18 | echo "success, binary 'czmod' is ready" 19 | else 20 | exit 2 21 | fi 22 | 23 | -------------------------------------------------------------------------------- /czmod.bash: -------------------------------------------------------------------------------- 1 | #! /usr/bin/bash 2 | 3 | SCRIPTPATH="$( cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 ; pwd -P )" 4 | CZMODPATH="$SCRIPTPATH/czmod" 5 | 6 | if [ ! -x "$CZMODPATH" ]; then 7 | SCRIPTPATH="$(readlink """${BASH_SOURCE[0]}""")" 8 | SCRIPTPATH="$( cd "$(dirname "$SCRIPTPATH")" >/dev/null 2>&1 ; pwd -P )" 9 | CZMODPATH="$SCRIPTPATH/czmod" 10 | fi 11 | 12 | if [ ! -x "$CZMODPATH" ]; then 13 | CZMODPATH="$(which czmod 2> /dev/null)" 14 | fi 15 | 16 | if [ ! -x "$CZMODPATH" ]; then 17 | echo "Error: not find czmod executable in your PATH !!" 18 | return 19 | fi 20 | 21 | CZPATH="$( cd "$(dirname "$CZMODPATH")" > /dev/null 2>&1 ; pwd -P )" 22 | PATH="$CZPATH:$PATH" 23 | 24 | case "$PROMPT_COMMAND" in 25 | *_zlua?--add*) 26 | PROMPT_COMMAND="${PROMPT_COMMAND/_zlua?--add/czmod --add}" 27 | ;; 28 | *czmod?--add*) 29 | ;; 30 | *_zlua_precmd*) 31 | ;; 32 | *) 33 | echo "z.lua is not initialized" 34 | ;; 35 | esac 36 | 37 | _zlua_precmd() { 38 | [ "$_ZL_PREVIOUS_PWD" = "$PWD" ] && return 39 | _ZL_PREVIOUS_PWD="$PWD" 40 | (czmod --add "$PWD" 2> /dev/null &) 41 | } 42 | 43 | 44 | -------------------------------------------------------------------------------- /czmod.c: -------------------------------------------------------------------------------- 1 | //===================================================================== 2 | // 3 | // czmod.c - c module to boost z.lua 4 | // 5 | // Created by skywind on 2020/03/11 6 | // Last Modified: 2020/03/11 16:37:01 7 | // 8 | //===================================================================== 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #if defined(_WIN32) || defined(_WIN64) || defined(WIN32) || defined(WIN64) 18 | #include 19 | #elif defined(__linux) 20 | // #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #endif 27 | 28 | #define IB_STRING_SSO 256 29 | 30 | #include "system/iposix.h" 31 | #include "system/imembase.h" 32 | 33 | #ifndef PATH_MAX 34 | #define PATH_MAX 4096 35 | #endif 36 | 37 | 38 | //---------------------------------------------------------------------- 39 | // INLINE 40 | //---------------------------------------------------------------------- 41 | #ifndef INLINE 42 | #if defined(__GNUC__) 43 | 44 | #if (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) 45 | #define INLINE __inline__ __attribute__((always_inline)) 46 | #else 47 | #define INLINE __inline__ 48 | #endif 49 | 50 | #elif (defined(_MSC_VER) || defined(__WATCOMC__)) 51 | #define INLINE __inline 52 | #else 53 | #define INLINE 54 | #endif 55 | #endif 56 | 57 | #if (!defined(__cplusplus)) && (!defined(inline)) 58 | #define inline INLINE 59 | #endif 60 | 61 | 62 | //--------------------------------------------------------------------- 63 | // internal functions 64 | //--------------------------------------------------------------------- 65 | static const char *get_data_file(void); 66 | 67 | 68 | //--------------------------------------------------------------------- 69 | // get environ 70 | //--------------------------------------------------------------------- 71 | static ib_string* os_getenv(const char *name) 72 | { 73 | char *p = getenv(name); 74 | if (p == NULL) { 75 | return NULL; 76 | } 77 | ib_string *text = ib_string_new(); 78 | ib_string_assign(text, p); 79 | return text; 80 | } 81 | 82 | 83 | //--------------------------------------------------------------------- 84 | // get data file 85 | //--------------------------------------------------------------------- 86 | static const char *get_data_file(void) 87 | { 88 | static ib_string *text = NULL; 89 | if (text != NULL) { 90 | return text->ptr; 91 | } 92 | text = os_getenv("_ZL_DATA"); 93 | if (text) { 94 | return text->ptr; 95 | } 96 | text = os_getenv("HOME"); 97 | if (text == NULL) { 98 | text = os_getenv("USERPROFILE"); 99 | } 100 | if (text == NULL) { 101 | return NULL; 102 | } 103 | ib_string_append(text, "/.zlua"); 104 | return text->ptr; 105 | } 106 | 107 | 108 | //--------------------------------------------------------------------- 109 | // load file content 110 | //--------------------------------------------------------------------- 111 | ib_string *load_content(const char *filename) 112 | { 113 | FILE *fp = fopen(filename, "r"); 114 | if (fp == NULL) { 115 | return NULL; 116 | } 117 | int fd = fileno(fp); 118 | flock(fd, LOCK_SH); 119 | ib_string *text = ib_string_new(); 120 | size_t block = 65536; 121 | ib_string_resize(text, block); 122 | size_t pos = 0; 123 | while (feof(fp) == 0) { 124 | size_t avail = text->size - pos; 125 | if (avail < block) { 126 | ib_string_resize(text, text->size + block); 127 | avail = text->size - pos; 128 | } 129 | size_t hr = fread(&(text->ptr[pos]), 1, avail, fp); 130 | pos += hr; 131 | } 132 | flock(fd, LOCK_UN); 133 | fclose(fp); 134 | ib_string_resize(text, pos); 135 | return text; 136 | } 137 | 138 | 139 | //--------------------------------------------------------------------- 140 | // path item 141 | //--------------------------------------------------------------------- 142 | typedef struct 143 | { 144 | ib_string *path; 145 | int rank; 146 | uint32_t timestamp; 147 | double frecent; 148 | } PathItem; 149 | 150 | static void item_delete(PathItem *item) 151 | { 152 | if (item) { 153 | if (item->path) { 154 | ib_string_delete(item->path); 155 | item->path = NULL; 156 | } 157 | ikmem_free(item); 158 | } 159 | }; 160 | 161 | PathItem* item_new(const char *path, int rank, uint32_t timestamp) 162 | { 163 | PathItem* item = (PathItem*)ikmem_malloc(sizeof(PathItem)); 164 | assert(item); 165 | item->path = ib_string_new_from(path); 166 | item->rank = rank; 167 | item->timestamp = timestamp; 168 | item->frecent = rank; 169 | return item; 170 | }; 171 | 172 | // compare item 173 | int item_compare(const void *p1, const void *p2) 174 | { 175 | PathItem *n1 = (PathItem*)p1; 176 | PathItem *n2 = (PathItem*)p2; 177 | if (n1->frecent == n2->frecent) return 0; 178 | return (n1->frecent > n2->frecent)? 1 : -1; 179 | } 180 | 181 | ib_array* ib_array_new_items(void) 182 | { 183 | return ib_array_new((void (*)(void*))item_delete); 184 | } 185 | 186 | 187 | //--------------------------------------------------------------------- 188 | // load data 189 | //--------------------------------------------------------------------- 190 | ib_array* data_load(const char *filename) 191 | { 192 | ib_string *content = load_content(filename); 193 | if (content == NULL) { 194 | return NULL; 195 | } 196 | else { 197 | ib_array *lines = ib_string_split_c(content, '\n'); 198 | int size = ib_array_size(lines); 199 | int i; 200 | ib_array *items = ib_array_new_items(); 201 | for (i = 0; i < size; i++) { 202 | ib_string *text = (ib_string*)ib_array_index(lines, i); 203 | int p1 = ib_string_find_c(text, '|', 0); 204 | if (p1 >= 0) { 205 | int p2 = ib_string_find_c(text, '|', p1 + 1); 206 | if (p2 >= 0) { 207 | uint32_t timestamp; 208 | int rank; 209 | text->ptr[p1] = 0; 210 | text->ptr[p2] = 0; 211 | rank = (int)atoi(text->ptr + p1 + 1); 212 | timestamp = (uint32_t)strtoul(text->ptr + p2 + 1, NULL, 10); 213 | PathItem *ni = item_new(text->ptr, rank, timestamp); 214 | ib_array_push(items, ni); 215 | } 216 | } 217 | } 218 | ib_array_delete(lines); 219 | return items; 220 | } 221 | return NULL; 222 | } 223 | 224 | 225 | //--------------------------------------------------------------------- 226 | // save data 227 | //--------------------------------------------------------------------- 228 | void data_save(const char *filename, ib_array *items) 229 | { 230 | ib_string *tmpname = ib_string_new_from(filename); 231 | FILE *fp; 232 | while (1) { 233 | char tmp[100]; 234 | ib_string_assign(tmpname, filename); 235 | sprintf(tmp, ".%u%03u%d", (uint32_t)time(NULL), 236 | (uint32_t)(clock() % 1000), rand() % 10000); 237 | ib_string_append(tmpname, tmp); 238 | if (iposix_path_isdir(tmpname->ptr) < 0) break; 239 | } 240 | fp = fopen(tmpname->ptr, "w"); 241 | if (fp) { 242 | int size = ib_array_size(items); 243 | int i; 244 | for (i = 0; i < size; i++) { 245 | PathItem *item = (PathItem*)ib_array_index(items, i); 246 | fprintf(fp, "%s|%u|%u\n", 247 | item->path->ptr, item->rank, item->timestamp); 248 | } 249 | fclose(fp); 250 | #ifdef _WIN32 251 | ReplaceFileA(filename, tmpname->ptr, NULL, 2, NULL, NULL); 252 | #else 253 | rename(tmpname->ptr, filename); 254 | #endif 255 | } 256 | ib_string_delete(tmpname); 257 | } 258 | 259 | 260 | //--------------------------------------------------------------------- 261 | // save data 262 | //--------------------------------------------------------------------- 263 | void data_write(const char *filename, ib_array *items) 264 | { 265 | FILE *fp; 266 | int fd; 267 | fp = fopen(filename, "w+"); 268 | if (fp) { 269 | int size = ib_array_size(items); 270 | int i; 271 | fd = fileno(fp); 272 | flock(fd, LOCK_EX); 273 | for (i = 0; i < size; i++) { 274 | PathItem *item = (PathItem*)ib_array_index(items, i); 275 | fprintf(fp, "%s|%u|%u\n", 276 | item->path->ptr, item->rank, item->timestamp); 277 | } 278 | fflush(fp); 279 | flock(fd, LOCK_UN); 280 | fclose(fp); 281 | } 282 | } 283 | 284 | 285 | //--------------------------------------------------------------------- 286 | // insert data 287 | //--------------------------------------------------------------------- 288 | void data_add(ib_array *items, const char *path) 289 | { 290 | ib_string *target = ib_string_new_from(path); 291 | int i = 0, size, found = 0; 292 | #if defined(_WIN32) 293 | for (i = 0; i < target->size; i++) { 294 | if (target->ptr[i] == '/') target->ptr[i] = '\\'; 295 | else { 296 | target->ptr[i] = (char)tolower(target->ptr[i]); 297 | } 298 | } 299 | #endif 300 | size = ib_array_size(items); 301 | for (i = 0; i < size; i++) { 302 | PathItem *item = (PathItem*)ib_array_index(items, i); 303 | int equal = 0; 304 | #if defined(_WIN32) 305 | if (item->path->size == target->size) { 306 | char *src = item->path->ptr; 307 | char *dst = target->ptr; 308 | int avail = target->size; 309 | for (; avail > 0; src++, dst++, avail--) { 310 | if (tolower(src[0]) != dst[0]) break; 311 | } 312 | equal = (avail == 0)? 1 : 0; 313 | } 314 | #else 315 | if (ib_string_compare(item->path, target) == 0) { 316 | equal = 1; 317 | } 318 | #endif 319 | if (equal) { 320 | found = 1; 321 | item->rank++; 322 | item->timestamp = (uint32_t)time(NULL); 323 | } 324 | } 325 | if (!found) { 326 | PathItem *ni = item_new(target->ptr, 1, (uint32_t)time(NULL)); 327 | ib_array_push(items, ni); 328 | } 329 | ib_string_delete(target); 330 | } 331 | 332 | 333 | //--------------------------------------------------------------------- 334 | // match string 335 | //--------------------------------------------------------------------- 336 | int string_match(const char *text, int argc, const char *argv[]) 337 | { 338 | int enhanced = 1; 339 | int pos = 0; 340 | int i; 341 | if (argc == 0) return 0; 342 | for (i = 0; i < argc; i++) { 343 | const char *keyword = argv[i]; 344 | const char *p = strstr(text + pos, keyword); 345 | if (p == NULL) { 346 | return -1; 347 | } 348 | pos = (int)(p - text) + ((int)strlen(keyword)); 349 | } 350 | if (enhanced != 0) { 351 | const char *keyword = argv[argc - 1]; 352 | const char *p1 = strrchr(text, '/'); 353 | const char *p2; 354 | if (p1 == NULL) { 355 | p1 = strrchr(text, '\\'); 356 | if (p1 == NULL) { 357 | return 0; 358 | } 359 | } 360 | else { 361 | p2 = strrchr(text, '\\'); 362 | if (p2 != NULL) { 363 | if (p2 > p1) { 364 | p1 = p2; 365 | } 366 | } 367 | } 368 | p2 = strstr(p1, keyword); 369 | if (p2 == NULL) { 370 | return -2; 371 | } 372 | } 373 | return 0; 374 | } 375 | 376 | 377 | //--------------------------------------------------------------------- 378 | // score path 379 | //--------------------------------------------------------------------- 380 | void data_score(ib_array *items, int mode) 381 | { 382 | uint32_t current = (uint32_t)time(NULL); 383 | int count = (int)ib_array_size(items); 384 | int i; 385 | for (i = 0; i < count; i++) { 386 | PathItem* item = (PathItem*)ib_array_index(items, i); 387 | if (mode == 0) { 388 | uint32_t ts = current - item->timestamp; 389 | if (ts < 3600) { 390 | item->frecent = item->rank * 4; 391 | } 392 | else if (ts < 86400) { 393 | item->frecent = item->rank * 2; 394 | } 395 | else if (ts < 604800) { 396 | item->frecent = item->rank * 0.5; 397 | } 398 | else { 399 | item->frecent = item->rank * 0.25; 400 | } 401 | } 402 | else if (mode == 1) { 403 | item->frecent = item->rank; 404 | } 405 | else { 406 | uint32_t ts = current - item->timestamp; 407 | item->frecent = -((double)ts); 408 | } 409 | } 410 | ib_array_sort(items, item_compare); 411 | ib_array_reverse(items); 412 | } 413 | 414 | 415 | //--------------------------------------------------------------------- 416 | // display data 417 | //--------------------------------------------------------------------- 418 | void data_print(ib_array *items) 419 | { 420 | int count = (int)ib_array_size(items); 421 | int i; 422 | for (i = 0; i < count; i++) { 423 | PathItem *item = (PathItem*)ib_array_index(items, count - i - 1); 424 | printf("%.2f: %s\n", item->frecent, item->path->ptr); 425 | } 426 | } 427 | 428 | 429 | //--------------------------------------------------------------------- 430 | // match 431 | //--------------------------------------------------------------------- 432 | ib_array* data_match(int argc, const char *argv[]) 433 | { 434 | const char *data = get_data_file(); 435 | ib_array *items = data_load(data); 436 | ib_array *result = NULL; 437 | if (items == NULL) { 438 | return NULL; 439 | } 440 | result = ib_array_new_items(); 441 | while (ib_array_size(items)) { 442 | PathItem* item = (PathItem*)ib_array_pop(items); 443 | int valid = 0; 444 | if (argc == 0) { 445 | valid = 1; 446 | } else { 447 | int hr = string_match(item->path->ptr, argc, argv); 448 | if (hr == 0) { 449 | valid = 1; 450 | } 451 | } 452 | if (valid) { 453 | ib_array_push(result, item); 454 | } else { 455 | item_delete(item); 456 | } 457 | } 458 | ib_array_delete(items); 459 | data_score(result, 0); 460 | return result; 461 | } 462 | 463 | 464 | //--------------------------------------------------------------------- 465 | // update database 466 | //--------------------------------------------------------------------- 467 | void z_update(const char *newpath) 468 | { 469 | const char *data = get_data_file(); 470 | int fd = open(data, O_CREAT | O_RDWR, 0666); 471 | ib_array *items; 472 | if (fd < 0) { 473 | return; 474 | } 475 | flock(fd, LOCK_EX); 476 | off_t size = lseek(fd, 0, SEEK_END); 477 | lseek(fd, 0, SEEK_SET); 478 | items = ib_array_new_items(); 479 | if (size > 0) { 480 | ib_string *content = ib_string_new(); 481 | int avail = (int)size; 482 | int start = 0; 483 | ib_array *array; 484 | int i, count; 485 | ib_string_resize(content, (int)size); 486 | while (avail > 0) { 487 | int hr = read(fd, content->ptr + start, avail); 488 | if (hr <= 0) { 489 | break; 490 | } 491 | avail -= hr; 492 | start += hr; 493 | } 494 | lseek(fd, 0, SEEK_SET); 495 | array = ib_string_split(content, "\n", 1); 496 | ib_string_delete(content); 497 | for (count = ib_array_size(array), i = 0; i < count; i++) { 498 | ib_string *line = (ib_string*)ib_array_index(array, i); 499 | int p1 = ib_string_find_c(line, '|', 0); 500 | int p2 = 0; 501 | if (p1 < 0) { 502 | continue; 503 | } 504 | p2 = ib_string_find_c(line, '|', p1 + 1); 505 | if (p2 >= 0) { 506 | uint32_t timestamp; 507 | int rank; 508 | line->ptr[p1] = 0; 509 | line->ptr[p2] = 0; 510 | rank = (int)atoi(line->ptr + p1 + 1); 511 | timestamp = (uint32_t)strtoul(line->ptr + p2 + 1, NULL, 10); 512 | PathItem *ni = item_new(line->ptr, rank, timestamp); 513 | ib_array_push(items, ni); 514 | } 515 | } 516 | ib_array_delete(array); 517 | } 518 | { 519 | int i, count = ib_array_size(items); 520 | int strsize = (int)strlen(newpath); 521 | int found = 0; 522 | uint64_t total = 0; 523 | for (i = 0; i < count; i++) { 524 | PathItem *item = (PathItem*)ib_array_index(items, i); 525 | total += item->rank; 526 | } 527 | if (total >= 5000) { 528 | ib_array *na = ib_array_new((void (*)(void*))item_delete); 529 | for (i = 0; i < count; i++) { 530 | PathItem *item = (PathItem*)ib_array_index(items, i); 531 | item->rank = (item->rank * 9) / 10; 532 | } 533 | while (ib_array_size(items) > 0) { 534 | PathItem *item = (PathItem*)ib_array_pop(items); 535 | if (item->rank == 0) { 536 | item_delete(item); 537 | } else { 538 | ib_array_push(na, item); 539 | } 540 | } 541 | ib_array_delete(items); 542 | items = na; 543 | ib_array_reverse(items); 544 | count = (int)ib_array_size(items); 545 | } 546 | for (i = 0; i < count; i++) { 547 | PathItem *item = (PathItem*)ib_array_index(items, i); 548 | if (item->path->size == strsize) { 549 | if (memcmp(item->path->ptr, newpath, strsize) == 0) { 550 | item->rank += 1; 551 | item->timestamp = (uint32_t)time(NULL); 552 | found = 1; 553 | break; 554 | } 555 | } 556 | } 557 | if (found == 0) { 558 | PathItem *item = item_new(newpath, 1, (uint32_t)time(NULL)); 559 | ib_array_push(items, item); 560 | } 561 | } 562 | { 563 | int i, count; 564 | count = (int)ib_array_size(items); 565 | static char text[PATH_MAX + 60]; 566 | ib_string *content = ib_string_new(); 567 | int avail, start; 568 | for (i = 0; i < count; i++) { 569 | PathItem *item = (PathItem*)ib_array_index(items, i); 570 | sprintf(text, "%s|%u|%u\n", item->path->ptr, item->rank, item->timestamp); 571 | ib_string_append(content, text); 572 | } 573 | start = 0; 574 | avail = content->size; 575 | while (avail > 0) { 576 | int hr = write(fd, content->ptr + start, avail); 577 | if (hr <= 0) { 578 | break; 579 | } 580 | start += hr; 581 | avail -= hr; 582 | } 583 | ftruncate(fd, content->size); 584 | ib_string_delete(content); 585 | } 586 | flock(fd, LOCK_UN); 587 | close(fd); 588 | } 589 | 590 | 591 | //--------------------------------------------------------------------- 592 | // add to database 593 | //--------------------------------------------------------------------- 594 | void z_add(const char *newpath) 595 | { 596 | const char *data = get_data_file(); 597 | ib_array *items = data_load(data); 598 | if (items == NULL) { 599 | items = ib_array_new_items(); 600 | } 601 | data_add(items, newpath); 602 | #if 0 603 | data_save(data, items); 604 | #else 605 | data_write(data, items); 606 | #endif 607 | ib_array_delete(items); 608 | } 609 | 610 | 611 | //--------------------------------------------------------------------- 612 | // match and display 613 | //--------------------------------------------------------------------- 614 | void z_echo(int argc, const char *argv[]) 615 | { 616 | ib_array *items = data_match(argc, argv); 617 | if (items == NULL) { 618 | return; 619 | } 620 | if (ib_array_size(items) > 0) { 621 | PathItem *item = ib_array_obj(items, PathItem*, 0); 622 | printf("%s\n", item->path->ptr); 623 | } 624 | ib_array_delete(items); 625 | } 626 | 627 | 628 | //--------------------------------------------------------------------- 629 | // main entry 630 | //--------------------------------------------------------------------- 631 | int main(int argc, const char *argv[]) 632 | { 633 | if (argc <= 1) { 634 | return 0; 635 | } 636 | if (strcmp(argv[1], "--add") == 0) { 637 | if (argc >= 3) { 638 | #if 0 639 | z_add(argv[2]); 640 | #else 641 | z_update(argv[2]); 642 | #endif 643 | } 644 | } 645 | else if (strcmp(argv[1], "-e") == 0) { 646 | z_echo(argc - 2, argv + 2); 647 | } 648 | return 0; 649 | } 650 | 651 | 652 | -------------------------------------------------------------------------------- /czmod.fish: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env fish 2 | 3 | set SCRIPTPATH (realpath (dirname (status -f))) 4 | set CZMODPATH "$SCRIPTPATH/czmod" 5 | 6 | if [ ! -x "$CZMODPATH" ] 7 | set SCRIPTPATH (readlink """$argv[1]""") 8 | set SCRIPTPATH (cd "(dirname "$SCRIPTPATH")" >/dev/null 2>&1; pwd -P) 9 | set CZMODPATH "$SCRIPTPATH/czmod" 10 | end 11 | 12 | if [ ! -x "$CZMODPATH" ] 13 | set CZMODPATH (which czmod 2> /dev/null) 14 | end 15 | 16 | if [ ! -x "$CZMODPATH" ] 17 | echo "Error: Unable to find czmod executable on your \$PATH" 18 | exit 1 19 | end 20 | 21 | function _zlua_precmd --on-event fish_prompt 22 | "$CZMODPATH" --add "$PWD" 2> /dev/null & 23 | end 24 | -------------------------------------------------------------------------------- /czmod.zsh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/zsh 2 | 3 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 4 | CZMODPATH="$SCRIPTPATH/czmod" 5 | 6 | if [ ! -x "$CZMODPATH" ]; then 7 | SCRIPTPATH="$(readlink """$0""")" 8 | SCRIPTPATH="$( cd "$(dirname "$SCRIPTPATH")" >/dev/null 2>&1 ; pwd -P )" 9 | CZMODPATH="$SCRIPTPATH/czmod" 10 | fi 11 | 12 | if [ ! -x "$CZMODPATH" ]; then 13 | CZMODPATH="$(which czmod 2> /dev/null)" 14 | fi 15 | 16 | if [ ! -x "$CZMODPATH" ]; then 17 | echo "Error: not find czmod executable in your PATH !!" 18 | return 19 | fi 20 | 21 | _zlua_precmd() { 22 | ("$CZMODPATH" --add "${PWD:a}" &) 23 | } 24 | 25 | 26 | -------------------------------------------------------------------------------- /system/imembase.c: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * 3 | * imembase.c - basic interface of memory operation 4 | * skywind3000 (at) gmail.com, 2006-2016 5 | * 6 | **********************************************************************/ 7 | 8 | #include "imembase.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | #if (defined(__BORLANDC__) || defined(__WATCOMC__)) 17 | #if defined(_WIN32) || defined(WIN32) 18 | #pragma warn -8002 19 | #pragma warn -8004 20 | #pragma warn -8008 21 | #pragma warn -8012 22 | #pragma warn -8027 23 | #pragma warn -8057 24 | #pragma warn -8066 25 | #endif 26 | #endif 27 | 28 | 29 | /*====================================================================*/ 30 | /* IALLOCATOR */ 31 | /*====================================================================*/ 32 | void *(*__ihook_malloc)(size_t size) = NULL; 33 | void (*__ihook_free)(void *) = NULL; 34 | void *(*__ihook_realloc)(void *, size_t size) = NULL; 35 | 36 | 37 | void* internal_malloc(struct IALLOCATOR *allocator, size_t size) 38 | { 39 | if (allocator != NULL) { 40 | return allocator->alloc(allocator, size); 41 | } 42 | if (__ihook_malloc != NULL) { 43 | return __ihook_malloc(size); 44 | } 45 | return malloc(size); 46 | } 47 | 48 | void internal_free(struct IALLOCATOR *allocator, void *ptr) 49 | { 50 | if (allocator != NULL) { 51 | allocator->free(allocator, ptr); 52 | return; 53 | } 54 | if (__ihook_free != NULL) { 55 | __ihook_free(ptr); 56 | return; 57 | } 58 | free(ptr); 59 | } 60 | 61 | void* internal_realloc(struct IALLOCATOR *allocator, void *ptr, size_t size) 62 | { 63 | if (allocator != NULL) { 64 | return allocator->realloc(allocator, ptr, size); 65 | } 66 | if (__ihook_realloc != NULL) { 67 | return __ihook_realloc(ptr, size); 68 | } 69 | return realloc(ptr, size); 70 | } 71 | 72 | 73 | /*====================================================================*/ 74 | /* IKMEM INTERFACE */ 75 | /*====================================================================*/ 76 | #ifndef IKMEM_ALLOCATOR 77 | #define IKMEM_ALLOCATOR NULL 78 | #endif 79 | 80 | struct IALLOCATOR *ikmem_allocator = IKMEM_ALLOCATOR; 81 | 82 | 83 | void* ikmem_malloc(size_t size) 84 | { 85 | return internal_malloc(ikmem_allocator, size); 86 | } 87 | 88 | void* ikmem_realloc(void *ptr, size_t size) 89 | { 90 | return internal_realloc(ikmem_allocator, ptr, size); 91 | } 92 | 93 | void ikmem_free(void *ptr) 94 | { 95 | internal_free(ikmem_allocator, ptr); 96 | } 97 | 98 | 99 | /*====================================================================*/ 100 | /* IVECTOR */ 101 | /*====================================================================*/ 102 | void iv_init(struct IVECTOR *v, struct IALLOCATOR *allocator) 103 | { 104 | if (v == 0) return; 105 | v->data = 0; 106 | v->size = 0; 107 | v->capacity = 0; 108 | v->allocator = allocator; 109 | } 110 | 111 | void iv_destroy(struct IVECTOR *v) 112 | { 113 | if (v == NULL) return; 114 | if (v->data) { 115 | internal_free(v->allocator, v->data); 116 | } 117 | v->data = NULL; 118 | v->size = 0; 119 | v->capacity = 0; 120 | } 121 | 122 | int iv_capacity(struct IVECTOR *v, size_t newcap) 123 | { 124 | if (newcap == v->capacity) 125 | return 0; 126 | if (newcap == 0) { 127 | if (v->capacity > 0) { 128 | internal_free(v->allocator, v->data); 129 | } 130 | v->data = NULL; 131 | v->capacity = 0; 132 | v->size = 0; 133 | } 134 | else { 135 | unsigned char *ptr = (unsigned char*) 136 | internal_malloc(v->allocator, newcap); 137 | if (ptr == NULL) { 138 | return -1; 139 | } 140 | if (v->data) { 141 | size_t minsize = (v->size <= newcap)? v->size : newcap; 142 | if (minsize > 0 && v->data) { 143 | memcpy(ptr, v->data, minsize); 144 | } 145 | internal_free(v->allocator, v->data); 146 | } 147 | v->data = ptr; 148 | v->capacity = newcap; 149 | if (v->size > v->capacity) { 150 | v->size = v->capacity; 151 | } 152 | } 153 | return 0; 154 | } 155 | 156 | int iv_resize(struct IVECTOR *v, size_t newsize) 157 | { 158 | if (newsize > v->capacity) { 159 | size_t capacity = v->capacity * 2; 160 | if (capacity < newsize) { 161 | capacity = sizeof(char*); 162 | while (capacity < newsize) { 163 | capacity = capacity * 2; 164 | } 165 | } 166 | if (iv_capacity(v, capacity) != 0) { 167 | return -1; 168 | } 169 | } 170 | v->size = newsize; 171 | return 0; 172 | } 173 | 174 | int iv_reserve(struct IVECTOR *v, size_t size) 175 | { 176 | return iv_capacity(v, (size >= v->size)? size : v->size); 177 | } 178 | 179 | int iv_push(struct IVECTOR *v, const void *data, size_t size) 180 | { 181 | size_t current = v->size; 182 | if (iv_resize(v, current + size) != 0) 183 | return -1; 184 | if (data != NULL) 185 | memcpy(v->data + current, data, size); 186 | return 0; 187 | } 188 | 189 | size_t iv_pop(struct IVECTOR *v, void *data, size_t size) 190 | { 191 | size_t current = v->size; 192 | if (size >= current) size = current; 193 | if (data != NULL) 194 | memcpy(data, v->data + current - size, size); 195 | iv_resize(v, current - size); 196 | return size; 197 | } 198 | 199 | int iv_insert(struct IVECTOR *v, size_t pos, const void *data, size_t size) 200 | { 201 | size_t current = v->size; 202 | if (pos > current) 203 | return -1; 204 | if (iv_resize(v, current + size) != 0) 205 | return -1; 206 | if (pos < current) { 207 | memmove(v->data + pos + size, v->data + pos, current - pos); 208 | } 209 | if (data != NULL) 210 | memcpy(v->data + pos, data, size); 211 | return 0; 212 | } 213 | 214 | int iv_erase(struct IVECTOR *v, size_t pos, size_t size) 215 | { 216 | size_t current = v->size; 217 | if (pos >= current) return 0; 218 | if (pos + size >= current) size = current - pos; 219 | if (size == 0) return 0; 220 | memmove(v->data + pos, v->data + pos + size, current - pos - size); 221 | if (iv_resize(v, current - size) != 0) 222 | return -1; 223 | return 0; 224 | } 225 | 226 | 227 | /*====================================================================*/ 228 | /* IMEMNODE */ 229 | /*====================================================================*/ 230 | void imnode_init(struct IMEMNODE *mn, ilong nodesize, struct IALLOCATOR *ac) 231 | { 232 | struct IMEMNODE *mnode = mn; 233 | 234 | assert(mnode != NULL); 235 | mnode->allocator = ac; 236 | 237 | iv_init(&mnode->vprev, ac); 238 | iv_init(&mnode->vnext, ac); 239 | iv_init(&mnode->vnode, ac); 240 | iv_init(&mnode->vdata, ac); 241 | iv_init(&mnode->vmem, ac); 242 | iv_init(&mnode->vmode, ac); 243 | 244 | nodesize = IROUND_UP(nodesize, 8); 245 | 246 | mnode->node_size = nodesize; 247 | mnode->node_free = 0; 248 | mnode->node_used = 0; 249 | mnode->node_max = 0; 250 | mnode->mem_max = 0; 251 | mnode->mem_count = 0; 252 | mnode->list_open = -1; 253 | mnode->list_close = -1; 254 | mnode->total_mem = 0; 255 | mnode->grow_limit = 0; 256 | mnode->extra = NULL; 257 | } 258 | 259 | void imnode_destroy(struct IMEMNODE *mnode) 260 | { 261 | ilong i; 262 | 263 | assert(mnode != NULL); 264 | if (mnode->mem_count > 0) { 265 | for (i = 0; i < mnode->mem_count && mnode->mmem; i++) { 266 | if (mnode->mmem[i]) { 267 | internal_free(mnode->allocator, mnode->mmem[i]); 268 | } 269 | mnode->mmem[i] = NULL; 270 | } 271 | mnode->mem_count = 0; 272 | mnode->mem_max = 0; 273 | iv_destroy(&mnode->vmem); 274 | mnode->mmem = NULL; 275 | } 276 | 277 | iv_destroy(&mnode->vprev); 278 | iv_destroy(&mnode->vnext); 279 | iv_destroy(&mnode->vnode); 280 | iv_destroy(&mnode->vdata); 281 | iv_destroy(&mnode->vmode); 282 | 283 | mnode->mprev = NULL; 284 | mnode->mnext = NULL; 285 | mnode->mnode = NULL; 286 | mnode->mdata = NULL; 287 | mnode->mmode = NULL; 288 | 289 | mnode->node_free = 0; 290 | mnode->node_used = 0; 291 | mnode->node_max = 0; 292 | mnode->list_open = -1; 293 | mnode->list_close= -1; 294 | mnode->total_mem = 0; 295 | } 296 | 297 | static int imnode_node_resize(struct IMEMNODE *mnode, ilong size) 298 | { 299 | size_t size1, size2; 300 | 301 | size1 = (size_t)(size * (ilong)sizeof(ilong)); 302 | size2 = (size_t)(size * (ilong)sizeof(void*)); 303 | 304 | if (iv_resize(&mnode->vprev, size1)) return -1; 305 | if (iv_resize(&mnode->vnext, size1)) return -2; 306 | if (iv_resize(&mnode->vnode, size1)) return -3; 307 | if (iv_resize(&mnode->vdata, size2)) return -5; 308 | if (iv_resize(&mnode->vmode, size1)) return -6; 309 | 310 | mnode->mprev = (ilong*)((void*)mnode->vprev.data); 311 | mnode->mnext = (ilong*)((void*)mnode->vnext.data); 312 | mnode->mnode = (ilong*)((void*)mnode->vnode.data); 313 | mnode->mdata =(void**)((void*)mnode->vdata.data); 314 | mnode->mmode = (ilong*)((void*)mnode->vmode.data); 315 | mnode->node_max = size; 316 | 317 | return 0; 318 | } 319 | 320 | static int imnode_mem_add(struct IMEMNODE*mnode, ilong node_count, void**mem) 321 | { 322 | size_t newsize; 323 | char *mptr; 324 | 325 | if (mnode->mem_count >= mnode->mem_max) { 326 | newsize = (mnode->mem_max <= 0)? 16 : mnode->mem_max * 2; 327 | if (iv_resize(&mnode->vmem, newsize * sizeof(void*))) 328 | return -1; 329 | mnode->mem_max = newsize; 330 | mnode->mmem = (char**)((void*)mnode->vmem.data); 331 | } 332 | newsize = node_count * mnode->node_size + 16; 333 | mptr = (char*)internal_malloc(mnode->allocator, newsize); 334 | if (mptr == NULL) return -2; 335 | 336 | mnode->mmem[mnode->mem_count++] = mptr; 337 | mnode->total_mem += newsize; 338 | mptr = (char*)IROUND_UP(((size_t)mptr), 16); 339 | 340 | if (mem) *mem = mptr; 341 | 342 | return 0; 343 | } 344 | 345 | 346 | static long imnode_grow(struct IMEMNODE *mnode) 347 | { 348 | ilong size_start = mnode->node_max; 349 | ilong size_endup; 350 | ilong retval, count, i, j; 351 | void *mptr; 352 | char *p; 353 | 354 | count = (mnode->node_max <= 0)? 8 : mnode->node_max; 355 | if (mnode->grow_limit > 0) { 356 | if (count > mnode->grow_limit) count = mnode->grow_limit; 357 | } 358 | if (count > 4096) count = 4096; 359 | size_endup = size_start + count; 360 | 361 | retval = imnode_node_resize(mnode, size_endup); 362 | if (retval) return -10 + (long)retval; 363 | 364 | retval = imnode_mem_add(mnode, count, &mptr); 365 | 366 | if (retval) { 367 | imnode_node_resize(mnode, size_start); 368 | mnode->node_max = size_start; 369 | return -20 + (long)retval; 370 | } 371 | 372 | p = (char*)mptr; 373 | for (i = mnode->node_max - 1, j = 0; j < count; i--, j++) { 374 | IMNODE_NODE(mnode, i) = 0; 375 | IMNODE_MODE(mnode, i) = 0; 376 | IMNODE_DATA(mnode, i) = p; 377 | IMNODE_PREV(mnode, i) = -1; 378 | IMNODE_NEXT(mnode, i) = mnode->list_open; 379 | if (mnode->list_open >= 0) IMNODE_PREV(mnode, mnode->list_open) = i; 380 | mnode->list_open = i; 381 | mnode->node_free++; 382 | p += mnode->node_size; 383 | } 384 | 385 | return 0; 386 | } 387 | 388 | 389 | ilong imnode_new(struct IMEMNODE *mnode) 390 | { 391 | ilong node, next; 392 | 393 | assert(mnode); 394 | if (mnode->list_open < 0) { 395 | if (imnode_grow(mnode)) return -2; 396 | } 397 | 398 | if (mnode->list_open < 0 || mnode->node_free <= 0) return -3; 399 | 400 | node = mnode->list_open; 401 | next = IMNODE_NEXT(mnode, node); 402 | if (next >= 0) IMNODE_PREV(mnode, next) = -1; 403 | mnode->list_open = next; 404 | 405 | IMNODE_PREV(mnode, node) = -1; 406 | IMNODE_NEXT(mnode, node) = mnode->list_close; 407 | 408 | if (mnode->list_close >= 0) IMNODE_PREV(mnode, mnode->list_close) = node; 409 | mnode->list_close = node; 410 | IMNODE_MODE(mnode, node) = 1; 411 | 412 | mnode->node_free--; 413 | mnode->node_used++; 414 | 415 | return node; 416 | } 417 | 418 | void imnode_del(struct IMEMNODE *mnode, ilong index) 419 | { 420 | ilong prev, next; 421 | 422 | assert(mnode); 423 | assert((index >= 0) && (index < mnode->node_max)); 424 | assert(IMNODE_MODE(mnode, index) != 0); 425 | 426 | next = IMNODE_NEXT(mnode, index); 427 | prev = IMNODE_PREV(mnode, index); 428 | 429 | if (next >= 0) IMNODE_PREV(mnode, next) = prev; 430 | if (prev >= 0) IMNODE_NEXT(mnode, prev) = next; 431 | else mnode->list_close = next; 432 | 433 | IMNODE_PREV(mnode, index) = -1; 434 | IMNODE_NEXT(mnode, index) = mnode->list_open; 435 | 436 | if (mnode->list_open >= 0) IMNODE_PREV(mnode, mnode->list_open) = index; 437 | mnode->list_open = index; 438 | 439 | IMNODE_MODE(mnode, index) = 0; 440 | mnode->node_free++; 441 | mnode->node_used--; 442 | } 443 | 444 | ilong imnode_head(const struct IMEMNODE *mnode) 445 | { 446 | return (mnode)? mnode->list_close : -1; 447 | } 448 | 449 | ilong imnode_next(const struct IMEMNODE *mnode, ilong index) 450 | { 451 | return (mnode)? IMNODE_NEXT(mnode, index) : -1; 452 | } 453 | 454 | ilong imnode_prev(const struct IMEMNODE *mnode, ilong index) 455 | { 456 | return (mnode)? IMNODE_PREV(mnode, index) : -1; 457 | } 458 | 459 | void *imnode_data(struct IMEMNODE *mnode, ilong index) 460 | { 461 | return (char*)IMNODE_DATA(mnode, index); 462 | } 463 | 464 | const void* imnode_data_const(const struct IMEMNODE *mnode, ilong index) 465 | { 466 | return (const char*)IMNODE_DATA(mnode, index); 467 | } 468 | 469 | 470 | 471 | 472 | /*====================================================================*/ 473 | /* IVECTOR / IMEMNODE MANAGEMENT */ 474 | /*====================================================================*/ 475 | 476 | ib_vector *iv_create(void) 477 | { 478 | ib_vector *vec; 479 | vec = (ib_vector*)ikmem_malloc(sizeof(ib_vector)); 480 | if (vec == NULL) return NULL; 481 | iv_init(vec, ikmem_allocator); 482 | return vec; 483 | } 484 | 485 | void iv_delete(ib_vector *vec) 486 | { 487 | assert(vec); 488 | iv_destroy(vec); 489 | ikmem_free(vec); 490 | } 491 | 492 | ib_memnode *imnode_create(ilong nodesize, int grow_limit) 493 | { 494 | ib_memnode *mnode; 495 | mnode = (ib_memnode*)ikmem_malloc(sizeof(ib_memnode)); 496 | if (mnode == NULL) return NULL; 497 | imnode_init(mnode, nodesize, ikmem_allocator); 498 | mnode->grow_limit = grow_limit; 499 | return mnode; 500 | } 501 | 502 | void imnode_delete(ib_memnode *mnode) 503 | { 504 | assert(mnode); 505 | imnode_destroy(mnode); 506 | ikmem_free(mnode); 507 | } 508 | 509 | 510 | /*--------------------------------------------------------------------*/ 511 | /* Collection - Array */ 512 | /*--------------------------------------------------------------------*/ 513 | 514 | struct ib_array 515 | { 516 | struct IVECTOR vec; 517 | void (*fn_destroy)(void*); 518 | size_t size; 519 | void **items; 520 | }; 521 | 522 | ib_array *ib_array_new(void (*destroy_func)(void*)) 523 | { 524 | ib_array *array = (ib_array*)ikmem_malloc(sizeof(ib_array)); 525 | if (array == NULL) return NULL; 526 | iv_init(&array->vec, ikmem_allocator); 527 | array->fn_destroy = destroy_func; 528 | array->size = 0; 529 | return array; 530 | }; 531 | 532 | 533 | void ib_array_delete(ib_array *array) 534 | { 535 | if (array->fn_destroy) { 536 | size_t n = array->size; 537 | size_t i; 538 | for (i = 0; i < n; i++) { 539 | array->fn_destroy(array->items[i]); 540 | array->items[i] = NULL; 541 | } 542 | } 543 | iv_destroy(&array->vec); 544 | array->size = 0; 545 | array->items = NULL; 546 | ikmem_free(array); 547 | } 548 | 549 | static void ib_array_update(ib_array *array) 550 | { 551 | array->items = (void**)array->vec.data; 552 | } 553 | 554 | void ib_array_reserve(ib_array *array, size_t new_size) 555 | { 556 | int hr = iv_obj_reserve(&array->vec, char*, new_size); 557 | if (hr != 0) { 558 | assert(hr == 0); 559 | } 560 | ib_array_update(array); 561 | } 562 | 563 | size_t ib_array_size(const ib_array *array) 564 | { 565 | return array->size; 566 | } 567 | 568 | void** ib_array_ptr(ib_array *array) 569 | { 570 | return array->items; 571 | } 572 | 573 | void* ib_array_index(ib_array *array, size_t index) 574 | { 575 | assert(index < array->size); 576 | return array->items[index]; 577 | } 578 | 579 | const void* ib_array_const_index(const ib_array *array, size_t index) 580 | { 581 | assert(index < array->size); 582 | return array->items[index]; 583 | } 584 | 585 | void ib_array_push(ib_array *array, void *item) 586 | { 587 | int hr = iv_obj_push(&array->vec, void*, &item); 588 | if (hr) { 589 | assert(hr == 0); 590 | } 591 | ib_array_update(array); 592 | array->size++; 593 | } 594 | 595 | void ib_array_push_left(ib_array *array, void *item) 596 | { 597 | int hr = iv_obj_insert(&array->vec, void*, 0, &item); 598 | if (hr) { 599 | assert(hr == 0); 600 | } 601 | ib_array_update(array); 602 | array->size++; 603 | } 604 | 605 | void ib_array_replace(ib_array *array, size_t index, void *item) 606 | { 607 | assert(index < array->size); 608 | if (array->fn_destroy) { 609 | array->fn_destroy(array->items[index]); 610 | } 611 | array->items[index] = item; 612 | } 613 | 614 | void* ib_array_pop(ib_array *array) 615 | { 616 | void *item; 617 | int hr; 618 | assert(array->size > 0); 619 | array->size--; 620 | item = array->items[array->size]; 621 | hr = iv_obj_resize(&array->vec, void*, array->size); 622 | ib_array_update(array); 623 | if (hr) { 624 | assert(hr == 0); 625 | } 626 | return item; 627 | } 628 | 629 | void* ib_array_pop_left(ib_array *array) 630 | { 631 | void *item; 632 | int hr; 633 | assert(array->size > 0); 634 | array->size--; 635 | item = array->items[0]; 636 | hr = iv_obj_erase(&array->vec, void*, 0, 1); 637 | ib_array_update(array); 638 | if (hr) { 639 | assert(hr == 0); 640 | } 641 | return item; 642 | } 643 | 644 | void ib_array_remove(ib_array *array, size_t index) 645 | { 646 | assert(index < array->size); 647 | if (array->fn_destroy) { 648 | array->fn_destroy(array->items[index]); 649 | } 650 | iv_obj_erase(&array->vec, void*, index, 1); 651 | ib_array_update(array); 652 | array->size--; 653 | } 654 | 655 | void ib_array_insert_before(ib_array *array, size_t index, void *item) 656 | { 657 | int hr = iv_obj_insert(&array->vec, void*, index, &item); 658 | if (hr) { 659 | assert(hr == 0); 660 | } 661 | ib_array_update(array); 662 | array->size++; 663 | } 664 | 665 | void* ib_array_pop_at(ib_array *array, size_t index) 666 | { 667 | void *item; 668 | int hr; 669 | assert(array->size > 0); 670 | item = array->items[index]; 671 | hr = iv_obj_erase(&array->vec, void*, index, 1); 672 | if (hr) { 673 | assert(hr == 0); 674 | } 675 | return item; 676 | } 677 | 678 | void ib_array_reverse(ib_array *array) 679 | { 680 | if (array->size > 0) { 681 | void **items = array->items; 682 | size_t size = array->size; 683 | size_t i, j; 684 | for (i = 0, j = size - 1; i < j; i++, j--) { 685 | void *tmp = items[i]; 686 | items[i] = items[j]; 687 | items[j] = tmp; 688 | } 689 | } 690 | } 691 | 692 | void ib_array_sort(ib_array *array, 693 | int (*compare)(const void*, const void*)) 694 | { 695 | if (array->size) { 696 | void **items = array->items; 697 | size_t size = array->size; 698 | size_t i, j; 699 | for (i = 0; i < size - 1; i++) { 700 | for (j = i + 1; j < size; j++) { 701 | if (compare(items[i], items[j]) > 0) { 702 | void *tmp = items[i]; 703 | items[i] = items[j]; 704 | items[j] = tmp; 705 | } 706 | } 707 | } 708 | } 709 | } 710 | 711 | void ib_array_for_each(ib_array *array, void (*iterator)(void *item)) 712 | { 713 | if (iterator) { 714 | void **items = array->items; 715 | size_t count = array->size; 716 | for (; count > 0; count--, items++) { 717 | iterator(items[0]); 718 | } 719 | } 720 | } 721 | 722 | ilong ib_array_search(const ib_array *array, 723 | int (*compare)(const void*, const void*), 724 | const void *item, 725 | ilong start_pos) 726 | { 727 | ilong size = (ilong)array->size; 728 | void **items = array->items; 729 | if (start_pos < 0) { 730 | start_pos = 0; 731 | } 732 | for (items = items + start_pos; start_pos < size; start_pos++) { 733 | if (compare(items[0], item) == 0) { 734 | return start_pos; 735 | } 736 | items++; 737 | } 738 | return -1; 739 | } 740 | 741 | ilong ib_array_bsearch(const ib_array *array, 742 | int (*compare)(const void*, const void*), 743 | const void *item) 744 | { 745 | ilong top, bottom, mid; 746 | void **items = array->items; 747 | if (array->size == 0) return -1; 748 | top = 0; 749 | bottom = (ilong)array->size - 1; 750 | while (1) { 751 | int hr; 752 | mid = (top + bottom) >> 1; 753 | hr = compare(item, items[mid]); 754 | if (hr < 0) bottom = mid; 755 | else if (hr > 0) top = mid; 756 | else return mid; 757 | if (top == bottom) break; 758 | } 759 | return -1; 760 | } 761 | 762 | 763 | 764 | /*====================================================================*/ 765 | /* Binary Search Tree */ 766 | /*====================================================================*/ 767 | 768 | struct ib_node *ib_node_first(struct ib_root *root) 769 | { 770 | struct ib_node *node = root->node; 771 | if (node == NULL) return NULL; 772 | while (node->left) 773 | node = node->left; 774 | return node; 775 | } 776 | 777 | struct ib_node *ib_node_last(struct ib_root *root) 778 | { 779 | struct ib_node *node = root->node; 780 | if (node == NULL) return NULL; 781 | while (node->right) 782 | node = node->right; 783 | return node; 784 | } 785 | 786 | struct ib_node *ib_node_next(struct ib_node *node) 787 | { 788 | if (node == NULL) return NULL; 789 | if (node->right) { 790 | node = node->right; 791 | while (node->left) 792 | node = node->left; 793 | } 794 | else { 795 | while (1) { 796 | struct ib_node *last = node; 797 | node = node->parent; 798 | if (node == NULL) break; 799 | if (node->left == last) break; 800 | } 801 | } 802 | return node; 803 | } 804 | 805 | struct ib_node *ib_node_prev(struct ib_node *node) 806 | { 807 | if (node == NULL) return NULL; 808 | if (node->left) { 809 | node = node->left; 810 | while (node->right) 811 | node = node->right; 812 | } 813 | else { 814 | while (1) { 815 | struct ib_node *last = node; 816 | node = node->parent; 817 | if (node == NULL) break; 818 | if (node->right == last) break; 819 | } 820 | } 821 | return node; 822 | } 823 | 824 | static inline void 825 | _ib_child_replace(struct ib_node *oldnode, struct ib_node *newnode, 826 | struct ib_node *parent, struct ib_root *root) 827 | { 828 | if (parent) { 829 | if (parent->left == oldnode) 830 | parent->left = newnode; 831 | else 832 | parent->right = newnode; 833 | } else { 834 | root->node = newnode; 835 | } 836 | } 837 | 838 | static inline struct ib_node * 839 | _ib_node_rotate_left(struct ib_node *node, struct ib_root *root) 840 | { 841 | struct ib_node *right = node->right; 842 | struct ib_node *parent = node->parent; 843 | node->right = right->left; 844 | ASSERTION(node && right); 845 | if (right->left) 846 | right->left->parent = node; 847 | right->left = node; 848 | right->parent = parent; 849 | _ib_child_replace(node, right, parent, root); 850 | node->parent = right; 851 | return right; 852 | } 853 | 854 | static inline struct ib_node * 855 | _ib_node_rotate_right(struct ib_node *node, struct ib_root *root) 856 | { 857 | struct ib_node *left = node->left; 858 | struct ib_node *parent = node->parent; 859 | node->left = left->right; 860 | ASSERTION(node && left); 861 | if (left->right) 862 | left->right->parent = node; 863 | left->right = node; 864 | left->parent = parent; 865 | _ib_child_replace(node, left, parent, root); 866 | node->parent = left; 867 | return left; 868 | } 869 | 870 | void ib_node_replace(struct ib_node *victim, struct ib_node *newnode, 871 | struct ib_root *root) 872 | { 873 | struct ib_node *parent = victim->parent; 874 | _ib_child_replace(victim, newnode, parent, root); 875 | if (victim->left) victim->left->parent = newnode; 876 | if (victim->right) victim->right->parent = newnode; 877 | newnode->left = victim->left; 878 | newnode->right = victim->right; 879 | newnode->parent = victim->parent; 880 | newnode->height = victim->height; 881 | } 882 | 883 | 884 | /*--------------------------------------------------------------------*/ 885 | /* avl - node manipulation */ 886 | /*--------------------------------------------------------------------*/ 887 | 888 | static inline int IB_MAX(int x, int y) 889 | { 890 | #if 1 891 | return (x < y)? y : x; /* this is faster with cmov on x86 */ 892 | #else 893 | return x - ((x - y) & ((x - y) >> (sizeof(int) * 8 - 1))); 894 | #endif 895 | } 896 | 897 | static inline void 898 | _ib_node_height_update(struct ib_node *node) 899 | { 900 | int h0 = IB_LEFT_HEIGHT(node); 901 | int h1 = IB_RIGHT_HEIGHT(node); 902 | node->height = IB_MAX(h0, h1) + 1; 903 | } 904 | 905 | static inline struct ib_node * 906 | _ib_node_fix_l(struct ib_node *node, struct ib_root *root) 907 | { 908 | struct ib_node *right = node->right; 909 | int rh0, rh1; 910 | ASSERTION(right); 911 | rh0 = IB_LEFT_HEIGHT(right); 912 | rh1 = IB_RIGHT_HEIGHT(right); 913 | if (rh0 > rh1) { 914 | right = _ib_node_rotate_right(right, root); 915 | _ib_node_height_update(right->right); 916 | _ib_node_height_update(right); 917 | /* _ib_node_height_update(node); */ 918 | } 919 | node = _ib_node_rotate_left(node, root); 920 | _ib_node_height_update(node->left); 921 | _ib_node_height_update(node); 922 | return node; 923 | } 924 | 925 | static inline struct ib_node * 926 | _ib_node_fix_r(struct ib_node *node, struct ib_root *root) 927 | { 928 | struct ib_node *left = node->left; 929 | int rh0, rh1; 930 | ASSERTION(left); 931 | rh0 = IB_LEFT_HEIGHT(left); 932 | rh1 = IB_RIGHT_HEIGHT(left); 933 | if (rh0 < rh1) { 934 | left = _ib_node_rotate_left(left, root); 935 | _ib_node_height_update(left->left); 936 | _ib_node_height_update(left); 937 | /* _ib_node_height_update(node); */ 938 | } 939 | node = _ib_node_rotate_right(node, root); 940 | _ib_node_height_update(node->right); 941 | _ib_node_height_update(node); 942 | return node; 943 | } 944 | 945 | static inline void 946 | _ib_node_rebalance(struct ib_node *node, struct ib_root *root) 947 | { 948 | while (node) { 949 | int h0 = (int)IB_LEFT_HEIGHT(node); 950 | int h1 = (int)IB_RIGHT_HEIGHT(node); 951 | int diff = h0 - h1; 952 | int height = IB_MAX(h0, h1) + 1; 953 | if (node->height != height) { 954 | node->height = height; 955 | } 956 | else if (diff >= -1 && diff <= 1) { 957 | break; 958 | } 959 | if (diff <= -2) { 960 | node = _ib_node_fix_l(node, root); 961 | } 962 | else if (diff >= 2) { 963 | node = _ib_node_fix_r(node, root); 964 | } 965 | node = node->parent; 966 | } 967 | } 968 | 969 | void ib_node_post_insert(struct ib_node *node, struct ib_root *root) 970 | { 971 | node->height = 1; 972 | 973 | for (node = node->parent; node; node = node->parent) { 974 | int h0 = (int)IB_LEFT_HEIGHT(node); 975 | int h1 = (int)IB_RIGHT_HEIGHT(node); 976 | int height = IB_MAX(h0, h1) + 1; 977 | int diff = h0 - h1; 978 | if (node->height == height) break; 979 | node->height = height; 980 | if (diff <= -2) { 981 | node = _ib_node_fix_l(node, root); 982 | } 983 | else if (diff >= 2) { 984 | node = _ib_node_fix_r(node, root); 985 | } 986 | } 987 | } 988 | 989 | void ib_node_erase(struct ib_node *node, struct ib_root *root) 990 | { 991 | struct ib_node *child, *parent; 992 | ASSERTION(node); 993 | if (node->left && node->right) { 994 | struct ib_node *old = node; 995 | struct ib_node *left; 996 | node = node->right; 997 | while ((left = node->left) != NULL) 998 | node = left; 999 | child = node->right; 1000 | parent = node->parent; 1001 | if (child) { 1002 | child->parent = parent; 1003 | } 1004 | _ib_child_replace(node, child, parent, root); 1005 | if (node->parent == old) 1006 | parent = node; 1007 | node->left = old->left; 1008 | node->right = old->right; 1009 | node->parent = old->parent; 1010 | node->height = old->height; 1011 | _ib_child_replace(old, node, old->parent, root); 1012 | ASSERTION(old->left); 1013 | old->left->parent = node; 1014 | if (old->right) { 1015 | old->right->parent = node; 1016 | } 1017 | } 1018 | else { 1019 | if (node->left == NULL) 1020 | child = node->right; 1021 | else 1022 | child = node->left; 1023 | parent = node->parent; 1024 | _ib_child_replace(node, child, parent, root); 1025 | if (child) { 1026 | child->parent = parent; 1027 | } 1028 | } 1029 | if (parent) { 1030 | _ib_node_rebalance(parent, root); 1031 | } 1032 | } 1033 | 1034 | 1035 | /* avl nodes destroy: fast tear down the whole tree */ 1036 | struct ib_node* ib_node_tear(struct ib_root *root, struct ib_node **next) 1037 | { 1038 | struct ib_node *node = *next; 1039 | struct ib_node *parent; 1040 | if (node == NULL) { 1041 | if (root->node == NULL) 1042 | return NULL; 1043 | node = root->node; 1044 | } 1045 | /* sink down to the leaf */ 1046 | while (1) { 1047 | if (node->left) node = node->left; 1048 | else if (node->right) node = node->right; 1049 | else break; 1050 | } 1051 | /* tear down one leaf */ 1052 | parent = node->parent; 1053 | if (parent == NULL) { 1054 | *next = NULL; 1055 | root->node = NULL; 1056 | return node; 1057 | } 1058 | if (parent->left == node) { 1059 | parent->left = NULL; 1060 | } else { 1061 | parent->right = NULL; 1062 | } 1063 | node->height = 0; 1064 | *next = parent; 1065 | return node; 1066 | } 1067 | 1068 | 1069 | 1070 | /*--------------------------------------------------------------------*/ 1071 | /* avltree - friendly interface */ 1072 | /*--------------------------------------------------------------------*/ 1073 | 1074 | void ib_tree_init(struct ib_tree *tree, 1075 | int (*compare)(const void*, const void*), size_t size, size_t offset) 1076 | { 1077 | tree->root.node = NULL; 1078 | tree->offset = offset; 1079 | tree->size = size; 1080 | tree->count = 0; 1081 | tree->compare = compare; 1082 | } 1083 | 1084 | 1085 | void *ib_tree_first(struct ib_tree *tree) 1086 | { 1087 | struct ib_node *node = ib_node_first(&tree->root); 1088 | if (!node) return NULL; 1089 | return IB_NODE2DATA(node, tree->offset); 1090 | } 1091 | 1092 | void *ib_tree_last(struct ib_tree *tree) 1093 | { 1094 | struct ib_node *node = ib_node_last(&tree->root); 1095 | if (!node) return NULL; 1096 | return IB_NODE2DATA(node, tree->offset); 1097 | } 1098 | 1099 | void *ib_tree_next(struct ib_tree *tree, void *data) 1100 | { 1101 | struct ib_node *nn; 1102 | if (!data) return NULL; 1103 | nn = IB_DATA2NODE(data, tree->offset); 1104 | nn = ib_node_next(nn); 1105 | if (!nn) return NULL; 1106 | return IB_NODE2DATA(nn, tree->offset); 1107 | } 1108 | 1109 | void *ib_tree_prev(struct ib_tree *tree, void *data) 1110 | { 1111 | struct ib_node *nn; 1112 | if (!data) return NULL; 1113 | nn = IB_DATA2NODE(data, tree->offset); 1114 | nn = ib_node_prev(nn); 1115 | if (!nn) return NULL; 1116 | return IB_NODE2DATA(nn, tree->offset); 1117 | } 1118 | 1119 | 1120 | /* require a temporary user structure (data) which contains the key */ 1121 | void *ib_tree_find(struct ib_tree *tree, const void *data) 1122 | { 1123 | struct ib_node *n = tree->root.node; 1124 | int (*compare)(const void*, const void*) = tree->compare; 1125 | int offset = (int)(tree->offset); 1126 | while (n) { 1127 | void *nd = IB_NODE2DATA(n, offset); 1128 | int hr = compare(data, nd); 1129 | if (hr == 0) { 1130 | return nd; 1131 | } 1132 | else if (hr < 0) { 1133 | n = n->left; 1134 | } 1135 | else { 1136 | n = n->right; 1137 | } 1138 | } 1139 | return NULL; 1140 | } 1141 | 1142 | void *ib_tree_nearest(struct ib_tree *tree, const void *data) 1143 | { 1144 | struct ib_node *n = tree->root.node; 1145 | struct ib_node *p = NULL; 1146 | int (*compare)(const void*, const void*) = tree->compare; 1147 | int offset = (int)(tree->offset); 1148 | while (n) { 1149 | void *nd = IB_NODE2DATA(n, offset); 1150 | int hr = compare(data, nd); 1151 | p = n; 1152 | if (n == 0) return nd; 1153 | else if (hr < 0) { 1154 | n = n->left; 1155 | } 1156 | else { 1157 | n = n->right; 1158 | } 1159 | } 1160 | return (p)? IB_NODE2DATA(p, offset) : NULL; 1161 | } 1162 | 1163 | 1164 | /* returns NULL for success, otherwise returns conflict node with same key */ 1165 | void *ib_tree_add(struct ib_tree *tree, void *data) 1166 | { 1167 | struct ib_node **link = &tree->root.node; 1168 | struct ib_node *parent = NULL; 1169 | struct ib_node *node = IB_DATA2NODE(data, tree->offset); 1170 | int (*compare)(const void*, const void*) = tree->compare; 1171 | int offset = (int)(tree->offset); 1172 | while (link[0]) { 1173 | void *pd; 1174 | int hr; 1175 | parent = link[0]; 1176 | pd = IB_NODE2DATA(parent, offset); 1177 | hr = compare(data, pd); 1178 | if (hr == 0) { 1179 | return pd; 1180 | } 1181 | else if (hr < 0) { 1182 | link = &(parent->left); 1183 | } 1184 | else { 1185 | link = &(parent->right); 1186 | } 1187 | } 1188 | ib_node_link(node, parent, link); 1189 | ib_node_post_insert(node, &tree->root); 1190 | tree->count++; 1191 | return NULL; 1192 | } 1193 | 1194 | 1195 | void ib_tree_remove(struct ib_tree *tree, void *data) 1196 | { 1197 | struct ib_node *node = IB_DATA2NODE(data, tree->offset); 1198 | if (!ib_node_empty(node)) { 1199 | ib_node_erase(node, &tree->root); 1200 | node->parent = node; 1201 | tree->count--; 1202 | } 1203 | } 1204 | 1205 | 1206 | void ib_tree_replace(struct ib_tree *tree, void *victim, void *newdata) 1207 | { 1208 | struct ib_node *vicnode = IB_DATA2NODE(victim, tree->offset); 1209 | struct ib_node *newnode = IB_DATA2NODE(newdata, tree->offset); 1210 | ib_node_replace(vicnode, newnode, &tree->root); 1211 | vicnode->parent = vicnode; 1212 | } 1213 | 1214 | 1215 | void ib_tree_clear(struct ib_tree *tree, void (*destroy)(void *data)) 1216 | { 1217 | while (1) { 1218 | void *data; 1219 | if (tree->root.node == NULL) break; 1220 | data = IB_NODE2DATA(tree->root.node, tree->offset); 1221 | ib_tree_remove(tree, data); 1222 | if (destroy) destroy(data); 1223 | } 1224 | } 1225 | 1226 | 1227 | /*--------------------------------------------------------------------*/ 1228 | /* fastbin - fixed size object allocator */ 1229 | /*--------------------------------------------------------------------*/ 1230 | 1231 | void ib_fastbin_init(struct ib_fastbin *fb, size_t obj_size) 1232 | { 1233 | const size_t align = sizeof(void*); 1234 | size_t need; 1235 | fb->start = NULL; 1236 | fb->endup = NULL; 1237 | fb->next = NULL; 1238 | fb->pages = NULL; 1239 | fb->obj_size = (obj_size + align - 1) & (~(align - 1)); 1240 | need = fb->obj_size * 32 + sizeof(void*) + 16; 1241 | fb->page_size = (align <= 2)? 8 : 32; 1242 | while (fb->page_size < need) { 1243 | fb->page_size *= 2; 1244 | } 1245 | fb->maximum = (align <= 2)? fb->page_size : 0x10000; 1246 | } 1247 | 1248 | void ib_fastbin_destroy(struct ib_fastbin *fb) 1249 | { 1250 | while (fb->pages) { 1251 | void *page = fb->pages; 1252 | void *next = IB_NEXT(page); 1253 | fb->pages = next; 1254 | ikmem_free(page); 1255 | } 1256 | fb->start = NULL; 1257 | fb->endup = NULL; 1258 | fb->next = NULL; 1259 | fb->pages = NULL; 1260 | } 1261 | 1262 | void* ib_fastbin_new(struct ib_fastbin *fb) 1263 | { 1264 | size_t obj_size = fb->obj_size; 1265 | void *obj; 1266 | obj = fb->next; 1267 | if (obj) { 1268 | fb->next = IB_NEXT(fb->next); 1269 | return obj; 1270 | } 1271 | if (fb->start + obj_size > fb->endup) { 1272 | char *page = (char*)ikmem_malloc(fb->page_size); 1273 | size_t lineptr = (size_t)page; 1274 | ASSERTION(page); 1275 | IB_NEXT(page) = fb->pages; 1276 | fb->pages = page; 1277 | lineptr = (lineptr + sizeof(void*) + 15) & (~15); 1278 | fb->start = (char*)lineptr; 1279 | fb->endup = (char*)page + fb->page_size; 1280 | if (fb->page_size < fb->maximum) { 1281 | fb->page_size *= 2; 1282 | } 1283 | } 1284 | obj = fb->start; 1285 | fb->start += obj_size; 1286 | ASSERTION(fb->start <= fb->endup); 1287 | return obj; 1288 | } 1289 | 1290 | void ib_fastbin_del(struct ib_fastbin *fb, void *ptr) 1291 | { 1292 | IB_NEXT(ptr) = fb->next; 1293 | fb->next = ptr; 1294 | } 1295 | 1296 | 1297 | /*--------------------------------------------------------------------*/ 1298 | /* string */ 1299 | /*--------------------------------------------------------------------*/ 1300 | 1301 | ib_string* ib_string_new(void) 1302 | { 1303 | struct ib_string* str = (ib_string*)ikmem_malloc(sizeof(ib_string)); 1304 | assert(str); 1305 | str->ptr = str->sso; 1306 | str->size = 0; 1307 | str->capacity = IB_STRING_SSO; 1308 | str->ptr[0] = 0; 1309 | return str; 1310 | } 1311 | 1312 | 1313 | void ib_string_delete(ib_string *str) 1314 | { 1315 | assert(str); 1316 | if (str) { 1317 | if (str->ptr && str->ptr != str->sso) 1318 | ikmem_free(str->ptr); 1319 | str->ptr = NULL; 1320 | str->size = str->capacity = 0; 1321 | } 1322 | ikmem_free(str); 1323 | } 1324 | 1325 | ib_string* ib_string_new_size(const char *text, int size) 1326 | { 1327 | struct ib_string *str = ib_string_new(); 1328 | size = (size > 0)? size : 0; 1329 | if (size > 0 && text) { 1330 | ib_string_resize(str, size); 1331 | memcpy(str->ptr, text, size); 1332 | } 1333 | return str; 1334 | } 1335 | 1336 | ib_string* ib_string_new_from(const char *text) 1337 | { 1338 | return ib_string_new_size(text, (text)? ((int)strlen(text)) : 0); 1339 | } 1340 | 1341 | static void _ib_string_set_capacity(ib_string *str, int capacity) 1342 | { 1343 | assert(str); 1344 | assert(capacity >= 0); 1345 | if (capacity <= IB_STRING_SSO) { 1346 | capacity = IB_STRING_SSO; 1347 | if (str->ptr != str->sso) { 1348 | if (str->size > 0) { 1349 | int csize = (str->size < capacity) ? str->size : capacity; 1350 | memcpy(str->sso, str->ptr, csize); 1351 | } 1352 | ikmem_free(str->ptr); 1353 | str->ptr = str->sso; 1354 | str->capacity = IB_STRING_SSO; 1355 | } 1356 | } 1357 | else { 1358 | char *ptr = (char*)ikmem_malloc(capacity + 2); 1359 | int csize = (capacity < str->size) ? capacity : str->size; 1360 | assert(ptr); 1361 | if (csize > 0) { 1362 | memcpy(ptr, str->ptr, csize); 1363 | } 1364 | if (str->ptr != str->sso) 1365 | ikmem_free(str->ptr); 1366 | str->ptr = ptr; 1367 | str->capacity = capacity; 1368 | } 1369 | if (str->size > str->capacity) 1370 | str->size = str->capacity; 1371 | str->ptr[str->size] = 0; 1372 | } 1373 | 1374 | ib_string* ib_string_resize(ib_string *str, int newsize) 1375 | { 1376 | assert(str && newsize >= 0); 1377 | if (newsize > str->capacity) { 1378 | int capacity = str->capacity * 2; 1379 | if (capacity < newsize) { 1380 | while (capacity < newsize) { 1381 | capacity = capacity * 2; 1382 | } 1383 | } 1384 | _ib_string_set_capacity(str, capacity); 1385 | } 1386 | str->size = newsize; 1387 | str->ptr[str->size] = 0; 1388 | return str; 1389 | } 1390 | 1391 | ib_string* ib_string_reserve(ib_string *str, int newsize) 1392 | { 1393 | int size = (newsize >= str->size)? newsize : str->size; 1394 | _ib_string_set_capacity(str, size); 1395 | return str; 1396 | } 1397 | 1398 | ib_string* ib_string_insert(ib_string *str, int pos, 1399 | const void *data, int size) 1400 | { 1401 | int current = str->size; 1402 | if (pos < 0 || pos > str->size) 1403 | return NULL; 1404 | ib_string_resize(str, str->size + size); 1405 | if (pos < current) { 1406 | memmove(str->ptr + pos + size, str->ptr + pos, current - pos); 1407 | } 1408 | if (data) { 1409 | memcpy(str->ptr + pos, data, size); 1410 | } 1411 | return str; 1412 | } 1413 | 1414 | ib_string* ib_string_insert_c(ib_string *str, int pos, char c) 1415 | { 1416 | int current = str->size; 1417 | if (pos < 0 || pos > str->size) 1418 | return NULL; 1419 | ib_string_resize(str, str->size + 1); 1420 | if (pos < current) { 1421 | memmove(str->ptr + pos + 1, str->ptr + pos, current - pos); 1422 | } 1423 | str->ptr[pos] = c; 1424 | return str; 1425 | } 1426 | 1427 | ib_string* ib_string_erase(ib_string *str, int pos, int size) 1428 | { 1429 | int current = str->size; 1430 | if (pos >= current) return 0; 1431 | if (pos + size >= current) size = current - pos; 1432 | if (size == 0) return 0; 1433 | memmove(str->ptr + pos, str->ptr + pos + size, current - pos - size); 1434 | return ib_string_resize(str, current - size); 1435 | } 1436 | 1437 | int ib_string_compare(const struct ib_string *a, const struct ib_string *b) 1438 | { 1439 | int minsize = (a->size < b->size)? a->size : b->size; 1440 | int hr = memcmp(a->ptr, b->ptr, minsize); 1441 | if (hr < 0) return -1; 1442 | else if (hr > 0) return 1; 1443 | if (a->size < b->size) return -1; 1444 | else if (a->size > b->size) return 1; 1445 | return 0; 1446 | } 1447 | 1448 | 1449 | ib_string* ib_string_assign(ib_string *str, const char *src) 1450 | { 1451 | return ib_string_assign_size(str, src, (int)strlen(src)); 1452 | } 1453 | 1454 | ib_string* ib_string_assign_size(ib_string *str, const char *src, int size) 1455 | { 1456 | assert(size >= 0); 1457 | ib_string_resize(str, size); 1458 | if (src) { 1459 | memcpy(str->ptr, src, size); 1460 | } 1461 | return str; 1462 | } 1463 | 1464 | 1465 | ib_string* ib_string_append(ib_string *str, const char *src) 1466 | { 1467 | return ib_string_append_size(str, src, (int)strlen(src)); 1468 | } 1469 | 1470 | 1471 | ib_string* ib_string_append_size(ib_string *str, const char *src, int size) 1472 | { 1473 | return ib_string_insert(str, str->size, src, size); 1474 | } 1475 | 1476 | ib_string* ib_string_append_c(ib_string *str, char c) 1477 | { 1478 | ib_string_resize(str, str->size + 1); 1479 | str->ptr[str->size - 1] = c; 1480 | return str; 1481 | } 1482 | 1483 | ib_string* ib_string_prepend(ib_string *str, const char *src) 1484 | { 1485 | return ib_string_prepend_size(str, src, (int)strlen(src)); 1486 | } 1487 | 1488 | ib_string* ib_string_prepend_size(ib_string *str, const char *src, int size) 1489 | { 1490 | return ib_string_insert(str, 0, src, size); 1491 | } 1492 | 1493 | ib_string* ib_string_prepend_c(ib_string *str, char c) 1494 | { 1495 | int current = str->size; 1496 | ib_string_resize(str, current + 1); 1497 | if (current > 0) { 1498 | memmove(str->ptr + 1, str->ptr, current); 1499 | } 1500 | str->ptr[0] = c; 1501 | return str; 1502 | } 1503 | 1504 | ib_string* ib_string_rewrite(ib_string *str, int pos, const char *src) 1505 | { 1506 | return ib_string_rewrite_size(str, pos, src, (int)strlen(src)); 1507 | } 1508 | 1509 | ib_string* ib_string_rewrite_size(ib_string *str, int pos, 1510 | const char *src, int size) 1511 | { 1512 | if (pos < 0) size += pos, pos = 0; 1513 | if (pos + size >= str->size) size = str->size - pos; 1514 | if (size <= 0) return str; 1515 | if (src) { 1516 | memcpy(str->ptr + pos, src, size); 1517 | } 1518 | return str; 1519 | } 1520 | 1521 | 1522 | int ib_string_find(const ib_string *str, const char *src, int len, int start) 1523 | { 1524 | char *text = str->ptr; 1525 | int pos = (start < 0)? 0 : start; 1526 | int length = (len >= 0)? len : ((int)strlen(src)); 1527 | int endup = str->size - length; 1528 | char ch; 1529 | if (length <= 0) return pos; 1530 | for (ch = src[0]; pos <= endup; pos++) { 1531 | if (text[pos] == ch) { 1532 | if (memcmp(text + pos, src, length) == 0) 1533 | return pos; 1534 | } 1535 | } 1536 | return -1; 1537 | } 1538 | 1539 | int ib_string_find_c(const ib_string *str, char ch, int start) 1540 | { 1541 | const char *text = str->ptr; 1542 | int pos = (start < 0)? 0 : start; 1543 | int endup = str->size; 1544 | for (; pos < endup; pos++) { 1545 | if (text[pos] == ch) return pos; 1546 | } 1547 | return -1; 1548 | } 1549 | 1550 | ib_array* ib_string_split(const ib_string *str, const char *sep, int len) 1551 | { 1552 | if (len == 0) { 1553 | return NULL; 1554 | } 1555 | else { 1556 | ib_array *array = ib_array_new((void (*)(void*))ib_string_delete); 1557 | int start = 0; 1558 | len = (len >= 0)? len : ((int)strlen(sep)); 1559 | while (1) { 1560 | int pos = ib_string_find(str, sep, len, start); 1561 | if (pos < 0) { 1562 | ib_string *newstr = ib_string_new(); 1563 | ib_string_assign_size(newstr, str->ptr + start, 1564 | str->size - start); 1565 | ib_array_push(array, newstr); 1566 | break; 1567 | } 1568 | else { 1569 | ib_string* newstr = ib_string_new(); 1570 | ib_string_assign_size(newstr, str->ptr + start, pos - start); 1571 | start = pos + len; 1572 | ib_array_push(array, newstr); 1573 | } 1574 | } 1575 | return array; 1576 | } 1577 | } 1578 | 1579 | ib_array* ib_string_split_c(const ib_string *str, char sep) 1580 | { 1581 | if (str == NULL) { 1582 | return NULL; 1583 | } 1584 | else { 1585 | ib_array *array = ib_array_new((void (*)(void*))ib_string_delete); 1586 | int start = 0; 1587 | while (1) { 1588 | int pos = ib_string_find_c(str, sep, start); 1589 | if (pos < 0) { 1590 | ib_string *newstr = ib_string_new(); 1591 | ib_string_assign_size(newstr, str->ptr + start, 1592 | str->size - start); 1593 | ib_array_push(array, newstr); 1594 | break; 1595 | } 1596 | else { 1597 | ib_string *newstr = ib_string_new(); 1598 | ib_string_assign_size(newstr, str->ptr + start, pos - start); 1599 | start = pos + 1; 1600 | ib_array_push(array, newstr); 1601 | } 1602 | } 1603 | return array; 1604 | } 1605 | } 1606 | 1607 | ib_string* ib_string_strip(ib_string *str, const char *seps) 1608 | { 1609 | const char *ptr = str->ptr; 1610 | const char *endup = str->ptr + str->size; 1611 | int off, pos; 1612 | for (; ptr < endup; ptr++) { 1613 | const char *sep = seps; 1614 | int match = 0; 1615 | for (; sep[0]; sep++) { 1616 | if (ptr[0] == sep[0]) { 1617 | match = 1; 1618 | break; 1619 | } 1620 | } 1621 | if (match == 0) break; 1622 | } 1623 | off = (int)(ptr - str->ptr); 1624 | if (off > 0) { 1625 | ib_string_erase(str, 0, off); 1626 | } 1627 | ptr = str->ptr; 1628 | pos = str->size; 1629 | for (; pos > 0; pos--) { 1630 | const char *sep = seps; 1631 | int match = 0; 1632 | for (; sep[0]; sep++) { 1633 | if (ptr[pos - 1] == sep[0]) { 1634 | match = 1; 1635 | break; 1636 | } 1637 | } 1638 | if (match == 0) break; 1639 | } 1640 | ib_string_resize(str, pos); 1641 | return str; 1642 | } 1643 | 1644 | ib_string* ib_string_replace_size(ib_string *str, int pos, int size, 1645 | const char *src, int len) 1646 | { 1647 | ib_string_erase(str, pos, size); 1648 | ib_string_insert(str, pos, src, len); 1649 | return str; 1650 | } 1651 | 1652 | 1653 | /*--------------------------------------------------------------------*/ 1654 | /* static hash table (closed hash table with avlnode) */ 1655 | /*--------------------------------------------------------------------*/ 1656 | 1657 | 1658 | void ib_hash_init(struct ib_hash_table *ht, 1659 | size_t (*hash)(const void *key), 1660 | int (*compare)(const void *key1, const void *key2)) 1661 | { 1662 | size_t i; 1663 | ht->count = 0; 1664 | ht->index_size = IB_HASH_INIT_SIZE; 1665 | ht->index_mask = ht->index_size - 1; 1666 | ht->hash = hash; 1667 | ht->compare = compare; 1668 | ilist_init(&ht->head); 1669 | ht->index = ht->init; 1670 | for (i = 0; i < IB_HASH_INIT_SIZE; i++) { 1671 | ht->index[i].avlroot.node = NULL; 1672 | ilist_init(&(ht->index[i].node)); 1673 | } 1674 | } 1675 | 1676 | struct ib_hash_node* ib_hash_node_first(struct ib_hash_table *ht) 1677 | { 1678 | struct ILISTHEAD *head = ht->head.next; 1679 | if (head != &ht->head) { 1680 | struct ib_hash_index *index = 1681 | ilist_entry(head, struct ib_hash_index, node); 1682 | struct ib_node *avlnode = ib_node_first(&index->avlroot); 1683 | if (avlnode == NULL) return NULL; 1684 | return IB_ENTRY(avlnode, struct ib_hash_node, avlnode); 1685 | } 1686 | return NULL; 1687 | } 1688 | 1689 | struct ib_hash_node* ib_hash_node_last(struct ib_hash_table *ht) 1690 | { 1691 | struct ILISTHEAD *head = ht->head.prev; 1692 | if (head != &ht->head) { 1693 | struct ib_hash_index *index = 1694 | ilist_entry(head, struct ib_hash_index, node); 1695 | struct ib_node *avlnode = ib_node_last(&index->avlroot); 1696 | if (avlnode == NULL) return NULL; 1697 | return IB_ENTRY(avlnode, struct ib_hash_node, avlnode); 1698 | } 1699 | return NULL; 1700 | } 1701 | 1702 | struct ib_hash_node* ib_hash_node_next(struct ib_hash_table *ht, 1703 | struct ib_hash_node *node) 1704 | { 1705 | struct ib_node *avlnode; 1706 | struct ib_hash_index *index; 1707 | struct ILISTHEAD *listnode; 1708 | if (node == NULL) return NULL; 1709 | avlnode = ib_node_next(&node->avlnode); 1710 | if (avlnode) { 1711 | return IB_ENTRY(avlnode, struct ib_hash_node, avlnode); 1712 | } 1713 | index = &(ht->index[node->hash & ht->index_mask]); 1714 | listnode = index->node.next; 1715 | if (listnode == &(ht->head)) { 1716 | return NULL; 1717 | } 1718 | index = ilist_entry(listnode, struct ib_hash_index, node); 1719 | avlnode = ib_node_first(&index->avlroot); 1720 | if (avlnode == NULL) return NULL; 1721 | return IB_ENTRY(avlnode, struct ib_hash_node, avlnode); 1722 | } 1723 | 1724 | struct ib_hash_node* ib_hash_node_prev(struct ib_hash_table *ht, 1725 | struct ib_hash_node *node) 1726 | { 1727 | struct ib_node *avlnode; 1728 | struct ib_hash_index *index; 1729 | struct ILISTHEAD *listnode; 1730 | if (node == NULL) return NULL; 1731 | avlnode = ib_node_prev(&node->avlnode); 1732 | if (avlnode) { 1733 | return IB_ENTRY(avlnode, struct ib_hash_node, avlnode); 1734 | } 1735 | index = &(ht->index[node->hash & ht->index_mask]); 1736 | listnode = index->node.prev; 1737 | if (listnode == &(ht->head)) { 1738 | return NULL; 1739 | } 1740 | index = ilist_entry(listnode, struct ib_hash_index, node); 1741 | avlnode = ib_node_last(&index->avlroot); 1742 | if (avlnode == NULL) return NULL; 1743 | return IB_ENTRY(avlnode, struct ib_hash_node, avlnode); 1744 | } 1745 | 1746 | struct ib_hash_node* ib_hash_find(struct ib_hash_table *ht, 1747 | const struct ib_hash_node *node) 1748 | { 1749 | size_t hash = node->hash; 1750 | const void *key = node->key; 1751 | struct ib_hash_index *index = &(ht->index[hash & ht->index_mask]); 1752 | struct ib_node *avlnode = index->avlroot.node; 1753 | int (*compare)(const void *, const void *) = ht->compare; 1754 | while (avlnode) { 1755 | struct ib_hash_node *snode = 1756 | IB_ENTRY(avlnode, struct ib_hash_node, avlnode); 1757 | size_t shash = snode->hash; 1758 | if (hash == shash) { 1759 | int hc = compare(key, snode->key); 1760 | if (hc == 0) return snode; 1761 | avlnode = (hc < 0)? avlnode->left : avlnode->right; 1762 | } 1763 | else { 1764 | avlnode = (hash < shash)? avlnode->left : avlnode->right; 1765 | } 1766 | } 1767 | return NULL; 1768 | } 1769 | 1770 | void ib_hash_erase(struct ib_hash_table *ht, struct ib_hash_node *node) 1771 | { 1772 | struct ib_hash_index *index; 1773 | ASSERTION(node && ht); 1774 | ASSERTION(!ib_node_empty(&node->avlnode)); 1775 | index = &ht->index[node->hash & ht->index_mask]; 1776 | if (index->avlroot.node == &node->avlnode && node->avlnode.height == 1) { 1777 | index->avlroot.node = NULL; 1778 | ilist_del_init(&index->node); 1779 | } 1780 | else { 1781 | ib_node_erase(&node->avlnode, &index->avlroot); 1782 | } 1783 | ib_node_init(&node->avlnode); 1784 | ht->count--; 1785 | } 1786 | 1787 | struct ib_node** ib_hash_track(struct ib_hash_table *ht, 1788 | const struct ib_hash_node *node, struct ib_node **parent) 1789 | { 1790 | size_t hash = node->hash; 1791 | const void *key = node->key; 1792 | struct ib_hash_index *index = &(ht->index[hash & ht->index_mask]); 1793 | struct ib_node **link = &index->avlroot.node; 1794 | struct ib_node *p = NULL; 1795 | int (*compare)(const void *key1, const void *key2) = ht->compare; 1796 | parent[0] = NULL; 1797 | while (link[0]) { 1798 | struct ib_hash_node *snode; 1799 | size_t shash; 1800 | p = link[0]; 1801 | snode = IB_ENTRY(p, struct ib_hash_node, avlnode); 1802 | shash = snode->hash; 1803 | if (hash == shash) { 1804 | int hc = compare(key, snode->key); 1805 | if (hc == 0) { 1806 | parent[0] = p; 1807 | return NULL; 1808 | } 1809 | link = (hc < 0)? (&p->left) : (&p->right); 1810 | } 1811 | else { 1812 | link = (hash < shash)? (&p->left) : (&p->right); 1813 | } 1814 | } 1815 | parent[0] = p; 1816 | return link; 1817 | } 1818 | 1819 | 1820 | struct ib_hash_node* ib_hash_add(struct ib_hash_table *ht, 1821 | struct ib_hash_node *node) 1822 | { 1823 | struct ib_hash_index *index = &(ht->index[node->hash & ht->index_mask]); 1824 | if (index->avlroot.node == NULL) { 1825 | index->avlroot.node = &node->avlnode; 1826 | node->avlnode.parent = NULL; 1827 | node->avlnode.left = NULL; 1828 | node->avlnode.right = NULL; 1829 | node->avlnode.height = 1; 1830 | ilist_add_tail(&index->node, &ht->head); 1831 | } 1832 | else { 1833 | struct ib_node **link, *parent; 1834 | link = ib_hash_track(ht, node, &parent); 1835 | if (link == NULL) { 1836 | ASSERTION(parent); 1837 | return IB_ENTRY(parent, struct ib_hash_node, avlnode); 1838 | } 1839 | ib_node_link(&node->avlnode, parent, link); 1840 | ib_node_post_insert(&node->avlnode, &index->avlroot); 1841 | } 1842 | ht->count++; 1843 | return NULL; 1844 | } 1845 | 1846 | 1847 | void ib_hash_replace(struct ib_hash_table *ht, 1848 | struct ib_hash_node *victim, struct ib_hash_node *newnode) 1849 | { 1850 | struct ib_hash_index *index = &ht->index[victim->hash & ht->index_mask]; 1851 | ib_node_replace(&victim->avlnode, &newnode->avlnode, &index->avlroot); 1852 | } 1853 | 1854 | void ib_hash_clear(struct ib_hash_table *ht, 1855 | void (*destroy)(struct ib_hash_node *node)) 1856 | { 1857 | while (!ilist_is_empty(&ht->head)) { 1858 | struct ib_hash_index *index = ilist_entry(ht->head.next, 1859 | struct ib_hash_index, node); 1860 | struct ib_node *next = NULL; 1861 | while (index->avlroot.node != NULL) { 1862 | struct ib_node *avlnode = ib_node_tear(&index->avlroot, &next); 1863 | ASSERTION(avlnode); 1864 | if (destroy) { 1865 | struct ib_hash_node *node = 1866 | IB_ENTRY(avlnode, struct ib_hash_node, avlnode); 1867 | destroy(node); 1868 | } 1869 | } 1870 | ilist_del_init(&index->node); 1871 | } 1872 | ht->count = 0; 1873 | } 1874 | 1875 | 1876 | void* ib_hash_swap(struct ib_hash_table *ht, void *ptr, size_t nbytes) 1877 | { 1878 | struct ib_hash_index *old_index = ht->index; 1879 | struct ib_hash_index *new_index = (struct ib_hash_index*)ptr; 1880 | size_t index_size = 1; 1881 | struct ILISTHEAD head; 1882 | size_t i; 1883 | ASSERTION(nbytes >= sizeof(struct ib_hash_index)); 1884 | if (new_index == NULL) { 1885 | if (ht->index == ht->init) { 1886 | return NULL; 1887 | } 1888 | new_index = ht->init; 1889 | index_size = IB_HASH_INIT_SIZE; 1890 | } 1891 | else if (new_index == old_index) { 1892 | return old_index; 1893 | } 1894 | if (new_index != ht->init) { 1895 | size_t test_size = sizeof(struct ib_hash_index); 1896 | while (test_size < nbytes) { 1897 | size_t next_size = test_size * 2; 1898 | if (next_size > nbytes) break; 1899 | test_size = next_size; 1900 | index_size = index_size * 2; 1901 | } 1902 | } 1903 | ht->index = new_index; 1904 | ht->index_size = index_size; 1905 | ht->index_mask = index_size - 1; 1906 | ht->count = 0; 1907 | for (i = 0; i < index_size; i++) { 1908 | ht->index[i].avlroot.node = NULL; 1909 | ilist_init(&ht->index[i].node); 1910 | } 1911 | ilist_replace(&ht->head, &head); 1912 | ilist_init(&ht->head); 1913 | while (!ilist_is_empty(&head)) { 1914 | struct ib_hash_index *index = ilist_entry(head.next, 1915 | struct ib_hash_index, node); 1916 | #if 1 1917 | struct ib_node *next = NULL; 1918 | while (index->avlroot.node) { 1919 | struct ib_node *avlnode = ib_node_tear(&index->avlroot, &next); 1920 | struct ib_hash_node *snode, *hr; 1921 | ASSERTION(avlnode); 1922 | snode = IB_ENTRY(avlnode, struct ib_hash_node, avlnode); 1923 | hr = ib_hash_add(ht, snode); 1924 | if (hr != NULL) { 1925 | ASSERTION(hr == NULL); 1926 | return NULL; 1927 | } 1928 | } 1929 | #else 1930 | while (index->avlroot.node) { 1931 | struct ib_node *avlnode = index->avlroot.node; 1932 | struct ib_hash_node *snode, *hr; 1933 | ib_node_erase(avlnode, &index->avlroot); 1934 | snode = IB_ENTRY(avlnode, struct ib_hash_node, avlnode); 1935 | hr = ib_hash_add(ht, snode); 1936 | ASSERTION(hr == NULL); 1937 | hr = hr; 1938 | } 1939 | #endif 1940 | ilist_del_init(&index->node); 1941 | } 1942 | return (old_index == ht->init)? NULL : old_index; 1943 | } 1944 | 1945 | 1946 | /*--------------------------------------------------------------------*/ 1947 | /* hash map, wrapper of ib_hash_table to support direct key/value */ 1948 | /*--------------------------------------------------------------------*/ 1949 | 1950 | struct ib_hash_entry* ib_map_first(struct ib_hash_map *hm) 1951 | { 1952 | struct ib_hash_node *node = ib_hash_node_first(&hm->ht); 1953 | if (node == NULL) return NULL; 1954 | return IB_ENTRY(node, struct ib_hash_entry, node); 1955 | } 1956 | 1957 | 1958 | struct ib_hash_entry* ib_map_last(struct ib_hash_map *hm) 1959 | { 1960 | struct ib_hash_node *node = ib_hash_node_last(&hm->ht); 1961 | if (node == NULL) return NULL; 1962 | return IB_ENTRY(node, struct ib_hash_entry, node); 1963 | } 1964 | 1965 | 1966 | struct ib_hash_entry* ib_map_next(struct ib_hash_map *hm, 1967 | struct ib_hash_entry *n) 1968 | { 1969 | struct ib_hash_node *node = ib_hash_node_next(&hm->ht, &n->node); 1970 | if (node == NULL) return NULL; 1971 | return IB_ENTRY(node, struct ib_hash_entry, node); 1972 | } 1973 | 1974 | 1975 | struct ib_hash_entry* ib_map_prev(struct ib_hash_map *hm, 1976 | struct ib_hash_entry *n) 1977 | { 1978 | struct ib_hash_node *node = ib_hash_node_prev(&hm->ht, &n->node); 1979 | if (node == NULL) return NULL; 1980 | return IB_ENTRY(node, struct ib_hash_entry, node); 1981 | } 1982 | 1983 | 1984 | void ib_map_init(struct ib_hash_map *hm, size_t (*hash)(const void*), 1985 | int (*compare)(const void *, const void *)) 1986 | { 1987 | hm->count = 0; 1988 | hm->key_copy = NULL; 1989 | hm->key_destroy = NULL; 1990 | hm->value_copy = NULL; 1991 | hm->value_destroy = NULL; 1992 | hm->insert = 0; 1993 | hm->fixed = 0; 1994 | ib_hash_init(&hm->ht, hash, compare); 1995 | ib_fastbin_init(&hm->fb, sizeof(struct ib_hash_entry)); 1996 | } 1997 | 1998 | void ib_map_destroy(struct ib_hash_map *hm) 1999 | { 2000 | void *ptr; 2001 | ib_map_clear(hm); 2002 | ptr = ib_hash_swap(&hm->ht, NULL, 0); 2003 | if (ptr) { 2004 | ikmem_free(ptr); 2005 | } 2006 | ib_fastbin_destroy(&hm->fb); 2007 | } 2008 | 2009 | struct ib_hash_entry* ib_map_find(struct ib_hash_map *hm, const void *key) 2010 | { 2011 | struct ib_hash_table *ht = &hm->ht; 2012 | struct ib_hash_node dummy; 2013 | struct ib_hash_node *rh; 2014 | void *ptr = (void*)key; 2015 | ib_hash_node_key(ht, &dummy, ptr); 2016 | rh = ib_hash_find(ht, &dummy); 2017 | return (rh == NULL)? NULL : IB_ENTRY(rh, struct ib_hash_entry, node); 2018 | } 2019 | 2020 | 2021 | void* ib_map_lookup(struct ib_hash_map *hm, const void *key, void *defval) 2022 | { 2023 | struct ib_hash_entry *entry = ib_map_find(hm, key); 2024 | if (entry == NULL) return defval; 2025 | return ib_hash_value(entry); 2026 | } 2027 | 2028 | static inline struct ib_hash_entry* 2029 | ib_hash_entry_allocate(struct ib_hash_map *hm, void *key, void *value) 2030 | { 2031 | struct ib_hash_entry *entry; 2032 | entry = (struct ib_hash_entry*)ib_fastbin_new(&hm->fb); 2033 | ASSERTION(entry); 2034 | if (hm->key_copy) entry->node.key = hm->key_copy(key); 2035 | else entry->node.key = key; 2036 | if (hm->value_copy) entry->value = hm->value_copy(value); 2037 | else entry->value = value; 2038 | return entry; 2039 | } 2040 | 2041 | static inline struct ib_hash_entry* 2042 | ib_hash_update(struct ib_hash_map *hm, void *key, void *value, int update) 2043 | { 2044 | size_t hash = hm->ht.hash(key); 2045 | struct ib_hash_index *index = &(hm->ht.index[hash & hm->ht.index_mask]); 2046 | struct ib_node **link = &index->avlroot.node; 2047 | struct ib_node *parent = NULL; 2048 | struct ib_hash_entry *entry; 2049 | int (*compare)(const void *key1, const void *key2) = hm->ht.compare; 2050 | if (index->avlroot.node == NULL) { 2051 | entry = ib_hash_entry_allocate(hm, key, value); 2052 | ASSERTION(entry); 2053 | entry->node.avlnode.height = 1; 2054 | entry->node.avlnode.left = NULL; 2055 | entry->node.avlnode.right = NULL; 2056 | entry->node.avlnode.parent = NULL; 2057 | entry->node.hash = hash; 2058 | index->avlroot.node = &(entry->node.avlnode); 2059 | ilist_add_tail(&index->node, &(hm->ht.head)); 2060 | hm->ht.count++; 2061 | hm->insert = 1; 2062 | return entry; 2063 | } 2064 | while (link[0]) { 2065 | struct ib_hash_node *snode; 2066 | size_t shash; 2067 | parent = link[0]; 2068 | snode = IB_ENTRY(parent, struct ib_hash_node, avlnode); 2069 | shash = snode->hash; 2070 | if (hash != shash) { 2071 | link = (hash < shash)? (&parent->left) : (&parent->right); 2072 | } else { 2073 | int hc = compare(key, snode->key); 2074 | if (hc == 0) { 2075 | entry = IB_ENTRY(snode, struct ib_hash_entry, node); 2076 | if (update) { 2077 | if (hm->value_destroy) { 2078 | hm->value_destroy(entry->value); 2079 | } 2080 | if (hm->value_copy == NULL) entry->value = value; 2081 | else entry->value = hm->value_copy(value); 2082 | } 2083 | hm->insert = 0; 2084 | return entry; 2085 | } else { 2086 | link = (hc < 0)? (&parent->left) : (&parent->right); 2087 | } 2088 | } 2089 | } 2090 | entry = ib_hash_entry_allocate(hm, key, value); 2091 | ASSERTION(entry); 2092 | entry->node.hash = hash; 2093 | ib_node_link(&(entry->node.avlnode), parent, link); 2094 | ib_node_post_insert(&(entry->node.avlnode), &index->avlroot); 2095 | hm->ht.count++; 2096 | hm->insert = 1; 2097 | return entry; 2098 | } 2099 | 2100 | static inline void ib_map_rehash(struct ib_hash_map *hm, size_t capacity) 2101 | { 2102 | size_t isize = hm->ht.index_size; 2103 | size_t limit = (capacity * 6) >> 2; /* capacity * 6 / 4 */ 2104 | if (isize < limit && hm->fixed == 0) { 2105 | size_t need = isize; 2106 | size_t size; 2107 | void *ptr; 2108 | while (need < limit) need <<= 1; 2109 | size = need * sizeof(struct ib_hash_index); 2110 | ptr = ikmem_malloc(size); 2111 | ASSERTION(ptr); 2112 | ptr = ib_hash_swap(&hm->ht, ptr, size); 2113 | if (ptr) { 2114 | ikmem_free(ptr); 2115 | } 2116 | } 2117 | } 2118 | 2119 | void ib_map_reserve(struct ib_hash_map *hm, size_t capacity) 2120 | { 2121 | ib_map_rehash(hm, capacity); 2122 | } 2123 | 2124 | struct ib_hash_entry* 2125 | ib_map_add(struct ib_hash_map *hm, void *key, void *value, int *success) 2126 | { 2127 | struct ib_hash_entry *entry = ib_hash_update(hm, key, value, 0); 2128 | if (success) success[0] = hm->insert; 2129 | ib_map_rehash(hm, hm->ht.count); 2130 | return entry; 2131 | } 2132 | 2133 | struct ib_hash_entry* 2134 | ib_map_set(struct ib_hash_map *hm, void *key, void *value) 2135 | { 2136 | struct ib_hash_entry *entry = ib_hash_update(hm, key, value, 0); 2137 | ib_map_rehash(hm, hm->ht.count); 2138 | return entry; 2139 | } 2140 | 2141 | void *ib_map_get(struct ib_hash_map *hm, const void *key) 2142 | { 2143 | return ib_map_lookup(hm, key, NULL); 2144 | } 2145 | 2146 | void ib_map_erase(struct ib_hash_map *hm, struct ib_hash_entry *entry) 2147 | { 2148 | ASSERTION(entry); 2149 | ASSERTION(!ib_node_empty(&(entry->node.avlnode))); 2150 | ib_hash_erase(&hm->ht, &entry->node); 2151 | ib_node_init(&(entry->node.avlnode)); 2152 | if (hm->key_destroy) hm->key_destroy(entry->node.key); 2153 | if (hm->value_destroy) hm->value_destroy(entry->value); 2154 | entry->node.key = NULL; 2155 | entry->value = NULL; 2156 | ib_fastbin_del(&hm->fb, entry); 2157 | } 2158 | 2159 | int ib_map_remove(struct ib_hash_map *hm, const void *key) 2160 | { 2161 | struct ib_hash_entry *entry; 2162 | entry = ib_map_find(hm, key); 2163 | if (entry == NULL) { 2164 | return -1; 2165 | } 2166 | ib_map_erase(hm, entry); 2167 | return 0; 2168 | } 2169 | 2170 | void ib_map_clear(struct ib_hash_map *hm) 2171 | { 2172 | while (1) { 2173 | struct ib_hash_entry *entry = ib_map_first(hm); 2174 | if (entry == NULL) break; 2175 | ib_map_erase(hm, entry); 2176 | } 2177 | ASSERTION(hm->count == 0); 2178 | } 2179 | 2180 | 2181 | /*--------------------------------------------------------------------*/ 2182 | /* common type hash and equal functions */ 2183 | /*--------------------------------------------------------------------*/ 2184 | size_t ib_hash_seed = 0x11223344; 2185 | 2186 | size_t ib_hash_func_uint(const void *key) 2187 | { 2188 | #if 0 2189 | size_t x = (size_t)key; 2190 | return (x * 2654435761u) ^ ib_hash_seed; 2191 | #else 2192 | return (size_t)key; 2193 | #endif 2194 | } 2195 | 2196 | size_t ib_hash_func_int(const void *key) 2197 | { 2198 | #if 0 2199 | size_t x = (size_t)key; 2200 | return (x * 2654435761u) ^ ib_hash_seed; 2201 | #else 2202 | return (size_t)key; 2203 | #endif 2204 | } 2205 | 2206 | size_t ib_hash_bytes_stl(const void *ptr, size_t size, size_t seed) 2207 | { 2208 | const unsigned char *buf = (const unsigned char*)ptr; 2209 | const size_t m = 0x5bd1e995; 2210 | size_t hash = size ^ seed; 2211 | for (; size >= 4; buf += 4, size -= 4) { 2212 | size_t k = *((IUINT32*)buf); 2213 | k *= m; 2214 | k = (k >> 24) * m; 2215 | hash = (hash * m) ^ k; 2216 | } 2217 | switch (size) { 2218 | case 3: hash ^= ((IUINT32)buf[2]) << 16; 2219 | case 2: hash ^= ((IUINT32)buf[1]) << 8; 2220 | case 1: hash ^= ((IUINT32)buf[0]); hash = hash * m; break; 2221 | } 2222 | hash = (hash ^ (hash >> 13)) * m; 2223 | return hash ^ (hash >> 15); 2224 | } 2225 | 2226 | size_t ib_hash_bytes_lua(const void *ptr, size_t size, size_t seed) 2227 | { 2228 | const unsigned char *name = (const unsigned char*)ptr; 2229 | size_t step = (size >> 5) + 1; 2230 | size_t h = size ^ seed, i; 2231 | for(i = size; i >= step; i -= step) 2232 | h = h ^ ((h << 5) + (h >> 2) + (size_t)name[i - 1]); 2233 | return h; 2234 | } 2235 | 2236 | size_t ib_hash_func_str(const void *key) 2237 | { 2238 | ib_string *str = (ib_string*)key; 2239 | #ifndef IB_HASH_BYTES_STL 2240 | return ib_hash_bytes_lua(str->ptr, str->size, ib_hash_seed); 2241 | #else 2242 | return ib_hash_bytes_stl(str->ptr, str->size, ib_hash_seed); 2243 | #endif 2244 | } 2245 | 2246 | size_t ib_hash_func_cstr(const void *key) 2247 | { 2248 | const char *str = (const char*)key; 2249 | size_t size = strlen(str); 2250 | #ifndef IB_HASH_BYTES_STL 2251 | return ib_hash_bytes_lua(str, size, ib_hash_seed); 2252 | #else 2253 | return ib_hash_bytes_stl(str, size, ib_hash_seed); 2254 | #endif 2255 | } 2256 | 2257 | int ib_hash_compare_uint(const void *key1, const void *key2) 2258 | { 2259 | size_t x = (size_t)key1; 2260 | size_t y = (size_t)key2; 2261 | if (x == y) return 0; 2262 | return (x < y)? -1 : 1; 2263 | } 2264 | 2265 | int ib_hash_compare_int(const void *key1, const void *key2) 2266 | { 2267 | ilong x = (ilong)key1; 2268 | ilong y = (ilong)key2; 2269 | if (x == y) return 0; 2270 | return (x < y)? -1 : 1; 2271 | } 2272 | 2273 | int ib_hash_compare_str(const void *key1, const void *key2) 2274 | { 2275 | return ib_string_compare((const ib_string*)key1, (const ib_string*)key2); 2276 | } 2277 | 2278 | int ib_compare_bytes(const void *p1, size_t s1, const void *p2, size_t s2) 2279 | { 2280 | size_t minsize = (s1 < s2)? s1 : s2; 2281 | int hr = memcmp(p1, p2, minsize); 2282 | if (hr == 0) { 2283 | if (s1 == s2) return 0; 2284 | return (s1 < s2)? -1 : 1; 2285 | } 2286 | else { 2287 | return (hr < 0)? -1 : 1; 2288 | } 2289 | } 2290 | 2291 | int ib_hash_compare_cstr(const void *key1, const void *key2) 2292 | { 2293 | const char *x = (const char*)key1; 2294 | const char *y = (const char*)key2; 2295 | return ib_compare_bytes(x, strlen(x), y, strlen(y)); 2296 | } 2297 | 2298 | 2299 | 2300 | struct ib_hash_entry *ib_map_find_uint(struct ib_hash_map *hm, iulong key) 2301 | { 2302 | struct ib_hash_entry *hr; 2303 | void *kk = (void*)key; 2304 | ib_map_search(hm, kk, ib_hash_func_uint, ib_hash_compare_uint, hr); 2305 | return hr; 2306 | } 2307 | 2308 | struct ib_hash_entry *ib_map_find_int(struct ib_hash_map *hm, ilong key) 2309 | { 2310 | struct ib_hash_entry *hr; 2311 | void *kk = (void*)key; 2312 | ib_map_search(hm, kk, ib_hash_func_int, ib_hash_compare_int, hr); 2313 | return hr; 2314 | } 2315 | 2316 | struct ib_hash_entry *ib_map_find_str(struct ib_hash_map *hm, const ib_string *key) 2317 | { 2318 | struct ib_hash_entry *hr; 2319 | void *kk = (void*)key; 2320 | ib_map_search(hm, kk, ib_hash_func_str, ib_hash_compare_str, hr); 2321 | return hr; 2322 | } 2323 | 2324 | struct ib_hash_entry *ib_map_find_cstr(struct ib_hash_map *hm, const char *key) 2325 | { 2326 | struct ib_hash_entry *hr; 2327 | void *kk = (void*)key; 2328 | ib_map_search(hm, kk, ib_hash_func_cstr, ib_hash_compare_cstr, hr); 2329 | return hr; 2330 | } 2331 | 2332 | 2333 | 2334 | 2335 | -------------------------------------------------------------------------------- /system/imembase.h: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * 3 | * imembase.h - basic interface of memory operation 4 | * skywind3000 (at) gmail.com, 2006-2016 5 | * 6 | **********************************************************************/ 7 | 8 | #ifndef __IMEMBASE_H__ 9 | #define __IMEMBASE_H__ 10 | 11 | #ifdef HAVE_CONFIG_H 12 | #include "config.h" 13 | #endif 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | 20 | /********************************************************************** 21 | * 32BIT INTEGER DEFINITION 22 | **********************************************************************/ 23 | #ifndef __INTEGER_32_BITS__ 24 | #define __INTEGER_32_BITS__ 25 | #if defined(__UINT32_TYPE__) && defined(__UINT32_TYPE__) 26 | typedef __UINT32_TYPE__ ISTDUINT32; 27 | typedef __INT32_TYPE__ ISTDINT32; 28 | #elif defined(__UINT_FAST32_TYPE__) && defined(__INT_FAST32_TYPE__) 29 | typedef __UINT_FAST32_TYPE__ ISTDUINT32; 30 | typedef __INT_FAST32_TYPE__ ISTDINT32; 31 | #elif defined(_WIN64) || defined(WIN64) || defined(__amd64__) || \ 32 | defined(__x86_64) || defined(__x86_64__) || defined(_M_IA64) || \ 33 | defined(_M_AMD64) 34 | typedef unsigned int ISTDUINT32; 35 | typedef int ISTDINT32; 36 | #elif defined(_WIN32) || defined(WIN32) || defined(__i386__) || \ 37 | defined(__i386) || defined(_M_X86) 38 | typedef unsigned long ISTDUINT32; 39 | typedef long ISTDINT32; 40 | #elif defined(__MACOS__) 41 | typedef UInt32 ISTDUINT32; 42 | typedef SInt32 ISTDINT32; 43 | #elif defined(__APPLE__) && defined(__MACH__) 44 | #include 45 | typedef u_int32_t ISTDUINT32; 46 | typedef int32_t ISTDINT32; 47 | #elif defined(__BEOS__) 48 | #include 49 | typedef u_int32_t ISTDUINT32; 50 | typedef int32_t ISTDINT32; 51 | #elif (defined(_MSC_VER) || defined(__BORLANDC__)) && (!defined(__MSDOS__)) 52 | typedef unsigned __int32 ISTDUINT32; 53 | typedef __int32 ISTDINT32; 54 | #elif defined(__GNUC__) && (__GNUC__ > 3) 55 | #include 56 | typedef uint32_t ISTDUINT32; 57 | typedef int32_t ISTDINT32; 58 | #else 59 | #include 60 | #if UINT_MAX == 0xFFFFU 61 | typedef unsigned long ISTDUINT32; 62 | typedef long ISTDINT32; 63 | #else 64 | typedef unsigned int ISTDUINT32; 65 | typedef int ISTDINT32; 66 | #endif 67 | #endif 68 | #endif 69 | 70 | 71 | /********************************************************************** 72 | * Global Macros 73 | **********************************************************************/ 74 | #ifndef __IUINT8_DEFINED 75 | #define __IUINT8_DEFINED 76 | typedef unsigned char IUINT8; 77 | #endif 78 | 79 | #ifndef __IINT8_DEFINED 80 | #define __IINT8_DEFINED 81 | typedef signed char IINT8; 82 | #endif 83 | 84 | #ifndef __IUINT16_DEFINED 85 | #define __IUINT16_DEFINED 86 | typedef unsigned short IUINT16; 87 | #endif 88 | 89 | #ifndef __IINT16_DEFINED 90 | #define __IINT16_DEFINED 91 | typedef signed short IINT16; 92 | #endif 93 | 94 | #ifndef __IINT32_DEFINED 95 | #define __IINT32_DEFINED 96 | typedef ISTDINT32 IINT32; 97 | #endif 98 | 99 | #ifndef __IUINT32_DEFINED 100 | #define __IUINT32_DEFINED 101 | typedef ISTDUINT32 IUINT32; 102 | #endif 103 | 104 | 105 | /*--------------------------------------------------------------------*/ 106 | /* INLINE */ 107 | /*--------------------------------------------------------------------*/ 108 | #ifndef INLINE 109 | #if defined(__GNUC__) 110 | 111 | #if (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) 112 | #define INLINE __inline__ __attribute__((always_inline)) 113 | #else 114 | #define INLINE __inline__ 115 | #endif 116 | 117 | #elif (defined(_MSC_VER) || defined(__WATCOMC__)) 118 | #define INLINE __inline 119 | #else 120 | #define INLINE 121 | #endif 122 | #endif 123 | 124 | #if (!defined(__cplusplus)) && (!defined(inline)) 125 | #define inline INLINE 126 | #endif 127 | 128 | /* you can change this by config.h or predefined macro */ 129 | #ifndef ASSERTION 130 | #define ASSERTION(x) ((void)0) 131 | #endif 132 | 133 | 134 | /*====================================================================*/ 135 | /* IULONG/ILONG (ensure sizeof(iulong) == sizeof(void*)) */ 136 | /*====================================================================*/ 137 | #ifndef __IULONG_DEFINED 138 | #define __IULONG_DEFINED 139 | typedef ptrdiff_t ilong; 140 | typedef size_t iulong; 141 | #endif 142 | 143 | #ifdef __cplusplus 144 | extern "C" { 145 | #endif 146 | 147 | 148 | /*====================================================================*/ 149 | /* IALLOCATOR */ 150 | /*====================================================================*/ 151 | struct IALLOCATOR 152 | { 153 | void *(*alloc)(struct IALLOCATOR *, size_t); 154 | void (*free)(struct IALLOCATOR *, void *); 155 | void *(*realloc)(struct IALLOCATOR *, void *, size_t); 156 | void *udata; 157 | }; 158 | 159 | void* internal_malloc(struct IALLOCATOR *allocator, size_t size); 160 | void internal_free(struct IALLOCATOR *allocator, void *ptr); 161 | void* internal_realloc(struct IALLOCATOR *allocator, void *ptr, size_t size); 162 | 163 | 164 | /*====================================================================*/ 165 | /* IKMEM INTERFACE */ 166 | /*====================================================================*/ 167 | extern struct IALLOCATOR *ikmem_allocator; 168 | 169 | void* ikmem_malloc(size_t size); 170 | void* ikmem_realloc(void *ptr, size_t size); 171 | void ikmem_free(void *ptr); 172 | 173 | 174 | /*====================================================================*/ 175 | /* IVECTOR */ 176 | /*====================================================================*/ 177 | struct IVECTOR 178 | { 179 | unsigned char *data; 180 | size_t size; 181 | size_t capacity; 182 | struct IALLOCATOR *allocator; 183 | }; 184 | 185 | void iv_init(struct IVECTOR *v, struct IALLOCATOR *allocator); 186 | void iv_destroy(struct IVECTOR *v); 187 | int iv_resize(struct IVECTOR *v, size_t newsize); 188 | int iv_reserve(struct IVECTOR *v, size_t newsize); 189 | 190 | size_t iv_pop(struct IVECTOR *v, void *data, size_t size); 191 | int iv_push(struct IVECTOR *v, const void *data, size_t size); 192 | int iv_insert(struct IVECTOR *v, size_t pos, const void *data, size_t size); 193 | int iv_erase(struct IVECTOR *v, size_t pos, size_t size); 194 | 195 | #define iv_size(v) ((v)->size) 196 | #define iv_data(v) ((v)->data) 197 | 198 | #define iv_entry(v, type) ((type*)iv_data(v)) 199 | 200 | #define iv_obj_index(v, type, index) (iv_entry(v, type)[index]) 201 | #define iv_obj_push(v, type, objptr) iv_push(v, objptr, sizeof(type)) 202 | #define iv_obj_pop(v, type, objptr) iv_pop(v, objptr, sizeof(type)) 203 | #define iv_obj_size(v, type) (((v)->size) / sizeof(type)) 204 | #define iv_obj_capacity(v, type) (((v)->capacity) / sizeof(type)) 205 | #define iv_obj_resize(v, type, count) iv_resize(v, (count) * sizeof(type)) 206 | #define iv_obj_reserve(v, type, count) iv_reserve(v, (count) * sizeof(type)) 207 | 208 | #define iv_obj_insert(v, type, pos, objptr) \ 209 | iv_insert(v, (pos) * sizeof(type), objptr, sizeof(type)) 210 | 211 | #define iv_obj_erase(v, type, pos, count) \ 212 | iv_erase(v, (pos) * sizeof(type), (count) * sizeof(type)) 213 | 214 | 215 | #define IROUND_SIZE(b) (((size_t)1) << (b)) 216 | #define IROUND_UP(s, n) (((s) + (n) - 1) & ~(((size_t)(n)) - 1)) 217 | 218 | 219 | /*====================================================================*/ 220 | /* IMEMNODE */ 221 | /*====================================================================*/ 222 | struct IMEMNODE 223 | { 224 | struct IALLOCATOR *allocator; /* memory allocator */ 225 | 226 | struct IVECTOR vprev; /* prev node link vector */ 227 | struct IVECTOR vnext; /* next node link vector */ 228 | struct IVECTOR vnode; /* node information data */ 229 | struct IVECTOR vdata; /* node data buffer vector */ 230 | struct IVECTOR vmode; /* mode of allocation */ 231 | ilong *mprev; /* prev node array */ 232 | ilong *mnext; /* next node array */ 233 | ilong *mnode; /* node info array */ 234 | void **mdata; /* node data array */ 235 | ilong *mmode; /* node mode array */ 236 | ilong *extra; /* extra user data */ 237 | ilong node_free; /* number of free nodes */ 238 | ilong node_used; /* number of allocated */ 239 | ilong node_max; /* number of all nodes */ 240 | ilong grow_limit; /* limit of growing */ 241 | 242 | ilong node_size; /* node data fixed size */ 243 | ilong node_shift; /* node data size shift */ 244 | 245 | struct IVECTOR vmem; /* mem-pages in the pool */ 246 | char **mmem; /* mem-pages array */ 247 | ilong mem_max; /* max num of memory pages */ 248 | ilong mem_count; /* number of mem-pages */ 249 | 250 | ilong list_open; /* the entry of open-list */ 251 | ilong list_close; /* the entry of close-list */ 252 | ilong total_mem; /* total memory size */ 253 | }; 254 | 255 | 256 | void imnode_init(struct IMEMNODE *mn, ilong nodesize, struct IALLOCATOR *ac); 257 | void imnode_destroy(struct IMEMNODE *mnode); 258 | ilong imnode_new(struct IMEMNODE *mnode); 259 | void imnode_del(struct IMEMNODE *mnode, ilong index); 260 | ilong imnode_head(const struct IMEMNODE *mnode); 261 | ilong imnode_next(const struct IMEMNODE *mnode, ilong index); 262 | ilong imnode_prev(const struct IMEMNODE *mnode, ilong index); 263 | void*imnode_data(struct IMEMNODE *mnode, ilong index); 264 | const void* imnode_data_const(const struct IMEMNODE *mnode, ilong index); 265 | 266 | #define IMNODE_NODE(mnodeptr, i) ((mnodeptr)->mnode[i]) 267 | #define IMNODE_PREV(mnodeptr, i) ((mnodeptr)->mprev[i]) 268 | #define IMNODE_NEXT(mnodeptr, i) ((mnodeptr)->mnext[i]) 269 | #define IMNODE_DATA(mnodeptr, i) ((mnodeptr)->mdata[i]) 270 | #define IMNODE_MODE(mnodeptr, i) ((mnodeptr)->mmode[i]) 271 | 272 | 273 | /*====================================================================*/ 274 | /* LIST DEFINITION */ 275 | /*====================================================================*/ 276 | #ifndef __ILIST_DEF__ 277 | #define __ILIST_DEF__ 278 | 279 | struct ILISTHEAD { 280 | struct ILISTHEAD *next, *prev; 281 | }; 282 | 283 | typedef struct ILISTHEAD ilist_head; 284 | 285 | 286 | /*--------------------------------------------------------------------*/ 287 | /* list init */ 288 | /*--------------------------------------------------------------------*/ 289 | #define ILIST_HEAD_INIT(name) { &(name), &(name) } 290 | #define ILIST_HEAD(name) \ 291 | struct ILISTHEAD name = ILIST_HEAD_INIT(name) 292 | 293 | #define ILIST_INIT(ptr) ( \ 294 | (ptr)->next = (ptr), (ptr)->prev = (ptr)) 295 | 296 | #define IOFFSETOF(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 297 | 298 | #define ICONTAINEROF(ptr, type, member) ( \ 299 | (type*)( ((char*)((type*)ptr)) - IOFFSETOF(type, member)) ) 300 | 301 | #define ILIST_ENTRY(ptr, type, member) ICONTAINEROF(ptr, type, member) 302 | 303 | 304 | /*--------------------------------------------------------------------*/ 305 | /* list operation */ 306 | /*--------------------------------------------------------------------*/ 307 | #define ILIST_ADD(node, head) ( \ 308 | (node)->prev = (head), (node)->next = (head)->next, \ 309 | (head)->next->prev = (node), (head)->next = (node)) 310 | 311 | #define ILIST_ADD_TAIL(node, head) ( \ 312 | (node)->prev = (head)->prev, (node)->next = (head), \ 313 | (head)->prev->next = (node), (head)->prev = (node)) 314 | 315 | #define ILIST_DEL_BETWEEN(p, n) ((n)->prev = (p), (p)->next = (n)) 316 | 317 | #define ILIST_DEL(entry) (\ 318 | (entry)->next->prev = (entry)->prev, \ 319 | (entry)->prev->next = (entry)->next, \ 320 | (entry)->next = 0, (entry)->prev = 0) 321 | 322 | #define ILIST_DEL_INIT(entry) do { \ 323 | ILIST_DEL(entry); ILIST_INIT(entry); } while (0) 324 | 325 | #define ILIST_IS_EMPTY(entry) ((entry) == (entry)->next) 326 | 327 | #define ilist_init ILIST_INIT 328 | #define ilist_entry ILIST_ENTRY 329 | #define ilist_add ILIST_ADD 330 | #define ilist_add_tail ILIST_ADD_TAIL 331 | #define ilist_del ILIST_DEL 332 | #define ilist_del_init ILIST_DEL_INIT 333 | #define ilist_is_empty ILIST_IS_EMPTY 334 | 335 | #define ILIST_FOREACH(iterator, head, TYPE, MEMBER) \ 336 | for ((iterator) = ilist_entry((head)->next, TYPE, MEMBER); \ 337 | &((iterator)->MEMBER) != (head); \ 338 | (iterator) = ilist_entry((iterator)->MEMBER.next, TYPE, MEMBER)) 339 | 340 | #define ilist_foreach(iterator, head, TYPE, MEMBER) \ 341 | ILIST_FOREACH(iterator, head, TYPE, MEMBER) 342 | 343 | #define ilist_foreach_entry(pos, head) \ 344 | for( (pos) = (head)->next; (pos) != (head) ; (pos) = (pos)->next ) 345 | 346 | 347 | #define __ilist_splice(list, head) do { \ 348 | ilist_head *first = (list)->next, *last = (list)->prev; \ 349 | ilist_head *at = (head)->next; \ 350 | (first)->prev = (head), (head)->next = (first); \ 351 | (last)->next = (at), (at)->prev = (last); } while (0) 352 | 353 | #define ilist_splice(list, head) do { \ 354 | if (!ilist_is_empty(list)) __ilist_splice(list, head); } while (0) 355 | 356 | #define ilist_splice_init(list, head) do { \ 357 | ilist_splice(list, head); ilist_init(list); } while (0) 358 | 359 | #define ilist_replace(oldnode, newnode) ( \ 360 | (newnode)->next = (oldnode)->next, \ 361 | (newnode)->next->prev = (newnode), \ 362 | (newnode)->prev = (oldnode)->prev, \ 363 | (newnode)->prev->next = (newnode)) 364 | 365 | #ifdef _MSC_VER 366 | #pragma warning(disable:4311) 367 | #pragma warning(disable:4312) 368 | #pragma warning(disable:4996) 369 | #endif 370 | 371 | #endif 372 | 373 | 374 | /*====================================================================*/ 375 | /* IMUTEX - mutex interfaces */ 376 | /*====================================================================*/ 377 | #ifndef IMUTEX_TYPE 378 | 379 | #ifndef IMUTEX_DISABLE 380 | #if (defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)) 381 | #if ((!defined(_M_PPC)) && (!defined(_M_PPC_BE)) && (!defined(_XBOX))) 382 | #ifndef _WIN32_WINNT 383 | #define _WIN32_WINNT 0x0500 384 | #endif 385 | #ifndef WIN32_LEAN_AND_MEAN 386 | #define WIN32_LEAN_AND_MEAN 387 | #endif 388 | #include 389 | #else 390 | #ifndef _XBOX 391 | #define _XBOX 392 | #endif 393 | #include 394 | #endif 395 | 396 | #define IMUTEX_TYPE CRITICAL_SECTION 397 | #define IMUTEX_INIT(m) InitializeCriticalSection((CRITICAL_SECTION*)(m)) 398 | #define IMUTEX_DESTROY(m) DeleteCriticalSection((CRITICAL_SECTION*)(m)) 399 | #define IMUTEX_LOCK(m) EnterCriticalSection((CRITICAL_SECTION*)(m)) 400 | #define IMUTEX_UNLOCK(m) LeaveCriticalSection((CRITICAL_SECTION*)(m)) 401 | 402 | #elif defined(__unix) || defined(__unix__) || defined(__MACH__) 403 | #include 404 | #include 405 | #define IMUTEX_TYPE pthread_mutex_t 406 | #define IMUTEX_INIT(m) pthread_mutex_init((pthread_mutex_t*)(m), 0) 407 | #define IMUTEX_DESTROY(m) pthread_mutex_destroy((pthread_mutex_t*)(m)) 408 | #define IMUTEX_LOCK(m) pthread_mutex_lock((pthread_mutex_t*)(m)) 409 | #define IMUTEX_UNLOCK(m) pthread_mutex_unlock((pthread_mutex_t*)(m)) 410 | #endif 411 | #endif 412 | 413 | #ifndef IMUTEX_TYPE 414 | #define IMUTEX_TYPE int 415 | #define IMUTEX_INIT(m) { (*(m)) = (*(m)); } 416 | #define IMUTEX_DESTROY(m) { (*(m)) = (*(m)); } 417 | #define IMUTEX_LOCK(m) { (*(m)) = (*(m)); } 418 | #define IMUTEX_UNLOCK(m) { (*(m)) = (*(m)); } 419 | #endif 420 | 421 | #endif 422 | 423 | 424 | 425 | /*====================================================================*/ 426 | /* IVECTOR / IMEMNODE MANAGEMENT */ 427 | /*====================================================================*/ 428 | 429 | typedef struct IVECTOR ib_vector; 430 | typedef struct IMEMNODE ib_memnode; 431 | 432 | ib_vector *iv_create(void); 433 | void iv_delete(ib_vector *vec); 434 | 435 | ib_memnode *imnode_create(ilong nodesize, int grow_limit); 436 | void imnode_delete(ib_memnode *); 437 | 438 | 439 | /*--------------------------------------------------------------------*/ 440 | /* Collection - Array */ 441 | /*--------------------------------------------------------------------*/ 442 | 443 | struct ib_array; 444 | typedef struct ib_array ib_array; 445 | 446 | ib_array *ib_array_new(void (*destroy_func)(void*)); 447 | void ib_array_delete(ib_array *array); 448 | void ib_array_reserve(ib_array *array, size_t new_size); 449 | size_t ib_array_size(const ib_array *array); 450 | void** ib_array_ptr(ib_array *array); 451 | void* ib_array_index(ib_array *array, size_t index); 452 | const void* ib_array_const_index(const ib_array *array, size_t index); 453 | void ib_array_push(ib_array *array, void *item); 454 | void ib_array_push_left(ib_array *array, void *item); 455 | void ib_array_replace(ib_array *array, size_t index, void *item); 456 | void* ib_array_pop(ib_array *array); 457 | void* ib_array_pop_left(ib_array *array); 458 | void ib_array_remove(ib_array *array, size_t index); 459 | void ib_array_insert_before(ib_array *array, size_t index, void *item); 460 | void* ib_array_pop_at(ib_array *array, size_t index); 461 | void ib_array_for_each(ib_array *array, void (*iterator)(void *item)); 462 | void ib_array_reverse(ib_array *array); 463 | 464 | #define ib_array_obj(array, type, index) \ 465 | ((type)ib_array_index((array), (index))) 466 | 467 | #define ib_array_obj_const(array, type, index) \ 468 | ((type)ib_array_const_index((array), (index))) 469 | 470 | void ib_array_sort(ib_array *array, 471 | int (*compare)(const void*, const void*)); 472 | 473 | ilong ib_array_search(const ib_array *array, 474 | int (*compare)(const void*, const void*), 475 | const void *item, 476 | ilong start_pos); 477 | 478 | ilong ib_array_bsearch(const ib_array *array, 479 | int (*compare)(const void*, const void*), 480 | const void *item); 481 | 482 | 483 | /*====================================================================*/ 484 | /* ib_node - binary search tree (can be used in rbtree & avl) */ 485 | /* color/balance won't be packed (can work without alignment) */ 486 | /*====================================================================*/ 487 | struct ib_node 488 | { 489 | struct ib_node *left; /* left child */ 490 | struct ib_node *right; /* right child */ 491 | struct ib_node *parent; /* pointing to node itself for empty node */ 492 | int height; /* equals to 1 + max height in childs */ 493 | }; 494 | 495 | struct ib_root 496 | { 497 | struct ib_node *node; /* root node */ 498 | }; 499 | 500 | 501 | /*--------------------------------------------------------------------*/ 502 | /* NODE MACROS */ 503 | /*--------------------------------------------------------------------*/ 504 | #define IB_OFFSET(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 505 | 506 | #define IB_NODE2DATA(n, o) ((void *)((size_t)(n) - (o))) 507 | #define IB_DATA2NODE(d, o) ((struct ib_node*)((size_t)(d) + (o))) 508 | 509 | #define IB_ENTRY(ptr, type, member) \ 510 | ((type*)IB_NODE2DATA(ptr, IB_OFFSET(type, member))) 511 | 512 | #define ib_node_init(node) do { ((node)->parent) = (node); } while (0) 513 | #define ib_node_empty(node) ((node)->parent == (node)) 514 | 515 | #define IB_LEFT_HEIGHT(node) (((node)->left)? ((node)->left)->height : 0) 516 | #define IB_RIGHT_HEIGHT(node) (((node)->right)? ((node)->right)->height : 0) 517 | 518 | 519 | /*--------------------------------------------------------------------*/ 520 | /* binary search tree - node manipulation */ 521 | /*--------------------------------------------------------------------*/ 522 | struct ib_node *ib_node_first(struct ib_root *root); 523 | struct ib_node *ib_node_last(struct ib_root *root); 524 | struct ib_node *ib_node_next(struct ib_node *node); 525 | struct ib_node *ib_node_prev(struct ib_node *node); 526 | 527 | void ib_node_replace(struct ib_node *victim, struct ib_node *newnode, 528 | struct ib_root *root); 529 | 530 | static inline void ib_node_link(struct ib_node *node, struct ib_node *parent, 531 | struct ib_node **ib_link) { 532 | node->parent = parent; 533 | node->height = 1; 534 | node->left = node->right = NULL; 535 | ib_link[0] = node; 536 | } 537 | 538 | 539 | /* avl insert rebalance and erase */ 540 | void ib_node_post_insert(struct ib_node *node, struct ib_root *root); 541 | void ib_node_erase(struct ib_node *node, struct ib_root *root); 542 | 543 | /* avl nodes destroy: fast tear down the whole tree */ 544 | struct ib_node* ib_node_tear(struct ib_root *root, struct ib_node **next); 545 | 546 | 547 | /*--------------------------------------------------------------------*/ 548 | /* avl - node templates */ 549 | /*--------------------------------------------------------------------*/ 550 | #define ib_node_find(root, what, compare_fn, res_node) do {\ 551 | struct ib_node *__n = (root)->node; \ 552 | (res_node) = NULL; \ 553 | while (__n) { \ 554 | int __hr = (compare_fn)(what, __n); \ 555 | if (__hr == 0) { (res_node) = __n; break; } \ 556 | else if (__hr < 0) { __n = __n->left; } \ 557 | else { __n = __n->right; } \ 558 | } \ 559 | } while (0) 560 | 561 | 562 | #define ib_node_add(root, newnode, compare_fn, duplicate_node) do { \ 563 | struct ib_node **__link = &((root)->node); \ 564 | struct ib_node *__parent = NULL; \ 565 | struct ib_node *__duplicate = NULL; \ 566 | int __hr = 1; \ 567 | while (__link[0]) { \ 568 | __parent = __link[0]; \ 569 | __hr = (compare_fn)(newnode, __parent); \ 570 | if (__hr == 0) { __duplicate = __parent; break; } \ 571 | else if (__hr < 0) { __link = &(__parent->left); } \ 572 | else { __link = &(__parent->right); } \ 573 | } \ 574 | (duplicate_node) = __duplicate; \ 575 | if (__duplicate == NULL) { \ 576 | ib_node_link(newnode, __parent, __link); \ 577 | ib_node_post_insert(newnode, root); \ 578 | } \ 579 | } while (0) 580 | 581 | 582 | /*--------------------------------------------------------------------*/ 583 | /* avltree - friendly interface */ 584 | /*--------------------------------------------------------------------*/ 585 | struct ib_tree 586 | { 587 | struct ib_root root; /* avl root */ 588 | size_t offset; /* node offset in user data structure */ 589 | size_t size; /* size of user data structure */ 590 | size_t count; /* node count */ 591 | /* returns 0 for equal, -1 for n1 < n2, 1 for n1 > n2 */ 592 | int (*compare)(const void *n1, const void *n2); 593 | }; 594 | 595 | 596 | /* initialize avltree, use IB_OFFSET(type, member) for "offset" 597 | * eg: 598 | * ib_tree_init(&mytree, mystruct_compare, 599 | * sizeof(struct mystruct_t), 600 | * IB_OFFSET(struct mystruct_t, node)); 601 | */ 602 | void ib_tree_init(struct ib_tree *tree, 603 | int (*compare)(const void*, const void*), size_t size, size_t offset); 604 | 605 | void *ib_tree_first(struct ib_tree *tree); 606 | void *ib_tree_last(struct ib_tree *tree); 607 | void *ib_tree_next(struct ib_tree *tree, void *data); 608 | void *ib_tree_prev(struct ib_tree *tree, void *data); 609 | 610 | /* require a temporary user structure (data) which contains the key */ 611 | void *ib_tree_find(struct ib_tree *tree, const void *data); 612 | void *ib_tree_nearest(struct ib_tree *tree, const void *data); 613 | 614 | /* returns NULL for success, otherwise returns conflict node with same key */ 615 | void *ib_tree_add(struct ib_tree *tree, void *data); 616 | 617 | void ib_tree_remove(struct ib_tree *tree, void *data); 618 | void ib_tree_replace(struct ib_tree *tree, void *victim, void *newdata); 619 | 620 | void ib_tree_clear(struct ib_tree *tree, void (*destroy)(void *data)); 621 | 622 | 623 | /*--------------------------------------------------------------------*/ 624 | /* fastbin - fixed size object allocator */ 625 | /*--------------------------------------------------------------------*/ 626 | struct ib_fastbin 627 | { 628 | size_t obj_size; 629 | size_t page_size; 630 | size_t maximum; 631 | char *start; 632 | char *endup; 633 | void *next; 634 | void *pages; 635 | }; 636 | 637 | 638 | #define IB_NEXT(ptr) (((void**)(ptr))[0]) 639 | 640 | void ib_fastbin_init(struct ib_fastbin *fb, size_t obj_size); 641 | void ib_fastbin_destroy(struct ib_fastbin *fb); 642 | 643 | void* ib_fastbin_new(struct ib_fastbin *fb); 644 | void ib_fastbin_del(struct ib_fastbin *fb, void *ptr); 645 | 646 | 647 | /*--------------------------------------------------------------------*/ 648 | /* string */ 649 | /*--------------------------------------------------------------------*/ 650 | struct ib_string; 651 | typedef struct ib_string ib_string; 652 | 653 | #ifndef IB_STRING_SSO 654 | #define IB_STRING_SSO 14 655 | #endif 656 | 657 | struct ib_string 658 | { 659 | char *ptr; 660 | int size; 661 | int capacity; 662 | char sso[IB_STRING_SSO + 2]; 663 | }; 664 | 665 | #define ib_string_ptr(str) ((str)->ptr) 666 | #define ib_string_size(str) ((str)->size) 667 | 668 | ib_string* ib_string_new(void); 669 | ib_string* ib_string_new_from(const char *text); 670 | ib_string* ib_string_new_size(const char *text, int size); 671 | 672 | void ib_string_delete(ib_string *str); 673 | 674 | ib_string* ib_string_resize(ib_string *str, int newsize); 675 | 676 | ib_string* ib_string_assign(ib_string *str, const char *src); 677 | ib_string* ib_string_assign_size(ib_string *str, const char *src, int size); 678 | 679 | ib_string* ib_string_erase(ib_string *str, int pos, int size); 680 | ib_string* ib_string_insert(ib_string *str, int pos, 681 | const void *data, int size); 682 | 683 | ib_string* ib_string_append(ib_string *str, const char *src); 684 | ib_string* ib_string_append_size(ib_string *str, const char *src, int size); 685 | ib_string* ib_string_append_c(ib_string *str, char c); 686 | 687 | ib_string* ib_string_prepend(ib_string *str, const char *src); 688 | ib_string* ib_string_prepend_size(ib_string *str, const char *src, int size); 689 | ib_string* ib_string_prepend_c(ib_string *str, char c); 690 | 691 | ib_string* ib_string_rewrite(ib_string *str, int pos, const char *src); 692 | ib_string* ib_string_rewrite_size(ib_string *str, int pos, 693 | const char *src, int size); 694 | 695 | int ib_string_compare(const struct ib_string *a, const struct ib_string *b); 696 | 697 | int ib_string_find(const ib_string *str, const char *src, int len, int start); 698 | int ib_string_find_c(const ib_string *str, char ch, int start); 699 | 700 | ib_array* ib_string_split(const ib_string *str, const char *sep, int len); 701 | ib_array* ib_string_split_c(const ib_string *str, char sep); 702 | 703 | ib_string* ib_string_strip(ib_string *str, const char *seps); 704 | 705 | 706 | /*--------------------------------------------------------------------*/ 707 | /* static hash table (closed hash table with avlnode) */ 708 | /*--------------------------------------------------------------------*/ 709 | struct ib_hash_node 710 | { 711 | struct ib_node avlnode; 712 | void *key; 713 | size_t hash; 714 | }; 715 | 716 | struct ib_hash_index 717 | { 718 | struct ILISTHEAD node; 719 | struct ib_root avlroot; 720 | }; 721 | 722 | #define IB_HASH_INIT_SIZE 8 723 | 724 | struct ib_hash_table 725 | { 726 | size_t count; 727 | size_t index_size; 728 | size_t index_mask; 729 | size_t (*hash)(const void *key); 730 | int (*compare)(const void *key1, const void *key2); 731 | struct ILISTHEAD head; 732 | struct ib_hash_index *index; 733 | struct ib_hash_index init[IB_HASH_INIT_SIZE]; 734 | }; 735 | 736 | 737 | void ib_hash_init(struct ib_hash_table *ht, 738 | size_t (*hash)(const void *key), 739 | int (*compare)(const void *key1, const void *key2)); 740 | 741 | struct ib_hash_node* ib_hash_node_first(struct ib_hash_table *ht); 742 | struct ib_hash_node* ib_hash_node_last(struct ib_hash_table *ht); 743 | 744 | struct ib_hash_node* ib_hash_node_next(struct ib_hash_table *ht, 745 | struct ib_hash_node *node); 746 | 747 | struct ib_hash_node* ib_hash_node_prev(struct ib_hash_table *ht, 748 | struct ib_hash_node *node); 749 | 750 | static inline void ib_hash_node_key(struct ib_hash_table *ht, 751 | struct ib_hash_node *node, void *key) { 752 | node->key = key; 753 | node->hash = ht->hash(key); 754 | } 755 | 756 | struct ib_hash_node* ib_hash_find(struct ib_hash_table *ht, 757 | const struct ib_hash_node *node); 758 | 759 | struct ib_node** ib_hash_track(struct ib_hash_table *ht, 760 | const struct ib_hash_node *node, struct ib_node **parent); 761 | 762 | struct ib_hash_node* ib_hash_add(struct ib_hash_table *ht, 763 | struct ib_hash_node *node); 764 | 765 | void ib_hash_erase(struct ib_hash_table *ht, struct ib_hash_node *node); 766 | 767 | void ib_hash_replace(struct ib_hash_table *ht, 768 | struct ib_hash_node *victim, struct ib_hash_node *newnode); 769 | 770 | void ib_hash_clear(struct ib_hash_table *ht, 771 | void (*destroy)(struct ib_hash_node *node)); 772 | 773 | /* re-index nbytes must be: sizeof(struct ib_hash_index) * n */ 774 | void* ib_hash_swap(struct ib_hash_table *ht, void *index, size_t nbytes); 775 | 776 | 777 | /*--------------------------------------------------------------------*/ 778 | /* fast inline search, compare function will be expanded inline here */ 779 | /*--------------------------------------------------------------------*/ 780 | #define ib_hash_search(ht, srcnode, result, compare) do { \ 781 | size_t __hash = (srcnode)->hash; \ 782 | const void *__key = (srcnode)->key; \ 783 | struct ib_hash_index *__index = \ 784 | &((ht)->index[__hash & ((ht)->index_mask)]); \ 785 | struct ib_node *__anode = __index->avlroot.node; \ 786 | (result) = NULL; \ 787 | while (__anode) { \ 788 | struct ib_hash_node *__snode = \ 789 | IB_ENTRY(__anode, struct ib_hash_node, avlnode); \ 790 | size_t __shash = __snode->hash; \ 791 | if (__hash == __shash) { \ 792 | int __hc = (compare)(__key, __snode->key); \ 793 | if (__hc == 0) { (result) = __snode; break; } \ 794 | __anode = (__hc < 0)? __anode->left : __anode->right; \ 795 | } else { \ 796 | __anode = (__hash < __shash)? __anode->left:__anode->right;\ 797 | } \ 798 | } \ 799 | } while (0) 800 | 801 | 802 | /*--------------------------------------------------------------------*/ 803 | /* hash map, wrapper of ib_hash_table to support direct key/value */ 804 | /*--------------------------------------------------------------------*/ 805 | struct ib_hash_entry 806 | { 807 | struct ib_hash_node node; 808 | void *value; 809 | }; 810 | 811 | struct ib_hash_map 812 | { 813 | size_t count; 814 | int insert; 815 | int fixed; 816 | int builtin; 817 | void* (*key_copy)(void *key); 818 | void (*key_destroy)(void *key); 819 | void* (*value_copy)(void *value); 820 | void (*value_destroy)(void *value); 821 | struct ib_fastbin fb; 822 | struct ib_hash_table ht; 823 | }; 824 | 825 | 826 | #define ib_hash_key(entry) ((entry)->node.key) 827 | #define ib_hash_value(entry) ((entry)->value) 828 | 829 | void ib_map_init(struct ib_hash_map *hm, size_t (*hash)(const void*), 830 | int (*compare)(const void *, const void *)); 831 | 832 | void ib_map_destroy(struct ib_hash_map *hm); 833 | 834 | struct ib_hash_entry* ib_map_first(struct ib_hash_map *hm); 835 | struct ib_hash_entry* ib_map_last(struct ib_hash_map *hm); 836 | 837 | struct ib_hash_entry* ib_map_next(struct ib_hash_map *hm, 838 | struct ib_hash_entry *n); 839 | struct ib_hash_entry* ib_map_prev(struct ib_hash_map *hm, 840 | struct ib_hash_entry *n); 841 | 842 | struct ib_hash_entry* ib_map_find(struct ib_hash_map *hm, const void *key); 843 | void* ib_map_lookup(struct ib_hash_map *hm, const void *key, void *defval); 844 | 845 | 846 | struct ib_hash_entry* ib_map_add(struct ib_hash_map *hm, 847 | void *key, void *value, int *success); 848 | 849 | struct ib_hash_entry* ib_map_set(struct ib_hash_map *hm, 850 | void *key, void *value); 851 | 852 | void* ib_map_get(struct ib_hash_map *hm, const void *key); 853 | 854 | void ib_map_erase(struct ib_hash_map *hm, struct ib_hash_entry *entry); 855 | 856 | 857 | /* returns 0 for success, -1 for key mismatch */ 858 | int ib_map_remove(struct ib_hash_map *hm, const void *key); 859 | 860 | void ib_map_clear(struct ib_hash_map *hm); 861 | 862 | 863 | /*--------------------------------------------------------------------*/ 864 | /* fast inline search template */ 865 | /*--------------------------------------------------------------------*/ 866 | 867 | #define ib_map_search(hm, srckey, hash_func, cmp_func, result) do { \ 868 | size_t __hash = (hash_func)(srckey); \ 869 | struct ib_hash_index *__index = \ 870 | &((hm)->ht.index[__hash & ((hm)->ht.index_mask)]); \ 871 | struct ib_node *__anode = __index->avlroot.node; \ 872 | (result) = NULL; \ 873 | while (__anode) { \ 874 | struct ib_hash_node *__snode = \ 875 | IB_ENTRY(__anode, struct ib_hash_node, avlnode); \ 876 | size_t __shash = __snode->hash; \ 877 | if (__hash == __shash) { \ 878 | int __hc = (cmp_func)((srckey), __snode->key); \ 879 | if (__hc == 0) { \ 880 | (result) = IB_ENTRY(__snode, \ 881 | struct ib_hash_entry, node);\ 882 | break; \ 883 | } \ 884 | __anode = (__hc < 0)? __anode->left : __anode->right; \ 885 | } else { \ 886 | __anode = (__hash < __shash)? __anode->left:__anode->right;\ 887 | } \ 888 | } \ 889 | } while (0) 890 | 891 | 892 | /*--------------------------------------------------------------------*/ 893 | /* common type hash */ 894 | /*--------------------------------------------------------------------*/ 895 | size_t ib_hash_func_uint(const void *key); 896 | int ib_hash_compare_uint(const void *key1, const void *key2); 897 | 898 | size_t ib_hash_func_int(const void *key); 899 | int ib_hash_compare_int(const void *key1, const void *key2); 900 | 901 | size_t ib_hash_func_str(const void *key); 902 | int ib_hash_compare_str(const void *key1, const void *key2); 903 | 904 | size_t ib_hash_func_cstr(const void *key); 905 | int ib_hash_compare_cstr(const void *key1, const void *key2); 906 | 907 | 908 | struct ib_hash_entry *ib_map_find_uint(struct ib_hash_map *hm, iulong key); 909 | struct ib_hash_entry *ib_map_find_int(struct ib_hash_map *hm, ilong key); 910 | struct ib_hash_entry *ib_map_find_str(struct ib_hash_map *hm, const ib_string *key); 911 | struct ib_hash_entry *ib_map_find_cstr(struct ib_hash_map *hm, const char *key); 912 | 913 | 914 | 915 | #ifdef __cplusplus 916 | } 917 | #endif 918 | 919 | #endif 920 | 921 | 922 | 923 | 924 | -------------------------------------------------------------------------------- /system/iposix.c: -------------------------------------------------------------------------------- 1 | //===================================================================== 2 | // 3 | // iposix.c - posix file system accessing 4 | // 5 | // NOTE: 6 | // for more information, please see the readme file. 7 | // 8 | //===================================================================== 9 | 10 | #include "iposix.h" 11 | 12 | #ifndef IDISABLE_FILE_SYSTEM_ACCESS 13 | //--------------------------------------------------------------------- 14 | // Global Definition 15 | //--------------------------------------------------------------------- 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) 26 | #include 27 | #endif 28 | 29 | #ifdef _WIN32 30 | #include 31 | #include 32 | #include 33 | #define ISYSNAME 'w' 34 | #else 35 | #ifndef __unix 36 | #define __unix 37 | #endif 38 | #define ISYSNAME 'u' 39 | #endif 40 | 41 | 42 | 43 | //--------------------------------------------------------------------- 44 | // Posix Stat 45 | //--------------------------------------------------------------------- 46 | #ifdef __unix 47 | typedef struct stat iposix_ostat_t; 48 | #define iposix_stat_proc stat 49 | #define iposix_lstat_proc lstat 50 | #define iposix_fstat_proc fstat 51 | #else 52 | typedef struct _stat iposix_ostat_t; 53 | #define iposix_stat_proc _stat 54 | #define iposix_lstat_proc _stat 55 | #define iposix_fstat_proc _fstat 56 | #endif 57 | 58 | 59 | #if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) 60 | #if defined(_S_IFMT) && (!defined(S_IFMT)) 61 | #define S_IFMT _S_IFMT 62 | #endif 63 | 64 | #if defined(_S_IFDIR) && (!defined(S_IFDIR)) 65 | #define S_IFDIR _S_IFDIR 66 | #endif 67 | 68 | #if defined(_S_IFCHR) && (!defined(S_IFCHR)) 69 | #define S_IFCHR _S_IFCHR 70 | #endif 71 | 72 | #if defined(_S_IFIFO) && (!defined(S_IFIFO)) 73 | #define S_IFIFO _S_IFIFO 74 | #endif 75 | 76 | #if defined(_S_IFREG) && (!defined(S_IFREG)) 77 | #define S_IFREG _S_IFREG 78 | #endif 79 | 80 | #if defined(_S_IREAD) && (!defined(S_IREAD)) 81 | #define S_IREAD _S_IREAD 82 | #endif 83 | 84 | #if defined(_S_IWRITE) && (!defined(S_IWRITE)) 85 | #define S_IWRITE _S_IWRITE 86 | #endif 87 | 88 | #if defined(_S_IEXEC) && (!defined(S_IEXEC)) 89 | #define S_IEXEC _S_IEXEC 90 | #endif 91 | #endif 92 | 93 | #define IX_FMT(m, t) (((m) & S_IFMT) == (t)) 94 | 95 | 96 | // convert stat structure 97 | void iposix_stat_convert(iposix_stat_t *ostat, const iposix_ostat_t *x) 98 | { 99 | ostat->st_mode = 0; 100 | 101 | #ifdef S_IFDIR 102 | if (IX_FMT(x->st_mode, S_IFDIR)) ostat->st_mode |= ISTAT_IFDIR; 103 | #endif 104 | #ifdef S_IFCHR 105 | if (IX_FMT(x->st_mode, S_IFCHR)) ostat->st_mode |= ISTAT_IFCHR; 106 | #endif 107 | #ifdef S_IFBLK 108 | if (IX_FMT(x->st_mode, S_IFBLK)) ostat->st_mode |= ISTAT_IFBLK; 109 | #endif 110 | #ifdef S_IFREG 111 | if (IX_FMT(x->st_mode, S_IFREG)) ostat->st_mode |= ISTAT_IFREG; 112 | #endif 113 | #ifdef S_IFIFO 114 | if (IX_FMT(x->st_mode, S_IFIFO)) ostat->st_mode |= ISTAT_IFIFO; 115 | #endif 116 | #ifdef S_IFLNK 117 | if (IX_FMT(x->st_mode, S_IFLNK)) ostat->st_mode |= ISTAT_IFLNK; 118 | #endif 119 | #ifdef S_IFSOCK 120 | if (IX_FMT(x->st_mode, S_IFSOCK)) ostat->st_mode |= ISTAT_IFSOCK; 121 | #endif 122 | #ifdef S_IFWHT 123 | if (IX_FMT(x->st_mode, S_IFWHT)) ostat->st_mode |= ISTAT_IFWHT; 124 | #endif 125 | 126 | #ifdef S_IREAD 127 | if (x->st_mode & S_IREAD) ostat->st_mode |= ISTAT_IRUSR; 128 | #endif 129 | 130 | #ifdef S_IWRITE 131 | if (x->st_mode & S_IWRITE) ostat->st_mode |= ISTAT_IWUSR; 132 | #endif 133 | 134 | #ifdef S_IEXEC 135 | if (x->st_mode & S_IEXEC) ostat->st_mode |= ISTAT_IXUSR; 136 | #endif 137 | 138 | #ifdef S_IRUSR 139 | if (x->st_mode & S_IRUSR) ostat->st_mode |= ISTAT_IRUSR; 140 | if (x->st_mode & S_IWUSR) ostat->st_mode |= ISTAT_IWUSR; 141 | if (x->st_mode & S_IXUSR) ostat->st_mode |= ISTAT_IXUSR; 142 | #endif 143 | 144 | #ifdef S_IRGRP 145 | if (x->st_mode & S_IRGRP) ostat->st_mode |= ISTAT_IRGRP; 146 | if (x->st_mode & S_IWGRP) ostat->st_mode |= ISTAT_IWGRP; 147 | if (x->st_mode & S_IXGRP) ostat->st_mode |= ISTAT_IXGRP; 148 | #endif 149 | 150 | #ifdef S_IROTH 151 | if (x->st_mode & S_IROTH) ostat->st_mode |= ISTAT_IROTH; 152 | if (x->st_mode & S_IWOTH) ostat->st_mode |= ISTAT_IWOTH; 153 | if (x->st_mode & S_IXOTH) ostat->st_mode |= ISTAT_IXOTH; 154 | #endif 155 | 156 | ostat->st_size = (IUINT64)x->st_size; 157 | 158 | ostat->atime = (IUINT32)x->st_atime; 159 | ostat->mtime = (IUINT32)x->st_mtime; 160 | ostat->ctime = (IUINT32)x->st_mtime; 161 | 162 | ostat->st_ino = (IUINT64)x->st_ino; 163 | ostat->st_dev = (IUINT32)x->st_dev; 164 | ostat->st_nlink = (IUINT32)x->st_nlink; 165 | ostat->st_uid = (IUINT32)x->st_uid; 166 | ostat->st_gid = (IUINT32)x->st_gid; 167 | ostat->st_rdev = (IUINT32)x->st_rdev; 168 | 169 | #ifdef __unix 170 | // #define IHAVE_STAT_ST_BLKSIZE 171 | // #define IHAVE_STAT_ST_BLOCKS 172 | // #define IHAVE_STAT_ST_FLAGS 173 | #endif 174 | 175 | #if defined(__unix) 176 | #ifdef IHAVE_STAT_ST_BLOCKS 177 | ostat->st_blocks = (IUINT32)x->st_blocks; 178 | #endif 179 | #ifdef IHAVE_STAT_ST_BLKSIZE 180 | ostat->st_blksize = (IUINT32)x->st_blksize; 181 | #endif 182 | #if !defined(__CYGWIN__) && defined(IHAVE_STAT_ST_FLAGS) 183 | ostat->st_flags = (IUINT32)x->st_flags; 184 | #endif 185 | #endif 186 | } 187 | 188 | // returns 0 for success, -1 for error 189 | int iposix_stat_imp(const char *path, iposix_stat_t *ostat) 190 | { 191 | iposix_ostat_t xstat; 192 | int retval; 193 | retval = iposix_stat_proc(path, &xstat); 194 | if (retval != 0) return -1; 195 | iposix_stat_convert(ostat, &xstat); 196 | return 0; 197 | } 198 | 199 | // returns 0 for success, -1 for error 200 | int iposix_lstat_imp(const char *path, iposix_stat_t *ostat) 201 | { 202 | iposix_ostat_t xstat; 203 | int retval; 204 | retval = iposix_lstat_proc(path, &xstat); 205 | if (retval != 0) return -1; 206 | iposix_stat_convert(ostat, &xstat); 207 | return 0; 208 | } 209 | 210 | // returns 0 for success, -1 for error 211 | int iposix_fstat(int fd, iposix_stat_t *ostat) 212 | { 213 | iposix_ostat_t xstat; 214 | int retval; 215 | retval = iposix_fstat_proc(fd, &xstat); 216 | if (retval != 0) return -1; 217 | iposix_stat_convert(ostat, &xstat); 218 | return 0; 219 | } 220 | 221 | // normalize stat path 222 | static void iposix_path_stat(const char *src, char *dst) 223 | { 224 | int size = (int)strlen(src); 225 | if (size > IPOSIX_MAXPATH) size = IPOSIX_MAXPATH; 226 | memcpy(dst, src, size + 1); 227 | if (size > 1) { 228 | int trim = 1; 229 | if (size == 3) { 230 | if (isalpha((int)dst[0]) && dst[1] == ':' && 231 | (dst[2] == '/' || dst[2] == '\\')) trim = 0; 232 | } 233 | if (size == 1) { 234 | if (dst[0] == '/' || dst[0] == '\\') trim = 0; 235 | } 236 | if (trim) { 237 | if (dst[size - 1] == '/' || dst[size - 1] == '\\') { 238 | dst[size - 1] = 0; 239 | size--; 240 | } 241 | } 242 | } 243 | } 244 | 245 | 246 | // returns 0 for success, -1 for error 247 | int iposix_stat(const char *path, iposix_stat_t *ostat) 248 | { 249 | char buf[IPOSIX_MAXBUFF]; 250 | iposix_path_stat(path, buf); 251 | return iposix_stat_imp(buf, ostat); 252 | } 253 | 254 | // returns 0 for success, -1 for error 255 | int iposix_lstat(const char *path, iposix_stat_t *ostat) 256 | { 257 | char buf[IPOSIX_MAXBUFF]; 258 | iposix_path_stat(path, buf); 259 | return iposix_lstat_imp(buf, ostat); 260 | } 261 | 262 | // get current directory 263 | char *iposix_getcwd(char *path, int size) 264 | { 265 | #ifdef _WIN32 266 | return _getcwd(path, size); 267 | #else 268 | return getcwd(path, size); 269 | #endif 270 | } 271 | 272 | // create directory 273 | int iposix_mkdir(const char *path, int mode) 274 | { 275 | #ifdef _WIN32 276 | return _mkdir(path); 277 | #else 278 | if (mode < 0) mode = 0755; 279 | return mkdir(path, mode); 280 | #endif 281 | } 282 | 283 | // change directory 284 | int iposix_chdir(const char *path) 285 | { 286 | #ifdef _WIN32 287 | return _chdir(path); 288 | #else 289 | return chdir(path); 290 | #endif 291 | } 292 | 293 | // check access 294 | int iposix_access(const char *path, int mode) 295 | { 296 | #ifdef _WIN32 297 | return _access(path, mode); 298 | #else 299 | return access(path, mode); 300 | #endif 301 | } 302 | 303 | // returns 1 for true 0 for false, -1 for not exist 304 | int iposix_path_isdir(const char *path) 305 | { 306 | iposix_stat_t s; 307 | int hr = iposix_stat(path, &s); 308 | if (hr != 0) return -1; 309 | return (ISTAT_ISDIR(s.st_mode))? 1 : 0; 310 | } 311 | 312 | // returns 1 for true 0 for false, -1 for not exist 313 | int iposix_path_isfile(const char *path) 314 | { 315 | iposix_stat_t s; 316 | int hr = iposix_stat(path, &s); 317 | if (hr != 0) return -1; 318 | return (ISTAT_ISDIR(s.st_mode))? 0 : 1; 319 | } 320 | 321 | // returns 1 for true 0 for false, -1 for not exist 322 | int iposix_path_islink(const char *path) 323 | { 324 | iposix_stat_t s; 325 | int hr = iposix_stat(path, &s); 326 | if (hr != 0) return -1; 327 | return (ISTAT_ISLNK(s.st_mode))? 1 : 0; 328 | } 329 | 330 | // returns 1 for true 0 for false 331 | int iposix_path_exists(const char *path) 332 | { 333 | iposix_stat_t s; 334 | int hr = iposix_stat(path, &s); 335 | if (hr != 0) return 0; 336 | return 1; 337 | } 338 | 339 | // returns file size, -1 for error 340 | IINT64 iposix_path_getsize(const char *path) 341 | { 342 | iposix_stat_t s; 343 | int hr = iposix_stat(path, &s); 344 | if (hr != 0) return -1; 345 | return (IINT64)s.st_size; 346 | } 347 | 348 | 349 | //--------------------------------------------------------------------- 350 | // Posix Path 351 | //--------------------------------------------------------------------- 352 | 353 | // 是否是绝对路径,如果是的话返回1,否则返回0 354 | int iposix_path_isabs(const char *path) 355 | { 356 | if (path == NULL) return 0; 357 | if (path[0] == '/') return 1; 358 | if (path[0] == 0) return 0; 359 | #ifdef _WIN32 360 | if (path[0] == IPATHSEP) return 1; 361 | if (isalpha(path[0]) && path[1] == ':') { 362 | if (path[2] == '/' || path[2] == '\\') return 1; 363 | } 364 | #endif 365 | return 0; 366 | } 367 | 368 | 369 | 370 | //--------------------------------------------------------------------- 371 | // iposix_string_t - basic string definition 372 | //--------------------------------------------------------------------- 373 | typedef struct 374 | { 375 | char *p; 376 | int l; 377 | int m; 378 | } iposix_string_t; 379 | 380 | 381 | //--------------------------------------------------------------------- 382 | // iposix_string_t interface 383 | //--------------------------------------------------------------------- 384 | #define _istrlen(s) ((s)->l) 385 | #define _istrch(s, i) (((i) >= 0)? ((s)->p)[i] : ((s)->p)[(s)->l + (i)]) 386 | 387 | static char *_istrset(iposix_string_t *s, const char *p, int max) 388 | { 389 | assert((max > 0) && p && s); 390 | s->p = (char*)p; 391 | s->l = strlen(p); 392 | s->m = max; 393 | return (char*)p; 394 | } 395 | 396 | static char *_istrcat(iposix_string_t *s, const char *p) 397 | { 398 | char *p1; 399 | 400 | assert(s && p); 401 | for (p1 = (char*)p; p1[0]; p1++, s->l++) { 402 | if (s->l >= s->m) break; 403 | s->p[s->l] = p1[0]; 404 | } 405 | return s->p; 406 | } 407 | 408 | static char *_istrcpy(iposix_string_t *s, const char *p) 409 | { 410 | assert(s && p); 411 | s->l = 0; 412 | return _istrcat(s, p); 413 | } 414 | 415 | static char *_istrcats(iposix_string_t *s1, const iposix_string_t *s2) 416 | { 417 | int i; 418 | assert(s1 && s2); 419 | for (i = 0; i < s2->l; i++, s1->l++) { 420 | if (s1->l >= s1->m) break; 421 | s1->p[s1->l] = s2->p[i]; 422 | } 423 | return s1->p; 424 | } 425 | 426 | static char *_icstr(iposix_string_t *s) 427 | { 428 | assert(s); 429 | if (s->l >= s->m) s->l = s->m - 1; 430 | if (s->l < 0) s->l = 0; 431 | s->p[s->l] = 0; 432 | return s->p; 433 | } 434 | 435 | static char _istrc(const iposix_string_t *s, int pos) 436 | { 437 | if (pos >= 0) return (pos > s->l)? 0 : s->p[pos]; 438 | return (pos < -(s->l))? 0 : s->p[s->l + pos]; 439 | } 440 | 441 | static char _istrchop(iposix_string_t *s) 442 | { 443 | char ch = _istrc(s, -1); 444 | s->l--; 445 | if (s->l < 0) s->l = 0; 446 | return ch; 447 | } 448 | 449 | static char *_istrctok(iposix_string_t *s, const char *p) 450 | { 451 | int i, k; 452 | 453 | assert(s && p); 454 | 455 | for (; _istrlen(s) > 0; ) { 456 | for (i = 0, k = 0; p[i] && k == 0; i++) { 457 | if (_istrc(s, -1) == p[i]) k++; 458 | } 459 | if (k == 0) break; 460 | _istrchop(s); 461 | } 462 | for (; _istrlen(s) > 0; ) { 463 | for (i = 0, k = 0; p[i] && k == 0; i++) { 464 | if (_istrc(s, -1) == p[i]) k++; 465 | } 466 | if (k) break; 467 | _istrchop(s); 468 | } 469 | 470 | return s->p; 471 | } 472 | 473 | static int _istrcmp(iposix_string_t *s, const char *p) 474 | { 475 | int i; 476 | for (i = 0; i < s->l && ((char*)p)[i]; i++) 477 | if (_istrc(s, i) != ((char*)p)[i]) break; 478 | if (((char*)p)[i] == 0 && i == s->l) return 0; 479 | return 1; 480 | } 481 | 482 | static char *_istrcatc(iposix_string_t *s, char ch) 483 | { 484 | char text[2] = " "; 485 | assert(s); 486 | text[0] = ch; 487 | return _istrcat(s, text); 488 | } 489 | 490 | static int istrtok(const char *p1, int *pos, const char *p2) 491 | { 492 | int i, j, k, r; 493 | 494 | assert(p1 && pos && p2); 495 | 496 | for (i = *pos; p1[i]; i++) { 497 | for (j = 0, k = 0; p2[j] && k == 0; j++) { 498 | if (p1[i] == p2[j]) k++; 499 | } 500 | if (k == 0) break; 501 | } 502 | *pos = i; 503 | r = i; 504 | 505 | if (p1[i] == 0) return -1; 506 | for (; p1[i]; i++) { 507 | for (j = 0, k = 0; p2[j] && k == 0; j++) { 508 | if (p1[i] == p2[j]) k++; 509 | } 510 | if (k) break; 511 | } 512 | *pos = i; 513 | 514 | return r; 515 | } 516 | 517 | 518 | //--------------------------------------------------------------------- 519 | // normalize path 520 | //--------------------------------------------------------------------- 521 | char *iposix_path_normal(const char *srcpath, char *path, int maxsize) 522 | { 523 | int i, p, c, k, r; 524 | iposix_string_t s1, s2; 525 | char *p1, *p2; 526 | char pp2[3]; 527 | 528 | assert(srcpath && path && maxsize > 0); 529 | 530 | if (srcpath[0] == 0) { 531 | if (maxsize > 0) path[0] = 0; 532 | return path; 533 | } 534 | 535 | for (p1 = (char*)srcpath; p1[0] && isspace((int)p1[0]); p1++); 536 | 537 | path[0] = 0; 538 | _istrset(&s1, path, maxsize); 539 | 540 | if (IPATHSEP == '\\') { 541 | pp2[0] = '/'; 542 | pp2[1] = '\\'; 543 | pp2[2] = 0; 544 | } else { 545 | pp2[0] = '/'; 546 | pp2[1] = 0; 547 | } 548 | 549 | p2 = pp2; 550 | 551 | if (p1[0] && p1[1] == ':' && (ISYSNAME == 'u' || ISYSNAME == 'w')) { 552 | _istrcatc(&s1, *p1++); 553 | _istrcatc(&s1, *p1++); 554 | } 555 | 556 | if (IPATHSEP == '/') { 557 | if (p1[0] == '/') _istrcatc(&s1, *p1++); 558 | } 559 | else if (p1[0] == '/' || p1[0] == IPATHSEP) { 560 | _istrcatc(&s1, IPATHSEP); 561 | p1++; 562 | } 563 | 564 | r = (_istrc(&s1, -1) == IPATHSEP)? 1 : 0; 565 | srcpath = (const char*)p1; 566 | 567 | for (i = 0, c = 0, k = 0; (p = istrtok(srcpath, &i, p2)) >= 0; k++) { 568 | s2.p = (char*)(srcpath + p); 569 | s2.l = s2.m = i - p; 570 | //_iputs(&s2); printf("*\n"); 571 | if (_istrcmp(&s2, ".") == 0) continue; 572 | if (_istrcmp(&s2, "..") == 0) { 573 | if (c != 0) { 574 | _istrctok(&s1, (IPATHSEP == '\\')? "/\\:" : "/"); 575 | c--; 576 | continue; 577 | } 578 | if (c == 0 && r) { 579 | continue; 580 | } 581 | } else { 582 | c++; 583 | } 584 | _istrcats(&s1, &s2); 585 | _istrcatc(&s1, IPATHSEP); 586 | } 587 | if (_istrlen(&s1) == 0) { 588 | _istrcpy(&s1, "."); 589 | } else { 590 | if (_istrc(&s1, -1) == IPATHSEP && c > 0) _istrchop(&s1); 591 | } 592 | return _icstr(&s1); 593 | } 594 | 595 | 596 | //--------------------------------------------------------------------- 597 | // join path 598 | //--------------------------------------------------------------------- 599 | char *iposix_path_join(const char *p1, const char *p2, char *path, int len) 600 | { 601 | iposix_string_t s; 602 | int maxsize = len; 603 | char *p, r; 604 | 605 | assert(p1 && p2 && maxsize > 0); 606 | 607 | for (; p1[0] && isspace((int)p1[0]); p1++); 608 | for (; p2[0] && isspace((int)p2[0]); p2++); 609 | r = 0; 610 | p = (char*)p2; 611 | if (IPATHSEP == '/') { 612 | if (p[0] == '/') r = 1; 613 | } else { 614 | if (p[0] == '/' || p[0] == IPATHSEP) r = 1; 615 | } 616 | 617 | if (p[0] && p[1] == ':' && (ISYSNAME == 'u' || ISYSNAME == 'w')) 618 | return iposix_path_normal(p2, path, maxsize); 619 | 620 | if (r && (p1[0] == 0 || p1[1] != ':' || p1[2])) 621 | return iposix_path_normal(p2, path, maxsize); 622 | 623 | p = (char*)malloc(maxsize + 10); 624 | 625 | if (p == NULL) { 626 | return iposix_path_normal(p1, path, maxsize); 627 | } 628 | 629 | iposix_path_normal(p1, p, maxsize); 630 | _istrset(&s, p, maxsize); 631 | 632 | r = 1; 633 | if (_istrlen(&s) <= 2 && _istrc(&s, 1) == ':') r = 0; 634 | if (_istrc(&s, -1) == IPATHSEP) r = 0; 635 | if (_istrlen(&s) == 0) r = 0; 636 | if (r) _istrcatc(&s, IPATHSEP); 637 | 638 | _istrcat(&s, p2); 639 | iposix_path_normal(_icstr(&s), path, maxsize); 640 | free(p); 641 | 642 | return path; 643 | } 644 | 645 | 646 | // 绝对路径 647 | char *iposix_path_abspath_u(const char *srcpath, char *path, int maxsize) 648 | { 649 | char *base; 650 | base = (char*)malloc(IPOSIX_MAXBUFF * 2); 651 | if (base == NULL) return NULL; 652 | iposix_getcwd(base, IPOSIX_MAXPATH); 653 | iposix_path_join(base, srcpath, path, maxsize); 654 | free(base); 655 | return path; 656 | } 657 | 658 | #ifdef _WIN32 659 | char *iposix_path_abspath_w(const char *srcpath, char *path, int maxsize) 660 | { 661 | char *fname; 662 | DWORD hr = GetFullPathNameA(srcpath, maxsize, path, &fname); 663 | if (hr == 0) return NULL; 664 | return path; 665 | } 666 | #endif 667 | 668 | 669 | // 绝对路径 670 | char *iposix_path_abspath(const char *srcpath, char *path, int maxsize) 671 | { 672 | #ifdef _WIN32 673 | return iposix_path_abspath_w(srcpath, path, maxsize); 674 | #else 675 | return iposix_path_abspath_u(srcpath, path, maxsize); 676 | #endif 677 | } 678 | 679 | // 路径分割:从右向左找到第一个"/"分成两个字符串 680 | int iposix_path_split(const char *path, char *p1, int l1, char *p2, int l2) 681 | { 682 | int length, i, k; 683 | length = (int)strlen(path); 684 | 685 | for (i = length - 1; i >= 0; i--) { 686 | if (IPATHSEP == '/') { 687 | if (path[i] == '/') break; 688 | } else { 689 | if (path[i] == '/' || path[i] == '\\') break; 690 | } 691 | } 692 | 693 | if (p1) { 694 | if (i < 0) { 695 | if (l1 > 0) p1[0] = 0; 696 | } 697 | else if (i == 0) { 698 | p1[0] = '/'; 699 | p1[1] = 0; 700 | } 701 | else { 702 | int size = i < l1 ? i : l1; 703 | memcpy(p1, path, size); 704 | if (size < l1) p1[size] = 0; 705 | } 706 | } 707 | 708 | k = length - i - 1; 709 | 710 | if (p2) { 711 | if (k <= 0) { 712 | if (l2 > 0) p2[0] = 0; 713 | } else { 714 | int size = k < l2 ? k : l2; 715 | memcpy(p2, path + i + 1, k); 716 | if (size < l2) p2[size] = 0; 717 | } 718 | } 719 | 720 | return 0; 721 | } 722 | 723 | 724 | // 扩展分割:分割文件主名与扩展名 725 | int iposix_path_splitext(const char *path, char *p1, int l1, 726 | char *p2, int l2) 727 | { 728 | int length, i, k, size; 729 | length = (int)strlen(path); 730 | for (i = length - 1, k = length; i >= 0; i--) { 731 | if (path[i] == '.') { 732 | k = i; 733 | break; 734 | } 735 | else if (IPATHSEP == '/') { 736 | if (path[i] == '/') break; 737 | 738 | } 739 | else { 740 | if (path[i] == '/' || path[i] == '\\') break; 741 | } 742 | } 743 | 744 | if (p1) { 745 | 746 | size = k < l1 ? k : l1; 747 | if (size > 0) memcpy(p1, path, size); 748 | if (size < l1) p1[size] = 0; 749 | } 750 | 751 | size = length - k - 1; 752 | if (size < 0) size = 0; 753 | size = size < l2 ? size : l2; 754 | 755 | if (p2) { 756 | if (size > 0) memcpy(p2, path + k + 1, size); 757 | if (size < l2) p2[size] = 0; 758 | } 759 | 760 | return 0; 761 | } 762 | 763 | 764 | //--------------------------------------------------------------------- 765 | // platform special 766 | //--------------------------------------------------------------------- 767 | 768 | // cross os GetModuleFileName, returns size for success, -1 for error 769 | int iposix_path_exepath(char *ptr, int size) 770 | { 771 | int retval = -1; 772 | #if defined(_WIN32) 773 | DWORD hr = GetModuleFileNameA(NULL, ptr, (DWORD)size); 774 | if (hr > 0) retval = (int)hr; 775 | #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) 776 | int mib[4]; 777 | size_t cb = (size_t)size; 778 | int hr; 779 | mib[0] = CTL_KERN; 780 | mib[1] = KERN_PROC; 781 | mib[2] = KERN_PROC_PATHNAME; 782 | mib[3] = -1; 783 | hr = sysctl(mib, 4, ptr, &cb, NULL, 0); 784 | if (hr >= 0) retval = (int)cb; 785 | #elif defined(linux) || defined(__CYGWIN__) 786 | FILE *fp; 787 | fp = fopen("/proc/self/exename", "r"); 788 | if (fp) { 789 | retval = fread(ptr, 1, size, fp); 790 | fclose(fp); 791 | } else { 792 | retval = 0; 793 | } 794 | #else 795 | #endif 796 | if (retval >= 0 && retval < size) { 797 | ptr[retval] = '\0'; 798 | } else if (size > 0) { 799 | ptr[0] = '\0'; 800 | } 801 | 802 | if (size > 0) ptr[size - 1] = 0; 803 | 804 | return retval; 805 | } 806 | 807 | // 取得进程可执行文件的目录 808 | int iposix_path_execwd(char *ptr, int size) 809 | { 810 | char *buffer; 811 | int retval; 812 | 813 | if (ptr) { 814 | if (size > 0) ptr[0] = 0; 815 | } 816 | 817 | buffer = (char*)malloc(IPOSIX_MAXBUFF * 2); 818 | if (buffer == NULL) { 819 | return -1; 820 | } 821 | 822 | retval = iposix_path_exepath(buffer, IPOSIX_MAXBUFF * 2); 823 | 824 | if (retval < 0) { 825 | free(buffer); 826 | return -2; 827 | } 828 | 829 | iposix_path_split(buffer, ptr, size, NULL, IPOSIX_MAXPATH); 830 | 831 | free(buffer); 832 | 833 | return 0; 834 | } 835 | 836 | 837 | // 递归创建路径:直接从 ilog移植过来 838 | int iposix_path_mkdir(const char *path, int mode) 839 | { 840 | int i, len; 841 | char str[IPOSIX_MAXBUFF]; 842 | 843 | len = (int)strlen(path); 844 | if (len > IPOSIX_MAXPATH) len = IPOSIX_MAXPATH; 845 | 846 | memcpy(str, path, len); 847 | str[len] = 0; 848 | 849 | #ifdef _WIN32 850 | for (i = 0; i < len; i++) { 851 | if (str[i] == '/') str[i] = '\\'; 852 | } 853 | #endif 854 | 855 | for (i = 0; i < len; i++) { 856 | if (str[i] == '/' || str[i] == '\\') { 857 | str[i] = '\0'; 858 | if (iposix_access(str, F_OK) != 0) { 859 | iposix_mkdir(str, mode); 860 | } 861 | str[i] = IPATHSEP; 862 | } 863 | } 864 | 865 | if (len > 0 && iposix_access(str, 0) != 0) { 866 | iposix_mkdir(str, mode); 867 | } 868 | 869 | return 0; 870 | } 871 | 872 | 873 | // 精简版取得可执行路径 874 | const char *iposix_get_exepath(void) 875 | { 876 | static int inited = 0; 877 | static char *ptr = NULL; 878 | if (inited == 0) { 879 | char *buffer = (char*)malloc(IPOSIX_MAXBUFF); 880 | char *b2; 881 | int size; 882 | if (buffer == NULL) { 883 | inited = -1; 884 | return ""; 885 | } 886 | if (iposix_path_exepath(buffer, IPOSIX_MAXPATH) != 0) { 887 | free(buffer); 888 | inited = -1; 889 | return ""; 890 | } 891 | size = (int)strlen(buffer); 892 | b2 = (char*)malloc(size + 1); 893 | if (b2 == NULL) { 894 | free(buffer); 895 | inited = -1; 896 | return ""; 897 | } 898 | memcpy(b2, buffer, size + 1); 899 | free(buffer); 900 | ptr = b2; 901 | inited = 1; 902 | } 903 | if (inited < 0) return ""; 904 | return ptr; 905 | } 906 | 907 | // 精简版取得可执行目录 908 | const char *iposix_get_execwd(void) 909 | { 910 | static int inited = 0; 911 | static char ptr[IPOSIX_MAXBUFF + 10]; 912 | if (inited == 0) { 913 | if (iposix_path_execwd(ptr, IPOSIX_MAXPATH) != 0) { 914 | inited = -1; 915 | return ""; 916 | } 917 | inited = 1; 918 | } 919 | if (inited < 0) return ""; 920 | return ptr; 921 | } 922 | 923 | #ifdef _MSC_VER 924 | #pragma warning(disable:4996) 925 | #endif 926 | 927 | // 文件路径格式化: 928 | // out - 输出路径,长度不小于 IPOSIX_MAXPATH 929 | // base - 根路径 930 | // ... - 后续的相对路径 931 | // 返回 - out 932 | // 假设可执行路径位于 /home/abc/work,那么: 933 | // iposix_path_format(out, iposix_get_execwd(), "images/%s", "abc.jpg") 934 | // 结果就是 /home/abc/work/images/abc.jpg 935 | char *iposix_path_format(char *out, const char *root, const char *fmt, ...) 936 | { 937 | char buffer[IPOSIX_MAXBUFF]; 938 | va_list argptr; 939 | va_start(argptr, fmt); 940 | vsprintf(buffer, fmt, argptr); 941 | va_end(argptr); 942 | return iposix_path_join(root, buffer, out, IPOSIX_MAXPATH); 943 | } 944 | 945 | 946 | 947 | /*-------------------------------------------------------------------*/ 948 | /* System Utilities */ 949 | /*-------------------------------------------------------------------*/ 950 | #ifndef IDISABLE_SHARED_LIBRARY 951 | #if defined(__unix) 952 | #include 953 | #endif 954 | #endif 955 | 956 | void *iposix_shared_open(const char *dllname) 957 | { 958 | #ifndef IDISABLE_SHARED_LIBRARY 959 | #ifdef __unix 960 | return dlopen(dllname, RTLD_LAZY); 961 | #else 962 | return (void*)LoadLibraryA(dllname); 963 | #endif 964 | #else 965 | return NULL; 966 | #endif 967 | } 968 | 969 | void *iposix_shared_get(void *shared, const char *name) 970 | { 971 | #ifndef IDISABLE_SHARED_LIBRARY 972 | #ifdef __unix 973 | return dlsym(shared, name); 974 | #else 975 | return (void*)GetProcAddress((HINSTANCE)shared, name); 976 | #endif 977 | #else 978 | return NULL; 979 | #endif 980 | } 981 | 982 | void iposix_shared_close(void *shared) 983 | { 984 | #ifndef IDISABLE_SHARED_LIBRARY 985 | #ifdef __unix 986 | dlclose(shared); 987 | #else 988 | FreeLibrary((HINSTANCE)shared); 989 | #endif 990 | #endif 991 | } 992 | 993 | /* load file content */ 994 | void *iposix_file_load_content(const char *filename, long *size) 995 | { 996 | size_t length, remain; 997 | char *ptr, *out; 998 | FILE *fp; 999 | 1000 | if ((fp = fopen(filename, "rb")) == NULL) { 1001 | if (size) size[0] = 0; 1002 | return NULL; 1003 | } 1004 | 1005 | fseek(fp, 0, SEEK_END); 1006 | length = ftell(fp); 1007 | fseek(fp, 0, SEEK_SET); 1008 | 1009 | // avoid zero-size file returns null 1010 | ptr = (char*)malloc(length + 8); 1011 | 1012 | if (ptr == NULL) { 1013 | fclose(fp); 1014 | if (size) size[0] = 0; 1015 | return NULL; 1016 | } 1017 | 1018 | for (remain = length, out = ptr; remain > 0; ) { 1019 | size_t ret = fread(out, 1, remain, fp); 1020 | if (ret == 0) break; 1021 | remain -= ret; 1022 | out += ret; 1023 | } 1024 | 1025 | fclose(fp); 1026 | 1027 | if (size) size[0] = length; 1028 | 1029 | return ptr; 1030 | } 1031 | 1032 | 1033 | /* save file content */ 1034 | int iposix_file_save_content(const char *filename, const void *data, long size) 1035 | { 1036 | const char *ptr = (const char*)data; 1037 | FILE *fp; 1038 | int hr = 0; 1039 | if ((fp = fopen(filename, "wb")) == NULL) return -1; 1040 | for (; size > 0; ) { 1041 | long written = (long)fwrite(ptr, 1, size, fp); 1042 | if (written <= 0) { 1043 | hr = -2; 1044 | break; 1045 | } 1046 | size -= written; 1047 | ptr += written; 1048 | } 1049 | fclose(fp); 1050 | return hr; 1051 | } 1052 | 1053 | 1054 | 1055 | #endif 1056 | 1057 | 1058 | 1059 | 1060 | -------------------------------------------------------------------------------- /system/iposix.h: -------------------------------------------------------------------------------- 1 | //===================================================================== 2 | // 3 | // iposix.h - posix file system accessing 4 | // 5 | // NOTE: 6 | // for more information, please see the readme file. 7 | // 8 | //===================================================================== 9 | #ifndef __IPOSIX_H__ 10 | #define __IPOSIX_H__ 11 | 12 | #ifdef HAVE_CONFIG_H 13 | #include "config.h" 14 | #endif 15 | 16 | 17 | /*-------------------------------------------------------------------*/ 18 | /* C99 Compatible */ 19 | /*-------------------------------------------------------------------*/ 20 | #if defined(linux) || defined(__linux) || defined(__linux__) 21 | #ifdef _POSIX_C_SOURCE 22 | #if _POSIX_C_SOURCE < 200112L 23 | #undef _POSIX_C_SOURCE 24 | #endif 25 | #endif 26 | 27 | #ifndef _POSIX_C_SOURCE 28 | #define _POSIX_C_SOURCE 200112L 29 | #endif 30 | 31 | #ifdef _GNU_SOURCE 32 | #undef _GNU_SOURCE 33 | #endif 34 | 35 | #ifdef _BSD_SOURCE 36 | #undef _BSD_SOURCE 37 | #endif 38 | 39 | #ifdef __BSD_VISIBLE 40 | #undef __BSD_VISIBLE 41 | #endif 42 | 43 | #ifdef _XOPEN_SOURCE 44 | #undef _XOPEN_SOURCE 45 | #endif 46 | 47 | #define _GNU_SOURCE 1 48 | #define _BSD_SOURCE 1 49 | #define __BSD_VISIBLE 1 50 | #define _XOPEN_SOURCE 600 51 | #endif 52 | 53 | 54 | #ifndef IDISABLE_FILE_SYSTEM_ACCESS 55 | //--------------------------------------------------------------------- 56 | // Global Definition 57 | //--------------------------------------------------------------------- 58 | #ifndef __INTEGER_32_BITS__ 59 | #define __INTEGER_32_BITS__ 60 | #if defined(__UINT32_TYPE__) && defined(__UINT32_TYPE__) 61 | typedef __UINT32_TYPE__ ISTDUINT32; 62 | typedef __INT32_TYPE__ ISTDINT32; 63 | #elif defined(__UINT_FAST32_TYPE__) && defined(__INT_FAST32_TYPE__) 64 | typedef __UINT_FAST32_TYPE__ ISTDUINT32; 65 | typedef __INT_FAST32_TYPE__ ISTDINT32; 66 | #elif defined(_WIN64) || defined(WIN64) || defined(__amd64__) || \ 67 | defined(__x86_64) || defined(__x86_64__) || defined(_M_IA64) || \ 68 | defined(_M_AMD64) 69 | typedef unsigned int ISTDUINT32; 70 | typedef int ISTDINT32; 71 | #elif defined(_WIN32) || defined(WIN32) || defined(__i386__) || \ 72 | defined(__i386) || defined(_M_X86) 73 | typedef unsigned long ISTDUINT32; 74 | typedef long ISTDINT32; 75 | #elif defined(__MACOS__) 76 | typedef UInt32 ISTDUINT32; 77 | typedef SInt32 ISTDINT32; 78 | #elif defined(__APPLE__) && defined(__MACH__) 79 | #include 80 | typedef u_int32_t ISTDUINT32; 81 | typedef int32_t ISTDINT32; 82 | #elif defined(__BEOS__) 83 | #include 84 | typedef u_int32_t ISTDUINT32; 85 | typedef int32_t ISTDINT32; 86 | #elif (defined(_MSC_VER) || defined(__BORLANDC__)) && (!defined(__MSDOS__)) 87 | typedef unsigned __int32 ISTDUINT32; 88 | typedef __int32 ISTDINT32; 89 | #elif defined(__GNUC__) && (__GNUC__ > 3) 90 | #include 91 | typedef uint32_t ISTDUINT32; 92 | typedef int32_t ISTDINT32; 93 | #else 94 | typedef unsigned long ISTDUINT32; 95 | typedef long ISTDINT32; 96 | #endif 97 | #endif 98 | 99 | 100 | #if (defined(__APPLE__) && defined(__MACH__)) || defined(__MACOS__) 101 | #ifndef __unix 102 | #define __unix 1 103 | #endif 104 | #endif 105 | 106 | #if defined(__unix__) || defined(unix) || defined(__linux) 107 | #ifndef __unix 108 | #define __unix 1 109 | #endif 110 | #endif 111 | 112 | #include 113 | #ifdef __unix 114 | #include 115 | #define IPATHSEP '/' 116 | #else 117 | #include 118 | #if defined(_WIN32) 119 | #define IPATHSEP '\\' 120 | #else 121 | #define IPATHSEP '/' 122 | #endif 123 | #endif 124 | 125 | 126 | #ifndef __IINT8_DEFINED 127 | #define __IINT8_DEFINED 128 | typedef char IINT8; 129 | #endif 130 | 131 | #ifndef __IUINT8_DEFINED 132 | #define __IUINT8_DEFINED 133 | typedef unsigned char IUINT8; 134 | #endif 135 | 136 | #ifndef __IUINT16_DEFINED 137 | #define __IUINT16_DEFINED 138 | typedef unsigned short IUINT16; 139 | #endif 140 | 141 | #ifndef __IINT16_DEFINED 142 | #define __IINT16_DEFINED 143 | typedef short IINT16; 144 | #endif 145 | 146 | #ifndef __IINT32_DEFINED 147 | #define __IINT32_DEFINED 148 | typedef ISTDINT32 IINT32; 149 | #endif 150 | 151 | #ifndef __IUINT32_DEFINED 152 | #define __IUINT32_DEFINED 153 | typedef ISTDUINT32 IUINT32; 154 | #endif 155 | 156 | #ifndef __IINT64_DEFINED 157 | #define __IINT64_DEFINED 158 | #if defined(_MSC_VER) || defined(__BORLANDC__) 159 | typedef __int64 IINT64; 160 | #else 161 | typedef long long IINT64; 162 | #endif 163 | #endif 164 | 165 | #ifndef __IUINT64_DEFINED 166 | #define __IUINT64_DEFINED 167 | #if defined(_MSC_VER) || defined(__BORLANDC__) 168 | typedef unsigned __int64 IUINT64; 169 | #else 170 | typedef unsigned long long IUINT64; 171 | #endif 172 | #endif 173 | 174 | #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) 175 | #ifndef _WIN32 176 | #define _WIN32 177 | #endif 178 | #endif 179 | 180 | 181 | #ifdef __cplusplus 182 | extern "C" { 183 | #endif 184 | 185 | //--------------------------------------------------------------------- 186 | // Posix Stat 187 | //--------------------------------------------------------------------- 188 | #define ISTAT_IFMT 0170000 // file type mask 189 | #define ISTAT_IFIFO 0010000 // named pipe (fifo) 190 | #define ISTAT_IFCHR 0020000 // charactor special 191 | #define ISTAT_IFDIR 0040000 // directory 192 | #define ISTAT_IFBLK 0060000 // block special 193 | #define ISTAT_IFREG 0100000 // regular 194 | #define ISTAT_IFLNK 0120000 // symbolic link 195 | #define ISTAT_IFSOCK 0140000 // socket 196 | #define ISTAT_IFWHT 0160000 // whiteout 197 | #define ISTAT_ISUID 0004000 // set user id on execution 198 | #define ISTAT_ISGID 0002000 // set group id on execution 199 | #define ISTAT_ISVXT 0001000 // swapped text even after use 200 | #define ISTAT_IRWXU 0000700 // owner RWX mask 201 | #define ISTAT_IRUSR 0000400 // owner read permission 202 | #define ISTAT_IWUSR 0000200 // owner writer permission 203 | #define ISTAT_IXUSR 0000100 // owner execution permission 204 | #define ISTAT_IRWXG 0000070 // group RWX mask 205 | #define ISTAT_IRGRP 0000040 // group read permission 206 | #define ISTAT_IWGRP 0000020 // group write permission 207 | #define ISTAT_IXGRP 0000010 // group execution permission 208 | #define ISTAT_IRWXO 0000007 // other RWX mask 209 | #define ISTAT_IROTH 0000004 // other read permission 210 | #define ISTAT_IWOTH 0000002 // other writer permission 211 | #define ISTAT_IXOTH 0000001 // other execution permission 212 | 213 | #define ISTAT_ISFMT(m, t) (((m) & ISTAT_IFMT) == (t)) 214 | #define ISTAT_ISDIR(m) ISTAT_ISFMT(m, ISTAT_IFDIR) 215 | #define ISTAT_ISCHR(m) ISTAT_ISFMT(m, ISTAT_IFCHR) 216 | #define ISTAT_ISBLK(m) ISTAT_ISFMT(m, ISTAT_IFBLK) 217 | #define ISTAT_ISREG(m) ISTAT_ISFMT(m, ISTAT_IFREG) 218 | #define ISTAT_ISFIFO(m) ISTAT_ISFMT(m, ISTAT_IFIFO) 219 | #define ISTAT_ISLNK(m) ISTAT_ISFMT(m, ISTAT_IFLNK) 220 | #define ISTAT_ISSOCK(m) ISTAT_ISFMT(m, ISTAT_IFSOCK) 221 | #define ISTAT_ISWHT(m) ISTAT_ISFMT(m, ISTAT_IFWHT) 222 | 223 | struct IPOSIX_STAT 224 | { 225 | IUINT32 st_mode; 226 | IUINT64 st_ino; 227 | IUINT32 st_dev; 228 | IUINT32 st_nlink; 229 | IUINT32 st_uid; 230 | IUINT32 st_gid; 231 | IUINT64 st_size; 232 | IUINT32 atime; 233 | IUINT32 mtime; 234 | IUINT32 ctime; 235 | IUINT32 st_blocks; 236 | IUINT32 st_blksize; 237 | IUINT32 st_rdev; 238 | IUINT32 st_flags; 239 | }; 240 | 241 | typedef struct IPOSIX_STAT iposix_stat_t; 242 | 243 | #define IPOSIX_MAXPATH 1024 244 | #define IPOSIX_MAXBUFF ((IPOSIX_MAXPATH) + 8) 245 | 246 | 247 | // returns 0 for success, -1 for error 248 | int iposix_stat(const char *path, iposix_stat_t *ostat); 249 | 250 | // returns 0 for success, -1 for error 251 | int iposix_lstat(const char *path, iposix_stat_t *ostat); 252 | 253 | // returns 0 for success, -1 for error 254 | int iposix_fstat(int fd, iposix_stat_t *ostat); 255 | 256 | // get current directory 257 | char *iposix_getcwd(char *path, int size); 258 | 259 | // create directory 260 | int iposix_mkdir(const char *path, int mode); 261 | 262 | // change directory 263 | int iposix_chdir(const char *path); 264 | 265 | #ifndef F_OK 266 | #define F_OK 0 267 | #endif 268 | 269 | #ifndef X_OK 270 | #define X_OK 1 271 | #endif 272 | 273 | #ifndef W_OK 274 | #define W_OK 2 275 | #endif 276 | 277 | #ifndef R_OK 278 | #define R_OK 4 279 | #endif 280 | 281 | // check access 282 | int iposix_access(const char *path, int mode); 283 | 284 | 285 | // returns 1 for true 0 for false, -1 for not exist 286 | int iposix_path_isdir(const char *path); 287 | 288 | // returns 1 for true 0 for false, -1 for not exist 289 | int iposix_path_isfile(const char *path); 290 | 291 | // returns 1 for true 0 for false, -1 for not exist 292 | int iposix_path_islink(const char *path); 293 | 294 | // returns 1 for true 0 for false 295 | int iposix_path_exists(const char *path); 296 | 297 | // returns file size, -1 for error 298 | IINT64 iposix_path_getsize(const char *path); 299 | 300 | 301 | //--------------------------------------------------------------------- 302 | // Posix Path 303 | //--------------------------------------------------------------------- 304 | 305 | // 是否是绝对路径,如果是的话返回1,否则返回0 306 | int iposix_path_isabs(const char *path); 307 | 308 | // 绝对路径 309 | char *iposix_path_abspath(const char *srcpath, char *path, int maxsize); 310 | 311 | // 归一化路径:去掉重复斜杠,以及处理掉".", ".."等。 312 | char *iposix_path_normal(const char *srcpath, char *path, int maxsize); 313 | 314 | // 连接路径 315 | char *iposix_path_join(const char *p1, const char *p2, char *path, int len); 316 | 317 | // 路径分割:从右向左找到第一个"/"分成两个字符串 318 | int iposix_path_split(const char *path, char *p1, int l1, char *p2, int l2); 319 | 320 | // 扩展分割:分割文件主名与扩展名 321 | int iposix_path_splitext(const char *path, char *p1, int l1, 322 | char *p2, int l2); 323 | 324 | 325 | //--------------------------------------------------------------------- 326 | // platform special 327 | //--------------------------------------------------------------------- 328 | 329 | // 取得进程可执行文件的文件名 330 | int iposix_path_exepath(char *ptr, int size); 331 | 332 | // 取得进程可执行文件的目录 333 | int iposix_path_execwd(char *ptr, int size); 334 | 335 | // 递归创建路径 336 | int iposix_path_mkdir(const char *path, int mode); 337 | 338 | // 精简版取得可执行路径 339 | const char *iposix_get_exepath(void); 340 | 341 | // 精简版取得可执行目录 342 | const char *iposix_get_execwd(void); 343 | 344 | 345 | // 文件路径格式化: 346 | // out - 输出路径,长度不小于 IPOSIX_MAXPATH 347 | // root - 根路径 348 | // ... - 后续的相对路径 349 | // 返回 - out 350 | // 假设可执行路径位于 /home/abc/work,那么: 351 | // iposix_path_format(out, iposix_get_execwd(), "images/%s", "abc.jpg") 352 | // 结果就是 /home/abc/work/images/abc.jpg 353 | char *iposix_path_format(char *out, const char *root, const char *fmt, ...); 354 | 355 | 356 | 357 | //--------------------------------------------------------------------- 358 | // System Utilities 359 | //--------------------------------------------------------------------- 360 | 361 | #ifndef IDISABLE_SHARED_LIBRARY 362 | 363 | /* LoadLibraryA */ 364 | void *iposix_shared_open(const char *dllname); 365 | 366 | /* GetProcAddress */ 367 | void *iposix_shared_get(void *shared, const char *name); 368 | 369 | /* FreeLibrary */ 370 | void iposix_shared_close(void *shared); 371 | 372 | #endif 373 | 374 | #ifndef IDISABLE_FILE_SYSTEM_ACCESS 375 | 376 | /* load file content, use free to dispose */ 377 | void *iposix_file_load_content(const char *filename, long *size); 378 | 379 | /* save file content */ 380 | int iposix_file_save_content(const char *filename, const void *data, long size); 381 | 382 | /* cross os GetModuleFileName, returns size for success, -1 for error */ 383 | int iposix_get_proc_pathname(char *ptr, int size); 384 | 385 | #endif 386 | 387 | 388 | 389 | #ifdef __cplusplus 390 | } 391 | #endif 392 | 393 | 394 | #endif 395 | 396 | 397 | #endif 398 | 399 | 400 | 401 | 402 | --------------------------------------------------------------------------------