dd887414cf845c8068acb63f859616956c09bb5b
[reactos.git] / reactos / tools / winebuild / utils.c
1 /*
2 * Small utility functions for winebuild
3 *
4 * Copyright 2000 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "config.h"
22
23 #if !defined(WIN32)
24 #undef strdup
25 #endif
26
27 #include <assert.h>
28 #include <ctype.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36
37 #include "build.h"
38
39 #define MAX_TMP_FILES 8
40 static const char *tmp_files[MAX_TMP_FILES];
41 static unsigned int nb_tmp_files;
42
43 /* atexit handler to clean tmp files */
44 static void cleanup_tmp_files(void)
45 {
46 unsigned int i;
47 for (i = 0; i < MAX_TMP_FILES; i++) if (tmp_files[i]) unlink( tmp_files[i] );
48 }
49
50
51 void *xmalloc (size_t size)
52 {
53 void *res;
54
55 res = malloc (size ? size : 1);
56 if (res == NULL)
57 {
58 fprintf (stderr, "Virtual memory exhausted.\n");
59 exit (1);
60 }
61 return res;
62 }
63
64 void *xrealloc (void *ptr, size_t size)
65 {
66 void *res = realloc (ptr, size);
67 if (size && res == NULL)
68 {
69 fprintf (stderr, "Virtual memory exhausted.\n");
70 exit (1);
71 }
72 return res;
73 }
74
75 char *xstrdup( const char *str )
76 {
77 char *res = strdup( str );
78 if (!res)
79 {
80 fprintf (stderr, "Virtual memory exhausted.\n");
81 exit (1);
82 }
83 return res;
84 }
85
86 char *strupper(char *s)
87 {
88 char *p;
89 for (p = s; *p; p++) *p = toupper(*p);
90 return s;
91 }
92
93 int strendswith(const char* str, const char* end)
94 {
95 int l = strlen(str);
96 int m = strlen(end);
97 return l >= m && strcmp(str + l - m, end) == 0;
98 }
99
100 void fatal_error( const char *msg, ... )
101 {
102 va_list valist;
103 va_start( valist, msg );
104 if (input_file_name)
105 {
106 fprintf( stderr, "%s:", input_file_name );
107 if (current_line)
108 fprintf( stderr, "%d:", current_line );
109 fputc( ' ', stderr );
110 }
111 else fprintf( stderr, "winebuild: " );
112 vfprintf( stderr, msg, valist );
113 va_end( valist );
114 exit(1);
115 }
116
117 void fatal_perror( const char *msg, ... )
118 {
119 va_list valist;
120 va_start( valist, msg );
121 if (input_file_name)
122 {
123 fprintf( stderr, "%s:", input_file_name );
124 if (current_line)
125 fprintf( stderr, "%d:", current_line );
126 fputc( ' ', stderr );
127 }
128 vfprintf( stderr, msg, valist );
129 perror( " " );
130 va_end( valist );
131 exit(1);
132 }
133
134 void error( const char *msg, ... )
135 {
136 va_list valist;
137 va_start( valist, msg );
138 if (input_file_name)
139 {
140 fprintf( stderr, "%s:", input_file_name );
141 if (current_line)
142 fprintf( stderr, "%d:", current_line );
143 fputc( ' ', stderr );
144 }
145 vfprintf( stderr, msg, valist );
146 va_end( valist );
147 nb_errors++;
148 }
149
150 void warning( const char *msg, ... )
151 {
152 va_list valist;
153
154 if (!display_warnings) return;
155 va_start( valist, msg );
156 if (input_file_name)
157 {
158 fprintf( stderr, "%s:", input_file_name );
159 if (current_line)
160 fprintf( stderr, "%d:", current_line );
161 fputc( ' ', stderr );
162 }
163 fprintf( stderr, "warning: " );
164 vfprintf( stderr, msg, valist );
165 va_end( valist );
166 }
167
168 /* get a name for a temp file, automatically cleaned up on exit */
169 char *get_temp_file_name( const char *prefix, const char *suffix )
170 {
171 char *name;
172 const char *ext;
173 int fd;
174
175 assert( nb_tmp_files < MAX_TMP_FILES );
176 if (!nb_tmp_files && !save_temps) atexit( cleanup_tmp_files );
177
178 if (!prefix || !prefix[0]) prefix = "winebuild";
179 if (!suffix) suffix = "";
180 if (!(ext = strchr( prefix, '.' ))) ext = prefix + strlen(prefix);
181 name = xmalloc( sizeof("/tmp/") + (ext - prefix) + sizeof(".XXXXXX") + strlen(suffix) );
182 strcpy( name, "/tmp/" );
183 memcpy( name + 5, prefix, ext - prefix );
184 strcpy( name + 5 + (ext - prefix), ".XXXXXX" );
185 strcat( name, suffix );
186
187 /* first try without the /tmp/ prefix */
188 if ((fd = mkstemps( name + 5, strlen(suffix) )) != -1)
189 name += 5;
190 else if ((fd = mkstemps( name, strlen(suffix) )) == -1)
191 fatal_error( "could not generate a temp file\n" );
192
193 close( fd );
194 tmp_files[nb_tmp_files++] = name;
195 return name;
196 }
197
198 /* output a standard header for generated files */
199 void output_standard_file_header( FILE *outfile )
200 {
201 if (spec_file_name)
202 fprintf( outfile, "/* File generated automatically from %s; do not edit! */\n",
203 spec_file_name );
204 else
205 fprintf( outfile, "/* File generated automatically; do not edit! */\n" );
206 fprintf( outfile,
207 "/* This file can be copied, modified and distributed without restriction. */\n\n" );
208 }
209
210 /* dump a byte stream into the assembly code */
211 void dump_bytes( FILE *outfile, const void *buffer, unsigned int size )
212 {
213 unsigned int i;
214 const unsigned char *ptr = buffer;
215
216 if (!size) return;
217 fprintf( outfile, "\t.byte " );
218 for (i = 0; i < size - 1; i++, ptr++)
219 {
220 if ((i % 16) == 15) fprintf( outfile, "0x%02x\n\t.byte ", *ptr );
221 else fprintf( outfile, "0x%02x,", *ptr );
222 }
223 fprintf( outfile, "0x%02x\n", *ptr );
224 }
225
226
227 /*******************************************************************
228 * open_input_file
229 *
230 * Open a file in the given srcdir and set the input_file_name global variable.
231 */
232 FILE *open_input_file( const char *srcdir, const char *name )
233 {
234 char *fullname;
235 FILE *file = fopen( name, "r" );
236
237 if (!file && srcdir)
238 {
239 fullname = xmalloc( strlen(srcdir) + strlen(name) + 2 );
240 strcpy( fullname, srcdir );
241 strcat( fullname, "/" );
242 strcat( fullname, name );
243 file = fopen( fullname, "r" );
244 }
245 else fullname = xstrdup( name );
246
247 if (!file) fatal_error( "Cannot open file '%s'\n", fullname );
248 input_file_name = fullname;
249 current_line = 1;
250 return file;
251 }
252
253
254 /*******************************************************************
255 * close_input_file
256 *
257 * Close the current input file (must have been opened with open_input_file).
258 */
259 void close_input_file( FILE *file )
260 {
261 fclose( file );
262 free( input_file_name );
263 input_file_name = NULL;
264 current_line = 0;
265 }
266
267
268 /*******************************************************************
269 * remove_stdcall_decoration
270 *
271 * Remove a possible @xx suffix from a function name.
272 * Return the numerical value of the suffix, or -1 if none.
273 */
274 int remove_stdcall_decoration( char *name )
275 {
276 char *p, *end = strrchr( name, '@' );
277 if (!end || !end[1] || end == name) return -1;
278 /* make sure all the rest is digits */
279 for (p = end + 1; *p; p++) if (!isdigit(*p)) return -1;
280 *end = 0;
281 return atoi( end + 1 );
282 }
283
284
285 /*******************************************************************
286 * assemble_file
287 *
288 * Run a file through the assembler.
289 */
290 void assemble_file( const char *src_file, const char *obj_file )
291 {
292 char *cmd;
293 int err;
294
295 if (!as_command) as_command = xstrdup("as");
296 cmd = xmalloc( strlen(as_command) + strlen(obj_file) + strlen(src_file) + 6 );
297 sprintf( cmd, "%s -o %s %s", as_command, obj_file, src_file );
298 if (verbose) fprintf( stderr, "%s\n", cmd );
299 err = system( cmd );
300 if (err) fatal_error( "%s failed with status %d\n", as_command, err );
301 free( cmd );
302 }
303
304
305 /*******************************************************************
306 * alloc_dll_spec
307 *
308 * Create a new dll spec file descriptor
309 */
310 DLLSPEC *alloc_dll_spec(void)
311 {
312 DLLSPEC *spec;
313
314 spec = xmalloc( sizeof(*spec) );
315 spec->file_name = NULL;
316 spec->dll_name = NULL;
317 spec->init_func = NULL;
318 spec->type = SPEC_WIN32;
319 spec->base = MAX_ORDINALS;
320 spec->limit = 0;
321 spec->stack_size = 0;
322 spec->heap_size = 0;
323 spec->nb_entry_points = 0;
324 spec->alloc_entry_points = 0;
325 spec->nb_names = 0;
326 spec->nb_resources = 0;
327 spec->characteristics = 0;
328 spec->subsystem = 0;
329 spec->subsystem_major = 4;
330 spec->subsystem_minor = 0;
331 spec->entry_points = NULL;
332 spec->names = NULL;
333 spec->ordinals = NULL;
334 spec->resources = NULL;
335 return spec;
336 }
337
338
339 /*******************************************************************
340 * free_dll_spec
341 *
342 * Free dll spec file descriptor
343 */
344 void free_dll_spec( DLLSPEC *spec )
345 {
346 int i;
347
348 for (i = 0; i < spec->nb_entry_points; i++)
349 {
350 ORDDEF *odp = &spec->entry_points[i];
351 free( odp->name );
352 free( odp->export_name );
353 free( odp->link_name );
354 }
355 free( spec->file_name );
356 free( spec->dll_name );
357 free( spec->init_func );
358 free( spec->entry_points );
359 free( spec->names );
360 free( spec->ordinals );
361 free( spec->resources );
362 free( spec );
363 }
364
365
366 /*******************************************************************
367 * make_c_identifier
368 *
369 * Map a string to a valid C identifier.
370 */
371 const char *make_c_identifier( const char *str )
372 {
373 static char buffer[256];
374 char *p;
375
376 for (p = buffer; *str && p < buffer+sizeof(buffer)-1; p++, str++)
377 {
378 if (isalnum(*str)) *p = *str;
379 else *p = '_';
380 }
381 *p = 0;
382 return buffer;
383 }
384
385
386 /*******************************************************************
387 * get_stub_name
388 *
389 * Generate an internal name for a stub entry point.
390 */
391 const char *get_stub_name( const ORDDEF *odp, const DLLSPEC *spec )
392 {
393 static char buffer[256];
394 if (odp->name || odp->export_name)
395 {
396 char *p;
397 sprintf( buffer, "__wine_stub_%s", odp->name ? odp->name : odp->export_name );
398 /* make sure name is a legal C identifier */
399 for (p = buffer; *p; p++) if (!isalnum(*p) && *p != '_') break;
400 if (!*p) return buffer;
401 }
402 sprintf( buffer, "__wine_stub_%s_%d", make_c_identifier(spec->file_name), odp->ordinal );
403 return buffer;
404 }
405
406
407 /*****************************************************************
408 * Function: get_alignment
409 *
410 * Description:
411 * According to the info page for gas, the .align directive behaves
412 * differently on different systems. On some architectures, the
413 * argument of a .align directive is the number of bytes to pad to, so
414 * to align on an 8-byte boundary you'd say
415 * .align 8
416 * On other systems, the argument is "the number of low-order zero bits
417 * that the location counter must have after advancement." So to
418 * align on an 8-byte boundary you'd say
419 * .align 3
420 *
421 * The reason gas is written this way is that it's trying to mimick
422 * native assemblers for the various architectures it runs on. gas
423 * provides other directives that work consistantly across
424 * architectures, but of course we want to work on all arches with or
425 * without gas. Hence this function.
426 *
427 *
428 * Parameters:
429 * align -- the number of bytes to align to. Must be a power of 2.
430 */
431 unsigned int get_alignment(unsigned int align)
432 {
433 unsigned int n;
434
435 assert( !(align & (align - 1)) );
436
437 switch(target_cpu)
438 {
439 case CPU_x86:
440 case CPU_x86_64:
441 case CPU_SPARC:
442 if (target_platform != PLATFORM_APPLE) return align;
443 /* fall through */
444 case CPU_POWERPC:
445 case CPU_ALPHA:
446 n = 0;
447 while ((1 << n) != align) n++;
448 return n;
449 }
450 /* unreached */
451 assert(0);
452 return 0;
453 }
454
455 /* return the page size for the target CPU */
456 unsigned int get_page_size(void)
457 {
458 switch(target_cpu)
459 {
460 case CPU_x86: return 4096;
461 case CPU_x86_64: return 4096;
462 case CPU_POWERPC: return 4096;
463 case CPU_SPARC: return 8192;
464 case CPU_ALPHA: return 8192;
465 }
466 /* unreached */
467 assert(0);
468 return 0;
469 }
470
471 /* return the size of a pointer on the target CPU */
472 unsigned int get_ptr_size(void)
473 {
474 switch(target_cpu)
475 {
476 case CPU_x86:
477 case CPU_POWERPC:
478 case CPU_SPARC:
479 case CPU_ALPHA:
480 return 4;
481 case CPU_x86_64:
482 return 8;
483 }
484 /* unreached */
485 assert(0);
486 return 0;
487 }
488
489 /* return the assembly name for a C symbol */
490 const char *asm_name( const char *sym )
491 {
492 static char buffer[256];
493
494 switch (target_platform)
495 {
496 case PLATFORM_APPLE:
497 case PLATFORM_WINDOWS:
498 buffer[0] = '_';
499 strcpy( buffer + 1, sym );
500 return buffer;
501 default:
502 return sym;
503 }
504 }
505
506 /* return an assembly function declaration for a C function name */
507 const char *func_declaration( const char *func )
508 {
509 static char buffer[256];
510
511 switch (target_platform)
512 {
513 case PLATFORM_APPLE:
514 return "";
515 case PLATFORM_WINDOWS:
516 sprintf( buffer, ".def _%s; .scl 2; .type 32; .endef", func );
517 break;
518 default:
519 sprintf( buffer, ".type %s,@function", func );
520 break;
521 }
522 return buffer;
523 }
524
525 /* output a size declaration for an assembly function */
526 void output_function_size( FILE *outfile, const char *name )
527 {
528 switch (target_platform)
529 {
530 case PLATFORM_APPLE:
531 case PLATFORM_WINDOWS:
532 break;
533 default:
534 fprintf( outfile, "\t.size %s, .-%s\n", name, name );
535 break;
536 }
537 }
538
539 /* return a global symbol declaration for an assembly symbol */
540 const char *asm_globl( const char *func )
541 {
542 static char buffer[256];
543
544 switch (target_platform)
545 {
546 case PLATFORM_APPLE:
547 sprintf( buffer, "\t.globl _%s\n\t.private_extern _%s\n_%s:", func, func, func );
548 return buffer;
549 case PLATFORM_WINDOWS:
550 sprintf( buffer, "\t.globl _%s\n_%s:", func, func );
551 return buffer;
552 default:
553 sprintf( buffer, "\t.globl %s\n\t.hidden %s\n%s:", func, func, func );
554 return buffer;
555 }
556 }
557
558 const char *get_asm_ptr_keyword(void)
559 {
560 switch(get_ptr_size())
561 {
562 case 4: return ".long";
563 case 8: return ".quad";
564 }
565 assert(0);
566 return NULL;
567 }
568
569 const char *get_asm_string_keyword(void)
570 {
571 switch (target_platform)
572 {
573 case PLATFORM_APPLE:
574 return ".asciz";
575 default:
576 return ".string";
577 }
578 }
579
580 const char *get_asm_short_keyword(void)
581 {
582 switch (target_platform)
583 {
584 default: return ".short";
585 }
586 }
587
588 const char *get_asm_string_section(void)
589 {
590 switch (target_platform)
591 {
592 case PLATFORM_APPLE: return ".cstring";
593 default: return ".section .rodata";
594 }
595 }