include: InterlockedExchangeAdd64 msvc intrinsic does not exist in x86.
[wine.git] / tools / tools.h
blob1e86e38356de8819189807c7a64c939015f609b3
1 /*
2 * Helper functions for the Wine tools
4 * Copyright 2021 Alexandre Julliard
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.
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.
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
21 #ifndef __WINE_TOOLS_H
22 #define __WINE_TOOLS_H
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <time.h>
32 #include <errno.h>
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
65 #if !defined(__GNUC__) && !defined(__attribute__)
66 #define __attribute__(x)
67 #endif
69 #ifndef max
70 #define max(a,b) (((a) > (b)) ? (a) : (b))
71 #endif
72 #ifndef min
73 #define min(a,b) (((a) < (b)) ? (a) : (b))
74 #endif
76 #ifndef ARRAY_SIZE
77 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
78 #endif
80 struct target
82 enum { CPU_i386, CPU_x86_64, CPU_ARM, CPU_ARM64 } cpu;
84 enum
86 PLATFORM_UNSPECIFIED,
87 PLATFORM_APPLE,
88 PLATFORM_ANDROID,
89 PLATFORM_LINUX,
90 PLATFORM_FREEBSD,
91 PLATFORM_SOLARIS,
92 PLATFORM_WINDOWS,
93 PLATFORM_MINGW,
94 PLATFORM_CYGWIN
95 } platform;
98 static inline void *xmalloc( size_t size )
100 void *res = malloc( size ? size : 1 );
102 if (res == NULL)
104 fprintf( stderr, "Virtual memory exhausted.\n" );
105 exit(1);
107 return res;
110 static inline void *xrealloc (void *ptr, size_t size)
112 void *res = realloc( ptr, size );
114 if (size && res == NULL)
116 fprintf( stderr, "Virtual memory exhausted.\n" );
117 exit(1);
119 return res;
122 static inline char *xstrdup( const char *str )
124 return strcpy( xmalloc( strlen(str)+1 ), str );
127 static inline int strendswith( const char *str, const char *end )
129 int l = strlen( str );
130 int m = strlen( end );
131 return l >= m && !strcmp( str + l - m, end );
134 static char *strmake( const char* fmt, ... ) __attribute__ ((__format__ (__printf__, 1, 2)));
135 static inline char *strmake( const char* fmt, ... )
137 int n;
138 size_t size = 100;
139 va_list ap;
141 for (;;)
143 char *p = xmalloc( size );
144 va_start( ap, fmt );
145 n = vsnprintf( p, size, fmt, ap );
146 va_end( ap );
147 if (n == -1) size *= 2;
148 else if ((size_t)n >= size) size = n + 1;
149 else return p;
150 free( p );
154 /* string array functions */
156 struct strarray
158 unsigned int count; /* strings in use */
159 unsigned int size; /* total allocated size */
160 const char **str;
163 static const struct strarray empty_strarray;
165 static inline void strarray_add( struct strarray *array, const char *str )
167 if (array->count == array->size)
169 if (array->size) array->size *= 2;
170 else array->size = 16;
171 array->str = xrealloc( array->str, sizeof(array->str[0]) * array->size );
173 array->str[array->count++] = str;
176 static inline void strarray_addall( struct strarray *array, struct strarray added )
178 unsigned int i;
180 for (i = 0; i < added.count; i++) strarray_add( array, added.str[i] );
183 static inline int strarray_exists( const struct strarray *array, const char *str )
185 unsigned int i;
187 for (i = 0; i < array->count; i++) if (!strcmp( array->str[i], str )) return 1;
188 return 0;
191 static inline void strarray_add_uniq( struct strarray *array, const char *str )
193 if (!strarray_exists( array, str )) strarray_add( array, str );
196 static inline void strarray_addall_uniq( struct strarray *array, struct strarray added )
198 unsigned int i;
200 for (i = 0; i < added.count; i++) strarray_add_uniq( array, added.str[i] );
203 static inline struct strarray strarray_fromstring( const char *str, const char *delim )
205 struct strarray array = empty_strarray;
206 char *buf = xstrdup( str );
207 const char *tok;
209 for (tok = strtok( buf, delim ); tok; tok = strtok( NULL, delim ))
210 strarray_add( &array, xstrdup( tok ));
211 free( buf );
212 return array;
215 static inline struct strarray strarray_frompath( const char *path )
217 if (!path) return empty_strarray;
218 #ifdef _WIN32
219 return strarray_fromstring( path, ";" );
220 #else
221 return strarray_fromstring( path, ":" );
222 #endif
225 static inline char *strarray_tostring( struct strarray array, const char *sep )
227 char *str;
228 unsigned int i, len = 1 + (array.count - 1) * strlen(sep);
230 if (!array.count) return xstrdup("");
231 for (i = 0; i < array.count; i++) len += strlen( array.str[i] );
232 str = xmalloc( len );
233 strcpy( str, array.str[0] );
234 for (i = 1; i < array.count; i++)
236 strcat( str, sep );
237 strcat( str, array.str[i] );
239 return str;
242 static inline void strarray_qsort( struct strarray *array, int (*func)(const char **, const char **) )
244 if (array->count) qsort( array->str, array->count, sizeof(*array->str), (void *)func );
247 static inline const char *strarray_bsearch( const struct strarray *array, const char *str,
248 int (*func)(const char **, const char **) )
250 char **res = NULL;
252 if (array->count) res = bsearch( &str, array->str, array->count, sizeof(*array->str), (void *)func );
253 return res ? *res : NULL;
256 static inline void strarray_trace( struct strarray args )
258 unsigned int i;
260 for (i = 0; i < args.count; i++)
262 if (strpbrk( args.str[i], " \t\n\r")) printf( "\"%s\"", args.str[i] );
263 else printf( "%s", args.str[i] );
264 putchar( i < args.count - 1 ? ' ' : '\n' );
268 static inline int strarray_spawn( struct strarray args )
270 #ifdef _WIN32
271 strarray_add( &args, NULL );
272 return _spawnvp( _P_WAIT, args.str[0], args.str );
273 #else
274 pid_t pid, wret;
275 int status;
277 if (!(pid = fork()))
279 strarray_add( &args, NULL );
280 execvp( args.str[0], (char **)args.str );
281 _exit(1);
283 if (pid == -1) return -1;
285 while (pid != (wret = waitpid( pid, &status, 0 )))
286 if (wret == -1 && errno != EINTR) break;
288 if (pid == wret && WIFEXITED(status)) return WEXITSTATUS(status);
289 return 255; /* abnormal exit with an abort or an interrupt */
290 #endif
293 static inline char *get_basename( const char *file )
295 const char *ret = strrchr( file, '/' );
296 return xstrdup( ret ? ret + 1 : file );
299 static inline char *get_basename_noext( const char *file )
301 char *ext, *ret = get_basename( file );
302 if ((ext = strrchr( ret, '.' ))) *ext = 0;
303 return ret;
306 static inline char *get_dirname( const char *file )
308 const char *end = strrchr( file, '/' );
309 if (!end) return xstrdup( "." );
310 if (end == file) end++;
311 return strmake( "%.*s", (int)(end - file), file );
314 static inline char *replace_extension( const char *name, const char *old_ext, const char *new_ext )
316 int name_len = strlen( name );
318 if (strendswith( name, old_ext )) name_len -= strlen( old_ext );
319 return strmake( "%.*s%s", name_len, name, new_ext );
323 static inline int make_temp_file( const char *prefix, const char *suffix, char **name )
325 static unsigned int value;
326 int fd, count;
327 const char *tmpdir = NULL;
329 if (!prefix) prefix = "tmp";
330 if (!suffix) suffix = "";
331 value += time(NULL) + getpid();
333 for (count = 0; count < 0x8000; count++)
335 if (tmpdir)
336 *name = strmake( "%s/%s-%08x%s", tmpdir, prefix, value, suffix );
337 else
338 *name = strmake( "%s-%08x%s", prefix, value, suffix );
339 fd = open( *name, O_RDWR | O_CREAT | O_EXCL, 0600 );
340 if (fd >= 0) return fd;
341 value += 7777;
342 if (errno == EACCES && !tmpdir && !strchr( prefix, '/' ))
344 if (!(tmpdir = getenv("TMPDIR"))) tmpdir = "/tmp";
346 free( *name );
348 fprintf( stderr, "failed to create temp file for %s%s\n", prefix, suffix );
349 exit(1);
353 static inline void *read_file( const char *name, size_t *size )
355 struct stat st;
356 int res, fd;
357 void *data;
359 if ((fd = open( name, O_RDONLY | O_BINARY )) == -1) return NULL;
360 fstat( fd, &st );
361 data = xmalloc( st.st_size );
362 res = read( fd, data, st.st_size );
363 if (res == -1)
365 free( data );
366 data = NULL;
367 *size = 0;
369 else *size = res;
370 close( fd );
371 return data;
375 static inline struct target get_default_target(void)
377 struct target target;
378 #ifdef __i386__
379 target.cpu = CPU_i386;
380 #elif defined(__x86_64__)
381 target.cpu = CPU_x86_64;
382 #elif defined(__arm__)
383 target.cpu = CPU_ARM;
384 #elif defined(__aarch64__)
385 target.cpu = CPU_ARM64;
386 #else
387 #error Unsupported CPU
388 #endif
390 #ifdef __APPLE__
391 target.platform = PLATFORM_APPLE;
392 #elif defined(__ANDROID__)
393 target.platform = PLATFORM_ANDROID;
394 #elif defined(__linux__)
395 target.platform = PLATFORM_LINUX;
396 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
397 target.platform = PLATFORM_FREEBSD;
398 #elif defined(__sun)
399 target.platform = PLATFORM_SOLARIS;
400 #elif defined(__CYGWIN__)
401 target.platform = PLATFORM_CYGWIN;
402 #elif defined(_WIN32)
403 target.platform = PLATFORM_MINGW;
404 #else
405 target.platform = PLATFORM_UNSPECIFIED;
406 #endif
408 return target;
412 static inline unsigned int get_target_ptr_size( struct target target )
414 static const unsigned int sizes[] =
416 [CPU_i386] = 4,
417 [CPU_x86_64] = 8,
418 [CPU_ARM] = 4,
419 [CPU_ARM64] = 8,
421 return sizes[target.cpu];
425 static inline void set_target_ptr_size( struct target *target, unsigned int size )
427 switch (target->cpu)
429 case CPU_i386:
430 if (size == 8) target->cpu = CPU_x86_64;
431 break;
432 case CPU_x86_64:
433 if (size == 4) target->cpu = CPU_i386;
434 break;
435 case CPU_ARM:
436 if (size == 8) target->cpu = CPU_ARM64;
437 break;
438 case CPU_ARM64:
439 if (size == 4) target->cpu = CPU_ARM;
440 break;
445 static inline int get_cpu_from_name( const char *name )
447 static const struct
449 const char *name;
450 int cpu;
451 } cpu_names[] =
453 { "i386", CPU_i386 },
454 { "i486", CPU_i386 },
455 { "i586", CPU_i386 },
456 { "i686", CPU_i386 },
457 { "i786", CPU_i386 },
458 { "x86_64", CPU_x86_64 },
459 { "amd64", CPU_x86_64 },
460 { "aarch64", CPU_ARM64 },
461 { "arm64", CPU_ARM64 },
462 { "arm", CPU_ARM },
464 unsigned int i;
466 for (i = 0; i < ARRAY_SIZE(cpu_names); i++)
467 if (!strncmp( cpu_names[i].name, name, strlen(cpu_names[i].name) )) return cpu_names[i].cpu;
468 return -1;
472 static inline int get_platform_from_name( const char *name )
474 static const struct
476 const char *name;
477 int platform;
478 } platform_names[] =
480 { "macos", PLATFORM_APPLE },
481 { "darwin", PLATFORM_APPLE },
482 { "android", PLATFORM_ANDROID },
483 { "linux", PLATFORM_LINUX },
484 { "freebsd", PLATFORM_FREEBSD },
485 { "solaris", PLATFORM_SOLARIS },
486 { "mingw32", PLATFORM_MINGW },
487 { "windows-gnu", PLATFORM_MINGW },
488 { "winnt", PLATFORM_MINGW },
489 { "windows", PLATFORM_WINDOWS },
490 { "cygwin", PLATFORM_CYGWIN },
492 unsigned int i;
494 for (i = 0; i < ARRAY_SIZE(platform_names); i++)
495 if (!strncmp( platform_names[i].name, name, strlen(platform_names[i].name) ))
496 return platform_names[i].platform;
497 return -1;
501 static inline const char *get_arch_dir( struct target target )
503 static const char *cpu_names[] =
505 [CPU_i386] = "i386",
506 [CPU_x86_64] = "x86_64",
507 [CPU_ARM] = "arm",
508 [CPU_ARM64] = "aarch64"
511 if (!cpu_names[target.cpu]) return "";
513 switch (target.platform)
515 case PLATFORM_WINDOWS:
516 case PLATFORM_CYGWIN:
517 case PLATFORM_MINGW:
518 return strmake( "/%s-windows", cpu_names[target.cpu] );
519 default:
520 return strmake( "/%s-unix", cpu_names[target.cpu] );
524 static inline int parse_target( const char *name, struct target *target )
526 int res;
527 char *p, *spec = xstrdup( name );
529 /* target specification is in the form CPU-MANUFACTURER-OS or CPU-MANUFACTURER-KERNEL-OS */
531 /* get the CPU part */
533 if ((p = strchr( spec, '-' )))
535 *p++ = 0;
536 if ((res = get_cpu_from_name( spec )) == -1)
538 free( spec );
539 return 0;
541 target->cpu = res;
543 else if (!strcmp( spec, "mingw32" ))
545 target->cpu = CPU_i386;
546 p = spec;
548 else
550 free( spec );
551 return 0;
554 /* get the OS part */
556 target->platform = PLATFORM_UNSPECIFIED; /* default value */
557 for (;;)
559 if ((res = get_platform_from_name( p )) != -1)
561 target->platform = res;
562 break;
564 if (!(p = strchr( p, '-' ))) break;
565 p++;
568 free( spec );
569 return 1;
573 static inline struct target init_argv0_target( const char *argv0 )
575 char *name = get_basename( argv0 );
576 struct target target;
578 if (!strchr( name, '-' ) || !parse_target( name, &target ))
579 target = get_default_target();
581 free( name );
582 return target;
586 /* output buffer management */
588 extern unsigned char *output_buffer;
589 extern size_t output_buffer_pos;
590 extern size_t output_buffer_size;
592 static inline void check_output_buffer_space( size_t size )
594 if (output_buffer_pos + size >= output_buffer_size)
596 output_buffer_size = max( output_buffer_size * 2, output_buffer_pos + size );
597 output_buffer = xrealloc( output_buffer, output_buffer_size );
601 static inline void init_output_buffer(void)
603 output_buffer_size = 1024;
604 output_buffer_pos = 0;
605 output_buffer = xmalloc( output_buffer_size );
608 static inline void put_data( const void *data, size_t size )
610 check_output_buffer_space( size );
611 memcpy( output_buffer + output_buffer_pos, data, size );
612 output_buffer_pos += size;
615 static inline void put_byte( unsigned char val )
617 check_output_buffer_space( 1 );
618 output_buffer[output_buffer_pos++] = val;
621 static inline void put_word( unsigned short val )
623 check_output_buffer_space( 2 );
624 output_buffer[output_buffer_pos++] = val;
625 output_buffer[output_buffer_pos++] = val >> 8;
628 static inline void put_dword( unsigned int val )
630 check_output_buffer_space( 4 );
631 output_buffer[output_buffer_pos++] = val;
632 output_buffer[output_buffer_pos++] = val >> 8;
633 output_buffer[output_buffer_pos++] = val >> 16;
634 output_buffer[output_buffer_pos++] = val >> 24;
637 static inline void put_qword( unsigned int val )
639 put_dword( val );
640 put_dword( 0 );
643 static inline void align_output( unsigned int align )
645 size_t size = align - (output_buffer_pos % align);
647 if (size == align) return;
648 check_output_buffer_space( size );
649 memset( output_buffer + output_buffer_pos, 0, size );
650 output_buffer_pos += size;
653 static inline void flush_output_buffer( const char *name )
655 int fd = open( name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666 );
657 if (fd == -1 || write( fd, output_buffer, output_buffer_pos ) != output_buffer_pos)
659 perror( name );
660 exit(1);
662 close( fd );
663 free( output_buffer );
666 /* command-line option parsing */
667 /* partly based on the Glibc getopt() implementation */
669 struct long_option
671 const char *name;
672 int has_arg;
673 int val;
676 static inline struct strarray parse_options( int argc, char **argv, const char *short_opts,
677 const struct long_option *long_opts, int long_only,
678 void (*callback)( int, char* ) )
680 struct strarray ret = empty_strarray;
681 const char *flag;
682 char *start, *end;
683 int i;
685 #define OPT_ERR(fmt) { callback( '?', strmake( fmt, argv[1] )); continue; }
687 for (i = 1; i < argc; i++)
689 if (argv[i][0] != '-' || !argv[i][1]) /* not an option */
691 strarray_add( &ret, argv[i] );
692 continue;
694 if (!strcmp( argv[i], "--" ))
696 /* add remaining args */
697 while (++i < argc) strarray_add( &ret, argv[i] );
698 break;
700 start = argv[i] + 1 + (argv[i][1] == '-');
702 if (argv[i][1] == '-' || (long_only && (argv[i][2] || !strchr( short_opts, argv[i][1] ))))
704 /* handle long option */
705 const struct long_option *opt, *found = NULL;
706 int count = 0;
708 if (!(end = strchr( start, '=' ))) end = start + strlen(start);
709 for (opt = long_opts; opt && opt->name; opt++)
711 if (strncmp( opt->name, start, end - start )) continue;
712 if (!opt->name[end - start]) /* exact match */
714 found = opt;
715 count = 1;
716 break;
718 if (!found)
720 found = opt;
721 count++;
723 else if (long_only || found->has_arg != opt->has_arg || found->val != opt->val)
725 count++;
729 if (count > 1) OPT_ERR( "option '%s' is ambiguous" );
731 if (found)
733 if (*end)
735 if (!found->has_arg) OPT_ERR( "argument not allowed in '%s'" );
736 end++; /* skip '=' */
738 else if (found->has_arg == 1)
740 if (i == argc - 1) OPT_ERR( "option '%s' requires an argument" );
741 end = argv[++i];
743 else end = NULL;
745 callback( found->val, end );
746 continue;
748 if (argv[i][1] == '-' || !long_only || !strchr( short_opts, argv[i][1] ))
749 OPT_ERR( "unrecognized option '%s'" );
752 /* handle short option */
753 for ( ; *start; start++)
755 if (!(flag = strchr( short_opts, *start ))) OPT_ERR( "invalid option '%s'" );
756 if (flag[1] == ':')
758 end = start + 1;
759 if (!*end) end = NULL;
760 if (flag[2] != ':' && !end)
762 if (i == argc - 1) OPT_ERR( "option '%s' requires an argument" );
763 end = argv[++i];
765 callback( *start, end );
766 break;
768 callback( *start, NULL );
771 return ret;
772 #undef OPT_ERR
775 #endif /* __WINE_TOOLS_H */