Back to home page

Wine source

 
 

    


File indexing completed on 2024-04-19 22:58:23

97ca9f8a3 Alex*0001 /*
                0002  * Helper functions for the Wine tools
                0003  *
                0004  * Copyright 2021 Alexandre Julliard
                0005  *
                0006  * This library is free software; you can redistribute it and/or
                0007  * modify it under the terms of the GNU Lesser General Public
                0008  * License as published by the Free Software Foundation; either
                0009  * version 2.1 of the License, or (at your option) any later version.
                0010  *
                0011  * This library is distributed in the hope that it will be useful,
                0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
                0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                0014  * Lesser General Public License for more details.
                0015  *
                0016  * You should have received a copy of the GNU Lesser General Public
                0017  * License along with this library; if not, write to the Free Software
                0018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
                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 /* string array functions */
                0166 
                0167 struct strarray
                0168 {
                0169     unsigned int count;  /* strings in use */
                0170     unsigned int size;   /* total allocated 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; /* abnormal exit with an abort or an interrupt */
                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 /* temp files management */
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 /* block signals while manipulating the temp files list */
                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     /* target specification is in the form CPU-MANUFACTURER-OS or CPU-MANUFACTURER-KERNEL-OS */
                0598 
                0599     /* get the CPU part */
                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     /* get the OS part */
                0623 
                0624     target->platform = PLATFORM_UNSPECIFIED;  /* default value */
                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 /* output buffer management */
                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 /* command-line option parsing */
                0758 /* partly based on the Glibc getopt() implementation */
                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])  /* not an option */
                0781         {
                0782             strarray_add( &ret, argv[i] );
                0783             continue;
                0784         }
                0785         if (!strcmp( argv[i], "--" ))
                0786         {
                0787             /* add remaining args */
                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             /* handle long option */
                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])  /* exact match */
                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++;  /* skip '=' */
                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         /* handle short option */
                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 /* __WINE_TOOLS_H */