1/* 2 util.h - utility functions 3 Copyright (C) 2016-2020, Przemyslaw Skibinski, Yann Collet 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License along 16 with this program; if not, write to the Free Software Foundation, Inc., 17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18*/ 19 20#ifndef UTIL_H_MODULE 21#define UTIL_H_MODULE 22 23#if defined (__cplusplus) 24extern "C" { 25#endif 26 27 28 29/*-**************************************** 30* Dependencies 31******************************************/ 32#include "platform.h" /* PLATFORM_POSIX_VERSION */ 33#include <stddef.h> /* size_t, ptrdiff_t */ 34#include <stdlib.h> /* malloc */ 35#include <string.h> /* strlen, strncpy */ 36#include <stdio.h> /* fprintf, fileno */ 37#include <assert.h> 38#include <sys/types.h> /* stat, utime */ 39#include <sys/stat.h> /* stat */ 40#if defined(_WIN32) 41# include <sys/utime.h> /* utime */ 42# include <io.h> /* _chmod */ 43#else 44# include <unistd.h> /* chown, stat */ 45# if PLATFORM_POSIX_VERSION < 200809L 46# include <utime.h> /* utime */ 47# else 48# include <fcntl.h> /* AT_FDCWD */ 49# include <sys/stat.h> /* for utimensat */ 50# endif 51#endif 52#include <time.h> /* time */ 53#include <limits.h> /* INT_MAX */ 54#include <errno.h> 55 56 57 58/*-************************************************************** 59* Basic Types 60*****************************************************************/ 61#if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) 62# include <stdint.h> 63 typedef uint8_t BYTE; 64 typedef uint16_t U16; 65 typedef int16_t S16; 66 typedef uint32_t U32; 67 typedef int32_t S32; 68 typedef uint64_t U64; 69 typedef int64_t S64; 70#else 71 typedef unsigned char BYTE; 72 typedef unsigned short U16; 73 typedef signed short S16; 74 typedef unsigned int U32; 75 typedef signed int S32; 76 typedef unsigned long long U64; 77 typedef signed long long S64; 78#endif 79 80 81/* ************************************************************ 82* Avoid fseek()'s 2GiB barrier with MSVC, MacOS, *BSD, MinGW 83***************************************************************/ 84#if defined(_MSC_VER) && (_MSC_VER >= 1400) 85# define UTIL_fseek _fseeki64 86#elif !defined(__64BIT__) && (PLATFORM_POSIX_VERSION >= 200112L) /* No point defining Large file for 64 bit */ 87# define UTIL_fseek fseeko 88#elif defined(__MINGW32__) && defined(__MSVCRT__) && !defined(__STRICT_ANSI__) && !defined(__NO_MINGW_LFS) 89# define UTIL_fseek fseeko64 90#else 91# define UTIL_fseek fseek 92#endif 93 94 95/*-**************************************** 96* Sleep functions: Windows - Posix - others 97******************************************/ 98#if defined(_WIN32) 99# include <windows.h> 100# define SET_REALTIME_PRIORITY SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS) 101# define UTIL_sleep(s) Sleep(1000*s) 102# define UTIL_sleepMilli(milli) Sleep(milli) 103#elif PLATFORM_POSIX_VERSION >= 0 /* Unix-like operating system */ 104# include <unistd.h> 105# include <sys/resource.h> /* setpriority */ 106# include <time.h> /* clock_t, nanosleep, clock, CLOCKS_PER_SEC */ 107# if defined(PRIO_PROCESS) 108# define SET_REALTIME_PRIORITY setpriority(PRIO_PROCESS, 0, -20) 109# else 110# define SET_REALTIME_PRIORITY /* disabled */ 111# endif 112# define UTIL_sleep(s) sleep(s) 113# if (defined(__linux__) && (PLATFORM_POSIX_VERSION >= 199309L)) || (PLATFORM_POSIX_VERSION >= 200112L) /* nanosleep requires POSIX.1-2001 */ 114# define UTIL_sleepMilli(milli) { struct timespec t; t.tv_sec=0; t.tv_nsec=milli*1000000ULL; nanosleep(&t, NULL); } 115# else 116# define UTIL_sleepMilli(milli) /* disabled */ 117# endif 118#else 119# define SET_REALTIME_PRIORITY /* disabled */ 120# define UTIL_sleep(s) /* disabled */ 121# define UTIL_sleepMilli(milli) /* disabled */ 122#endif 123 124 125/*-**************************************** 126* stat() functions 127******************************************/ 128#if defined(_MSC_VER) 129# define UTIL_TYPE_stat __stat64 130# define UTIL_stat _stat64 131# define UTIL_fstat _fstat64 132# define UTIL_STAT_MODE_ISREG(st_mode) ((st_mode) & S_IFREG) 133#elif defined(__MINGW32__) && defined (__MSVCRT__) 134# define UTIL_TYPE_stat _stati64 135# define UTIL_stat _stati64 136# define UTIL_fstat _fstati64 137# define UTIL_STAT_MODE_ISREG(st_mode) ((st_mode) & S_IFREG) 138#else 139# define UTIL_TYPE_stat stat 140# define UTIL_stat stat 141# define UTIL_fstat fstat 142# define UTIL_STAT_MODE_ISREG(st_mode) (S_ISREG(st_mode)) 143#endif 144 145 146/*-**************************************** 147* fileno() function 148******************************************/ 149#if defined(_MSC_VER) 150# define UTIL_fileno _fileno 151#else 152# define UTIL_fileno fileno 153#endif 154 155/* ************************************* 156* Constants 157***************************************/ 158#define LIST_SIZE_INCREASE (8*1024) 159 160 161/*-**************************************** 162* Compiler specifics 163******************************************/ 164#if defined(__INTEL_COMPILER) 165# pragma warning(disable : 177) /* disable: message #177: function was declared but never referenced, useful with UTIL_STATIC */ 166#endif 167#if defined(__GNUC__) 168# define UTIL_STATIC static __attribute__((unused)) 169#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) 170# define UTIL_STATIC static inline 171#elif defined(_MSC_VER) 172# define UTIL_STATIC static __inline 173#else 174# define UTIL_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ 175#endif 176 177 178 179/*-**************************************** 180* Allocation functions 181******************************************/ 182/* 183 * A modified version of realloc(). 184 * If UTIL_realloc() fails the original block is freed. 185*/ 186UTIL_STATIC void* UTIL_realloc(void* ptr, size_t size) 187{ 188 void* const newptr = realloc(ptr, size); 189 if (newptr) return newptr; 190 free(ptr); 191 return NULL; 192} 193 194 195/*-**************************************** 196* String functions 197******************************************/ 198/* 199 * A modified version of realloc(). 200 * If UTIL_realloc() fails the original block is freed. 201*/ 202UTIL_STATIC int UTIL_sameString(const char* a, const char* b) 203{ 204 assert(a!=NULL && b!=NULL); /* unsupported scenario */ 205 if (a==NULL) return 0; 206 if (b==NULL) return 0; 207 return !strcmp(a,b); 208} 209 210 211/*-**************************************** 212* Time functions 213******************************************/ 214#if defined(_WIN32) /* Windows */ 215 216 typedef LARGE_INTEGER UTIL_time_t; 217 UTIL_STATIC UTIL_time_t UTIL_getTime(void) { UTIL_time_t x; QueryPerformanceCounter(&x); return x; } 218 UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd) 219 { 220 static LARGE_INTEGER ticksPerSecond; 221 static int init = 0; 222 if (!init) { 223 if (!QueryPerformanceFrequency(&ticksPerSecond)) 224 fprintf(stderr, "ERROR: QueryPerformanceFrequency() failure\n"); 225 init = 1; 226 } 227 return 1000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart; 228 } 229 UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_time_t clockStart, UTIL_time_t clockEnd) 230 { 231 static LARGE_INTEGER ticksPerSecond; 232 static int init = 0; 233 if (!init) { 234 if (!QueryPerformanceFrequency(&ticksPerSecond)) 235 fprintf(stderr, "ERROR: QueryPerformanceFrequency() failure\n"); 236 init = 1; 237 } 238 return 1000000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart; 239 } 240 241#elif defined(__APPLE__) && defined(__MACH__) 242 243 #include <mach/mach_time.h> 244 typedef U64 UTIL_time_t; 245 UTIL_STATIC UTIL_time_t UTIL_getTime(void) { return mach_absolute_time(); } 246 UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd) 247 { 248 static mach_timebase_info_data_t rate; 249 static int init = 0; 250 if (!init) { 251 mach_timebase_info(&rate); 252 init = 1; 253 } 254 return (((clockEnd - clockStart) * (U64)rate.numer) / ((U64)rate.denom)) / 1000ULL; 255 } 256 UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_time_t clockStart, UTIL_time_t clockEnd) 257 { 258 static mach_timebase_info_data_t rate; 259 static int init = 0; 260 if (!init) { 261 mach_timebase_info(&rate); 262 init = 1; 263 } 264 return ((clockEnd - clockStart) * (U64)rate.numer) / ((U64)rate.denom); 265 } 266 267#elif (PLATFORM_POSIX_VERSION >= 200112L) && (defined __UCLIBC__ || (defined(__GLIBC__) && ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 17) || __GLIBC__ > 2) ) ) 268 269 #include <time.h> 270 typedef struct timespec UTIL_time_t; 271 UTIL_STATIC UTIL_time_t UTIL_getTime(void) 272 { 273 UTIL_time_t now; 274 if (clock_gettime(CLOCK_MONOTONIC, &now)) 275 fprintf(stderr, "ERROR: Failed to get time\n"); /* we could also exit() */ 276 return now; 277 } 278 UTIL_STATIC UTIL_time_t UTIL_getSpanTime(UTIL_time_t begin, UTIL_time_t end) 279 { 280 UTIL_time_t diff; 281 if (end.tv_nsec < begin.tv_nsec) { 282 diff.tv_sec = (end.tv_sec - 1) - begin.tv_sec; 283 diff.tv_nsec = (end.tv_nsec + 1000000000ULL) - begin.tv_nsec; 284 } else { 285 diff.tv_sec = end.tv_sec - begin.tv_sec; 286 diff.tv_nsec = end.tv_nsec - begin.tv_nsec; 287 } 288 return diff; 289 } 290 UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_time_t begin, UTIL_time_t end) 291 { 292 UTIL_time_t const diff = UTIL_getSpanTime(begin, end); 293 U64 micro = 0; 294 micro += 1000000ULL * diff.tv_sec; 295 micro += diff.tv_nsec / 1000ULL; 296 return micro; 297 } 298 UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_time_t begin, UTIL_time_t end) 299 { 300 UTIL_time_t const diff = UTIL_getSpanTime(begin, end); 301 U64 nano = 0; 302 nano += 1000000000ULL * diff.tv_sec; 303 nano += diff.tv_nsec; 304 return nano; 305 } 306 307#else /* relies on standard C (note : clock_t measurements can be wrong when using multi-threading) */ 308 309 typedef clock_t UTIL_time_t; 310 UTIL_STATIC UTIL_time_t UTIL_getTime(void) { return clock(); } 311 UTIL_STATIC U64 UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; } 312 UTIL_STATIC U64 UTIL_getSpanTimeNano(UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; } 313#endif 314 315 316/* returns time span in microseconds */ 317UTIL_STATIC U64 UTIL_clockSpanMicro(UTIL_time_t clockStart) 318{ 319 UTIL_time_t const clockEnd = UTIL_getTime(); 320 return UTIL_getSpanTimeMicro(clockStart, clockEnd); 321} 322 323/* returns time span in nanoseconds */ 324UTIL_STATIC U64 UTIL_clockSpanNano(UTIL_time_t clockStart) 325{ 326 UTIL_time_t const clockEnd = UTIL_getTime(); 327 return UTIL_getSpanTimeNano(clockStart, clockEnd); 328} 329 330UTIL_STATIC void UTIL_waitForNextTick(void) 331{ 332 UTIL_time_t const clockStart = UTIL_getTime(); 333 UTIL_time_t clockEnd; 334 do { 335 clockEnd = UTIL_getTime(); 336 } while (UTIL_getSpanTimeNano(clockStart, clockEnd) == 0); 337} 338 339 340 341/*-**************************************** 342* File functions 343******************************************/ 344#if defined(_MSC_VER) 345 #define chmod _chmod 346 typedef struct __stat64 stat_t; 347#else 348 typedef struct stat stat_t; 349#endif 350 351 352UTIL_STATIC int UTIL_isRegFile(const char* infilename); 353UTIL_STATIC int UTIL_isRegFD(int fd); 354 355 356UTIL_STATIC int UTIL_setFileStat(const char *filename, stat_t *statbuf) 357{ 358 int res = 0; 359 360 if (!UTIL_isRegFile(filename)) 361 return -1; 362 363 { 364#if defined(_WIN32) || (PLATFORM_POSIX_VERSION < 200809L) 365 struct utimbuf timebuf; 366 timebuf.actime = time(NULL); 367 timebuf.modtime = statbuf->st_mtime; 368 res += utime(filename, &timebuf); /* set access and modification times */ 369#else 370 struct timespec timebuf[2]; 371 memset(timebuf, 0, sizeof(timebuf)); 372 timebuf[0].tv_nsec = UTIME_NOW; 373 timebuf[1].tv_sec = statbuf->st_mtime; 374 res += utimensat(AT_FDCWD, filename, timebuf, 0); /* set access and modification times */ 375#endif 376 } 377 378#if !defined(_WIN32) 379 res += chown(filename, statbuf->st_uid, statbuf->st_gid); /* Copy ownership */ 380#endif 381 382 res += chmod(filename, statbuf->st_mode & 07777); /* Copy file permissions */ 383 384 errno = 0; 385 return -res; /* number of errors is returned */ 386} 387 388 389UTIL_STATIC int UTIL_getFDStat(int fd, stat_t *statbuf) 390{ 391 int r; 392#if defined(_MSC_VER) 393 r = _fstat64(fd, statbuf); 394 if (r || !(statbuf->st_mode & S_IFREG)) return 0; /* No good... */ 395#else 396 r = fstat(fd, statbuf); 397 if (r || !S_ISREG(statbuf->st_mode)) return 0; /* No good... */ 398#endif 399 return 1; 400} 401 402UTIL_STATIC int UTIL_getFileStat(const char* infilename, stat_t *statbuf) 403{ 404 int r; 405#if defined(_MSC_VER) 406 r = _stat64(infilename, statbuf); 407 if (r || !(statbuf->st_mode & S_IFREG)) return 0; /* No good... */ 408#else 409 r = stat(infilename, statbuf); 410 if (r || !S_ISREG(statbuf->st_mode)) return 0; /* No good... */ 411#endif 412 return 1; 413} 414 415 416UTIL_STATIC int UTIL_isRegFD(int fd) 417{ 418 stat_t statbuf; 419#ifdef _WIN32 420 /* Windows runtime library always open file descriptors 0, 1 and 2 in text mode, therefore we can't use them for binary I/O */ 421 if(fd < 3) return 0; 422#endif 423 return UTIL_getFDStat(fd, &statbuf); /* Only need to know whether it is a regular file */ 424} 425 426 427UTIL_STATIC int UTIL_isRegFile(const char* infilename) 428{ 429 stat_t statbuf; 430 return UTIL_getFileStat(infilename, &statbuf); /* Only need to know whether it is a regular file */ 431} 432 433 434UTIL_STATIC U32 UTIL_isDirectory(const char* infilename) 435{ 436 int r; 437 stat_t statbuf; 438#if defined(_MSC_VER) 439 r = _stat64(infilename, &statbuf); 440 if (!r && (statbuf.st_mode & _S_IFDIR)) return 1; 441#else 442 r = stat(infilename, &statbuf); 443 if (!r && S_ISDIR(statbuf.st_mode)) return 1; 444#endif 445 return 0; 446} 447 448 449UTIL_STATIC U64 UTIL_getOpenFileSize(FILE* file) 450{ 451 int r; 452 int fd; 453 struct UTIL_TYPE_stat statbuf; 454 455 fd = UTIL_fileno(file); 456 if (fd < 0) { 457 perror("fileno"); 458 exit(1); 459 } 460 r = UTIL_fstat(fd, &statbuf); 461 if (r || !UTIL_STAT_MODE_ISREG(statbuf.st_mode)) return 0; /* No good... */ 462 return (U64)statbuf.st_size; 463} 464 465 466UTIL_STATIC U64 UTIL_getFileSize(const char* infilename) 467{ 468 int r; 469 struct UTIL_TYPE_stat statbuf; 470 471 r = UTIL_stat(infilename, &statbuf); 472 if (r || !UTIL_STAT_MODE_ISREG(statbuf.st_mode)) return 0; /* No good... */ 473 return (U64)statbuf.st_size; 474} 475 476 477UTIL_STATIC U64 UTIL_getTotalFileSize(const char** fileNamesTable, unsigned nbFiles) 478{ 479 U64 total = 0; 480 unsigned n; 481 for (n=0; n<nbFiles; n++) 482 total += UTIL_getFileSize(fileNamesTable[n]); 483 return total; 484} 485 486 487#ifdef _WIN32 488# define UTIL_HAS_CREATEFILELIST 489 490UTIL_STATIC int UTIL_prepareFileList(const char* dirName, char** bufStart, size_t* pos, char** bufEnd) 491{ 492 char* path; 493 size_t dirLength, nbFiles = 0; 494 WIN32_FIND_DATAA cFile; 495 HANDLE hFile; 496 497 dirLength = strlen(dirName); 498 path = (char*) malloc(dirLength + 3); 499 if (!path) return 0; 500 501 memcpy(path, dirName, dirLength); 502 path[dirLength] = '\\'; 503 path[dirLength+1] = '*'; 504 path[dirLength+2] = 0; 505 506 hFile=FindFirstFileA(path, &cFile); 507 if (hFile == INVALID_HANDLE_VALUE) { 508 fprintf(stderr, "Cannot open directory '%s'\n", dirName); 509 return 0; 510 } 511 free(path); 512 513 do { 514 size_t pathLength; 515 int const fnameLength = (int)strlen(cFile.cFileName); 516 path = (char*) malloc(dirLength + fnameLength + 2); 517 if (!path) { FindClose(hFile); return 0; } 518 memcpy(path, dirName, dirLength); 519 path[dirLength] = '\\'; 520 memcpy(path+dirLength+1, cFile.cFileName, fnameLength); 521 pathLength = dirLength+1+fnameLength; 522 path[pathLength] = 0; 523 if (cFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { 524 if (strcmp (cFile.cFileName, "..") == 0 || 525 strcmp (cFile.cFileName, ".") == 0) continue; 526 527 nbFiles += UTIL_prepareFileList(path, bufStart, pos, bufEnd); /* Recursively call "UTIL_prepareFileList" with the new path. */ 528 if (*bufStart == NULL) { free(path); FindClose(hFile); return 0; } 529 } 530 else if ((cFile.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) || (cFile.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) || (cFile.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED)) { 531 if (*bufStart + *pos + pathLength >= *bufEnd) { 532 ptrdiff_t newListSize = (*bufEnd - *bufStart) + LIST_SIZE_INCREASE; 533 *bufStart = (char*)UTIL_realloc(*bufStart, newListSize); 534 *bufEnd = *bufStart + newListSize; 535 if (*bufStart == NULL) { free(path); FindClose(hFile); return 0; } 536 } 537 if (*bufStart + *pos + pathLength < *bufEnd) { 538 strncpy(*bufStart + *pos, path, *bufEnd - (*bufStart + *pos)); 539 *pos += pathLength + 1; 540 nbFiles++; 541 } 542 } 543 free(path); 544 } while (FindNextFileA(hFile, &cFile)); 545 546 FindClose(hFile); 547 assert(nbFiles < INT_MAX); 548 return (int)nbFiles; 549} 550 551#elif defined(__linux__) || (PLATFORM_POSIX_VERSION >= 200112L) /* opendir, readdir require POSIX.1-2001 */ 552# define UTIL_HAS_CREATEFILELIST 553# include <dirent.h> /* opendir, readdir */ 554# include <string.h> /* strerror, memcpy */ 555 556UTIL_STATIC int UTIL_prepareFileList(const char* dirName, char** bufStart, size_t* pos, char** bufEnd) 557{ 558 DIR* dir; 559 struct dirent * entry; 560 size_t dirLength; 561 int nbFiles = 0; 562 563 if (!(dir = opendir(dirName))) { 564 fprintf(stderr, "Cannot open directory '%s': %s\n", dirName, strerror(errno)); 565 return 0; 566 } 567 568 dirLength = strlen(dirName); 569 errno = 0; 570 while ((entry = readdir(dir)) != NULL) { 571 char* path; 572 size_t fnameLength, pathLength; 573 if (strcmp (entry->d_name, "..") == 0 || 574 strcmp (entry->d_name, ".") == 0) continue; 575 fnameLength = strlen(entry->d_name); 576 path = (char*)malloc(dirLength + fnameLength + 2); 577 if (!path) { closedir(dir); return 0; } 578 memcpy(path, dirName, dirLength); 579 path[dirLength] = '/'; 580 memcpy(path+dirLength+1, entry->d_name, fnameLength); 581 pathLength = dirLength+1+fnameLength; 582 path[pathLength] = 0; 583 584 if (UTIL_isDirectory(path)) { 585 nbFiles += UTIL_prepareFileList(path, bufStart, pos, bufEnd); /* Recursively call "UTIL_prepareFileList" with the new path. */ 586 if (*bufStart == NULL) { free(path); closedir(dir); return 0; } 587 } else { 588 if (*bufStart + *pos + pathLength >= *bufEnd) { 589 size_t const newListSize = (size_t)(*bufEnd - *bufStart) + LIST_SIZE_INCREASE; 590 *bufStart = (char*)UTIL_realloc(*bufStart, newListSize); 591 *bufEnd = *bufStart + newListSize; 592 if (*bufStart == NULL) { free(path); closedir(dir); return 0; } 593 } 594 if (*bufStart + *pos + pathLength < *bufEnd) { 595 strncpy(*bufStart + *pos, path, *bufEnd - (*bufStart + *pos)); 596 *pos += pathLength + 1; 597 nbFiles++; 598 } 599 } 600 free(path); 601 errno = 0; /* clear errno after UTIL_isDirectory, UTIL_prepareFileList */ 602 } 603 604 if (errno != 0) { 605 fprintf(stderr, "readdir(%s) error: %s\n", dirName, strerror(errno)); 606 free(*bufStart); 607 *bufStart = NULL; 608 } 609 closedir(dir); 610 return nbFiles; 611} 612 613#else 614 615UTIL_STATIC int UTIL_prepareFileList(const char* dirName, char** bufStart, size_t* pos, char** bufEnd) 616{ 617 (void)bufStart; (void)bufEnd; (void)pos; 618 fprintf(stderr, "Directory %s ignored (compiled without _WIN32 or _POSIX_C_SOURCE)\n", dirName); 619 return 0; 620} 621 622#endif /* #ifdef _WIN32 */ 623 624/* 625 * UTIL_createFileList - takes a list of files and directories (params: inputNames, inputNamesNb), scans directories, 626 * and returns a new list of files (params: return value, allocatedBuffer, allocatedNamesNb). 627 * After finishing usage of the list the structures should be freed with UTIL_freeFileList(params: return value, allocatedBuffer) 628 * In case of error UTIL_createFileList returns NULL and UTIL_freeFileList should not be called. 629 */ 630UTIL_STATIC const char** 631UTIL_createFileList(const char** inputNames, unsigned inputNamesNb, 632 char** allocatedBuffer, unsigned* allocatedNamesNb) 633{ 634 size_t pos; 635 unsigned i, nbFiles; 636 char* buf = (char*)malloc(LIST_SIZE_INCREASE); 637 size_t bufSize = LIST_SIZE_INCREASE; 638 const char** fileTable; 639 640 if (!buf) return NULL; 641 642 for (i=0, pos=0, nbFiles=0; i<inputNamesNb; i++) { 643 if (!UTIL_isDirectory(inputNames[i])) { 644 size_t const len = strlen(inputNames[i]) + 1; /* include nul char */ 645 if (pos + len >= bufSize) { 646 while (pos + len >= bufSize) bufSize += LIST_SIZE_INCREASE; 647 buf = (char*)UTIL_realloc(buf, bufSize); 648 if (!buf) return NULL; 649 } 650 assert(pos + len < bufSize); 651 memcpy(buf + pos, inputNames[i], len); 652 pos += len; 653 nbFiles++; 654 } else { 655 char* bufend = buf + bufSize; 656 nbFiles += (unsigned)UTIL_prepareFileList(inputNames[i], &buf, &pos, &bufend); 657 if (buf == NULL) return NULL; 658 assert(bufend > buf); 659 bufSize = (size_t)(bufend - buf); 660 } } 661 662 if (nbFiles == 0) { free(buf); return NULL; } 663 664 fileTable = (const char**)malloc(((size_t)nbFiles+1) * sizeof(const char*)); 665 if (!fileTable) { free(buf); return NULL; } 666 667 for (i=0, pos=0; i<nbFiles; i++) { 668 fileTable[i] = buf + pos; 669 pos += strlen(fileTable[i]) + 1; 670 } 671 672 if (pos > bufSize) { 673 free(buf); 674 free((void*)fileTable); 675 return NULL; 676 } /* can this happen ? */ 677 678 *allocatedBuffer = buf; 679 *allocatedNamesNb = nbFiles; 680 681 return fileTable; 682} 683 684 685UTIL_STATIC void 686UTIL_freeFileList(const char** filenameTable, char* allocatedBuffer) 687{ 688 free(allocatedBuffer); 689 free((void*)filenameTable); 690} 691 692 693#if defined (__cplusplus) 694} 695#endif 696 697#endif /* UTIL_H_MODULE */ 698