File indexing completed on 2024-04-19 22:58:23
97ca9f8a3… Alex*0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 #ifndef __WINE_TOOLS_H
0022 #define __WINE_TOOLS_H
0023
8772b3849… Alex*0024 #ifndef __WINE_CONFIG_H
0025 # error You must include config.h to use this header
0026 #endif
0027
004f36772… Gera*0028 #include <limits.h>
97ca9f8a3… Alex*0029 #include <stdarg.h>
0030 #include <stdio.h>
0031 #include <stdlib.h>
0032 #include <string.h>
2a08d6ce8… Alex*0033 #include <sys/types.h>
207068c48… Alex*0034 #include <sys/stat.h>
9f0ae8c99… Alex*0035 #include <signal.h>
55701c667… Alex*0036 #include <fcntl.h>
0037 #include <time.h>
2a08d6ce8… Alex*0038 #include <errno.h>
ecb651c01… Alex*0039 #ifdef HAVE_SYS_SYSCTL_H
0040 # include <sys/sysctl.h>
0041 #endif
2a08d6ce8… Alex*0042
339950a78… Alex*0043 #ifdef _WIN32
207068c48… Alex*0044 # include <direct.h>
0045 # include <io.h>
2a08d6ce8… Alex*0046 # include <process.h>
207068c48… Alex*0047 # define mkdir(path,mode) mkdir(path)
0048 # ifndef S_ISREG
0049 # define S_ISREG(mod) (((mod) & _S_IFMT) == _S_IFREG)
0050 # endif
0051 # ifdef _MSC_VER
0052 # define popen _popen
0053 # define pclose _pclose
0054 # define strtoll _strtoi64
0055 # define strtoull _strtoui64
0056 # define strncasecmp _strnicmp
0057 # define strcasecmp _stricmp
0058 # endif
2a08d6ce8… Alex*0059 #else
5206c7147… Bren*0060 extern char **environ;
0061 # include <spawn.h>
2a08d6ce8… Alex*0062 # include <sys/wait.h>
0063 # include <unistd.h>
207068c48… Alex*0064 # ifndef O_BINARY
0065 # define O_BINARY 0
0066 # endif
0067 # ifndef __int64
0068 # if defined(__x86_64__) || defined(__aarch64__) || defined(__powerpc64__)
0069 # define __int64 long
0070 # else
0071 # define __int64 long long
0072 # endif
0073 # endif
2a08d6ce8… Alex*0074 #endif
97ca9f8a3… Alex*0075
0076 #if !defined(__GNUC__) && !defined(__attribute__)
0077 #define __attribute__(x)
0078 #endif
0079
0080 #ifndef max
0081 #define max(a,b) (((a) > (b)) ? (a) : (b))
0082 #endif
0083 #ifndef min
0084 #define min(a,b) (((a) < (b)) ? (a) : (b))
0085 #endif
0086
0087 #ifndef ARRAY_SIZE
0088 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
0089 #endif
0090
d969d02e2… Alex*0091 struct target
0092 {
a0a2ef5a2… Jace*0093 enum { CPU_i386, CPU_x86_64, CPU_ARM, CPU_ARM64, CPU_ARM64EC } cpu;
d969d02e2… Alex*0094
0095 enum
0096 {
0097 PLATFORM_UNSPECIFIED,
0098 PLATFORM_APPLE,
0099 PLATFORM_ANDROID,
0100 PLATFORM_LINUX,
0101 PLATFORM_FREEBSD,
0102 PLATFORM_SOLARIS,
0103 PLATFORM_WINDOWS,
0104 PLATFORM_MINGW,
0105 PLATFORM_CYGWIN
0106 } platform;
0107 };
97ca9f8a3… Alex*0108
0109 static inline void *xmalloc( size_t size )
0110 {
0111 void *res = malloc( size ? size : 1 );
0112
0113 if (res == NULL)
0114 {
0115 fprintf( stderr, "Virtual memory exhausted.\n" );
0116 exit(1);
0117 }
0118 return res;
0119 }
0120
0121 static inline void *xrealloc (void *ptr, size_t size)
0122 {
0123 void *res = realloc( ptr, size );
0124
0125 if (size && res == NULL)
0126 {
0127 fprintf( stderr, "Virtual memory exhausted.\n" );
0128 exit(1);
0129 }
0130 return res;
0131 }
0132
0133 static inline char *xstrdup( const char *str )
0134 {
0135 return strcpy( xmalloc( strlen(str)+1 ), str );
0136 }
0137
0138 static inline int strendswith( const char *str, const char *end )
0139 {
0140 int l = strlen( str );
0141 int m = strlen( end );
0142 return l >= m && !strcmp( str + l - m, end );
0143 }
0144
0145 static char *strmake( const char* fmt, ... ) __attribute__ ((__format__ (__printf__, 1, 2)));
0146 static inline char *strmake( const char* fmt, ... )
0147 {
0148 int n;
0149 size_t size = 100;
0150 va_list ap;
0151
0152 for (;;)
0153 {
0154 char *p = xmalloc( size );
0155 va_start( ap, fmt );
0156 n = vsnprintf( p, size, fmt, ap );
0157 va_end( ap );
0158 if (n == -1) size *= 2;
0159 else if ((size_t)n >= size) size = n + 1;
0160 else return p;
0161 free( p );
0162 }
0163 }
0164
0165
0166
0167 struct strarray
0168 {
0169 unsigned int count;
0170 unsigned int size;
0171 const char **str;
0172 };
0173
0174 static const struct strarray empty_strarray;
0175
0176 static inline void strarray_add( struct strarray *array, const char *str )
0177 {
0178 if (array->count == array->size)
0179 {
0180 if (array->size) array->size *= 2;
0181 else array->size = 16;
0182 array->str = xrealloc( array->str, sizeof(array->str[0]) * array->size );
0183 }
0184 array->str[array->count++] = str;
0185 }
0186
0187 static inline void strarray_addall( struct strarray *array, struct strarray added )
0188 {
0189 unsigned int i;
0190
0191 for (i = 0; i < added.count; i++) strarray_add( array, added.str[i] );
0192 }
0193
0194 static inline int strarray_exists( const struct strarray *array, const char *str )
0195 {
0196 unsigned int i;
0197
0198 for (i = 0; i < array->count; i++) if (!strcmp( array->str[i], str )) return 1;
0199 return 0;
0200 }
0201
0202 static inline void strarray_add_uniq( struct strarray *array, const char *str )
0203 {
0204 if (!strarray_exists( array, str )) strarray_add( array, str );
0205 }
0206
0207 static inline void strarray_addall_uniq( struct strarray *array, struct strarray added )
0208 {
0209 unsigned int i;
0210
0211 for (i = 0; i < added.count; i++) strarray_add_uniq( array, added.str[i] );
0212 }
0213
0214 static inline struct strarray strarray_fromstring( const char *str, const char *delim )
0215 {
0216 struct strarray array = empty_strarray;
0217 char *buf = xstrdup( str );
0218 const char *tok;
0219
0220 for (tok = strtok( buf, delim ); tok; tok = strtok( NULL, delim ))
0221 strarray_add( &array, xstrdup( tok ));
0222 free( buf );
0223 return array;
0224 }
0225
0226 static inline struct strarray strarray_frompath( const char *path )
0227 {
0228 if (!path) return empty_strarray;
339950a78… Alex*0229 #ifdef _WIN32
97ca9f8a3… Alex*0230 return strarray_fromstring( path, ";" );
0231 #else
0232 return strarray_fromstring( path, ":" );
0233 #endif
0234 }
0235
0236 static inline char *strarray_tostring( struct strarray array, const char *sep )
0237 {
0238 char *str;
0239 unsigned int i, len = 1 + (array.count - 1) * strlen(sep);
0240
0241 if (!array.count) return xstrdup("");
0242 for (i = 0; i < array.count; i++) len += strlen( array.str[i] );
0243 str = xmalloc( len );
0244 strcpy( str, array.str[0] );
0245 for (i = 1; i < array.count; i++)
0246 {
0247 strcat( str, sep );
0248 strcat( str, array.str[i] );
0249 }
0250 return str;
0251 }
0252
0253 static inline void strarray_qsort( struct strarray *array, int (*func)(const char **, const char **) )
0254 {
0255 if (array->count) qsort( array->str, array->count, sizeof(*array->str), (void *)func );
0256 }
0257
0258 static inline const char *strarray_bsearch( const struct strarray *array, const char *str,
0259 int (*func)(const char **, const char **) )
0260 {
0261 char **res = NULL;
0262
0263 if (array->count) res = bsearch( &str, array->str, array->count, sizeof(*array->str), (void *)func );
0264 return res ? *res : NULL;
0265 }
0266
2a08d6ce8… Alex*0267 static inline void strarray_trace( struct strarray args )
0268 {
0269 unsigned int i;
0270
0271 for (i = 0; i < args.count; i++)
0272 {
0273 if (strpbrk( args.str[i], " \t\n\r")) printf( "\"%s\"", args.str[i] );
0274 else printf( "%s", args.str[i] );
0275 putchar( i < args.count - 1 ? ' ' : '\n' );
0276 }
0277 }
0278
0279 static inline int strarray_spawn( struct strarray args )
0280 {
339950a78… Alex*0281 #ifdef _WIN32
2a08d6ce8… Alex*0282 strarray_add( &args, NULL );
0283 return _spawnvp( _P_WAIT, args.str[0], args.str );
0284 #else
0285 pid_t pid, wret;
0286 int status;
0287
5206c7147… Bren*0288 strarray_add( &args, NULL );
0289 if (posix_spawnp( &pid, args.str[0], NULL, NULL, (char **)args.str, environ ))
0290 return -1;
2a08d6ce8… Alex*0291
0292 while (pid != (wret = waitpid( pid, &status, 0 )))
0293 if (wret == -1 && errno != EINTR) break;
0294
0295 if (pid == wret && WIFEXITED(status)) return WEXITSTATUS(status);
0296 return 255;
0297 #endif
0298 }
97ca9f8a3… Alex*0299
9e3959bd9… Alex*0300 static inline char *get_basename( const char *file )
0301 {
0302 const char *ret = strrchr( file, '/' );
0303 return xstrdup( ret ? ret + 1 : file );
0304 }
0305
0306 static inline char *get_basename_noext( const char *file )
0307 {
0308 char *ext, *ret = get_basename( file );
0309 if ((ext = strrchr( ret, '.' ))) *ext = 0;
0310 return ret;
0311 }
0312
0313 static inline char *get_dirname( const char *file )
0314 {
0315 const char *end = strrchr( file, '/' );
0316 if (!end) return xstrdup( "." );
0317 if (end == file) end++;
0318 return strmake( "%.*s", (int)(end - file), file );
0319 }
0320
0321 static inline char *replace_extension( const char *name, const char *old_ext, const char *new_ext )
0322 {
0323 int name_len = strlen( name );
0324
0325 if (strendswith( name, old_ext )) name_len -= strlen( old_ext );
0326 return strmake( "%.*s%s", name_len, name, new_ext );
0327 }
0328
bdc40b4b6… Alex*0329
9e3959bd9… Alex*0330
bdc40b4b6… Alex*0331 extern const char *temp_dir;
ca398e276… Alex*0332 extern struct strarray temp_files;
bdc40b4b6… Alex*0333
0334 static inline char *make_temp_dir(void)
55701c667… Alex*0335 {
bdc40b4b6… Alex*0336 unsigned int value = time(NULL) + getpid();
0337 int count;
0338 char *name;
55701c667… Alex*0339 const char *tmpdir = NULL;
0340
0341 for (count = 0; count < 0x8000; count++)
0342 {
0343 if (tmpdir)
bdc40b4b6… Alex*0344 name = strmake( "%s/tmp%08x", tmpdir, value );
55701c667… Alex*0345 else
bdc40b4b6… Alex*0346 name = strmake( "tmp%08x", value );
0347 if (!mkdir( name, 0700 )) return name;
55701c667… Alex*0348 value += 7777;
bdc40b4b6… Alex*0349 if (errno == EACCES && !tmpdir)
55701c667… Alex*0350 {
0351 if (!(tmpdir = getenv("TMPDIR"))) tmpdir = "/tmp";
0352 }
bdc40b4b6… Alex*0353 free( name );
0354 }
0355 fprintf( stderr, "failed to create directory for temp files\n" );
0356 exit(1);
0357 }
0358
ca398e276… Alex*0359 static inline char *make_temp_file( const char *prefix, const char *suffix )
bdc40b4b6… Alex*0360 {
0361 static unsigned int value;
0362 int fd, count;
ca398e276… Alex*0363 char *name;
bdc40b4b6… Alex*0364
0365 if (!temp_dir) temp_dir = make_temp_dir();
0366 if (!suffix) suffix = "";
0367 if (!prefix) prefix = "tmp";
0368 else prefix = get_basename_noext( prefix );
0369
0370 for (count = 0; count < 0x8000; count++)
0371 {
ca398e276… Alex*0372 name = strmake( "%s/%s-%08x%s", temp_dir, prefix, value++, suffix );
0373 fd = open( name, O_RDWR | O_CREAT | O_EXCL, 0600 );
0374 if (fd >= 0)
0375 {
9f0ae8c99… Alex*0376 #ifdef HAVE_SIGPROCMASK
0377 sigset_t mask_set, old_set;
0378
0379 sigemptyset( &mask_set );
0380 sigaddset( &mask_set, SIGHUP );
0381 sigaddset( &mask_set, SIGTERM );
0382 sigaddset( &mask_set, SIGINT );
0383 sigprocmask( SIG_BLOCK, &mask_set, &old_set );
ca398e276… Alex*0384 strarray_add( &temp_files, name );
9f0ae8c99… Alex*0385 sigprocmask( SIG_SETMASK, &old_set, NULL );
0386 #else
0387 strarray_add( &temp_files, name );
0388 #endif
ca398e276… Alex*0389 close( fd );
0390 return name;
0391 }
0392 free( name );
55701c667… Alex*0393 }
bdc40b4b6… Alex*0394 fprintf( stderr, "failed to create temp file for %s%s in %s\n", prefix, suffix, temp_dir );
55701c667… Alex*0395 exit(1);
0396 }
0397
ca398e276… Alex*0398 static inline void remove_temp_files(void)
0399 {
0400 unsigned int i;
0401
0402 for (i = 0; i < temp_files.count; i++) if (temp_files.str[i]) unlink( temp_files.str[i] );
0403 if (temp_dir) rmdir( temp_dir );
0404 }
0405
9c4cbde78… Alex*0406
ae8797c8e… Alex*0407 static inline void init_signals( void (*cleanup)(int) )
0408 {
0409 signal( SIGTERM, cleanup );
0410 signal( SIGINT, cleanup );
0411 #ifdef SIGHUP
0412 signal( SIGHUP, cleanup );
0413 #endif
0414 }
0415
0416
c562952f9… Alex*0417 static inline void *read_file( const char *name, size_t *size )
0418 {
0419 struct stat st;
0420 int res, fd;
0421 void *data;
0422
0423 if ((fd = open( name, O_RDONLY | O_BINARY )) == -1) return NULL;
0424 fstat( fd, &st );
0425 data = xmalloc( st.st_size );
0426 res = read( fd, data, st.st_size );
0427 if (res == -1)
0428 {
0429 free( data );
0430 data = NULL;
0431 *size = 0;
0432 }
0433 else *size = res;
0434 close( fd );
0435 return data;
0436 }
0437
0438
d969d02e2… Alex*0439 static inline struct target get_default_target(void)
0440 {
0441 struct target target;
0442 #ifdef __i386__
0443 target.cpu = CPU_i386;
0444 #elif defined(__x86_64__)
0445 target.cpu = CPU_x86_64;
0446 #elif defined(__arm__)
0447 target.cpu = CPU_ARM;
0448 #elif defined(__aarch64__)
0449 target.cpu = CPU_ARM64;
0450 #else
0451 #error Unsupported CPU
0452 #endif
0453
0454 #ifdef __APPLE__
0455 target.platform = PLATFORM_APPLE;
0456 #elif defined(__ANDROID__)
0457 target.platform = PLATFORM_ANDROID;
0458 #elif defined(__linux__)
0459 target.platform = PLATFORM_LINUX;
0460 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
0461 target.platform = PLATFORM_FREEBSD;
0462 #elif defined(__sun)
0463 target.platform = PLATFORM_SOLARIS;
0464 #elif defined(__CYGWIN__)
0465 target.platform = PLATFORM_CYGWIN;
0466 #elif defined(_WIN32)
0467 target.platform = PLATFORM_MINGW;
0468 #else
0469 target.platform = PLATFORM_UNSPECIFIED;
0470 #endif
0471
0472 return target;
0473 }
0474
0475
0476 static inline unsigned int get_target_ptr_size( struct target target )
0477 {
0478 static const unsigned int sizes[] =
0479 {
0480 [CPU_i386] = 4,
0481 [CPU_x86_64] = 8,
0482 [CPU_ARM] = 4,
0483 [CPU_ARM64] = 8,
a0a2ef5a2… Jace*0484 [CPU_ARM64EC] = 8,
d969d02e2… Alex*0485 };
0486 return sizes[target.cpu];
0487 }
0488
0489
0490 static inline void set_target_ptr_size( struct target *target, unsigned int size )
0491 {
0492 switch (target->cpu)
0493 {
0494 case CPU_i386:
0495 if (size == 8) target->cpu = CPU_x86_64;
0496 break;
0497 case CPU_x86_64:
0498 if (size == 4) target->cpu = CPU_i386;
0499 break;
0500 case CPU_ARM:
0501 if (size == 8) target->cpu = CPU_ARM64;
0502 break;
0503 case CPU_ARM64:
a0a2ef5a2… Jace*0504 case CPU_ARM64EC:
d969d02e2… Alex*0505 if (size == 4) target->cpu = CPU_ARM;
0506 break;
0507 }
0508 }
0509
0510
0511 static inline int get_cpu_from_name( const char *name )
0512 {
0513 static const struct
0514 {
0515 const char *name;
0516 int cpu;
0517 } cpu_names[] =
0518 {
0519 { "i386", CPU_i386 },
0520 { "i486", CPU_i386 },
0521 { "i586", CPU_i386 },
0522 { "i686", CPU_i386 },
0523 { "i786", CPU_i386 },
0524 { "x86_64", CPU_x86_64 },
0525 { "amd64", CPU_x86_64 },
0526 { "aarch64", CPU_ARM64 },
a0a2ef5a2… Jace*0527 { "arm64ec", CPU_ARM64EC },
d969d02e2… Alex*0528 { "arm64", CPU_ARM64 },
0529 { "arm", CPU_ARM },
0530 };
0531 unsigned int i;
0532
0533 for (i = 0; i < ARRAY_SIZE(cpu_names); i++)
0534 if (!strncmp( cpu_names[i].name, name, strlen(cpu_names[i].name) )) return cpu_names[i].cpu;
0535 return -1;
0536 }
0537
0538
0539 static inline int get_platform_from_name( const char *name )
0540 {
0541 static const struct
0542 {
0543 const char *name;
0544 int platform;
0545 } platform_names[] =
0546 {
0547 { "macos", PLATFORM_APPLE },
0548 { "darwin", PLATFORM_APPLE },
0549 { "android", PLATFORM_ANDROID },
0550 { "linux", PLATFORM_LINUX },
0551 { "freebsd", PLATFORM_FREEBSD },
0552 { "solaris", PLATFORM_SOLARIS },
0553 { "mingw32", PLATFORM_MINGW },
0554 { "windows-gnu", PLATFORM_MINGW },
0555 { "winnt", PLATFORM_MINGW },
0556 { "windows", PLATFORM_WINDOWS },
0557 { "cygwin", PLATFORM_CYGWIN },
0558 };
0559 unsigned int i;
0560
0561 for (i = 0; i < ARRAY_SIZE(platform_names); i++)
0562 if (!strncmp( platform_names[i].name, name, strlen(platform_names[i].name) ))
0563 return platform_names[i].platform;
0564 return -1;
0565 };
0566
0567
0568 static inline const char *get_arch_dir( struct target target )
0569 {
0570 static const char *cpu_names[] =
0571 {
a0a2ef5a2… Jace*0572 [CPU_i386] = "i386",
0573 [CPU_x86_64] = "x86_64",
0574 [CPU_ARM] = "arm",
0575 [CPU_ARM64] = "aarch64",
ba50573f9… Jace*0576 [CPU_ARM64EC] = "aarch64",
d969d02e2… Alex*0577 };
0578
0579 if (!cpu_names[target.cpu]) return "";
0580
0581 switch (target.platform)
0582 {
0583 case PLATFORM_WINDOWS:
0584 case PLATFORM_CYGWIN:
0585 case PLATFORM_MINGW:
0586 return strmake( "/%s-windows", cpu_names[target.cpu] );
0587 default:
0588 return strmake( "/%s-unix", cpu_names[target.cpu] );
0589 }
0590 }
0591
0592 static inline int parse_target( const char *name, struct target *target )
0593 {
0594 int res;
0595 char *p, *spec = xstrdup( name );
0596
0597
0598
0599
0600
0601 if ((p = strchr( spec, '-' )))
0602 {
0603 *p++ = 0;
0604 if ((res = get_cpu_from_name( spec )) == -1)
0605 {
0606 free( spec );
0607 return 0;
0608 }
0609 target->cpu = res;
0610 }
0611 else if (!strcmp( spec, "mingw32" ))
0612 {
0613 target->cpu = CPU_i386;
0614 p = spec;
0615 }
0616 else
0617 {
0618 free( spec );
0619 return 0;
0620 }
0621
0622
0623
0624 target->platform = PLATFORM_UNSPECIFIED;
0625 for (;;)
0626 {
0627 if ((res = get_platform_from_name( p )) != -1)
0628 {
0629 target->platform = res;
0630 break;
0631 }
0632 if (!(p = strchr( p, '-' ))) break;
0633 p++;
0634 }
0635
0636 free( spec );
0637 return 1;
0638 }
0639
0640
0641 static inline struct target init_argv0_target( const char *argv0 )
0642 {
0643 char *name = get_basename( argv0 );
0644 struct target target;
0645
0646 if (!strchr( name, '-' ) || !parse_target( name, &target ))
0647 target = get_default_target();
0648
0649 free( name );
0650 return target;
0651 }
0652
0653
ecb651c01… Alex*0654 static inline char *get_argv0_dir( const char *argv0 )
0655 {
0656 #ifndef _WIN32
0657 char *dir = NULL;
0658
0659 #if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
0660 dir = realpath( "/proc/self/exe", NULL );
0661 #elif defined (__FreeBSD__) || defined(__DragonFly__)
0662 static int pathname[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
0663 size_t path_size = PATH_MAX;
0664 char *path = xmalloc( path_size );
0665 if (!sysctl( pathname, ARRAY_SIZE(pathname), path, &path_size, NULL, 0 ))
0666 dir = realpath( path, NULL );
0667 free( path );
0668 #endif
0669 if (!dir && !(dir = realpath( argv0, NULL ))) return NULL;
0670 return get_dirname( dir );
0671 #else
0672 return get_dirname( argv0 );
0673 #endif
0674 }
0675
0676
b53773cff… Alex*0677
0678
0679 extern unsigned char *output_buffer;
0680 extern size_t output_buffer_pos;
0681 extern size_t output_buffer_size;
0682
0683 static inline void check_output_buffer_space( size_t size )
0684 {
0685 if (output_buffer_pos + size >= output_buffer_size)
0686 {
0687 output_buffer_size = max( output_buffer_size * 2, output_buffer_pos + size );
0688 output_buffer = xrealloc( output_buffer, output_buffer_size );
0689 }
0690 }
0691
0692 static inline void init_output_buffer(void)
0693 {
0694 output_buffer_size = 1024;
0695 output_buffer_pos = 0;
0696 output_buffer = xmalloc( output_buffer_size );
0697 }
0698
0699 static inline void put_data( const void *data, size_t size )
0700 {
0701 check_output_buffer_space( size );
0702 memcpy( output_buffer + output_buffer_pos, data, size );
0703 output_buffer_pos += size;
0704 }
0705
0706 static inline void put_byte( unsigned char val )
0707 {
0708 check_output_buffer_space( 1 );
0709 output_buffer[output_buffer_pos++] = val;
0710 }
0711
0712 static inline void put_word( unsigned short val )
0713 {
0714 check_output_buffer_space( 2 );
0715 output_buffer[output_buffer_pos++] = val;
0716 output_buffer[output_buffer_pos++] = val >> 8;
0717 }
0718
0719 static inline void put_dword( unsigned int val )
0720 {
0721 check_output_buffer_space( 4 );
0722 output_buffer[output_buffer_pos++] = val;
0723 output_buffer[output_buffer_pos++] = val >> 8;
0724 output_buffer[output_buffer_pos++] = val >> 16;
0725 output_buffer[output_buffer_pos++] = val >> 24;
0726 }
0727
0728 static inline void put_qword( unsigned int val )
0729 {
0730 put_dword( val );
0731 put_dword( 0 );
0732 }
0733
0734 static inline void align_output( unsigned int align )
0735 {
0736 size_t size = align - (output_buffer_pos % align);
0737
0738 if (size == align) return;
0739 check_output_buffer_space( size );
0740 memset( output_buffer + output_buffer_pos, 0, size );
0741 output_buffer_pos += size;
0742 }
0743
0744 static inline void flush_output_buffer( const char *name )
0745 {
0746 int fd = open( name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666 );
0747
0748 if (fd == -1 || write( fd, output_buffer, output_buffer_pos ) != output_buffer_pos)
0749 {
0750 perror( name );
0751 exit(1);
0752 }
0753 close( fd );
0754 free( output_buffer );
0755 }
0756
9c4cbde78… Alex*0757
0758
0759
0760 struct long_option
0761 {
0762 const char *name;
0763 int has_arg;
0764 int val;
0765 };
0766
0767 static inline struct strarray parse_options( int argc, char **argv, const char *short_opts,
0768 const struct long_option *long_opts, int long_only,
0769 void (*callback)( int, char* ) )
0770 {
0771 struct strarray ret = empty_strarray;
0772 const char *flag;
0773 char *start, *end;
0774 int i;
0775
5d1995500… Matt*0776 #define OPT_ERR(fmt) { callback( '?', strmake( fmt, argv[i] )); continue; }
9c4cbde78… Alex*0777
0778 for (i = 1; i < argc; i++)
0779 {
0780 if (argv[i][0] != '-' || !argv[i][1])
0781 {
0782 strarray_add( &ret, argv[i] );
0783 continue;
0784 }
0785 if (!strcmp( argv[i], "--" ))
0786 {
0787
0788 while (++i < argc) strarray_add( &ret, argv[i] );
0789 break;
0790 }
0791 start = argv[i] + 1 + (argv[i][1] == '-');
0792
0793 if (argv[i][1] == '-' || (long_only && (argv[i][2] || !strchr( short_opts, argv[i][1] ))))
0794 {
0795
0796 const struct long_option *opt, *found = NULL;
0797 int count = 0;
0798
0799 if (!(end = strchr( start, '=' ))) end = start + strlen(start);
0800 for (opt = long_opts; opt && opt->name; opt++)
0801 {
0802 if (strncmp( opt->name, start, end - start )) continue;
0803 if (!opt->name[end - start])
0804 {
0805 found = opt;
0806 count = 1;
0807 break;
0808 }
0809 if (!found)
0810 {
0811 found = opt;
0812 count++;
0813 }
0814 else if (long_only || found->has_arg != opt->has_arg || found->val != opt->val)
0815 {
0816 count++;
0817 }
0818 }
0819
0820 if (count > 1) OPT_ERR( "option '%s' is ambiguous" );
0821
0822 if (found)
0823 {
0824 if (*end)
0825 {
0826 if (!found->has_arg) OPT_ERR( "argument not allowed in '%s'" );
0827 end++;
0828 }
0829 else if (found->has_arg == 1)
0830 {
0831 if (i == argc - 1) OPT_ERR( "option '%s' requires an argument" );
0832 end = argv[++i];
0833 }
0834 else end = NULL;
0835
0836 callback( found->val, end );
0837 continue;
0838 }
0839 if (argv[i][1] == '-' || !long_only || !strchr( short_opts, argv[i][1] ))
0840 OPT_ERR( "unrecognized option '%s'" );
0841 }
0842
0843
0844 for ( ; *start; start++)
0845 {
0846 if (!(flag = strchr( short_opts, *start ))) OPT_ERR( "invalid option '%s'" );
0847 if (flag[1] == ':')
0848 {
0849 end = start + 1;
0850 if (!*end) end = NULL;
0851 if (flag[2] != ':' && !end)
0852 {
0853 if (i == argc - 1) OPT_ERR( "option '%s' requires an argument" );
0854 end = argv[++i];
0855 }
0856 callback( *start, end );
0857 break;
0858 }
0859 callback( *start, NULL );
0860 }
0861 }
0862 return ret;
0863 #undef OPT_ERR
0864 }
0865
97ca9f8a3… Alex*0866 #endif