Added Korean resources.
[wine.git] / tools / winebuild / parser.c
blob27c01061dbfa03a93478177304672683d6c1da06
1 /*
2 * Spec file parser
4 * Copyright 1993 Robert J. Amstadt
5 * Copyright 1995 Martin von Loewis
6 * Copyright 1995, 1996, 1997 Alexandre Julliard
7 * Copyright 1997 Eric Youngdale
8 * Copyright 1999 Ulrich Weigand
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "config.h"
26 #include "wine/port.h"
28 #include <assert.h>
29 #include <ctype.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
34 #include "winbase.h"
35 #include "build.h"
37 int current_line = 0;
39 static SPEC_TYPE SpecType = SPEC_WIN32;
41 static char ParseBuffer[512];
42 static char TokenBuffer[512];
43 static char *ParseNext = ParseBuffer;
44 static FILE *input_file;
46 static const char * const TypeNames[TYPE_NBTYPES] =
48 "variable", /* TYPE_VARIABLE */
49 "pascal16", /* TYPE_PASCAL_16 */
50 "pascal", /* TYPE_PASCAL */
51 "equate", /* TYPE_ABS */
52 "stub", /* TYPE_STUB */
53 "stdcall", /* TYPE_STDCALL */
54 "cdecl", /* TYPE_CDECL */
55 "varargs", /* TYPE_VARARGS */
56 "extern", /* TYPE_EXTERN */
57 "forward" /* TYPE_FORWARD */
60 static const char * const FlagNames[] =
62 "noimport", /* FLAG_NOIMPORT */
63 "norelay", /* FLAG_NORELAY */
64 "ret64", /* FLAG_RET64 */
65 "i386", /* FLAG_I386 */
66 "register", /* FLAG_REGISTER */
67 "interrupt", /* FLAG_INTERRUPT */
68 NULL
71 static int IsNumberString(const char *s)
73 while (*s) if (!isdigit(*s++)) return 0;
74 return 1;
77 inline static int is_token_separator( char ch )
79 return (ch == '(' || ch == ')' || ch == '-');
82 static const char * GetTokenInLine(void)
84 char *p = ParseNext;
85 char *token = TokenBuffer;
88 * Remove initial white space.
90 while (isspace(*p)) p++;
92 if ((*p == '\0') || (*p == '#')) return NULL;
95 * Find end of token.
97 if (is_token_separator(*p))
99 /* a separator is always a complete token */
100 *token++ = *p++;
102 else while (*p != '\0' && !is_token_separator(*p) && !isspace(*p))
104 if (*p == '\\') p++;
105 if (*p) *token++ = *p++;
107 *token = '\0';
108 ParseNext = p;
109 return TokenBuffer;
112 static const char * GetToken( int allow_eof )
114 const char *token;
116 while ((token = GetTokenInLine()) == NULL)
118 ParseNext = ParseBuffer;
119 current_line++;
120 if (fgets(ParseBuffer, sizeof(ParseBuffer), input_file) == NULL)
122 if (!allow_eof) fatal_error( "Unexpected end of file\n" );
123 return NULL;
126 return token;
130 /*******************************************************************
131 * ParseIgnore
133 * Parse an 'ignore' definition.
135 static void ParseIgnore(void)
137 const char *token = GetToken(0);
138 if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token );
139 for (;;)
141 token = GetToken(0);
142 if (*token == ')') break;
143 add_ignore_symbol( token );
148 /*******************************************************************
149 * ParseVariable
151 * Parse a variable definition.
153 static void ParseVariable( ORDDEF *odp )
155 char *endptr;
156 int *value_array;
157 int n_values;
158 int value_array_size;
160 const char *token = GetToken(0);
161 if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token );
163 n_values = 0;
164 value_array_size = 25;
165 value_array = xmalloc(sizeof(*value_array) * value_array_size);
167 for (;;)
169 token = GetToken(0);
170 if (*token == ')')
171 break;
173 value_array[n_values++] = strtol(token, &endptr, 0);
174 if (n_values == value_array_size)
176 value_array_size += 25;
177 value_array = xrealloc(value_array,
178 sizeof(*value_array) * value_array_size);
181 if (endptr == NULL || *endptr != '\0')
182 fatal_error( "Expected number value, got '%s'\n", token );
185 odp->u.var.n_values = n_values;
186 odp->u.var.values = xrealloc(value_array, sizeof(*value_array) * n_values);
190 /*******************************************************************
191 * ParseExportFunction
193 * Parse a function definition.
195 static void ParseExportFunction( ORDDEF *odp )
197 const char *token;
198 unsigned int i;
200 switch(SpecType)
202 case SPEC_WIN16:
203 if (odp->type == TYPE_STDCALL)
204 fatal_error( "'stdcall' not supported for Win16\n" );
205 if (odp->type == TYPE_VARARGS)
206 fatal_error( "'varargs' not supported for Win16\n" );
207 break;
208 case SPEC_WIN32:
209 if ((odp->type == TYPE_PASCAL) || (odp->type == TYPE_PASCAL_16))
210 fatal_error( "'pascal' not supported for Win32\n" );
211 if (odp->flags & FLAG_INTERRUPT)
212 fatal_error( "'interrupt' not supported for Win32\n" );
213 break;
214 default:
215 break;
218 token = GetToken(0);
219 if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token );
221 for (i = 0; i < sizeof(odp->u.func.arg_types); i++)
223 token = GetToken(0);
224 if (*token == ')')
225 break;
227 if (!strcmp(token, "word"))
228 odp->u.func.arg_types[i] = 'w';
229 else if (!strcmp(token, "s_word"))
230 odp->u.func.arg_types[i] = 's';
231 else if (!strcmp(token, "long") || !strcmp(token, "segptr"))
232 odp->u.func.arg_types[i] = 'l';
233 else if (!strcmp(token, "ptr"))
234 odp->u.func.arg_types[i] = 'p';
235 else if (!strcmp(token, "str"))
236 odp->u.func.arg_types[i] = 't';
237 else if (!strcmp(token, "wstr"))
238 odp->u.func.arg_types[i] = 'W';
239 else if (!strcmp(token, "segstr"))
240 odp->u.func.arg_types[i] = 'T';
241 else if (!strcmp(token, "double"))
243 odp->u.func.arg_types[i++] = 'l';
244 if (i < sizeof(odp->u.func.arg_types)) odp->u.func.arg_types[i] = 'l';
246 else fatal_error( "Unknown variable type '%s'\n", token );
248 if (SpecType == SPEC_WIN32)
250 if (strcmp(token, "long") &&
251 strcmp(token, "ptr") &&
252 strcmp(token, "str") &&
253 strcmp(token, "wstr") &&
254 strcmp(token, "double"))
256 fatal_error( "Type '%s' not supported for Win32\n", token );
260 if ((*token != ')') || (i >= sizeof(odp->u.func.arg_types)))
261 fatal_error( "Too many arguments\n" );
263 odp->u.func.arg_types[i] = '\0';
264 if (odp->type == TYPE_VARARGS)
265 odp->flags |= FLAG_NORELAY; /* no relay debug possible for varags entry point */
266 odp->link_name = xstrdup( GetToken(0) );
270 /*******************************************************************
271 * ParseEquate
273 * Parse an 'equate' definition.
275 static void ParseEquate( ORDDEF *odp )
277 char *endptr;
279 const char *token = GetToken(0);
280 int value = strtol(token, &endptr, 0);
281 if (endptr == NULL || *endptr != '\0')
282 fatal_error( "Expected number value, got '%s'\n", token );
283 if (SpecType == SPEC_WIN32)
284 fatal_error( "'equate' not supported for Win32\n" );
285 odp->u.abs.value = value;
289 /*******************************************************************
290 * ParseStub
292 * Parse a 'stub' definition.
294 static void ParseStub( ORDDEF *odp )
296 odp->u.func.arg_types[0] = '\0';
297 odp->link_name = xstrdup("");
301 /*******************************************************************
302 * ParseExtern
304 * Parse an 'extern' definition.
306 static void ParseExtern( ORDDEF *odp )
308 if (SpecType == SPEC_WIN16) fatal_error( "'extern' not supported for Win16\n" );
309 odp->link_name = xstrdup( GetToken(0) );
310 /* 'extern' definitions are not available for implicit import */
311 odp->flags |= FLAG_NOIMPORT;
315 /*******************************************************************
316 * ParseForward
318 * Parse a 'forward' definition.
320 static void ParseForward( ORDDEF *odp )
322 if (SpecType == SPEC_WIN16) fatal_error( "'forward' not supported for Win16\n" );
323 odp->link_name = xstrdup( GetToken(0) );
327 /*******************************************************************
328 * ParseFlags
330 * Parse the optional flags for an entry point
332 static const char *ParseFlags( ORDDEF *odp )
334 unsigned int i;
335 const char *token;
339 token = GetToken(0);
340 for (i = 0; FlagNames[i]; i++)
341 if (!strcmp( FlagNames[i], token )) break;
342 if (!FlagNames[i]) fatal_error( "Unknown flag '%s'\n", token );
343 odp->flags |= 1 << i;
344 token = GetToken(0);
345 } while (*token == '-');
347 return token;
350 /*******************************************************************
351 * fix_export_name
353 * Fix an exported function name by removing a possible @xx suffix
355 static void fix_export_name( char *name )
357 char *p, *end = strrchr( name, '@' );
358 if (!end || !end[1] || end == name) return;
359 /* make sure all the rest is digits */
360 for (p = end + 1; *p; p++) if (!isdigit(*p)) return;
361 *end = 0;
364 /*******************************************************************
365 * ParseOrdinal
367 * Parse an ordinal definition.
369 static void ParseOrdinal(int ordinal)
371 const char *token;
373 ORDDEF *odp = xmalloc( sizeof(*odp) );
374 memset( odp, 0, sizeof(*odp) );
375 EntryPoints[nb_entry_points++] = odp;
377 token = GetToken(0);
379 for (odp->type = 0; odp->type < TYPE_NBTYPES; odp->type++)
380 if (TypeNames[odp->type] && !strcmp( token, TypeNames[odp->type] ))
381 break;
383 if (odp->type >= TYPE_NBTYPES)
384 fatal_error( "Expected type after ordinal, found '%s' instead\n", token );
386 token = GetToken(0);
387 if (*token == '-') token = ParseFlags( odp );
389 odp->name = xstrdup( token );
390 fix_export_name( odp->name );
391 odp->lineno = current_line;
392 odp->ordinal = ordinal;
394 switch(odp->type)
396 case TYPE_VARIABLE:
397 ParseVariable( odp );
398 break;
399 case TYPE_PASCAL_16:
400 case TYPE_PASCAL:
401 case TYPE_STDCALL:
402 case TYPE_VARARGS:
403 case TYPE_CDECL:
404 ParseExportFunction( odp );
405 break;
406 case TYPE_ABS:
407 ParseEquate( odp );
408 break;
409 case TYPE_STUB:
410 ParseStub( odp );
411 break;
412 case TYPE_EXTERN:
413 ParseExtern( odp );
414 break;
415 case TYPE_FORWARD:
416 ParseForward( odp );
417 break;
418 default:
419 assert( 0 );
422 #ifndef __i386__
423 if (odp->flags & FLAG_I386)
425 /* ignore this entry point on non-Intel archs */
426 EntryPoints[--nb_entry_points] = NULL;
427 free( odp );
428 return;
430 #endif
432 if (ordinal != -1)
434 if (ordinal >= MAX_ORDINALS) fatal_error( "Ordinal number %d too large\n", ordinal );
435 if (ordinal > Limit) Limit = ordinal;
436 if (ordinal < Base) Base = ordinal;
437 odp->ordinal = ordinal;
438 Ordinals[ordinal] = odp;
441 if (!strcmp( odp->name, "@" ))
443 if (ordinal == -1)
444 fatal_error( "Nameless function needs an explicit ordinal number\n" );
445 if (SpecType != SPEC_WIN32)
446 fatal_error( "Nameless functions not supported for Win16\n" );
447 odp->name[0] = 0;
449 else Names[nb_names++] = odp;
453 static int name_compare( const void *name1, const void *name2 )
455 ORDDEF *odp1 = *(ORDDEF **)name1;
456 ORDDEF *odp2 = *(ORDDEF **)name2;
457 return strcmp( odp1->name, odp2->name );
460 /*******************************************************************
461 * sort_names
463 * Sort the name array and catch duplicates.
465 static void sort_names(void)
467 int i;
469 if (!nb_names) return;
471 /* sort the list of names */
472 qsort( Names, nb_names, sizeof(Names[0]), name_compare );
474 /* check for duplicate names */
475 for (i = 0; i < nb_names - 1; i++)
477 if (!strcmp( Names[i]->name, Names[i+1]->name ))
479 current_line = max( Names[i]->lineno, Names[i+1]->lineno );
480 fatal_error( "'%s' redefined (previous definition at line %d)\n",
481 Names[i]->name, min( Names[i]->lineno, Names[i+1]->lineno ) );
487 /*******************************************************************
488 * ParseTopLevel
490 * Parse a spec file.
492 SPEC_TYPE ParseTopLevel( FILE *file, int def_only )
494 const char *token;
496 input_file = file;
497 current_line = 1;
498 while ((token = GetToken(1)) != NULL)
500 if (strcmp(token, "name") == 0)
502 strcpy(DLLName, GetToken(0));
504 else if (strcmp(token, "file") == 0)
506 strcpy(DLLFileName, GetToken(0));
508 else if (strcmp(token, "type") == 0)
510 token = GetToken(0);
511 if (!strcmp(token, "win16" )) SpecType = SPEC_WIN16;
512 else if (!strcmp(token, "win32" )) SpecType = SPEC_WIN32;
513 else fatal_error( "Type must be 'win16' or 'win32'\n" );
515 else if (strcmp(token, "mode") == 0)
517 token = GetToken(0);
518 if (!strcmp(token, "dll" )) SpecMode = SPEC_MODE_DLL;
519 else if (!strcmp(token, "guiexe" )) SpecMode = SPEC_MODE_GUIEXE;
520 else if (!strcmp(token, "cuiexe" )) SpecMode = SPEC_MODE_CUIEXE;
521 else if (!strcmp(token, "guiexe_unicode" )) SpecMode = SPEC_MODE_GUIEXE_UNICODE;
522 else if (!strcmp(token, "cuiexe_unicode" )) SpecMode = SPEC_MODE_CUIEXE_UNICODE;
523 else fatal_error( "Mode must be 'dll', 'guiexe', 'cuiexe', 'guiexe_unicode' or 'cuiexe_unicode'\n" );
525 else if (strcmp(token, "heap") == 0)
527 token = GetToken(0);
528 if (!IsNumberString(token)) fatal_error( "Expected number after heap\n" );
529 DLLHeapSize = atoi(token);
531 else if (strcmp(token, "stack") == 0)
533 token = GetToken(0);
534 if (!IsNumberString(token)) fatal_error( "Expected number after stack\n" );
535 stack_size = atoi(token);
537 else if (strcmp(token, "init") == 0)
539 if (SpecType == SPEC_WIN16)
540 fatal_error( "init cannot be used for Win16 spec files\n" );
541 init_func = xstrdup( GetToken(0) );
543 else if (strcmp(token, "rsrc") == 0)
545 if (!def_only)
547 if (SpecType != SPEC_WIN16) load_res32_file( GetToken(0) );
548 else load_res16_file( GetToken(0) );
550 else GetToken(0); /* skip it */
552 else if (strcmp(token, "owner") == 0)
554 if (SpecType != SPEC_WIN16)
555 fatal_error( "Owner only supported for Win16 spec files\n" );
556 strcpy( owner_name, GetToken(0) );
558 else if (strcmp(token, "ignore") == 0)
560 if (SpecType != SPEC_WIN32)
561 fatal_error( "'ignore' only supported for Win32 spec files\n" );
562 ParseIgnore();
564 else if (strcmp(token, "@") == 0)
566 if (SpecType != SPEC_WIN32)
567 fatal_error( "'@' ordinals not supported for Win16\n" );
568 ParseOrdinal( -1 );
570 else if (IsNumberString(token))
572 ParseOrdinal( atoi(token) );
574 else
575 fatal_error( "Expected name, id, length or ordinal\n" );
578 if (!DLLFileName[0])
580 if (SpecMode == SPEC_MODE_DLL)
582 strcpy( DLLFileName, DLLName );
583 /* Append .dll to name if no extension present */
584 if (!strrchr( DLLFileName, '.'))
585 strcat( DLLFileName, ".dll" );
587 else
588 sprintf( DLLFileName, "%s.exe", DLLName );
591 if (SpecType == SPEC_WIN16 && !owner_name[0])
592 fatal_error( "'owner' not specified for Win16 dll\n" );
594 current_line = 0; /* no longer parsing the input file */
595 sort_names();
596 return SpecType;
600 /*******************************************************************
601 * add_debug_channel
603 static void add_debug_channel( const char *name )
605 int i;
607 for (i = 0; i < nb_debug_channels; i++)
608 if (!strcmp( debug_channels[i], name )) return;
610 debug_channels = xrealloc( debug_channels, (nb_debug_channels + 1) * sizeof(*debug_channels));
611 debug_channels[nb_debug_channels++] = xstrdup(name);
615 /*******************************************************************
616 * parse_debug_channels
618 * Parse a source file and extract the debug channel definitions.
620 void parse_debug_channels( const char *srcdir, const char *filename )
622 FILE *file;
623 int eol_seen = 1;
624 char *fullname = NULL;
626 if (srcdir)
628 fullname = xmalloc( strlen(srcdir) + strlen(filename) + 2 );
629 strcpy( fullname, srcdir );
630 strcat( fullname, "/" );
631 strcat( fullname, filename );
633 else fullname = xstrdup( filename );
635 if (!(file = fopen( fullname, "r" ))) fatal_error( "Cannot open file '%s'\n", fullname );
636 input_file_name = fullname;
637 current_line = 1;
638 while (fgets( ParseBuffer, sizeof(ParseBuffer), file ))
640 char *channel, *end, *p = ParseBuffer;
642 p = ParseBuffer + strlen(ParseBuffer) - 1;
643 if (!eol_seen) /* continuation line */
645 eol_seen = (*p == '\n');
646 continue;
648 if ((eol_seen = (*p == '\n'))) *p = 0;
650 p = ParseBuffer;
651 while (isspace(*p)) p++;
652 if (!memcmp( p, "WINE_DECLARE_DEBUG_CHANNEL", 26 ) ||
653 !memcmp( p, "WINE_DEFAULT_DEBUG_CHANNEL", 26 ))
655 p += 26;
656 while (isspace(*p)) p++;
657 if (*p != '(')
658 fatal_error( "invalid debug channel specification '%s'\n", ParseBuffer );
659 p++;
660 while (isspace(*p)) p++;
661 if (!isalpha(*p))
662 fatal_error( "invalid debug channel specification '%s'\n", ParseBuffer );
663 channel = p;
664 while (isalnum(*p) || *p == '_') p++;
665 end = p;
666 while (isspace(*p)) p++;
667 if (*p != ')')
668 fatal_error( "invalid debug channel specification '%s'\n", ParseBuffer );
669 *end = 0;
670 add_debug_channel( channel );
672 current_line++;
674 fclose( file );
675 input_file_name = NULL;
676 current_line = 0;
677 free( fullname );