Filenames may contain '/' and '\'.
[wine] / tools / wrc / parser.l
1 /* -*-C-*-
2  *
3  * Copyright 1998-2000  Bertho A. Stultiens (BS)
4  *
5  * 21-May-2000 BS       - Fixed the ident requirement of resource names
6  *                        which can be keywords.
7  * 30-Apr-2000 BS       - Reintegration into the wine-tree
8  * 11-Jan-2000 BS       - Very drastic cleanup because we don't have a
9  *                        preprocessor in here anymore.
10  * 02-Jan-2000 BS       - Removed the preprocessor code
11  * 23-Dec-1999 BS       - Removed the copyright for Martin von Loewis.
12  *                        There is really nothing left of his code in 
13  *                        this parser.
14  * 20-Jun-1998 BS       - Changed the filename conversion. Filenames are
15  *                        case-sensitive inder *nix, but not under dos.
16  *                        default behaviour is to convert to lower case.
17  *                      - All backslashes are converted to forward and
18  *                        both single and double slash is recognized as
19  *                        MS/Borland does.
20  *                      - Fixed a bug in 'yywf' case that prevented
21  *                        double quoted names to be scanned propperly.
22  *
23  * 19-May-1998 BS       - Started to build a preprocessor.
24  *                      - Changed keyword processing completely to
25  *                        table-lookups.
26  *
27  * 20-Apr-1998 BS       - Added ';' comment stripping
28  *
29  * 17-Apr-1998 BS       - Made the win32 keywords optional when compiling in
30  *                        16bit mode
31  *
32  * 15-Apr-1998 BS       - Changed string handling to include escapes
33  *                      - Added unicode string handling (no codepage
34  *                        translation though).
35  *                      - 'Borrowed' the main idea of string scanning from
36  *                        the flex manual pages.
37  *                      - Added conditional handling of scanning depending
38  *                        on the state of the parser. This was mainly required
39  *                        to distinguish a file to load or raw data that
40  *                        follows. MS's definition of filenames is rather
41  *                        complex... It can be unquoted or double quoted. If
42  *                        double quoted, then the '\\' char is not automatically
43  *                        escaped according to Borland's rc compiler, but it
44  *                        accepts both "\\path\\file.rc" and "\path\file.rc".
45  *                        This makes life very hard! I go for the escaped
46  *                        version, as this seems to be the documented way...
47  *                      - Single quoted strings are now parsed and converted
48  *                        here.
49  *                      - Added comment stripping. The implementation is
50  *                        'borrowed' from the flex manpages.
51  *                      - Rebuild string processing so that it may contain
52  *                        escaped '\0'.
53  */
54
55 /* Exclusive string handling */
56 %x yystr
57 /* Exclusive unicode string handling */
58 %x yylstr
59 /* Exclusive rcdata single quoted data handling */
60 %x yyrcd
61 /* Exclusive comment eating... */
62 %x comment
63 /* Set when stripping c-junk */
64 %x pp_stripe
65 %x pp_strips
66 %x pp_stripp
67 %x pp_stripp_final
68 /* Set when scanning #line style directives */
69 %x pp_line
70
71 %option stack
72 %option never-interactive
73
74 /* Some shortcut definitions */
75 ws      [ \f\t\r]
76 cident  [a-zA-Z_][0-9a-zA-Z_]*
77
78 %{
79
80 /*#define LEX_DEBUG*/
81
82 #include "config.h"
83
84 #include <stdio.h>
85 #include <stdlib.h>
86 #include <string.h>
87 #include <ctype.h>
88 #include <assert.h>
89
90 #include "wrc.h"
91 #include "utils.h"
92 #include "preproc.h"
93 #include "parser.h"
94 #include "newstruc.h"
95
96 #include "y.tab.h"
97
98 #define YY_USE_PROTOS
99 #define YY_NO_UNPUT
100 #define YY_NO_TOP_STATE
101
102 /* Always update the current character position within a line */
103 #define YY_USER_ACTION  char_number+=yyleng; wanted_id = want_id; want_id = 0;
104
105 static void addcchar(char c);
106 static void addwchar(short s);
107 static string_t *get_buffered_cstring(void);
108 static string_t *get_buffered_wstring(void);
109 static string_t *make_string(char *s);
110
111 static char *cbuffer;           /* Buffers for string collection */
112 static int cbufidx;
113 static int cbufalloc = 0;
114 static short *wbuffer;
115 static int wbufidx;
116 static int wbufalloc = 0;
117 static int stripslevel = 0;     /* Count {} during pp_strips/pp_stripe mode */
118 static int stripplevel = 0;     /* Count () during pp_strips mode */
119 static int cjunk_tagline;       /* Where did we start stripping (helps error tracking) */
120
121 /*
122  * This one is a bit tricky.
123  * We set 'want_id' in the parser to get the first
124  * identifier we get across in the scanner, but we
125  * also want it to be reset at nearly any token we
126  * see. Exceptions are:
127  * - newlines
128  * - comments
129  * - whitespace
130  *
131  * The scanner will automatically reset 'want_id'
132  * after *each* scanner reduction and puts is value
133  * into the var below. In this way we can see the
134  * state after the YY_RULE_SETUP (i.e. the user action;
135  * see above) and don't have to worry too much when
136  * it needs to be reset.
137  */
138 static int wanted_id = 0;
139 static int save_wanted_id;      /* To save across comment reductions */
140
141 struct keyword {
142         char    *keyword;
143         int     token;
144         int     isextension;
145         int     needcase;
146         int     alwayskw;
147 };
148
149 static struct keyword keywords[] = {
150         { "ACCELERATORS",       tACCELERATORS,          0, 0, 0},
151         { "ALT",                tALT,                   0, 0, 0},
152         { "ASCII",              tASCII,                 0, 0, 0},
153         { "AUTO3STATE",         tAUTO3STATE,            1, 0, 0},
154         { "AUTOCHECKBOX",       tAUTOCHECKBOX,          1, 0, 0},
155         { "AUTORADIOBUTTON",    tAUTORADIOBUTTON,       1, 0, 0},
156         { "BEGIN",              tBEGIN,                 0, 0, 0},
157         { "BITMAP",             tBITMAP,                0, 0, 0},
158         { "BLOCK",              tBLOCK,                 0, 0, 0},
159         { "BUTTON",             tBUTTON,                1, 0, 0},
160         { "CAPTION",            tCAPTION,               0, 0, 0},
161         { "CHARACTERISTICS",    tCHARACTERISTICS,       1, 0, 0},
162         { "CHECKBOX",           tCHECKBOX,              0, 0, 0},
163         { "CHECKED",            tCHECKED,               0, 0, 0},
164         { "CLASS",              tCLASS,                 0, 0, 0},
165         { "COMBOBOX",           tCOMBOBOX,              0, 0, 0},
166         { "CONTROL",            tCONTROL,               0, 0, 0},
167         { "CTEXT",              tCTEXT,                 0, 0, 0},
168         { "CURSOR",             tCURSOR,                0, 0, 0},
169         { "DEFPUSHBUTTON",      tDEFPUSHBUTTON,         0, 0, 0},
170         { "DIALOG",             tDIALOG,                0, 0, 0},
171         { "DIALOGEX",           tDIALOGEX,              1, 0, 0},
172         { "DISCARDABLE",        tDISCARDABLE,           0, 0, 0},
173         { "DLGINIT",            tDLGINIT,               0, 0, 0},
174         { "EDITTEXT",           tEDITTEXT,              0, 0, 0},
175         { "END",                tEND,                   0, 0, 0},
176         { "enum",               tENUM,                  0, 1, 1},
177         { "EXSTYLE",            tEXSTYLE,               0, 0, 0},
178         { "extern",             tEXTERN,                0, 1, 1},
179         { "FILEFLAGS",          tFILEFLAGS,             0, 0, 0},
180         { "FILEFLAGSMASK",      tFILEFLAGSMASK,         0, 0, 0},
181         { "FILEOS",             tFILEOS,                0, 0, 0},
182         { "FILESUBTYPE",        tFILESUBTYPE,           0, 0, 0},
183         { "FILETYPE",           tFILETYPE,              0, 0, 0},
184         { "FILEVERSION",        tFILEVERSION,           0, 0, 0},
185         { "FIXED",              tFIXED,                 0, 0, 0},
186         { "FONT",               tFONT,                  0, 0, 0},
187         { "FONTDIR",            tFONTDIR,               0, 0, 0},       /* This is a Borland BRC extension */
188         { "GRAYED",             tGRAYED,                0, 0, 0},
189         { "GROUPBOX",           tGROUPBOX,              0, 0, 0},
190         { "HELP",               tHELP,                  0, 0, 0},
191         { "ICON",               tICON,                  0, 0, 0},
192         { "IMPURE",             tIMPURE,                0, 0, 0},
193         { "INACTIVE",           tINACTIVE,              0, 0, 0},
194         { "inline",             tINLINE,                0, 1, 1},
195         { "LANGUAGE",           tLANGUAGE,              1, 0, 1},
196         { "LISTBOX",            tLISTBOX,               0, 0, 0},
197         { "LOADONCALL",         tLOADONCALL,            0, 0, 0},
198         { "LTEXT",              tLTEXT,                 0, 0, 0},
199         { "MENU",               tMENU,                  0, 0, 0},
200         { "MENUBARBREAK",       tMENUBARBREAK,          0, 0, 0},
201         { "MENUBREAK",          tMENUBREAK,             0, 0, 0},
202         { "MENUEX",             tMENUEX,                1, 0, 0},
203         { "MENUITEM",           tMENUITEM,              0, 0, 0},
204         { "MESSAGETABLE",       tMESSAGETABLE,          1, 0, 0},
205         { "MOVEABLE",           tMOVEABLE,              0, 0, 0},
206         { "NOINVERT",           tNOINVERT,              0, 0, 0},
207         { "NOT",                tNOT,                   0, 0, 0},
208         { "POPUP",              tPOPUP,                 0, 0, 0},
209         { "PRELOAD",            tPRELOAD,               0, 0, 0},
210         { "PRODUCTVERSION",     tPRODUCTVERSION,        0, 0, 0},
211         { "PURE",               tPURE,                  0, 0, 0},
212         { "PUSHBUTTON",         tPUSHBUTTON,            0, 0, 0},
213         { "RADIOBUTTON",        tRADIOBUTTON,           0, 0, 0},
214         { "RCDATA",             tRCDATA,                0, 0, 0},
215         { "RTEXT",              tRTEXT,                 0, 0, 0},
216         { "SCROLLBAR",          tSCROLLBAR,             0, 0, 0},
217         { "SEPARATOR",          tSEPARATOR,             0, 0, 0},
218         { "SHIFT",              tSHIFT,                 0, 0, 0},
219         { "STATE3",             tSTATE3,                1, 0, 0},
220         { "static",             tSTATIC,                0, 1, 1},
221         { "STRING",             tSTRING,                0, 0, 0},
222         { "STRINGTABLE",        tSTRINGTABLE,           0, 0, 1},
223         { "struct",             tSTRUCT,                0, 1, 1},
224         { "STYLE",              tSTYLE,                 0, 0, 0},
225         { "TOOLBAR",            tTOOLBAR,               1, 0, 0},
226         { "typedef",            tTYPEDEF,               0, 1, 1},
227         { "VALUE",              tVALUE,                 0, 0, 0},
228         { "VERSION",            tVERSION,               1, 0, 0},
229         { "VERSIONINFO",        tVERSIONINFO,           0, 0, 0},
230         { "VIRTKEY",            tVIRTKEY,               0, 0, 0}
231 };
232
233 #define NKEYWORDS       (sizeof(keywords)/sizeof(keywords[0]))
234 #define KWP(p)          ((struct keyword *)(p))
235 static int kw_cmp_func(const void *s1, const void *s2)
236 {
237         int ret;
238         ret = strcasecmp(KWP(s1)->keyword, KWP(s2)->keyword);
239         if(!ret && (KWP(s1)->needcase || KWP(s2)->needcase))
240                 return strcmp(KWP(s1)->keyword, KWP(s2)->keyword);
241         else
242                 return ret;
243 }
244
245 #define KW_BSEARCH
246 #define DO_SORT
247 static struct keyword *iskeyword(char *kw)
248 {
249         struct keyword *kwp;
250         struct keyword key;
251         key.keyword = kw;
252         key.needcase = 0;
253 #ifdef DO_SORT
254         {
255                 /* Make sure that it is sorted for bsearsh */
256                 static int sorted = 0;
257                 if(!sorted)
258                 {
259                         qsort(keywords, NKEYWORDS, sizeof(keywords[0]), kw_cmp_func);
260                         sorted = 1;
261                 }
262         }
263 #endif
264 #ifdef KW_BSEARCH
265         kwp = bsearch(&key, keywords, NKEYWORDS, sizeof(keywords[0]), kw_cmp_func);
266 #else
267         {
268                 int i;
269                 for(i = 0; i < NKEYWORDS; i++)
270                 {
271                         if(!kw_cmp_func(&key, &keywords[i]))
272                                 break;
273                 }
274                 if(i < NKEYWORDS)
275                         kwp = &keywords[i];
276                 else
277                         kwp = NULL;
278         }
279 #endif
280
281         if(kwp == NULL || (kwp->isextension && !extensions))
282                 return NULL;
283         else
284                 return kwp;
285 }
286
287 %}
288
289 /*
290  **************************************************************************
291  * The flexer starts here
292  **************************************************************************
293  */
294 %%
295         /*
296          * Catch the GCC-style line statements here and parse them.
297          * This has the advantage that you can #include at any
298          * stage in the resource file.
299          * The preprocessor generates line directives in the format:
300          * # <linenum> "filename" <codes>
301          *
302          * Codes can be a sequence of:
303          * - 1 start of new file
304          * - 2 returning to previous
305          * - 3 system header
306          * - 4 interpret as C-code
307          *
308          * 4 is not used and 1 mutually excludes 2
309          * Anyhow, we are not really interested in these at all
310          * because we only want to know the linenumber and
311          * filename.
312          */
313 <INITIAL,pp_strips,pp_stripp>^{ws}*\#{ws}*      yy_push_state(pp_line);
314 <pp_line>[^\n]* {
315                 int lineno;
316                 char *cptr;
317                 char *fname;
318                 yy_pop_state();
319                 lineno = (int)strtol(yytext, &cptr, 10);
320                 if(!lineno)
321                         yyerror("Malformed '#...' line-directive; invalid linenumber");
322                 fname = strchr(cptr, '"');
323                 if(!fname)
324                         yyerror("Malformed '#...' line-directive; missing filename");
325                 fname++;
326                 cptr = strchr(fname, '"');
327                 if(!cptr)
328                         yyerror("Malformed '#...' line-directive; missing terminating \"");
329                 *cptr = '\0';
330                 line_number = lineno - 1;       /* We didn't read the newline */
331                 input_name = xstrdup(fname);
332         }
333
334         /*
335          * Strip everything until a ';' taking
336          * into account braces {} for structures,
337          * classes and enums.
338          */
339 <pp_strips>\{                   stripslevel++;
340 <pp_strips>\}                   stripslevel--;
341 <pp_strips>;                    if(!stripslevel) yy_pop_state();
342 <pp_strips>\/[^*\n]             ; /* To catch comments */
343 <pp_strips>[^\{\};\n#/]*        ; /* Ignore rest */
344 <pp_strips>\n                   line_number++; char_number = 1;
345
346 <pp_stripp>\(                   stripplevel++;
347 <pp_stripp>\)                   {
348                                         stripplevel--;
349                                         if(!stripplevel)
350                                         {
351                                                 yy_pop_state();
352                                                 yy_push_state(pp_stripp_final);
353                                         }
354                                 }
355 <pp_stripp>\/[^*\n]             ; /* To catch comments */
356 <pp_stripp>[^\(\);\n#/]*        ; /* Ignore rest */
357 <pp_stripp>\n                   line_number++; char_number = 1;
358
359 <pp_stripp_final>{ws}*          ; /* Ignore */
360 <pp_stripp_final>;              yy_pop_state(); /* Kill the semicolon */
361 <pp_stripp_final>\n             line_number++; char_number = 1; yy_pop_state();
362 <pp_stripp_final>.              yyless(0); yy_pop_state();
363
364 \{                      return tBEGIN;
365 \}                      return tEND;
366
367 [0-9]+[lL]?             { yylval.num = strtoul(yytext,  0, 10); return toupper(yytext[yyleng-1]) == 'L' ? tLNUMBER : tNUMBER; }
368 0[xX][0-9A-Fa-f]+[lL]?  { yylval.num = strtoul(yytext,  0, 16); return toupper(yytext[yyleng-1]) == 'L' ? tLNUMBER : tNUMBER; }
369 0[oO][0-7]+[lL]?        { yylval.num = strtoul(yytext+2, 0, 8); return toupper(yytext[yyleng-1]) == 'L' ? tLNUMBER : tNUMBER; }
370
371         /*
372          * The next two rules scan identifiers and filenames.
373          * This is achieved by using the priority ruling
374          * of the scanner where a '.' is valid in a filename
375          * and *only* in a filename. In this case, the second
376          * rule will be reduced because it is longer.
377          */
378 [A-Za-z_0-9]+           {
379                                 struct keyword *tok = iskeyword(yytext);
380
381                                 if(tok)
382                                 {
383                                         if(tok->token == tCLASS && !strcmp(yytext, "class"))
384                                                 return tCPPCLASS;
385                                         else if(wanted_id && !tok->alwayskw)
386                                         {
387                                                 yylval.str = make_string(yytext);
388                                                 return tIDENT;
389                                         }
390                                         else
391                                                 return tok->token;
392                                 }
393                                 else
394                                 {
395                                         yylval.str = make_string(yytext);
396                                         return tIDENT;
397                                 }
398                         }
399 [A-Za-z_0-9./\\]+               yylval.str = make_string(yytext); return tFILENAME;
400
401         /*
402          * Wide string scanning
403          */
404 L\"                     {
405                                 yy_push_state(yylstr);
406                                 wbufidx = 0;
407                                 if(!win32)
408                                         yywarning("16bit resource contains unicode strings\n");
409                         }
410 <yylstr>\"{ws}+ |
411 <yylstr>\"              {
412                                 yy_pop_state();
413                                 yylval.str = get_buffered_wstring();
414                                 return tSTRING;
415                         }
416 <yylstr>\\[0-7]{1,6}    { /* octal escape sequence */
417                                 int result;
418                                 result = strtol(yytext+1, 0, 8);
419                                 if ( result > 0xffff )
420                                         yyerror("Character constant out of range");
421                                 addwchar((short)result);
422                         }
423 <yylstr>\\x[0-9a-fA-F]{4} {  /* hex escape sequence */
424                                 int result;
425                                 result = strtol(yytext+2, 0, 16);
426                                 addwchar((short)result);
427                         }
428 <yylstr>\\x[0-9a-fA-F]{1,3} {  yyerror("Invalid hex escape sequence '%s'", yytext); }
429
430 <yylstr>\\[0-9]+        yyerror("Bad escape secuence");
431 <yylstr>\\a             addwchar('\a');
432 <yylstr>\\b             addwchar('\b');
433 <yylstr>\\f             addwchar('\f');
434 <yylstr>\\n             addwchar('\n');
435 <yylstr>\\r             addwchar('\r');
436 <yylstr>\\t             addwchar('\t');
437 <yylstr>\\v             addwchar('\v');
438 <yylstr>\\(\n|.)        addwchar(yytext[1]);
439 <yylstr>\\\r\n          addwchar(yytext[2]);
440 <yylstr>\"\"            addcchar('\"');         /* "bla""bla"  -> "bla\"bla" */
441 <yylstr>\\\"\"          addcchar('\"');         /* "bla\""bla" -> "bla\"bla" */
442 <yylstr>\"{ws}+\"       ;                       /* "bla" "bla" -> "blabla" */
443 <yylstr>[^\\\n\"]+      {
444                                 char *yptr = yytext;
445                                 while(*yptr)    /* FIXME: codepage translation */
446                                         addwchar(*yptr++ & 0xff);
447                         }
448 <yylstr>\n              yyerror("Unterminated string");
449
450         /*
451          * Normal string scanning
452          */
453 \"                      yy_push_state(yystr); cbufidx = 0;
454 <yystr>\"{ws}+  |
455 <yystr>\"               {
456                                 yy_pop_state();
457                                 yylval.str = get_buffered_cstring();
458                                 return tSTRING;
459                         }
460 <yystr>\\[0-7]{1,3}     { /* octal escape sequence */
461                                 int result;
462                                 result = strtol(yytext+1, 0, 8);
463                                 if ( result > 0xff )
464                                         yyerror("Character constant out of range");
465                                 addcchar((char)result);
466                         }
467 <yystr>\\x[0-9a-fA-F]{2} {  /* hex escape sequence */
468                                 int result;
469                                 result = strtol(yytext+2, 0, 16);
470                                 addcchar((char)result);
471                         }
472 <yystr>\\x[0-9a-fA-F]   {  yyerror("Invalid hex escape sequence '%s'", yytext); }
473
474 <yystr>\\[0-9]+         yyerror("Bad escape secuence");
475 <yystr>\\a              addcchar('\a');
476 <yystr>\\b              addcchar('\b');
477 <yystr>\\f              addcchar('\f');
478 <yystr>\\n              addcchar('\n');
479 <yystr>\\r              addcchar('\r');
480 <yystr>\\t              addcchar('\t');
481 <yystr>\\v              addcchar('\v');
482 <yystr>\\(\n|.)         addcchar(yytext[1]);
483 <yystr>\\\r\n           addcchar(yytext[2]);
484 <yystr>[^\\\n\"]+       {
485                                 char *yptr = yytext;
486                                 while(*yptr)
487                                         addcchar(*yptr++);
488                         }
489 <yystr>\"\"             addcchar('\"');         /* "bla""bla"   -> "bla\"bla" */
490 <yystr>\\\"\"           addcchar('\"');         /* "bla\""bla"  -> "bla\"bla" */
491 <yystr>\"{ws}+\"        ;                       /* "bla" "bla"  -> "blabla" */
492 <yystr>\n               yyerror("Unterminated string");
493
494         /*
495          * Raw data scanning
496          */
497 \'                      yy_push_state(yyrcd); cbufidx = 0;
498 <yyrcd>\'               {
499                                 yy_pop_state();
500                                 yylval.raw = new_raw_data();
501                                 yylval.raw->size = cbufidx;
502                                 yylval.raw->data = xmalloc(yylval.raw->size);
503                                 memcpy(yylval.raw->data, cbuffer, yylval.raw->size);
504                                 return tRAWDATA;
505                         }
506 <yyrcd>[0-9a-fA-F]{2}   {
507                                 int result;
508                                 result = strtol(yytext, 0, 16);
509                                 addcchar((char)result);
510                         }
511 <yyrcd>{ws}+            ;       /* Ignore space */
512 <yyrcd>\n               line_number++; char_number = 1;
513 <yyrcd>.                yyerror("Malformed data-line");
514
515         /*
516          * Comment stripping
517          * Should never occur after preprocessing
518          */
519 <INITIAL,pp_stripp,pp_strips>"/*"       {
520                                 yy_push_state(comment);
521                                 save_wanted_id = wanted_id;
522                                 if(!no_preprocess)
523                                         yywarning("Found comments after preprocessing, please report");
524                         }
525 <comment>[^*\n]*        ;
526 <comment>"*"+[^*/\n]*   ;
527 <comment>\n             line_number++; char_number = 1;
528 <comment>"*"+"/"        yy_pop_state(); want_id = save_wanted_id;
529
530 ;[^\n]*                 want_id = wanted_id; /* not really comment, but left-over c-junk */
531 "//"[^\n]*              want_id = wanted_id; if(!no_preprocess) yywarning("Found comments after preprocessing, please report");
532
533 \n                      {
534                                 want_id = wanted_id;
535                                 line_number++;
536                                 char_number = 1;
537                                 if(want_nl)
538                                 {
539                                         want_nl = 0;
540                                         return tNL;
541                                 }
542                         }
543 {ws}+                   want_id = wanted_id;    /* Eat whitespace */
544
545 <INITIAL>.              return yytext[0];
546
547 <<EOF>>                 {
548                                 if(YY_START == pp_strips || YY_START == pp_stripe || YY_START == pp_stripp || YY_START == pp_stripp_final)
549                                         yyerror("Unexpected end of file during c-junk scanning (started at %d)", cjunk_tagline);
550                                 else
551                                         yyterminate();
552                         }
553
554 <*>.|\n                 {
555                                 /* Catch all rule to find any unmatched text */
556                                 if(*yytext == '\n')
557                                 {
558                                         line_number++;
559                                         char_number = 1;
560                                 }
561                                 yywarning("Unmatched text '%c' (0x%02x) YY_START=%d stripslevel=%d",
562                                         isprint(*yytext & 0xff) ? *yytext : '.', *yytext, YY_START,stripslevel);
563                         }
564
565 %%
566
567 #ifndef yywrap
568 int yywrap(void)
569 {
570 #if 0
571         if(bufferstackidx > 0)
572         {
573                 return 0;
574         }
575 #endif
576         return 1;
577 }
578 #endif
579
580 /* These dup functions copy the enclosed '\0' from
581  * the resource string.
582  */
583 static void addcchar(char c)
584 {
585         if(cbufidx >= cbufalloc)
586         {
587                 cbufalloc += 1024;
588                 cbuffer = xrealloc(cbuffer, cbufalloc * sizeof(cbuffer[0]));
589                 if(cbufalloc > 65536)
590                         yywarning("Reallocating string buffer larger than 64kB");
591         }
592         cbuffer[cbufidx++] = c;
593 }
594
595 static void addwchar(short s)
596 {
597         if(wbufidx >= wbufalloc)
598         {
599                 wbufalloc += 1024;
600                 wbuffer = xrealloc(wbuffer, wbufalloc * sizeof(wbuffer[0]));
601                 if(wbufalloc > 65536)
602                         yywarning("Reallocating wide string buffer larger than 64kB");
603         }
604
605         /*
606          * BS 08-Aug-1999 FIXME: The '& 0xff' is probably a bug, but I have
607          * not experienced it yet and I seem to remember that this was for
608          * a reason. But, as so many things you tend to forget why.
609          * I guess that there were problems due to the sign extension of
610          * shorts WRT chars (e.g. 0x80 becomes 0xff80 instead of 0x0080).
611          * This should then be fixed in the lexer calling the function.
612          */
613         wbuffer[wbufidx++] = (short)(s & 0xff);
614 }
615
616 static string_t *get_buffered_cstring(void)
617 {
618         string_t *str = new_string();
619         str->size = cbufidx;
620         str->type = str_char;
621         str->str.cstr = (char *)xmalloc(cbufidx+1);
622         memcpy(str->str.cstr, cbuffer, cbufidx);
623         str->str.cstr[cbufidx] = '\0';
624         return str;
625 }
626
627 static string_t *get_buffered_wstring(void)
628 {
629         string_t *str = new_string();
630         str->size = wbufidx;
631         str->type = str_unicode;
632         str->str.wstr = (short *)xmalloc(2*(wbufidx+1));
633         memcpy(str->str.wstr, wbuffer, wbufidx);
634         str->str.wstr[wbufidx] = 0;
635         return str;
636 }
637
638 static string_t *make_string(char *s)
639 {
640         string_t *str = new_string();
641         str->size = strlen(s);
642         str->type = str_char;
643         str->str.cstr = (char *)xmalloc(str->size+1);
644         memcpy(str->str.cstr, s, str->size+1);
645         return str;
646 }
647
648 /* Called from the parser to kill c-junk */
649 void strip_extern(void)
650 {
651         cjunk_tagline = line_number;
652         yy_push_state(pp_stripe);
653 }
654
655 void strip_til_semicolon(void)
656 {
657         cjunk_tagline = line_number;
658         yy_push_state(pp_strips);
659 }
660
661 void strip_til_parenthesis(void)
662 {
663         cjunk_tagline = line_number;
664         stripplevel = 1;        /* One scanned already */
665         yy_push_state(pp_stripp);
666 }
667