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