]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - binutils/rclex.c
Automatic date update in version.in
[thirdparty/binutils-gdb.git] / binutils / rclex.c
CommitLineData
4a594fce
NC
1/* rclex.c -- lexer for Windows rc files parser */
2
fd67aa11 3/* Copyright (C) 1997-2024 Free Software Foundation, Inc.
4a594fce
NC
4
5 Written by Kai Tietz, Onevision.
6
7 This file is part of GNU Binutils.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
32866df7 11 the Free Software Foundation; either version 3 of the License, or
4a594fce
NC
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
22 02110-1301, USA. */
23
32866df7 24
4a594fce
NC
25/* This is a lexer used by the Windows rc file parser. It basically
26 just recognized a bunch of keywords. */
27
28#include "sysdep.h"
29#include "bfd.h"
30#include "bucomm.h"
31#include "libiberty.h"
32#include "safe-ctype.h"
33#include "windres.h"
34#include "rcparse.h"
35
36#include <assert.h>
37
38/* Whether we are in rcdata mode, in which we returns the lengths of
39 strings. */
40
41static int rcdata_mode;
42
222c2bf0 43/* Whether we are suppressing lines from cpp (including windows.h or
4a594fce
NC
44 headers from your C sources may bring in externs and typedefs).
45 When active, we return IGNORED_TOKEN, which lets us ignore these
46 outside of resource constructs. Thus, it isn't required to protect
47 all the non-preprocessor lines in your header files with #ifdef
48 RC_INVOKED. It also means your RC file can't include other RC
49 files if they're named "*.h". Sorry. Name them *.rch or whatever. */
50
51static int suppress_cpp_data;
52
53#define IGNORE_CPP(x) (suppress_cpp_data ? IGNORED_TOKEN : (x))
54
55/* The first filename we detect in the cpp output. We use this to
56 tell included files from the original file. */
57
58static char *initial_fn;
59
60/* List of allocated strings. */
61
62struct alloc_string
63{
64 struct alloc_string *next;
65 char *s;
66};
67
68static struct alloc_string *strings;
69
70struct rclex_keywords
71{
72 const char *name;
73 int tok;
74};
75
76#define K(KEY) { #KEY, KEY }
77#define KRT(KEY) { #KEY, RT_##KEY }
78
79static const struct rclex_keywords keywds[] =
80{
81 K(ACCELERATORS), K(ALT), K(ANICURSOR), K(ANIICON), K(ASCII),
82 K(AUTO3STATE), K(AUTOCHECKBOX), K(AUTORADIOBUTTON),
83 K(BEDIT), { "BEGIN", BEG }, K(BITMAP), K(BLOCK), K(BUTTON),
84 K(CAPTION), K(CHARACTERISTICS), K(CHECKBOX), K(CHECKED),
85 K(CLASS), K(COMBOBOX), K(CONTROL), K(CTEXT), K(CURSOR),
86 K(DEFPUSHBUTTON), K(DIALOG), K(DIALOGEX), K(DISCARDABLE),
87 K(DLGINCLUDE), K(DLGINIT),
88 K(EDITTEXT), K(END), K(EXSTYLE),
89 K(FILEFLAGS), K(FILEFLAGSMASK), K(FILEOS), K(FILESUBTYPE),
90 K(FILETYPE), K(FILEVERSION), K(FIXED), K(FONT), K(FONTDIR),
91 K(GRAYED), KRT(GROUP_CURSOR), KRT(GROUP_ICON), K(GROUPBOX),
92 K(HEDIT), K(HELP), K(HTML),
93 K(ICON), K(IEDIT), K(IMPURE), K(INACTIVE),
94 K(LANGUAGE), K(LISTBOX), K(LOADONCALL), K(LTEXT),
95 K(MANIFEST), K(MENU), K(MENUBARBREAK), K(MENUBREAK),
96 K(MENUEX), K(MENUITEM), K(MESSAGETABLE), K(MOVEABLE),
d90171de 97 K(NOINVERT), K(NOT), K(OWNERDRAW),
4a594fce
NC
98 K(PLUGPLAY), K(POPUP), K(PRELOAD), K(PRODUCTVERSION),
99 K(PURE), K(PUSHBOX), K(PUSHBUTTON),
100 K(RADIOBUTTON), K(RCDATA), K(RTEXT),
101 K(SCROLLBAR), K(SEPARATOR), K(SHIFT), K(STATE3),
102 K(STRINGTABLE), K(STYLE),
103 K(TOOLBAR),
104 K(USERBUTTON),
105 K(VALUE), { "VERSION", VERSIONK }, K(VERSIONINFO),
106 K(VIRTKEY), K(VXD),
107 { NULL, 0 },
108};
109
110/* External input stream from resrc */
111extern FILE *cpp_pipe;
112
113/* Lexical scanner helpers. */
114static int rclex_lastch = -1;
115static size_t rclex_tok_max = 0;
116static size_t rclex_tok_pos = 0;
117static char *rclex_tok = NULL;
118
119static int
120rclex_translatekeyword (const char *key)
121{
122 if (key && ISUPPER (key[0]))
123 {
124 const struct rclex_keywords *kw = &keywds[0];
125
126 do
127 {
128 if (! strcmp (kw->name, key))
129 return kw->tok;
130 ++kw;
131 }
132 while (kw->name != NULL);
133 }
134 return STRING;
135}
136
137/* Handle a C preprocessor line. */
138
139static void
140cpp_line (void)
141{
142 const char *s = rclex_tok;
143 int line;
144 char *send, *fn;
d856f2dd 145 size_t len, mlen;
4a594fce
NC
146
147 ++s;
148 while (ISSPACE (*s))
149 ++s;
3aade688 150
d856f2dd
NC
151 /* Check for #pragma code_page ( DEFAULT | <nr>). */
152 len = strlen (s);
153 mlen = strlen ("pragma");
154 if (len > mlen && memcmp (s, "pragma", mlen) == 0 && ISSPACE (s[mlen]))
155 {
156 const char *end;
157
158 s += mlen + 1;
159 while (ISSPACE (*s))
160 ++s;
161 len = strlen (s);
162 mlen = strlen ("code_page");
163 if (len <= mlen || memcmp (s, "code_page", mlen) != 0)
164 /* FIXME: We ought to issue a warning message about an unrecognised pragma. */
165 return;
166 s += mlen;
167 while (ISSPACE (*s))
168 ++s;
169 if (*s != '(')
170 /* FIXME: We ought to issue an error message about a malformed pragma. */
171 return;
172 ++s;
173 while (ISSPACE (*s))
174 ++s;
175 if (*s == 0 || (end = strchr (s, ')')) == NULL)
176 /* FIXME: We ought to issue an error message about a malformed pragma. */
177 return;
178 len = (size_t) (end - s);
179 fn = xmalloc (len + 1);
180 if (len)
181 memcpy (fn, s, len);
182 fn[len] = 0;
183 while (len > 0 && (fn[len - 1] > 0 && fn[len - 1] <= 0x20))
184 fn[--len] = 0;
185 if (! len || (len == strlen ("DEFAULT") && strcasecmp (fn, "DEFAULT") == 0))
186 wind_current_codepage = wind_default_codepage;
187 else if (len > 0)
188 {
189 rc_uint_type ncp;
190
191 if (fn[0] == '0' && (fn[1] == 'x' || fn[1] == 'X'))
192 ncp = (rc_uint_type) strtol (fn + 2, NULL, 16);
193 else
194 ncp = (rc_uint_type) strtol (fn, NULL, 10);
195 if (ncp == CP_UTF16 || ! unicode_is_valid_codepage (ncp))
196 fatal (_("invalid value specified for pragma code_page.\n"));
197 wind_current_codepage = ncp;
198 }
199 free (fn);
200 return;
201 }
202
4a594fce
NC
203 line = strtol (s, &send, 0);
204 if (*send != '\0' && ! ISSPACE (*send))
205 return;
206
207 /* Subtract 1 because we are about to count the newline. */
208 rc_lineno = line - 1;
209
210 s = send;
211 while (ISSPACE (*s))
212 ++s;
213
214 if (*s != '"')
215 return;
216
217 ++s;
218 send = strchr (s, '"');
219 if (send == NULL)
220 return;
221
222 fn = xmalloc (send - s + 1);
223 strncpy (fn, s, send - s);
224 fn[send - s] = '\0';
225
226 free (rc_filename);
227 rc_filename = fn;
228
229 if (! initial_fn)
230 {
231 initial_fn = xmalloc (strlen (fn) + 1);
232 strcpy (initial_fn, fn);
233 }
234
235 /* Allow the initial file, regardless of name. Suppress all other
236 files if they end in ".h" (this allows included "*.rc"). */
237 if (strcmp (initial_fn, fn) == 0
238 || strcmp (fn + strlen (fn) - 2, ".h") != 0)
239 suppress_cpp_data = 0;
240 else
241 suppress_cpp_data = 1;
242}
243
244/* Allocate a string of a given length. */
245
246static char *
247get_string (int len)
248{
249 struct alloc_string *as;
250
251 as = xmalloc (sizeof *as);
252 as->s = xmalloc (len);
253
254 as->next = strings;
255 strings = as;
256
257 return as->s;
258}
259
260/* Handle a quoted string. The quotes are stripped. A pair of quotes
261 in a string are turned into a single quote. Adjacent strings are
262 merged separated by whitespace are merged, as in C. */
263
264static char *
265handle_quotes (rc_uint_type *len)
266{
267 const char *input = rclex_tok;
268 char *ret, *s;
269 const char *t;
270 int ch;
271 int num_xdigits;
272
273 ret = get_string (strlen (input) + 1);
274
275 s = ret;
276 t = input;
277 if (*t == '"')
278 ++t;
279 while (*t != '\0')
280 {
281 if (*t == '\\')
282 {
283 ++t;
284 switch (*t)
285 {
286 case '\0':
287 rcparse_warning ("backslash at end of string");
288 break;
289
290 case '\"':
291 rcparse_warning ("use \"\" to put \" in a string");
292 *s++ = '"';
293 ++t;
294 break;
295
296 case 'a':
297 *s++ = ESCAPE_B; /* Strange, but true... */
298 ++t;
299 break;
300
301 case 'b':
302 *s++ = ESCAPE_B;
303 ++t;
304 break;
305
306 case 'f':
307 *s++ = ESCAPE_F;
308 ++t;
309 break;
310
311 case 'n':
312 *s++ = ESCAPE_N;
313 ++t;
314 break;
315
316 case 'r':
317 *s++ = ESCAPE_R;
318 ++t;
319 break;
320
321 case 't':
322 *s++ = ESCAPE_T;
323 ++t;
324 break;
325
326 case 'v':
327 *s++ = ESCAPE_V;
328 ++t;
329 break;
330
331 case '\\':
332 *s++ = *t++;
333 break;
334
335 case '0': case '1': case '2': case '3':
336 case '4': case '5': case '6': case '7':
337 ch = *t - '0';
338 ++t;
339 if (*t >= '0' && *t <= '7')
340 {
341 ch = (ch << 3) | (*t - '0');
342 ++t;
343 if (*t >= '0' && *t <= '7')
344 {
345 ch = (ch << 3) | (*t - '0');
346 ++t;
347 }
348 }
349 *s++ = ch;
350 break;
351
352 case 'x': case 'X':
353 ++t;
354 ch = 0;
355 /* We only handle single byte chars here. Make sure
356 we finish an escape sequence like "/xB0ABC" after
357 the first two digits. */
358 num_xdigits = 2;
359 while (num_xdigits--)
360 {
361 if (*t >= '0' && *t <= '9')
362 ch = (ch << 4) | (*t - '0');
363 else if (*t >= 'a' && *t <= 'f')
364 ch = (ch << 4) | (*t - 'a' + 10);
365 else if (*t >= 'A' && *t <= 'F')
366 ch = (ch << 4) | (*t - 'A' + 10);
367 else
368 break;
369 ++t;
370 }
371 *s++ = ch;
372 break;
373
374 default:
375 rcparse_warning ("unrecognized escape sequence");
376 *s++ = '\\';
377 *s++ = *t++;
378 break;
379 }
380 }
381 else if (*t != '"')
382 *s++ = *t++;
383 else if (t[1] == '\0')
384 break;
385 else if (t[1] == '"')
386 {
387 *s++ = '"';
388 t += 2;
389 }
390 else
391 {
4a594fce 392 ++t;
a87a00ea
NC
393 if (! ISSPACE (*t))
394 rcparse_warning ("unexpected character after '\"'");
4a594fce
NC
395 while (ISSPACE (*t))
396 {
397 if ((*t) == '\n')
398 ++rc_lineno;
399 ++t;
400 }
401 if (*t == '\0')
402 break;
403 assert (*t == '"');
404 ++t;
405 }
406 }
407
408 *s = '\0';
409
410 *len = s - ret;
411
412 return ret;
413}
414
415/* Allocate a unicode string of a given length. */
416
417static unichar *
418get_unistring (int len)
419{
420 return (unichar *) get_string (len * sizeof (unichar));
421}
422
423/* Handle a quoted unicode string. The quotes are stripped. A pair of quotes
424 in a string are turned into a single quote. Adjacent strings are
425 merged separated by whitespace are merged, as in C. */
426
427static unichar *
428handle_uniquotes (rc_uint_type *len)
429{
430 const char *input = rclex_tok;
431 unichar *ret, *s;
432 const char *t;
433 int ch;
434 int num_xdigits;
435
436 ret = get_unistring (strlen (input) + 1);
437
438 s = ret;
439 t = input;
440 if ((*t == 'L' || *t == 'l') && t[1] == '"')
441 t += 2;
442 else if (*t == '"')
443 ++t;
444 while (*t != '\0')
445 {
446 if (*t == '\\')
447 {
448 ++t;
449 switch (*t)
450 {
451 case '\0':
452 rcparse_warning ("backslash at end of string");
453 break;
454
455 case '\"':
456 rcparse_warning ("use \"\" to put \" in a string");
457 break;
458
459 case 'a':
460 *s++ = ESCAPE_B; /* Strange, but true... */
461 ++t;
462 break;
463
464 case 'b':
465 *s++ = ESCAPE_B;
466 ++t;
467 break;
468
469 case 'f':
470 *s++ = ESCAPE_F;
471 ++t;
472 break;
473
474 case 'n':
475 *s++ = ESCAPE_N;
476 ++t;
477 break;
478
479 case 'r':
480 *s++ = ESCAPE_R;
481 ++t;
482 break;
483
484 case 't':
485 *s++ = ESCAPE_T;
486 ++t;
487 break;
488
489 case 'v':
490 *s++ = ESCAPE_V;
491 ++t;
492 break;
493
494 case '\\':
495 *s++ = (unichar) *t++;
496 break;
497
498 case '0': case '1': case '2': case '3':
499 case '4': case '5': case '6': case '7':
500 ch = *t - '0';
501 ++t;
502 if (*t >= '0' && *t <= '7')
503 {
504 ch = (ch << 3) | (*t - '0');
505 ++t;
506 if (*t >= '0' && *t <= '7')
507 {
508 ch = (ch << 3) | (*t - '0');
509 ++t;
510 }
511 }
512 *s++ = (unichar) ch;
513 break;
514
515 case 'x': case 'X':
516 ++t;
517 ch = 0;
518 /* We only handle two byte chars here. Make sure
519 we finish an escape sequence like "/xB0ABC" after
520 the first two digits. */
521 num_xdigits = 4;
522 while (num_xdigits--)
523 {
524 if (*t >= '0' && *t <= '9')
525 ch = (ch << 4) | (*t - '0');
526 else if (*t >= 'a' && *t <= 'f')
527 ch = (ch << 4) | (*t - 'a' + 10);
528 else if (*t >= 'A' && *t <= 'F')
529 ch = (ch << 4) | (*t - 'A' + 10);
530 else
531 break;
532 ++t;
533 }
534 *s++ = (unichar) ch;
535 break;
536
537 default:
538 rcparse_warning ("unrecognized escape sequence");
539 *s++ = '\\';
540 *s++ = (unichar) *t++;
541 break;
542 }
543 }
544 else if (*t != '"')
545 *s++ = (unichar) *t++;
546 else if (t[1] == '\0')
547 break;
548 else if (t[1] == '"')
549 {
550 *s++ = '"';
551 t += 2;
552 }
553 else
554 {
555 ++t;
556 assert (ISSPACE (*t));
557 while (ISSPACE (*t))
558 {
559 if ((*t) == '\n')
560 ++rc_lineno;
561 ++t;
562 }
563 if (*t == '\0')
564 break;
565 assert (*t == '"');
566 ++t;
567 }
568 }
569
570 *s = '\0';
571
572 *len = s - ret;
573
574 return ret;
575}
576
577/* Discard all the strings we have allocated. The parser calls this
578 when it no longer needs them. */
579
580void
581rcparse_discard_strings (void)
582{
583 struct alloc_string *as;
584
585 as = strings;
586 while (as != NULL)
587 {
588 struct alloc_string *n;
589
590 free (as->s);
591 n = as->next;
592 free (as);
593 as = n;
594 }
595
596 strings = NULL;
597}
598
599/* Enter rcdata mode. */
600void
601rcparse_rcdata (void)
602{
603 rcdata_mode = 1;
604}
605
606/* Go back to normal mode from rcdata mode. */
607void
608rcparse_normal (void)
609{
610 rcdata_mode = 0;
611}
612
613static void
614rclex_tok_add_char (int ch)
615{
616 if (! rclex_tok || rclex_tok_max <= rclex_tok_pos)
617 {
618 char *h = xmalloc (rclex_tok_max + 9);
619
620 if (! h)
621 abort ();
622 if (rclex_tok)
623 {
624 memcpy (h, rclex_tok, rclex_tok_pos + 1);
625 free (rclex_tok);
626 }
627 else
628 rclex_tok_pos = 0;
629 rclex_tok_max += 8;
630 rclex_tok = h;
631 }
632 if (ch != -1)
633 rclex_tok[rclex_tok_pos++] = (char) ch;
634 rclex_tok[rclex_tok_pos] = 0;
635}
636
637static int
638rclex_readch (void)
639{
640 int r = -1;
641
642 if ((r = rclex_lastch) != -1)
643 rclex_lastch = -1;
644 else
645 {
646 char ch;
647 do
648 {
649 if (! cpp_pipe || feof (cpp_pipe)
650 || fread (&ch, 1, 1,cpp_pipe) != 1)
651 break;
652 r = ((int) ch) & 0xff;
653 }
654 while (r == 0 || r == '\r');
655 }
656 rclex_tok_add_char (r);
657 return r;
658}
659
660static int
661rclex_peekch (void)
662{
663 int r;
664
665 if ((r = rclex_lastch) == -1)
666 {
667 if ((r = rclex_readch ()) != -1)
668 {
669 rclex_lastch = r;
670 if (rclex_tok_pos > 0)
671 rclex_tok[--rclex_tok_pos] = 0;
672 }
673 }
674 return r;
675}
676
677static void
678rclex_string (void)
679{
680 int c;
a87a00ea 681
4a594fce
NC
682 while ((c = rclex_peekch ()) != -1)
683 {
684 if (c == '\n')
685 break;
686 if (c == '\\')
687 {
688 rclex_readch ();
689 if ((c = rclex_peekch ()) == -1 || c == '\n')
690 break;
691 rclex_readch ();
692 }
693 else if (rclex_readch () == '"')
694 {
a87a00ea
NC
695 /* PR 6714
696 Skip any whitespace after the end of the double quotes. */
697 do
698 {
699 c = rclex_peekch ();
700 if (ISSPACE (c))
701 rclex_readch ();
702 else
703 c = -1;
704 }
705 while (c != -1);
3aade688 706
4a594fce
NC
707 if (rclex_peekch () == '"')
708 rclex_readch ();
709 else
710 break;
711 }
712 }
713}
714
715static rc_uint_type
716read_digit (int ch)
717{
718 rc_uint_type base = 10;
719 rc_uint_type ret, val;
720 int warned = 0;
721
722 ret = 0;
723 if (ch == '0')
724 {
725 base = 8;
726 switch (rclex_peekch ())
727 {
728 case 'o': case 'O':
729 rclex_readch ();
730 base = 8;
731 break;
732
733 case 'x': case 'X':
734 rclex_readch ();
735 base = 16;
736 break;
737 }
738 }
739 else
740 ret = (rc_uint_type) (ch - '0');
741 while ((ch = rclex_peekch ()) != -1)
742 {
743 if (ISDIGIT (ch))
744 val = (rc_uint_type) (ch - '0');
745 else if (ch >= 'a' && ch <= 'f')
746 val = (rc_uint_type) ((ch - 'a') + 10);
747 else if (ch >= 'A' && ch <= 'F')
748 val = (rc_uint_type) ((ch - 'A') + 10);
749 else
750 break;
751 rclex_readch ();
752 if (! warned && val >= base)
753 {
754 warned = 1;
755 rcparse_warning ("digit exceeds base");
756 }
757 ret *= base;
758 ret += val;
759 }
760 return ret;
761}
762
763/* yyparser entry method. */
764
765int
766yylex (void)
767{
768 char *s;
769 unichar *us;
770 rc_uint_type length;
771 int ch;
772
773 /* Make sure that rclex_tok is initialized. */
774 if (! rclex_tok)
775 rclex_tok_add_char (-1);
776
777 do
778 {
779 do
780 {
781 /* Clear token. */
782 rclex_tok_pos = 0;
783 rclex_tok[0] = 0;
3aade688 784
4a594fce
NC
785 if ((ch = rclex_readch ()) == -1)
786 return -1;
787 if (ch == '\n')
788 ++rc_lineno;
789 }
790 while (ch <= 0x20);
791
792 switch (ch)
793 {
794 case '#':
795 while ((ch = rclex_peekch ()) != -1 && ch != '\n')
796 rclex_readch ();
797 cpp_line ();
798 ch = IGNORED_TOKEN;
799 break;
3aade688 800
4a594fce
NC
801 case '{':
802 ch = IGNORE_CPP (BEG);
803 break;
3aade688 804
4a594fce
NC
805 case '}':
806 ch = IGNORE_CPP (END);
807 break;
3aade688 808
4a594fce
NC
809 case '0': case '1': case '2': case '3': case '4':
810 case '5': case '6': case '7': case '8': case '9':
811 yylval.i.val = read_digit (ch);
812 yylval.i.dword = 0;
813 switch (rclex_peekch ())
814 {
815 case 'l': case 'L':
816 rclex_readch ();
817 yylval.i.dword = 1;
818 break;
819 }
820 ch = IGNORE_CPP (NUMBER);
821 break;
822 case '"':
823 rclex_string ();
824 ch = IGNORE_CPP ((! rcdata_mode ? QUOTEDSTRING : SIZEDSTRING));
825 if (ch == IGNORED_TOKEN)
826 break;
827 s = handle_quotes (&length);
828 if (! rcdata_mode)
829 yylval.s = s;
830 else
831 {
832 yylval.ss.length = length;
833 yylval.ss.s = s;
834 }
835 break;
836 case 'L': case 'l':
837 if (rclex_peekch () == '"')
838 {
839 rclex_readch ();
840 rclex_string ();
841 ch = IGNORE_CPP ((! rcdata_mode ? QUOTEDUNISTRING : SIZEDUNISTRING));
842 if (ch == IGNORED_TOKEN)
843 break;
844 us = handle_uniquotes (&length);
845 if (! rcdata_mode)
846 yylval.uni = us;
847 else
848 {
849 yylval.suni.length = length;
850 yylval.suni.s = us;
851 }
852 break;
853 }
854 /* Fall through. */
855 default:
856 if (ISIDST (ch) || ch=='$')
857 {
aeafac0c
KT
858 while ((ch = rclex_peekch ()) != -1
859 && (ISIDNUM (ch) || ch == '$' || ch == '.'
860 || ch == ':' || ch == '\\' || ch == '/'
e36ea2de 861 || ch == '_' || ch == '-')
aeafac0c 862 )
4a594fce
NC
863 rclex_readch ();
864 ch = IGNORE_CPP (rclex_translatekeyword (rclex_tok));
865 if (ch == STRING)
866 {
867 s = get_string (strlen (rclex_tok) + 1);
868 strcpy (s, rclex_tok);
869 yylval.s = s;
870 }
871 else if (ch == BLOCK)
872 {
873 const char *hs = NULL;
874
875 switch (yylex ())
876 {
877 case STRING:
878 case QUOTEDSTRING:
879 hs = yylval.s;
880 break;
881 case SIZEDSTRING:
882 hs = yylval.s = yylval.ss.s;
883 break;
884 }
885 if (! hs)
886 {
887 rcparse_warning ("BLOCK expects a string as argument.");
888 ch = IGNORED_TOKEN;
889 }
890 else if (! strcmp (hs, "StringFileInfo"))
891 ch = BLOCKSTRINGFILEINFO;
892 else if (! strcmp (hs, "VarFileInfo"))
893 ch = BLOCKVARFILEINFO;
894 }
895 break;
896 }
897 ch = IGNORE_CPP (ch);
898 break;
899 }
900 }
901 while (ch == IGNORED_TOKEN);
902
903 return ch;
904}