Reactos
at master 965 lines 25 kB view raw
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 21#ifndef __WINE_TOOLS_H 22#define __WINE_TOOLS_H 23 24#ifndef __WINE_CONFIG_H 25# error You must include config.h to use this header 26#endif 27 28#include <limits.h> 29#include <stdarg.h> 30#include <stdio.h> 31#include <stdlib.h> 32#include <string.h> 33#include <sys/types.h> 34#include <sys/stat.h> 35#include <signal.h> 36#include <fcntl.h> 37#include <time.h> 38#include <errno.h> 39#ifdef HAVE_SYS_SYSCTL_H 40# include <sys/sysctl.h> 41#endif 42 43#ifdef _WIN32 44# include <direct.h> 45# include <io.h> 46# include <process.h> 47# define mkdir(path,mode) mkdir(path) 48# ifndef S_ISREG 49# define S_ISREG(mod) (((mod) & _S_IFMT) == _S_IFREG) 50# endif 51# ifdef _MSC_VER 52# define popen _popen 53# define pclose _pclose 54# define strtoll _strtoi64 55# define strtoull _strtoui64 56# define strncasecmp _strnicmp 57# define strcasecmp _stricmp 58# endif 59#ifdef __REACTOS__ 60#define MAX_PATH 260 61#define ARRAYSIZE(x) (sizeof(x) / sizeof((x)[0])) 62#else 63# include <windef.h> 64# include <winbase.h> 65#endif 66#else 67extern char **environ; 68# include <spawn.h> 69# include <sys/wait.h> 70# include <unistd.h> 71# ifndef O_BINARY 72# define O_BINARY 0 73# endif 74# ifndef __int64 75# if defined(__x86_64__) || defined(__aarch64__) || defined(__powerpc64__) 76# define __int64 long 77# else 78# define __int64 long long 79# endif 80# endif 81#endif 82 83#if !defined(__GNUC__) && !defined(__attribute__) 84#define __attribute__(x) 85#endif 86 87#ifndef max 88#define max(a,b) (((a) > (b)) ? (a) : (b)) 89#endif 90#ifndef min 91#define min(a,b) (((a) < (b)) ? (a) : (b)) 92#endif 93 94#ifndef ARRAY_SIZE 95#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 96#endif 97 98struct target 99{ 100 enum { CPU_i386, CPU_x86_64, CPU_ARM, CPU_ARM64, CPU_ARM64EC } cpu; 101 102 enum 103 { 104 PLATFORM_UNSPECIFIED, 105 PLATFORM_APPLE, 106 PLATFORM_ANDROID, 107 PLATFORM_LINUX, 108 PLATFORM_FREEBSD, 109 PLATFORM_SOLARIS, 110 PLATFORM_WINDOWS, 111 PLATFORM_MINGW, 112 PLATFORM_CYGWIN 113 } platform; 114}; 115 116static inline void *xmalloc( size_t size ) 117{ 118 void *res = malloc( size ? size : 1 ); 119 120 if (res == NULL) 121 { 122 fprintf( stderr, "Virtual memory exhausted.\n" ); 123 exit(1); 124 } 125 return res; 126} 127 128static inline void *xrealloc (void *ptr, size_t size) 129{ 130 void *res = realloc( ptr, size ); 131 132 if (size && res == NULL) 133 { 134 fprintf( stderr, "Virtual memory exhausted.\n" ); 135 exit(1); 136 } 137 return res; 138} 139 140static inline char *xstrdup( const char *str ) 141{ 142 return strcpy( xmalloc( strlen(str)+1 ), str ); 143} 144 145static inline int strendswith( const char *str, const char *end ) 146{ 147 int l = strlen( str ); 148 int m = strlen( end ); 149 return l >= m && !strcmp( str + l - m, end ); 150} 151 152static char *strmake( const char* fmt, ... ) __attribute__ ((__format__ (__printf__, 1, 2))); 153static inline char *strmake( const char* fmt, ... ) 154{ 155 int n; 156 size_t size = 100; 157 va_list ap; 158 159 for (;;) 160 { 161 char *p = xmalloc( size ); 162 va_start( ap, fmt ); 163 n = vsnprintf( p, size, fmt, ap ); 164 va_end( ap ); 165 if (n == -1) size *= 2; 166 else if ((size_t)n >= size) size = n + 1; 167 else return p; 168 free( p ); 169 } 170} 171 172/* string array functions */ 173 174struct strarray 175{ 176 unsigned int count; /* strings in use */ 177 unsigned int size; /* total allocated size */ 178 const char **str; 179}; 180 181static const struct strarray empty_strarray; 182 183static inline void strarray_add( struct strarray *array, const char *str ) 184{ 185 if (array->count == array->size) 186 { 187 if (array->size) array->size *= 2; 188 else array->size = 16; 189 array->str = xrealloc( array->str, sizeof(array->str[0]) * array->size ); 190 } 191 array->str[array->count++] = str; 192} 193 194static inline void strarray_addall( struct strarray *array, struct strarray added ) 195{ 196 unsigned int i; 197 198 for (i = 0; i < added.count; i++) strarray_add( array, added.str[i] ); 199} 200 201static inline int strarray_exists( const struct strarray *array, const char *str ) 202{ 203 unsigned int i; 204 205 for (i = 0; i < array->count; i++) if (!strcmp( array->str[i], str )) return 1; 206 return 0; 207} 208 209static inline void strarray_add_uniq( struct strarray *array, const char *str ) 210{ 211 if (!strarray_exists( array, str )) strarray_add( array, str ); 212} 213 214static inline void strarray_addall_uniq( struct strarray *array, struct strarray added ) 215{ 216 unsigned int i; 217 218 for (i = 0; i < added.count; i++) strarray_add_uniq( array, added.str[i] ); 219} 220 221static inline struct strarray strarray_fromstring( const char *str, const char *delim ) 222{ 223 struct strarray array = empty_strarray; 224 char *buf = xstrdup( str ); 225 const char *tok; 226 227 for (tok = strtok( buf, delim ); tok; tok = strtok( NULL, delim )) 228 strarray_add( &array, xstrdup( tok )); 229 free( buf ); 230 return array; 231} 232 233static inline struct strarray strarray_frompath( const char *path ) 234{ 235 if (!path) return empty_strarray; 236#ifdef _WIN32 237 return strarray_fromstring( path, ";" ); 238#else 239 return strarray_fromstring( path, ":" ); 240#endif 241} 242 243static inline char *strarray_tostring( struct strarray array, const char *sep ) 244{ 245 char *str; 246 unsigned int i, len = 1 + (array.count - 1) * strlen(sep); 247 248 if (!array.count) return xstrdup(""); 249 for (i = 0; i < array.count; i++) len += strlen( array.str[i] ); 250 str = xmalloc( len ); 251 strcpy( str, array.str[0] ); 252 for (i = 1; i < array.count; i++) 253 { 254 strcat( str, sep ); 255 strcat( str, array.str[i] ); 256 } 257 return str; 258} 259 260static inline void strarray_qsort( struct strarray *array, int (*func)(const char **, const char **) ) 261{ 262 if (array->count) qsort( array->str, array->count, sizeof(*array->str), (void *)func ); 263} 264 265static inline const char *strarray_bsearch( const struct strarray *array, const char *str, 266 int (*func)(const char **, const char **) ) 267{ 268 char **res = NULL; 269 270 if (array->count) res = bsearch( &str, array->str, array->count, sizeof(*array->str), (void *)func ); 271 return res ? *res : NULL; 272} 273 274static inline void strarray_trace( struct strarray args ) 275{ 276 unsigned int i; 277 278 for (i = 0; i < args.count; i++) 279 { 280 if (strpbrk( args.str[i], " \t\n\r")) printf( "\"%s\"", args.str[i] ); 281 else printf( "%s", args.str[i] ); 282 putchar( i < args.count - 1 ? ' ' : '\n' ); 283 } 284} 285 286static inline int strarray_spawn( struct strarray args ) 287{ 288#ifdef _WIN32 289 strarray_add( &args, NULL ); 290 return _spawnvp( _P_WAIT, args.str[0], args.str ); 291#else 292 pid_t pid, wret; 293 int status; 294 295 strarray_add( &args, NULL ); 296 if (posix_spawnp( &pid, args.str[0], NULL, NULL, (char **)args.str, environ )) 297 return -1; 298 299 while (pid != (wret = waitpid( pid, &status, 0 ))) 300 if (wret == -1 && errno != EINTR) break; 301 302 if (pid == wret && WIFEXITED(status)) return WEXITSTATUS(status); 303 return 255; /* abnormal exit with an abort or an interrupt */ 304#endif 305} 306 307static inline char *get_basename( const char *file ) 308{ 309 const char *ret = strrchr( file, '/' ); 310 return xstrdup( ret ? ret + 1 : file ); 311} 312 313static inline char *get_basename_noext( const char *file ) 314{ 315 char *ext, *ret = get_basename( file ); 316 if ((ext = strrchr( ret, '.' ))) *ext = 0; 317 return ret; 318} 319 320static inline char *get_dirname( const char *file ) 321{ 322 const char *end = strrchr( file, '/' ); 323 if (!end) return xstrdup( "." ); 324 if (end == file) end++; 325 return strmake( "%.*s", (int)(end - file), file ); 326} 327 328static inline char *replace_extension( const char *name, const char *old_ext, const char *new_ext ) 329{ 330 int name_len = strlen( name ); 331 332 if (strendswith( name, old_ext )) name_len -= strlen( old_ext ); 333 return strmake( "%.*s%s", name_len, name, new_ext ); 334} 335 336/* build a path with the relative dir from 'from' to 'dest' appended to base */ 337static inline char *build_relative_path( const char *base, const char *from, const char *dest ) 338{ 339 const char *start; 340 char *ret; 341 unsigned int dotdots = 0; 342 343 for (;;) 344 { 345 while (*from == '/') from++; 346 while (*dest == '/') dest++; 347 start = dest; /* save start of next path element */ 348 if (!*from) break; 349 350 while (*from && *from != '/' && *from == *dest) { from++; dest++; } 351 if ((!*from || *from == '/') && (!*dest || *dest == '/')) continue; 352 353 do /* count remaining elements in 'from' */ 354 { 355 dotdots++; 356 while (*from && *from != '/') from++; 357 while (*from == '/') from++; 358 } 359 while (*from); 360 break; 361 } 362 363 ret = xmalloc( strlen(base) + 3 * dotdots + strlen(start) + 2 ); 364 strcpy( ret, base ); 365 while (dotdots--) strcat( ret, "/.." ); 366 367 if (!start[0]) return ret; 368 strcat( ret, "/" ); 369 strcat( ret, start ); 370 return ret; 371} 372 373/* temp files management */ 374 375extern const char *temp_dir; 376extern struct strarray temp_files; 377 378static inline char *make_temp_dir(void) 379{ 380 unsigned int value = time(NULL) + getpid(); 381 int count; 382 char *name; 383 const char *tmpdir = NULL; 384 385 for (count = 0; count < 0x8000; count++) 386 { 387 if (tmpdir) 388 name = strmake( "%s/tmp%08x", tmpdir, value ); 389 else 390 name = strmake( "tmp%08x", value ); 391 if (!mkdir( name, 0700 )) return name; 392 value += 7777; 393 if (errno == EACCES && !tmpdir) 394 { 395#if defined(__REACTOS__) && defined(_WIN32) 396 if (!(tmpdir = getenv("TEMP"))) tmpdir = "temp"; 397#else 398 if (!(tmpdir = getenv("TMPDIR"))) tmpdir = "/tmp"; 399#endif 400 } 401 free( name ); 402 } 403 fprintf( stderr, "failed to create directory for temp files\n" ); 404 exit(1); 405} 406 407static inline char *make_temp_file( const char *prefix, const char *suffix ) 408{ 409 static unsigned int value; 410 int fd, count; 411 char *name; 412 413 if (!temp_dir) temp_dir = make_temp_dir(); 414 if (!suffix) suffix = ""; 415 if (!prefix) prefix = "tmp"; 416 else prefix = get_basename_noext( prefix ); 417 418 for (count = 0; count < 0x8000; count++) 419 { 420 name = strmake( "%s/%s-%08x%s", temp_dir, prefix, value++, suffix ); 421 fd = open( name, O_RDWR | O_CREAT | O_EXCL, 0600 ); 422 if (fd >= 0) 423 { 424#ifdef HAVE_SIGPROCMASK /* block signals while manipulating the temp files list */ 425 sigset_t mask_set, old_set; 426 427 sigemptyset( &mask_set ); 428 sigaddset( &mask_set, SIGHUP ); 429 sigaddset( &mask_set, SIGTERM ); 430 sigaddset( &mask_set, SIGINT ); 431 sigprocmask( SIG_BLOCK, &mask_set, &old_set ); 432 strarray_add( &temp_files, name ); 433 sigprocmask( SIG_SETMASK, &old_set, NULL ); 434#else 435 strarray_add( &temp_files, name ); 436#endif 437 close( fd ); 438 return name; 439 } 440 free( name ); 441 } 442 fprintf( stderr, "failed to create temp file for %s%s in %s\n", prefix, suffix, temp_dir ); 443 exit(1); 444} 445 446static inline void remove_temp_files(void) 447{ 448 unsigned int i; 449 450 for (i = 0; i < temp_files.count; i++) if (temp_files.str[i]) unlink( temp_files.str[i] ); 451 if (temp_dir) rmdir( temp_dir ); 452} 453 454 455static inline void init_signals( void (*cleanup)(int) ) 456{ 457 signal( SIGTERM, cleanup ); 458 signal( SIGINT, cleanup ); 459#ifdef SIGHUP 460 signal( SIGHUP, cleanup ); 461#endif 462} 463 464 465static inline void *read_file( const char *name, size_t *size ) 466{ 467 struct stat st; 468 int res, fd; 469 void *data; 470 471 if ((fd = open( name, O_RDONLY | O_BINARY )) == -1) return NULL; 472 fstat( fd, &st ); 473 data = xmalloc( st.st_size ); 474 res = read( fd, data, st.st_size ); 475 if (res == -1) 476 { 477 free( data ); 478 data = NULL; 479 *size = 0; 480 } 481 else *size = res; 482 close( fd ); 483 return data; 484} 485 486 487static inline struct target get_default_target(void) 488{ 489 struct target target; 490#ifdef __i386__ 491 target.cpu = CPU_i386; 492#elif defined(__x86_64__) 493 target.cpu = CPU_x86_64; 494#elif defined(__arm__) 495 target.cpu = CPU_ARM; 496#elif defined(__aarch64__) 497 target.cpu = CPU_ARM64; 498#else 499#error Unsupported CPU 500#endif 501 502#ifdef __APPLE__ 503 target.platform = PLATFORM_APPLE; 504#elif defined(__ANDROID__) 505 target.platform = PLATFORM_ANDROID; 506#elif defined(__linux__) 507 target.platform = PLATFORM_LINUX; 508#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 509 target.platform = PLATFORM_FREEBSD; 510#elif defined(__sun) 511 target.platform = PLATFORM_SOLARIS; 512#elif defined(__CYGWIN__) 513 target.platform = PLATFORM_CYGWIN; 514#elif defined(_WIN32) 515 target.platform = PLATFORM_MINGW; 516#else 517 target.platform = PLATFORM_UNSPECIFIED; 518#endif 519 520 return target; 521} 522 523 524static inline unsigned int get_target_ptr_size( struct target target ) 525{ 526 static const unsigned int sizes[] = 527 { 528 [CPU_i386] = 4, 529 [CPU_x86_64] = 8, 530 [CPU_ARM] = 4, 531 [CPU_ARM64] = 8, 532 [CPU_ARM64EC] = 8, 533 }; 534 return sizes[target.cpu]; 535} 536 537 538static inline void set_target_ptr_size( struct target *target, unsigned int size ) 539{ 540 switch (target->cpu) 541 { 542 case CPU_i386: 543 if (size == 8) target->cpu = CPU_x86_64; 544 break; 545 case CPU_x86_64: 546 if (size == 4) target->cpu = CPU_i386; 547 break; 548 case CPU_ARM: 549 if (size == 8) target->cpu = CPU_ARM64; 550 break; 551 case CPU_ARM64: 552 case CPU_ARM64EC: 553 if (size == 4) target->cpu = CPU_ARM; 554 break; 555 } 556} 557 558 559static inline int get_cpu_from_name( const char *name ) 560{ 561 static const struct 562 { 563 const char *name; 564 int cpu; 565 } cpu_names[] = 566 { 567 { "i386", CPU_i386 }, 568 { "i486", CPU_i386 }, 569 { "i586", CPU_i386 }, 570 { "i686", CPU_i386 }, 571 { "i786", CPU_i386 }, 572 { "x86_64", CPU_x86_64 }, 573 { "amd64", CPU_x86_64 }, 574 { "aarch64", CPU_ARM64 }, 575 { "arm64ec", CPU_ARM64EC }, 576 { "arm64", CPU_ARM64 }, 577 { "arm", CPU_ARM }, 578 }; 579 unsigned int i; 580 581 for (i = 0; i < ARRAY_SIZE(cpu_names); i++) 582 if (!strncmp( cpu_names[i].name, name, strlen(cpu_names[i].name) )) return cpu_names[i].cpu; 583 return -1; 584} 585 586 587static inline int get_platform_from_name( const char *name ) 588{ 589 static const struct 590 { 591 const char *name; 592 int platform; 593 } platform_names[] = 594 { 595 { "macos", PLATFORM_APPLE }, 596 { "darwin", PLATFORM_APPLE }, 597 { "android", PLATFORM_ANDROID }, 598 { "linux", PLATFORM_LINUX }, 599 { "freebsd", PLATFORM_FREEBSD }, 600 { "solaris", PLATFORM_SOLARIS }, 601 { "mingw32", PLATFORM_MINGW }, 602 { "windows-gnu", PLATFORM_MINGW }, 603 { "winnt", PLATFORM_MINGW }, 604 { "windows", PLATFORM_WINDOWS }, 605 { "cygwin", PLATFORM_CYGWIN }, 606 }; 607 unsigned int i; 608 609 for (i = 0; i < ARRAY_SIZE(platform_names); i++) 610 if (!strncmp( platform_names[i].name, name, strlen(platform_names[i].name) )) 611 return platform_names[i].platform; 612 return -1; 613}; 614 615 616static inline const char *get_arch_dir( struct target target ) 617{ 618 static const char *cpu_names[] = 619 { 620 [CPU_i386] = "i386", 621 [CPU_x86_64] = "x86_64", 622 [CPU_ARM] = "arm", 623 [CPU_ARM64] = "aarch64", 624 [CPU_ARM64EC] = "aarch64", 625 }; 626 627 if (!cpu_names[target.cpu]) return ""; 628 629 switch (target.platform) 630 { 631 case PLATFORM_WINDOWS: 632 case PLATFORM_CYGWIN: 633 case PLATFORM_MINGW: 634 return strmake( "/%s-windows", cpu_names[target.cpu] ); 635 default: 636 return strmake( "/%s-unix", cpu_names[target.cpu] ); 637 } 638} 639 640static inline int parse_target( const char *name, struct target *target ) 641{ 642 int res; 643 char *p, *spec = xstrdup( name ); 644 645 /* target specification is in the form CPU-MANUFACTURER-OS or CPU-MANUFACTURER-KERNEL-OS */ 646 647 /* get the CPU part */ 648 649 if ((p = strchr( spec, '-' ))) 650 { 651 *p++ = 0; 652 if ((res = get_cpu_from_name( spec )) == -1) 653 { 654 free( spec ); 655 return 0; 656 } 657 target->cpu = res; 658 } 659 else if (!strcmp( spec, "mingw32" )) 660 { 661 target->cpu = CPU_i386; 662 p = spec; 663 } 664 else 665 { 666 free( spec ); 667 return 0; 668 } 669 670 /* get the OS part */ 671 672 target->platform = PLATFORM_UNSPECIFIED; /* default value */ 673 for (;;) 674 { 675 if ((res = get_platform_from_name( p )) != -1) 676 { 677 target->platform = res; 678 break; 679 } 680 if (!(p = strchr( p, '-' ))) break; 681 p++; 682 } 683 684 free( spec ); 685 return 1; 686} 687 688 689static inline struct target init_argv0_target( const char *argv0 ) 690{ 691 char *name = get_basename( argv0 ); 692 struct target target; 693 694 if (!strchr( name, '-' ) || !parse_target( name, &target )) 695 target = get_default_target(); 696 697 free( name ); 698 return target; 699} 700 701 702static inline char *get_bindir( const char *argv0 ) 703{ 704#ifdef __REACTOS__ 705 return NULL; 706#else 707#ifndef _WIN32 708 char *dir = NULL; 709 710#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) \ 711 || defined(__CYGWIN__) || defined(__MSYS__) 712 dir = realpath( "/proc/self/exe", NULL ); 713#elif defined (__FreeBSD__) || defined(__DragonFly__) 714 static int pathname[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; 715 size_t path_size = PATH_MAX; 716 char *path = xmalloc( path_size ); 717 if (!sysctl( pathname, ARRAY_SIZE(pathname), path, &path_size, NULL, 0 )) 718 dir = realpath( path, NULL ); 719 free( path ); 720#endif 721 if (!dir && !(dir = realpath( argv0, NULL ))) return NULL; 722 return get_dirname( dir ); 723#else 724 char path[MAX_PATH], *p; 725 GetModuleFileNameA( NULL, path, ARRAYSIZE(path) ); 726 for (p = path; *p; p++) if (*p == '\\') *p = '/'; 727 return get_dirname( path ); 728#endif 729#endif 730} 731 732#ifdef LIBDIR 733static inline const char *get_libdir( const char *bindir ) 734{ 735#ifdef BINDIR 736 if (bindir) return build_relative_path( bindir, BINDIR, LIBDIR ); 737#endif 738 return LIBDIR; 739} 740#endif 741 742#ifdef DATADIR 743static inline const char *get_datadir( const char *bindir ) 744{ 745#ifdef BINDIR 746 if (bindir) return build_relative_path( bindir, BINDIR, DATADIR ); 747#endif 748 return DATADIR; 749} 750#endif 751 752#ifdef INCLUDEDIR 753static inline const char *get_includedir( const char *bindir ) 754{ 755#ifdef BINDIR 756 if (bindir) return build_relative_path( bindir, BINDIR, INCLUDEDIR ); 757#endif 758 return INCLUDEDIR; 759} 760#endif 761 762static inline const char *get_nlsdir( const char *bindir, const char *srcdir ) 763{ 764 if (bindir && strendswith( bindir, srcdir )) return strmake( "%s/../../nls", bindir ); 765#ifdef DATADIR 766 else 767 { 768 const char *datadir = get_datadir( bindir ); 769 if (datadir) return strmake( "%s/wine/nls", datadir ); 770 } 771#endif 772 return NULL; 773} 774 775 776/* output buffer management */ 777 778extern unsigned char *output_buffer; 779extern size_t output_buffer_pos; 780extern size_t output_buffer_size; 781 782static inline void check_output_buffer_space( size_t size ) 783{ 784 if (output_buffer_pos + size >= output_buffer_size) 785 { 786 output_buffer_size = max( output_buffer_size * 2, output_buffer_pos + size ); 787 output_buffer = xrealloc( output_buffer, output_buffer_size ); 788 } 789} 790 791static inline void init_output_buffer(void) 792{ 793 output_buffer_size = 1024; 794 output_buffer_pos = 0; 795 output_buffer = xmalloc( output_buffer_size ); 796} 797 798static inline void put_data( const void *data, size_t size ) 799{ 800 check_output_buffer_space( size ); 801 memcpy( output_buffer + output_buffer_pos, data, size ); 802 output_buffer_pos += size; 803} 804 805static inline void put_byte( unsigned char val ) 806{ 807 check_output_buffer_space( 1 ); 808 output_buffer[output_buffer_pos++] = val; 809} 810 811static inline void put_word( unsigned short val ) 812{ 813 check_output_buffer_space( 2 ); 814 output_buffer[output_buffer_pos++] = val; 815 output_buffer[output_buffer_pos++] = val >> 8; 816} 817 818static inline void put_dword( unsigned int val ) 819{ 820 check_output_buffer_space( 4 ); 821 output_buffer[output_buffer_pos++] = val; 822 output_buffer[output_buffer_pos++] = val >> 8; 823 output_buffer[output_buffer_pos++] = val >> 16; 824 output_buffer[output_buffer_pos++] = val >> 24; 825} 826 827static inline void put_qword( unsigned int val ) 828{ 829 put_dword( val ); 830 put_dword( 0 ); 831} 832 833static inline void align_output( unsigned int align ) 834{ 835 size_t size = align - (output_buffer_pos % align); 836 837 if (size == align) return; 838 check_output_buffer_space( size ); 839 memset( output_buffer + output_buffer_pos, 0, size ); 840 output_buffer_pos += size; 841} 842 843static inline void flush_output_buffer( const char *name ) 844{ 845 int fd = open( name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666 ); 846 847 if (fd == -1 || write( fd, output_buffer, output_buffer_pos ) != output_buffer_pos) 848 { 849 perror( name ); 850 exit(1); 851 } 852 close( fd ); 853 free( output_buffer ); 854} 855 856/* command-line option parsing */ 857/* partly based on the Glibc getopt() implementation */ 858 859struct long_option 860{ 861 const char *name; 862 int has_arg; 863 int val; 864}; 865 866static inline struct strarray parse_options( int argc, char **argv, const char *short_opts, 867 const struct long_option *long_opts, int long_only, 868 void (*callback)( int, char* ) ) 869{ 870 struct strarray ret = empty_strarray; 871 const char *flag; 872 char *start, *end; 873 int i; 874 875#define OPT_ERR(fmt) { callback( '?', strmake( fmt, argv[i] )); continue; } 876 877 for (i = 1; i < argc; i++) 878 { 879 if (argv[i][0] != '-' || !argv[i][1]) /* not an option */ 880 { 881 strarray_add( &ret, argv[i] ); 882 continue; 883 } 884 if (!strcmp( argv[i], "--" )) 885 { 886 /* add remaining args */ 887 while (++i < argc) strarray_add( &ret, argv[i] ); 888 break; 889 } 890 start = argv[i] + 1 + (argv[i][1] == '-'); 891 892 if (argv[i][1] == '-' || (long_only && (argv[i][2] || !strchr( short_opts, argv[i][1] )))) 893 { 894 /* handle long option */ 895 const struct long_option *opt, *found = NULL; 896 int count = 0; 897 898 if (!(end = strchr( start, '=' ))) end = start + strlen(start); 899 for (opt = long_opts; opt && opt->name; opt++) 900 { 901 if (strncmp( opt->name, start, end - start )) continue; 902 if (!opt->name[end - start]) /* exact match */ 903 { 904 found = opt; 905 count = 1; 906 break; 907 } 908 if (!found) 909 { 910 found = opt; 911 count++; 912 } 913 else if (long_only || found->has_arg != opt->has_arg || found->val != opt->val) 914 { 915 count++; 916 } 917 } 918 919 if (count > 1) OPT_ERR( "option '%s' is ambiguous" ); 920 921 if (found) 922 { 923 if (*end) 924 { 925 if (!found->has_arg) OPT_ERR( "argument not allowed in '%s'" ); 926 end++; /* skip '=' */ 927 } 928 else if (found->has_arg == 1) 929 { 930 if (i == argc - 1) OPT_ERR( "option '%s' requires an argument" ); 931 end = argv[++i]; 932 } 933 else end = NULL; 934 935 callback( found->val, end ); 936 continue; 937 } 938 if (argv[i][1] == '-' || !long_only || !strchr( short_opts, argv[i][1] )) 939 OPT_ERR( "unrecognized option '%s'" ); 940 } 941 942 /* handle short option */ 943 for ( ; *start; start++) 944 { 945 if (!(flag = strchr( short_opts, *start ))) OPT_ERR( "invalid option '%s'" ); 946 if (flag[1] == ':') 947 { 948 end = start + 1; 949 if (!*end) end = NULL; 950 if (flag[2] != ':' && !end) 951 { 952 if (i == argc - 1) OPT_ERR( "option '%s' requires an argument" ); 953 end = argv[++i]; 954 } 955 callback( *start, end ); 956 break; 957 } 958 callback( *start, NULL ); 959 } 960 } 961 return ret; 962#undef OPT_ERR 963} 964 965#endif /* __WINE_TOOLS_H */