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