Phil Krylov <phil@newstar.rinet.ru>
[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
34 #include "build.h"
35
36 void *xmalloc (size_t size)
37 {
38 void *res;
39
40 res = malloc (size ? size : 1);
41 if (res == NULL)
42 {
43 fprintf (stderr, "Virtual memory exhausted.\n");
44 exit (1);
45 }
46 return res;
47 }
48
49 void *xrealloc (void *ptr, size_t size)
50 {
51 void *res = realloc (ptr, size);
52 if (size && res == NULL)
53 {
54 fprintf (stderr, "Virtual memory exhausted.\n");
55 exit (1);
56 }
57 return res;
58 }
59
60 char *xstrdup( const char *str )
61 {
62 char *res = strdup( str );
63 if (!res)
64 {
65 fprintf (stderr, "Virtual memory exhausted.\n");
66 exit (1);
67 }
68 return res;
69 }
70
71 char *strupper(char *s)
72 {
73 char *p;
74 for (p = s; *p; p++) *p = toupper(*p);
75 return s;
76 }
77
78 int strendswith(const char* str, const char* end)
79 {
80 int l = strlen(str);
81 int m = strlen(end);
82 return l >= m && strcmp(str + l - m, end) == 0;
83 }
84
85 void fatal_error( const char *msg, ... )
86 {
87 va_list valist;
88 va_start( valist, msg );
89 if (input_file_name)
90 {
91 fprintf( stderr, "%s:", input_file_name );
92 if (current_line)
93 fprintf( stderr, "%d:", current_line );
94 fputc( ' ', stderr );
95 }
96 else fprintf( stderr, "winebuild: " );
97 vfprintf( stderr, msg, valist );
98 va_end( valist );
99 exit(1);
100 }
101
102 void fatal_perror( const char *msg, ... )
103 {
104 va_list valist;
105 va_start( valist, msg );
106 if (input_file_name)
107 {
108 fprintf( stderr, "%s:", input_file_name );
109 if (current_line)
110 fprintf( stderr, "%d:", current_line );
111 fputc( ' ', stderr );
112 }
113 vfprintf( stderr, msg, valist );
114 perror( " " );
115 va_end( valist );
116 exit(1);
117 }
118
119 void error( const char *msg, ... )
120 {
121 va_list valist;
122 va_start( valist, msg );
123 if (input_file_name)
124 {
125 fprintf( stderr, "%s:", input_file_name );
126 if (current_line)
127 fprintf( stderr, "%d:", current_line );
128 fputc( ' ', stderr );
129 }
130 vfprintf( stderr, msg, valist );
131 va_end( valist );
132 nb_errors++;
133 }
134
135 void warning( const char *msg, ... )
136 {
137 va_list valist;
138
139 if (!display_warnings) return;
140 va_start( valist, msg );
141 if (input_file_name)
142 {
143 fprintf( stderr, "%s:", input_file_name );
144 if (current_line)
145 fprintf( stderr, "%d:", current_line );
146 fputc( ' ', stderr );
147 }
148 fprintf( stderr, "warning: " );
149 vfprintf( stderr, msg, valist );
150 va_end( valist );
151 }
152
153 /* output a standard header for generated files */
154 void output_standard_file_header( FILE *outfile )
155 {
156 if (spec_file_name)
157 fprintf( outfile, "/* File generated automatically from %s; do not edit! */\n",
158 spec_file_name );
159 else
160 fprintf( outfile, "/* File generated automatically; do not edit! */\n" );
161 fprintf( outfile,
162 "/* This file can be copied, modified and distributed without restriction. */\n\n" );
163 }
164
165 /* dump a byte stream into the assembly code */
166 void dump_bytes( FILE *outfile, const unsigned char *data, int len,
167 const char *label, int constant )
168 {
169 int i;
170
171 fprintf( outfile, "\nstatic %sunsigned char %s[%d] = {",
172 constant ? "const " : "", label, len );
173 for (i = 0; i < len; i++)
174 {
175 if (!(i & 7)) fprintf( outfile, "\n " );
176 fprintf( outfile, "0x%02x", *data++ );
177 if (i < len - 1) fprintf( outfile, "," );
178 }
179 fprintf( outfile, "\n};\n" );
180 }
181
182
183 /*******************************************************************
184 * open_input_file
185 *
186 * Open a file in the given srcdir and set the input_file_name global variable.
187 */
188 FILE *open_input_file( const char *srcdir, const char *name )
189 {
190 char *fullname;
191 FILE *file = fopen( name, "r" );
192
193 if (!file && srcdir)
194 {
195 fullname = xmalloc( strlen(srcdir) + strlen(name) + 2 );
196 strcpy( fullname, srcdir );
197 strcat( fullname, "/" );
198 strcat( fullname, name );
199 file = fopen( fullname, "r" );
200 }
201 else fullname = xstrdup( name );
202
203 if (!file) fatal_error( "Cannot open file '%s'\n", fullname );
204 input_file_name = fullname;
205 current_line = 1;
206 return file;
207 }
208
209
210 /*******************************************************************
211 * close_input_file
212 *
213 * Close the current input file (must have been opened with open_input_file).
214 */
215 void close_input_file( FILE *file )
216 {
217 fclose( file );
218 free( input_file_name );
219 input_file_name = NULL;
220 current_line = 0;
221 }
222
223
224 /*******************************************************************
225 * remove_stdcall_decoration
226 *
227 * Remove a possible @xx suffix from a function name.
228 * Return the numerical value of the suffix, or -1 if none.
229 */
230 int remove_stdcall_decoration( char *name )
231 {
232 char *p, *end = strrchr( name, '@' );
233 if (!end || !end[1] || end == name) return -1;
234 /* make sure all the rest is digits */
235 for (p = end + 1; *p; p++) if (!isdigit(*p)) return -1;
236 *end = 0;
237 return atoi( end + 1 );
238 }
239
240
241 /*******************************************************************
242 * alloc_dll_spec
243 *
244 * Create a new dll spec file descriptor
245 */
246 DLLSPEC *alloc_dll_spec(void)
247 {
248 DLLSPEC *spec;
249
250 spec = xmalloc( sizeof(*spec) );
251 spec->file_name = NULL;
252 spec->dll_name = NULL;
253 spec->owner_name = NULL;
254 spec->init_func = NULL;
255 spec->type = SPEC_WIN32;
256 spec->base = MAX_ORDINALS;
257 spec->limit = 0;
258 spec->stack_size = 0;
259 spec->heap_size = 0;
260 spec->nb_entry_points = 0;
261 spec->alloc_entry_points = 0;
262 spec->nb_names = 0;
263 spec->nb_resources = 0;
264 spec->characteristics = 0;
265 spec->subsystem = 0;
266 spec->subsystem_major = 4;
267 spec->subsystem_minor = 0;
268 spec->entry_points = NULL;
269 spec->names = NULL;
270 spec->ordinals = NULL;
271 spec->resources = NULL;
272 return spec;
273 }
274
275
276 /*******************************************************************
277 * free_dll_spec
278 *
279 * Free dll spec file descriptor
280 */
281 void free_dll_spec( DLLSPEC *spec )
282 {
283 int i;
284
285 for (i = 0; i < spec->nb_entry_points; i++)
286 {
287 ORDDEF *odp = &spec->entry_points[i];
288 free( odp->name );
289 free( odp->export_name );
290 free( odp->link_name );
291 }
292 free( spec->file_name );
293 free( spec->dll_name );
294 free( spec->owner_name );
295 free( spec->init_func );
296 free( spec->entry_points );
297 free( spec->names );
298 free( spec->ordinals );
299 free( spec->resources );
300 free( spec );
301 }
302
303
304 /*******************************************************************
305 * make_c_identifier
306 *
307 * Map a string to a valid C identifier.
308 */
309 const char *make_c_identifier( const char *str )
310 {
311 static char buffer[256];
312 char *p;
313
314 for (p = buffer; *str && p < buffer+sizeof(buffer)-1; p++, str++)
315 {
316 if (isalnum(*str)) *p = *str;
317 else *p = '_';
318 }
319 *p = 0;
320 return buffer;
321 }
322
323
324 /*****************************************************************
325 * Function: get_alignment
326 *
327 * Description:
328 * According to the info page for gas, the .align directive behaves
329 * differently on different systems. On some architectures, the
330 * argument of a .align directive is the number of bytes to pad to, so
331 * to align on an 8-byte boundary you'd say
332 * .align 8
333 * On other systems, the argument is "the number of low-order zero bits
334 * that the location counter must have after advancement." So to
335 * align on an 8-byte boundary you'd say
336 * .align 3
337 *
338 * The reason gas is written this way is that it's trying to mimick
339 * native assemblers for the various architectures it runs on. gas
340 * provides other directives that work consistantly across
341 * architectures, but of course we want to work on all arches with or
342 * without gas. Hence this function.
343 *
344 *
345 * Parameters:
346 * align -- the number of bytes to align to. Must be a power of 2.
347 */
348 unsigned int get_alignment(unsigned int align)
349 {
350 unsigned int n;
351
352 assert( !(align & (align - 1)) );
353
354 switch(target_cpu)
355 {
356 case CPU_x86:
357 case CPU_SPARC:
358 if (target_platform != PLATFORM_APPLE) return align;
359 /* fall through */
360 case CPU_POWERPC:
361 case CPU_ALPHA:
362 n = 0;
363 while ((1 << n) != align) n++;
364 return n;
365 }
366 /* unreached */
367 assert(0);
368 return 0;
369 }
370
371 /* return the page size for the target CPU */
372 unsigned int get_page_size(void)
373 {
374 switch(target_cpu)
375 {
376 case CPU_x86: return 4096;
377 case CPU_POWERPC: return 4096;
378 case CPU_SPARC: return 8192;
379 case CPU_ALPHA: return 8192;
380 }
381 /* unreached */
382 assert(0);
383 return 0;
384 }
385
386 /* return the assembly name for a C symbol */
387 const char *asm_name( const char *sym )
388 {
389 static char buffer[256];
390
391 switch (target_platform)
392 {
393 case PLATFORM_APPLE:
394 case PLATFORM_WINDOWS:
395 buffer[0] = '_';
396 strcpy( buffer + 1, sym );
397 return buffer;
398 default:
399 return sym;
400 }
401 }
402
403 /* return an assembly function declaration for a C function name */
404 const char *func_declaration( const char *func )
405 {
406 static char buffer[256];
407
408 switch (target_platform)
409 {
410 case PLATFORM_APPLE:
411 return "";
412 case PLATFORM_WINDOWS:
413 sprintf( buffer, ".def _%s; .scl 2; .type 32; .endef", func );
414 break;
415 case PLATFORM_SVR4:
416 sprintf( buffer, ".type %s,2", func );
417 break;
418 default:
419 sprintf( buffer, ".type %s,@function", func );
420 break;
421 }
422 return buffer;
423 }
424
425 /* return a size declaration for an assembly function */
426 const char *func_size( const char *func )
427 {
428 static char buffer[256];
429
430 switch (target_platform)
431 {
432 case PLATFORM_APPLE:
433 case PLATFORM_WINDOWS:
434 return "";
435 default:
436 sprintf( buffer, ".size %s, .-%s", func, func );
437 return buffer;
438 }
439 }
440
441 const char *get_asm_string_keyword(void)
442 {
443 switch (target_platform)
444 {
445 case PLATFORM_APPLE:
446 case PLATFORM_SVR4:
447 return ".asciz";
448 default:
449 return ".string";
450 }
451 }
452
453 const char *get_asm_short_keyword(void)
454 {
455 switch (target_platform)
456 {
457 case PLATFORM_SVR4: return ".half";
458 default: return ".short";
459 }
460 }