d2d1: Create feature level 10.0 device context state objects.
[wine.git] / tools / tools.h
blob1065d25c6d673cda9064389fcdd280264122c714
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 struct target get_default_target(void)
355 struct target target;
356 #ifdef __i386__
357 target.cpu = CPU_i386;
358 #elif defined(__x86_64__)
359 target.cpu = CPU_x86_64;
360 #elif defined(__arm__)
361 target.cpu = CPU_ARM;
362 #elif defined(__aarch64__)
363 target.cpu = CPU_ARM64;
364 #else
365 #error Unsupported CPU
366 #endif
368 #ifdef __APPLE__
369 target.platform = PLATFORM_APPLE;
370 #elif defined(__ANDROID__)
371 target.platform = PLATFORM_ANDROID;
372 #elif defined(__linux__)
373 target.platform = PLATFORM_LINUX;
374 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
375 target.platform = PLATFORM_FREEBSD;
376 #elif defined(__sun)
377 target.platform = PLATFORM_SOLARIS;
378 #elif defined(__CYGWIN__)
379 target.platform = PLATFORM_CYGWIN;
380 #elif defined(_WIN32)
381 target.platform = PLATFORM_MINGW;
382 #else
383 target.platform = PLATFORM_UNSPECIFIED;
384 #endif
386 return target;
390 static inline unsigned int get_target_ptr_size( struct target target )
392 static const unsigned int sizes[] =
394 [CPU_i386] = 4,
395 [CPU_x86_64] = 8,
396 [CPU_ARM] = 4,
397 [CPU_ARM64] = 8,
399 return sizes[target.cpu];
403 static inline void set_target_ptr_size( struct target *target, unsigned int size )
405 switch (target->cpu)
407 case CPU_i386:
408 if (size == 8) target->cpu = CPU_x86_64;
409 break;
410 case CPU_x86_64:
411 if (size == 4) target->cpu = CPU_i386;
412 break;
413 case CPU_ARM:
414 if (size == 8) target->cpu = CPU_ARM64;
415 break;
416 case CPU_ARM64:
417 if (size == 4) target->cpu = CPU_ARM;
418 break;
423 static inline int get_cpu_from_name( const char *name )
425 static const struct
427 const char *name;
428 int cpu;
429 } cpu_names[] =
431 { "i386", CPU_i386 },
432 { "i486", CPU_i386 },
433 { "i586", CPU_i386 },
434 { "i686", CPU_i386 },
435 { "i786", CPU_i386 },
436 { "x86_64", CPU_x86_64 },
437 { "amd64", CPU_x86_64 },
438 { "aarch64", CPU_ARM64 },
439 { "arm64", CPU_ARM64 },
440 { "arm", CPU_ARM },
442 unsigned int i;
444 for (i = 0; i < ARRAY_SIZE(cpu_names); i++)
445 if (!strncmp( cpu_names[i].name, name, strlen(cpu_names[i].name) )) return cpu_names[i].cpu;
446 return -1;
450 static inline int get_platform_from_name( const char *name )
452 static const struct
454 const char *name;
455 int platform;
456 } platform_names[] =
458 { "macos", PLATFORM_APPLE },
459 { "darwin", PLATFORM_APPLE },
460 { "android", PLATFORM_ANDROID },
461 { "linux", PLATFORM_LINUX },
462 { "freebsd", PLATFORM_FREEBSD },
463 { "solaris", PLATFORM_SOLARIS },
464 { "mingw32", PLATFORM_MINGW },
465 { "windows-gnu", PLATFORM_MINGW },
466 { "winnt", PLATFORM_MINGW },
467 { "windows", PLATFORM_WINDOWS },
468 { "cygwin", PLATFORM_CYGWIN },
470 unsigned int i;
472 for (i = 0; i < ARRAY_SIZE(platform_names); i++)
473 if (!strncmp( platform_names[i].name, name, strlen(platform_names[i].name) ))
474 return platform_names[i].platform;
475 return -1;
479 static inline const char *get_arch_dir( struct target target )
481 static const char *cpu_names[] =
483 [CPU_i386] = "i386",
484 [CPU_x86_64] = "x86_64",
485 [CPU_ARM] = "arm",
486 [CPU_ARM64] = "aarch64"
489 if (!cpu_names[target.cpu]) return "";
491 switch (target.platform)
493 case PLATFORM_WINDOWS:
494 case PLATFORM_CYGWIN:
495 case PLATFORM_MINGW:
496 return strmake( "/%s-windows", cpu_names[target.cpu] );
497 default:
498 return strmake( "/%s-unix", cpu_names[target.cpu] );
502 static inline int parse_target( const char *name, struct target *target )
504 int res;
505 char *p, *spec = xstrdup( name );
507 /* target specification is in the form CPU-MANUFACTURER-OS or CPU-MANUFACTURER-KERNEL-OS */
509 /* get the CPU part */
511 if ((p = strchr( spec, '-' )))
513 *p++ = 0;
514 if ((res = get_cpu_from_name( spec )) == -1)
516 free( spec );
517 return 0;
519 target->cpu = res;
521 else if (!strcmp( spec, "mingw32" ))
523 target->cpu = CPU_i386;
524 p = spec;
526 else
528 free( spec );
529 return 0;
532 /* get the OS part */
534 target->platform = PLATFORM_UNSPECIFIED; /* default value */
535 for (;;)
537 if ((res = get_platform_from_name( p )) != -1)
539 target->platform = res;
540 break;
542 if (!(p = strchr( p, '-' ))) break;
543 p++;
546 free( spec );
547 return 1;
551 static inline struct target init_argv0_target( const char *argv0 )
553 char *name = get_basename( argv0 );
554 struct target target;
556 if (!strchr( name, '-' ) || !parse_target( name, &target ))
557 target = get_default_target();
559 free( name );
560 return target;
564 /* output buffer management */
566 extern unsigned char *output_buffer;
567 extern size_t output_buffer_pos;
568 extern size_t output_buffer_size;
570 static inline void check_output_buffer_space( size_t size )
572 if (output_buffer_pos + size >= output_buffer_size)
574 output_buffer_size = max( output_buffer_size * 2, output_buffer_pos + size );
575 output_buffer = xrealloc( output_buffer, output_buffer_size );
579 static inline void init_output_buffer(void)
581 output_buffer_size = 1024;
582 output_buffer_pos = 0;
583 output_buffer = xmalloc( output_buffer_size );
586 static inline void put_data( const void *data, size_t size )
588 check_output_buffer_space( size );
589 memcpy( output_buffer + output_buffer_pos, data, size );
590 output_buffer_pos += size;
593 static inline void put_byte( unsigned char val )
595 check_output_buffer_space( 1 );
596 output_buffer[output_buffer_pos++] = val;
599 static inline void put_word( unsigned short val )
601 check_output_buffer_space( 2 );
602 output_buffer[output_buffer_pos++] = val;
603 output_buffer[output_buffer_pos++] = val >> 8;
606 static inline void put_dword( unsigned int val )
608 check_output_buffer_space( 4 );
609 output_buffer[output_buffer_pos++] = val;
610 output_buffer[output_buffer_pos++] = val >> 8;
611 output_buffer[output_buffer_pos++] = val >> 16;
612 output_buffer[output_buffer_pos++] = val >> 24;
615 static inline void put_qword( unsigned int val )
617 put_dword( val );
618 put_dword( 0 );
621 static inline void align_output( unsigned int align )
623 size_t size = align - (output_buffer_pos % align);
625 if (size == align) return;
626 check_output_buffer_space( size );
627 memset( output_buffer + output_buffer_pos, 0, size );
628 output_buffer_pos += size;
631 static inline void flush_output_buffer( const char *name )
633 int fd = open( name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666 );
635 if (fd == -1 || write( fd, output_buffer, output_buffer_pos ) != output_buffer_pos)
637 perror( name );
638 exit(1);
640 close( fd );
641 free( output_buffer );
644 /* command-line option parsing */
645 /* partly based on the Glibc getopt() implementation */
647 struct long_option
649 const char *name;
650 int has_arg;
651 int val;
654 static inline struct strarray parse_options( int argc, char **argv, const char *short_opts,
655 const struct long_option *long_opts, int long_only,
656 void (*callback)( int, char* ) )
658 struct strarray ret = empty_strarray;
659 const char *flag;
660 char *start, *end;
661 int i;
663 #define OPT_ERR(fmt) { callback( '?', strmake( fmt, argv[1] )); continue; }
665 for (i = 1; i < argc; i++)
667 if (argv[i][0] != '-' || !argv[i][1]) /* not an option */
669 strarray_add( &ret, argv[i] );
670 continue;
672 if (!strcmp( argv[i], "--" ))
674 /* add remaining args */
675 while (++i < argc) strarray_add( &ret, argv[i] );
676 break;
678 start = argv[i] + 1 + (argv[i][1] == '-');
680 if (argv[i][1] == '-' || (long_only && (argv[i][2] || !strchr( short_opts, argv[i][1] ))))
682 /* handle long option */
683 const struct long_option *opt, *found = NULL;
684 int count = 0;
686 if (!(end = strchr( start, '=' ))) end = start + strlen(start);
687 for (opt = long_opts; opt && opt->name; opt++)
689 if (strncmp( opt->name, start, end - start )) continue;
690 if (!opt->name[end - start]) /* exact match */
692 found = opt;
693 count = 1;
694 break;
696 if (!found)
698 found = opt;
699 count++;
701 else if (long_only || found->has_arg != opt->has_arg || found->val != opt->val)
703 count++;
707 if (count > 1) OPT_ERR( "option '%s' is ambiguous" );
709 if (found)
711 if (*end)
713 if (!found->has_arg) OPT_ERR( "argument not allowed in '%s'" );
714 end++; /* skip '=' */
716 else if (found->has_arg == 1)
718 if (i == argc - 1) OPT_ERR( "option '%s' requires an argument" );
719 end = argv[++i];
721 else end = NULL;
723 callback( found->val, end );
724 continue;
726 if (argv[i][1] == '-' || !long_only || !strchr( short_opts, argv[i][1] ))
727 OPT_ERR( "unrecognized option '%s'" );
730 /* handle short option */
731 for ( ; *start; start++)
733 if (!(flag = strchr( short_opts, *start ))) OPT_ERR( "invalid option '%s'" );
734 if (flag[1] == ':')
736 end = start + 1;
737 if (!*end) end = NULL;
738 if (flag[2] != ':' && !end)
740 if (i == argc - 1) OPT_ERR( "option '%s' requires an argument" );
741 end = argv[++i];
743 callback( *start, end );
744 break;
746 callback( *start, NULL );
749 return ret;
750 #undef OPT_ERR
753 #endif /* __WINE_TOOLS_H */