tools.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. /*
  2. * Helper functions for the Wine tools
  3. *
  4. * Copyright 2021 Alexandre Julliard
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  19. */
  20. #ifndef __WINE_TOOLS_H
  21. #define __WINE_TOOLS_H
  22. #include <stdarg.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <sys/types.h>
  27. #include <sys/stat.h>
  28. #include <fcntl.h>
  29. #include <time.h>
  30. #include <errno.h>
  31. #ifdef HAVE_UNISTD_H
  32. # include <unistd.h>
  33. #endif
  34. #ifdef _WIN32
  35. # include <direct.h>
  36. # include <io.h>
  37. # include <process.h>
  38. # define mkdir(path,mode) mkdir(path)
  39. # ifndef S_ISREG
  40. # define S_ISREG(mod) (((mod) & _S_IFMT) == _S_IFREG)
  41. # endif
  42. # ifdef _MSC_VER
  43. # define popen _popen
  44. # define pclose _pclose
  45. # define strtoll _strtoi64
  46. # define strtoull _strtoui64
  47. # define strncasecmp _strnicmp
  48. # define strcasecmp _stricmp
  49. # endif
  50. #else
  51. # include <sys/wait.h>
  52. # include <unistd.h>
  53. # ifndef O_BINARY
  54. # define O_BINARY 0
  55. # endif
  56. # ifndef __int64
  57. # if defined(__x86_64__) || defined(__aarch64__) || defined(__powerpc64__)
  58. # define __int64 long
  59. # else
  60. # define __int64 long long
  61. # endif
  62. # endif
  63. #endif
  64. #if !defined(__GNUC__) && !defined(__attribute__)
  65. #define __attribute__(x)
  66. #endif
  67. #ifndef max
  68. #define max(a,b) (((a) > (b)) ? (a) : (b))
  69. #endif
  70. #ifndef min
  71. #define min(a,b) (((a) < (b)) ? (a) : (b))
  72. #endif
  73. #ifndef ARRAY_SIZE
  74. #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
  75. #endif
  76. struct target
  77. {
  78. enum { CPU_i386, CPU_x86_64, CPU_ARM, CPU_ARM64 } cpu;
  79. enum
  80. {
  81. PLATFORM_UNSPECIFIED,
  82. PLATFORM_APPLE,
  83. PLATFORM_ANDROID,
  84. PLATFORM_LINUX,
  85. PLATFORM_FREEBSD,
  86. PLATFORM_SOLARIS,
  87. PLATFORM_WINDOWS,
  88. PLATFORM_MINGW,
  89. PLATFORM_CYGWIN
  90. } platform;
  91. };
  92. static inline void *xmalloc( size_t size )
  93. {
  94. void *res = malloc( size ? size : 1 );
  95. if (res == NULL)
  96. {
  97. fprintf( stderr, "Virtual memory exhausted.\n" );
  98. exit(1);
  99. }
  100. return res;
  101. }
  102. static inline void *xrealloc (void *ptr, size_t size)
  103. {
  104. void *res = realloc( ptr, size );
  105. if (size && res == NULL)
  106. {
  107. fprintf( stderr, "Virtual memory exhausted.\n" );
  108. exit(1);
  109. }
  110. return res;
  111. }
  112. static inline char *xstrdup( const char *str )
  113. {
  114. return strcpy( xmalloc( strlen(str)+1 ), str );
  115. }
  116. static inline int strendswith( const char *str, const char *end )
  117. {
  118. int l = strlen( str );
  119. int m = strlen( end );
  120. return l >= m && !strcmp( str + l - m, end );
  121. }
  122. static char *strmake( const char* fmt, ... ) __attribute__ ((__format__ (__printf__, 1, 2)));
  123. static inline char *strmake( const char* fmt, ... )
  124. {
  125. int n;
  126. size_t size = 100;
  127. va_list ap;
  128. for (;;)
  129. {
  130. char *p = xmalloc( size );
  131. va_start( ap, fmt );
  132. n = vsnprintf( p, size, fmt, ap );
  133. va_end( ap );
  134. if (n == -1) size *= 2;
  135. else if ((size_t)n >= size) size = n + 1;
  136. else return p;
  137. free( p );
  138. }
  139. }
  140. /* string array functions */
  141. struct strarray
  142. {
  143. unsigned int count; /* strings in use */
  144. unsigned int size; /* total allocated size */
  145. const char **str;
  146. };
  147. static const struct strarray empty_strarray;
  148. static inline void strarray_add( struct strarray *array, const char *str )
  149. {
  150. if (array->count == array->size)
  151. {
  152. if (array->size) array->size *= 2;
  153. else array->size = 16;
  154. array->str = xrealloc( array->str, sizeof(array->str[0]) * array->size );
  155. }
  156. array->str[array->count++] = str;
  157. }
  158. static inline void strarray_addall( struct strarray *array, struct strarray added )
  159. {
  160. unsigned int i;
  161. for (i = 0; i < added.count; i++) strarray_add( array, added.str[i] );
  162. }
  163. static inline int strarray_exists( const struct strarray *array, const char *str )
  164. {
  165. unsigned int i;
  166. for (i = 0; i < array->count; i++) if (!strcmp( array->str[i], str )) return 1;
  167. return 0;
  168. }
  169. static inline void strarray_add_uniq( struct strarray *array, const char *str )
  170. {
  171. if (!strarray_exists( array, str )) strarray_add( array, str );
  172. }
  173. static inline void strarray_addall_uniq( struct strarray *array, struct strarray added )
  174. {
  175. unsigned int i;
  176. for (i = 0; i < added.count; i++) strarray_add_uniq( array, added.str[i] );
  177. }
  178. static inline struct strarray strarray_fromstring( const char *str, const char *delim )
  179. {
  180. struct strarray array = empty_strarray;
  181. char *buf = xstrdup( str );
  182. const char *tok;
  183. for (tok = strtok( buf, delim ); tok; tok = strtok( NULL, delim ))
  184. strarray_add( &array, xstrdup( tok ));
  185. free( buf );
  186. return array;
  187. }
  188. static inline struct strarray strarray_frompath( const char *path )
  189. {
  190. if (!path) return empty_strarray;
  191. #ifdef _WIN32
  192. return strarray_fromstring( path, ";" );
  193. #else
  194. return strarray_fromstring( path, ":" );
  195. #endif
  196. }
  197. static inline char *strarray_tostring( struct strarray array, const char *sep )
  198. {
  199. char *str;
  200. unsigned int i, len = 1 + (array.count - 1) * strlen(sep);
  201. if (!array.count) return xstrdup("");
  202. for (i = 0; i < array.count; i++) len += strlen( array.str[i] );
  203. str = xmalloc( len );
  204. strcpy( str, array.str[0] );
  205. for (i = 1; i < array.count; i++)
  206. {
  207. strcat( str, sep );
  208. strcat( str, array.str[i] );
  209. }
  210. return str;
  211. }
  212. static inline void strarray_qsort( struct strarray *array, int (*func)(const char **, const char **) )
  213. {
  214. if (array->count) qsort( array->str, array->count, sizeof(*array->str), (void *)func );
  215. }
  216. static inline const char *strarray_bsearch( const struct strarray *array, const char *str,
  217. int (*func)(const char **, const char **) )
  218. {
  219. char **res = NULL;
  220. if (array->count) res = bsearch( &str, array->str, array->count, sizeof(*array->str), (void *)func );
  221. return res ? *res : NULL;
  222. }
  223. static inline void strarray_trace( struct strarray args )
  224. {
  225. unsigned int i;
  226. for (i = 0; i < args.count; i++)
  227. {
  228. if (strpbrk( args.str[i], " \t\n\r")) printf( "\"%s\"", args.str[i] );
  229. else printf( "%s", args.str[i] );
  230. putchar( i < args.count - 1 ? ' ' : '\n' );
  231. }
  232. }
  233. static inline int strarray_spawn( struct strarray args )
  234. {
  235. #ifdef _WIN32
  236. strarray_add( &args, NULL );
  237. return _spawnvp( _P_WAIT, args.str[0], args.str );
  238. #else
  239. pid_t pid, wret;
  240. int status;
  241. if (!(pid = fork()))
  242. {
  243. strarray_add( &args, NULL );
  244. execvp( args.str[0], (char **)args.str );
  245. _exit(1);
  246. }
  247. if (pid == -1) return -1;
  248. while (pid != (wret = waitpid( pid, &status, 0 )))
  249. if (wret == -1 && errno != EINTR) break;
  250. if (pid == wret && WIFEXITED(status)) return WEXITSTATUS(status);
  251. return 255; /* abnormal exit with an abort or an interrupt */
  252. #endif
  253. }
  254. static inline char *get_basename( const char *file )
  255. {
  256. const char *ret = strrchr( file, '/' );
  257. return xstrdup( ret ? ret + 1 : file );
  258. }
  259. static inline char *get_basename_noext( const char *file )
  260. {
  261. char *ext, *ret = get_basename( file );
  262. if ((ext = strrchr( ret, '.' ))) *ext = 0;
  263. return ret;
  264. }
  265. static inline char *get_dirname( const char *file )
  266. {
  267. const char *end = strrchr( file, '/' );
  268. if (!end) return xstrdup( "." );
  269. if (end == file) end++;
  270. return strmake( "%.*s", (int)(end - file), file );
  271. }
  272. static inline char *replace_extension( const char *name, const char *old_ext, const char *new_ext )
  273. {
  274. int name_len = strlen( name );
  275. if (strendswith( name, old_ext )) name_len -= strlen( old_ext );
  276. return strmake( "%.*s%s", name_len, name, new_ext );
  277. }
  278. static inline int make_temp_file( const char *prefix, const char *suffix, char **name )
  279. {
  280. static unsigned int value;
  281. int fd, count;
  282. const char *tmpdir = NULL;
  283. if (!prefix) prefix = "tmp";
  284. if (!suffix) suffix = "";
  285. value += time(NULL) + getpid();
  286. for (count = 0; count < 0x8000; count++)
  287. {
  288. if (tmpdir)
  289. *name = strmake( "%s/%s-%08x%s", tmpdir, prefix, value, suffix );
  290. else
  291. *name = strmake( "%s-%08x%s", prefix, value, suffix );
  292. fd = open( *name, O_RDWR | O_CREAT | O_EXCL, 0600 );
  293. if (fd >= 0) return fd;
  294. value += 7777;
  295. if (errno == EACCES && !tmpdir && !strchr( prefix, '/' ))
  296. {
  297. if (!(tmpdir = getenv("TMPDIR"))) tmpdir = "/tmp";
  298. }
  299. free( *name );
  300. }
  301. fprintf( stderr, "failed to create temp file for %s%s\n", prefix, suffix );
  302. exit(1);
  303. }
  304. static inline struct target get_default_target(void)
  305. {
  306. struct target target;
  307. #ifdef __i386__
  308. target.cpu = CPU_i386;
  309. #elif defined(__x86_64__)
  310. target.cpu = CPU_x86_64;
  311. #elif defined(__arm__)
  312. target.cpu = CPU_ARM;
  313. #elif defined(__aarch64__)
  314. target.cpu = CPU_ARM64;
  315. #else
  316. #error Unsupported CPU
  317. #endif
  318. #ifdef __APPLE__
  319. target.platform = PLATFORM_APPLE;
  320. #elif defined(__ANDROID__)
  321. target.platform = PLATFORM_ANDROID;
  322. #elif defined(__linux__)
  323. target.platform = PLATFORM_LINUX;
  324. #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
  325. target.platform = PLATFORM_FREEBSD;
  326. #elif defined(__sun)
  327. target.platform = PLATFORM_SOLARIS;
  328. #elif defined(__CYGWIN__)
  329. target.platform = PLATFORM_CYGWIN;
  330. #elif defined(_WIN32)
  331. target.platform = PLATFORM_MINGW;
  332. #else
  333. target.platform = PLATFORM_UNSPECIFIED;
  334. #endif
  335. return target;
  336. }
  337. static inline unsigned int get_target_ptr_size( struct target target )
  338. {
  339. static const unsigned int sizes[] =
  340. {
  341. [CPU_i386] = 4,
  342. [CPU_x86_64] = 8,
  343. [CPU_ARM] = 4,
  344. [CPU_ARM64] = 8,
  345. };
  346. return sizes[target.cpu];
  347. }
  348. static inline void set_target_ptr_size( struct target *target, unsigned int size )
  349. {
  350. switch (target->cpu)
  351. {
  352. case CPU_i386:
  353. if (size == 8) target->cpu = CPU_x86_64;
  354. break;
  355. case CPU_x86_64:
  356. if (size == 4) target->cpu = CPU_i386;
  357. break;
  358. case CPU_ARM:
  359. if (size == 8) target->cpu = CPU_ARM64;
  360. break;
  361. case CPU_ARM64:
  362. if (size == 4) target->cpu = CPU_ARM;
  363. break;
  364. }
  365. }
  366. static inline int get_cpu_from_name( const char *name )
  367. {
  368. static const struct
  369. {
  370. const char *name;
  371. int cpu;
  372. } cpu_names[] =
  373. {
  374. { "i386", CPU_i386 },
  375. { "i486", CPU_i386 },
  376. { "i586", CPU_i386 },
  377. { "i686", CPU_i386 },
  378. { "i786", CPU_i386 },
  379. { "x86_64", CPU_x86_64 },
  380. { "amd64", CPU_x86_64 },
  381. { "aarch64", CPU_ARM64 },
  382. { "arm64", CPU_ARM64 },
  383. { "arm", CPU_ARM },
  384. };
  385. unsigned int i;
  386. for (i = 0; i < ARRAY_SIZE(cpu_names); i++)
  387. if (!strncmp( cpu_names[i].name, name, strlen(cpu_names[i].name) )) return cpu_names[i].cpu;
  388. return -1;
  389. }
  390. static inline int get_platform_from_name( const char *name )
  391. {
  392. static const struct
  393. {
  394. const char *name;
  395. int platform;
  396. } platform_names[] =
  397. {
  398. { "macos", PLATFORM_APPLE },
  399. { "darwin", PLATFORM_APPLE },
  400. { "android", PLATFORM_ANDROID },
  401. { "linux", PLATFORM_LINUX },
  402. { "freebsd", PLATFORM_FREEBSD },
  403. { "solaris", PLATFORM_SOLARIS },
  404. { "mingw32", PLATFORM_MINGW },
  405. { "windows-gnu", PLATFORM_MINGW },
  406. { "winnt", PLATFORM_MINGW },
  407. { "windows", PLATFORM_WINDOWS },
  408. { "cygwin", PLATFORM_CYGWIN },
  409. };
  410. unsigned int i;
  411. for (i = 0; i < ARRAY_SIZE(platform_names); i++)
  412. if (!strncmp( platform_names[i].name, name, strlen(platform_names[i].name) ))
  413. return platform_names[i].platform;
  414. return -1;
  415. };
  416. static inline const char *get_arch_dir( struct target target )
  417. {
  418. static const char *cpu_names[] =
  419. {
  420. [CPU_i386] = "i386",
  421. [CPU_x86_64] = "x86_64",
  422. [CPU_ARM] = "arm",
  423. [CPU_ARM64] = "aarch64"
  424. };
  425. if (!cpu_names[target.cpu]) return "";
  426. switch (target.platform)
  427. {
  428. case PLATFORM_WINDOWS:
  429. case PLATFORM_CYGWIN:
  430. case PLATFORM_MINGW:
  431. return strmake( "/%s-windows", cpu_names[target.cpu] );
  432. default:
  433. return strmake( "/%s-unix", cpu_names[target.cpu] );
  434. }
  435. }
  436. static inline int parse_target( const char *name, struct target *target )
  437. {
  438. int res;
  439. char *p, *spec = xstrdup( name );
  440. /* target specification is in the form CPU-MANUFACTURER-OS or CPU-MANUFACTURER-KERNEL-OS */
  441. /* get the CPU part */
  442. if ((p = strchr( spec, '-' )))
  443. {
  444. *p++ = 0;
  445. if ((res = get_cpu_from_name( spec )) == -1)
  446. {
  447. free( spec );
  448. return 0;
  449. }
  450. target->cpu = res;
  451. }
  452. else if (!strcmp( spec, "mingw32" ))
  453. {
  454. target->cpu = CPU_i386;
  455. p = spec;
  456. }
  457. else
  458. {
  459. free( spec );
  460. return 0;
  461. }
  462. /* get the OS part */
  463. target->platform = PLATFORM_UNSPECIFIED; /* default value */
  464. for (;;)
  465. {
  466. if ((res = get_platform_from_name( p )) != -1)
  467. {
  468. target->platform = res;
  469. break;
  470. }
  471. if (!(p = strchr( p, '-' ))) break;
  472. p++;
  473. }
  474. free( spec );
  475. return 1;
  476. }
  477. static inline struct target init_argv0_target( const char *argv0 )
  478. {
  479. char *name = get_basename( argv0 );
  480. struct target target;
  481. if (!strchr( name, '-' ) || !parse_target( name, &target ))
  482. target = get_default_target();
  483. free( name );
  484. return target;
  485. }
  486. /* command-line option parsing */
  487. /* partly based on the Glibc getopt() implementation */
  488. struct long_option
  489. {
  490. const char *name;
  491. int has_arg;
  492. int val;
  493. };
  494. static inline struct strarray parse_options( int argc, char **argv, const char *short_opts,
  495. const struct long_option *long_opts, int long_only,
  496. void (*callback)( int, char* ) )
  497. {
  498. struct strarray ret = empty_strarray;
  499. const char *flag;
  500. char *start, *end;
  501. int i;
  502. #define OPT_ERR(fmt) { callback( '?', strmake( fmt, argv[1] )); continue; }
  503. for (i = 1; i < argc; i++)
  504. {
  505. if (argv[i][0] != '-' || !argv[i][1]) /* not an option */
  506. {
  507. strarray_add( &ret, argv[i] );
  508. continue;
  509. }
  510. if (!strcmp( argv[i], "--" ))
  511. {
  512. /* add remaining args */
  513. while (++i < argc) strarray_add( &ret, argv[i] );
  514. break;
  515. }
  516. start = argv[i] + 1 + (argv[i][1] == '-');
  517. if (argv[i][1] == '-' || (long_only && (argv[i][2] || !strchr( short_opts, argv[i][1] ))))
  518. {
  519. /* handle long option */
  520. const struct long_option *opt, *found = NULL;
  521. int count = 0;
  522. if (!(end = strchr( start, '=' ))) end = start + strlen(start);
  523. for (opt = long_opts; opt && opt->name; opt++)
  524. {
  525. if (strncmp( opt->name, start, end - start )) continue;
  526. if (!opt->name[end - start]) /* exact match */
  527. {
  528. found = opt;
  529. count = 1;
  530. break;
  531. }
  532. if (!found)
  533. {
  534. found = opt;
  535. count++;
  536. }
  537. else if (long_only || found->has_arg != opt->has_arg || found->val != opt->val)
  538. {
  539. count++;
  540. }
  541. }
  542. if (count > 1) OPT_ERR( "option '%s' is ambiguous" );
  543. if (found)
  544. {
  545. if (*end)
  546. {
  547. if (!found->has_arg) OPT_ERR( "argument not allowed in '%s'" );
  548. end++; /* skip '=' */
  549. }
  550. else if (found->has_arg == 1)
  551. {
  552. if (i == argc - 1) OPT_ERR( "option '%s' requires an argument" );
  553. end = argv[++i];
  554. }
  555. else end = NULL;
  556. callback( found->val, end );
  557. continue;
  558. }
  559. if (argv[i][1] == '-' || !long_only || !strchr( short_opts, argv[i][1] ))
  560. OPT_ERR( "unrecognized option '%s'" );
  561. }
  562. /* handle short option */
  563. for ( ; *start; start++)
  564. {
  565. if (!(flag = strchr( short_opts, *start ))) OPT_ERR( "invalid option '%s'" );
  566. if (flag[1] == ':')
  567. {
  568. end = start + 1;
  569. if (!*end) end = NULL;
  570. if (flag[2] != ':' && !end)
  571. {
  572. if (i == argc - 1) OPT_ERR( "option '%s' requires an argument" );
  573. end = argv[++i];
  574. }
  575. callback( *start, end );
  576. break;
  577. }
  578. callback( *start, NULL );
  579. }
  580. }
  581. return ret;
  582. #undef OPT_ERR
  583. }
  584. #endif /* __WINE_TOOLS_H */