1218822Sdim/* rclex.c -- lexer for Windows rc files parser */ 238889Sjdp 3218822Sdim/* Copyright 1997, 1998, 1999, 2001, 2002, 2003, 2005, 2006, 2007 4218822Sdim Free Software Foundation, Inc. 538889Sjdp 6218822Sdim Written by Kai Tietz, Onevision. 738889Sjdp 838889Sjdp This file is part of GNU Binutils. 938889Sjdp 1038889Sjdp This program is free software; you can redistribute it and/or modify 1138889Sjdp it under the terms of the GNU General Public License as published by 1238889Sjdp the Free Software Foundation; either version 2 of the License, or 1338889Sjdp (at your option) any later version. 1438889Sjdp 1538889Sjdp This program is distributed in the hope that it will be useful, 1638889Sjdp but WITHOUT ANY WARRANTY; without even the implied warranty of 1738889Sjdp MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1838889Sjdp GNU General Public License for more details. 1938889Sjdp 2038889Sjdp You should have received a copy of the GNU General Public License 2138889Sjdp along with this program; if not, write to the Free Software 22218822Sdim Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 23218822Sdim 02110-1301, USA. */ 2438889Sjdp 25218822Sdim/* This is a lexer used by the Windows rc file parser. It basically 26218822Sdim just recognized a bunch of keywords. */ 2738889Sjdp 28218822Sdim#include "sysdep.h" 2938889Sjdp#include "bfd.h" 3038889Sjdp#include "bucomm.h" 3138889Sjdp#include "libiberty.h" 3292828Sobrien#include "safe-ctype.h" 3338889Sjdp#include "windres.h" 3438889Sjdp#include "rcparse.h" 3538889Sjdp 3638889Sjdp#include <assert.h> 3738889Sjdp 3838889Sjdp/* Whether we are in rcdata mode, in which we returns the lengths of 3938889Sjdp strings. */ 4038889Sjdp 4138889Sjdpstatic int rcdata_mode; 4238889Sjdp 4361843Sobrien/* Whether we are supressing lines from cpp (including windows.h or 4461843Sobrien headers from your C sources may bring in externs and typedefs). 4561843Sobrien When active, we return IGNORED_TOKEN, which lets us ignore these 4661843Sobrien outside of resource constructs. Thus, it isn't required to protect 4761843Sobrien all the non-preprocessor lines in your header files with #ifdef 4861843Sobrien RC_INVOKED. It also means your RC file can't include other RC 4961843Sobrien files if they're named "*.h". Sorry. Name them *.rch or whatever. */ 5061843Sobrien 5161843Sobrienstatic int suppress_cpp_data; 5261843Sobrien 53218822Sdim#define IGNORE_CPP(x) (suppress_cpp_data ? IGNORED_TOKEN : (x)) 5461843Sobrien 5561843Sobrien/* The first filename we detect in the cpp output. We use this to 5661843Sobrien tell included files from the original file. */ 5761843Sobrien 5861843Sobrienstatic char *initial_fn; 5961843Sobrien 6038889Sjdp/* List of allocated strings. */ 6138889Sjdp 6238889Sjdpstruct alloc_string 6338889Sjdp{ 6438889Sjdp struct alloc_string *next; 6538889Sjdp char *s; 6638889Sjdp}; 6738889Sjdp 6838889Sjdpstatic struct alloc_string *strings; 6938889Sjdp 70218822Sdimstruct rclex_keywords 71218822Sdim{ 72218822Sdim const char *name; 73218822Sdim int tok; 74218822Sdim}; 7538889Sjdp 76218822Sdim#define K(KEY) { #KEY, KEY } 77218822Sdim#define KRT(KEY) { #KEY, RT_##KEY } 7838889Sjdp 79218822Sdimstatic const struct rclex_keywords keywds[] = 8038889Sjdp{ 81218822Sdim K(ACCELERATORS), K(ALT), K(ANICURSOR), K(ANIICON), K(ASCII), 82218822Sdim K(AUTO3STATE), K(AUTOCHECKBOX), K(AUTORADIOBUTTON), 83218822Sdim K(BEDIT), { "BEGIN", BEG }, K(BITMAP), K(BLOCK), K(BUTTON), 84218822Sdim K(CAPTION), K(CHARACTERISTICS), K(CHECKBOX), K(CHECKED), 85218822Sdim K(CLASS), K(COMBOBOX), K(CONTROL), K(CTEXT), K(CURSOR), 86218822Sdim K(DEFPUSHBUTTON), K(DIALOG), K(DIALOGEX), K(DISCARDABLE), 87218822Sdim K(DLGINCLUDE), K(DLGINIT), 88218822Sdim K(EDITTEXT), K(END), K(EXSTYLE), 89218822Sdim K(FILEFLAGS), K(FILEFLAGSMASK), K(FILEOS), K(FILESUBTYPE), 90218822Sdim K(FILETYPE), K(FILEVERSION), K(FIXED), K(FONT), K(FONTDIR), 91218822Sdim K(GRAYED), KRT(GROUP_CURSOR), KRT(GROUP_ICON), K(GROUPBOX), 92218822Sdim K(HEDIT), K(HELP), K(HTML), 93218822Sdim K(ICON), K(IEDIT), K(IMPURE), K(INACTIVE), 94218822Sdim K(LANGUAGE), K(LISTBOX), K(LOADONCALL), K(LTEXT), 95218822Sdim K(MANIFEST), K(MENU), K(MENUBARBREAK), K(MENUBREAK), 96218822Sdim K(MENUEX), K(MENUITEM), K(MESSAGETABLE), K(MOVEABLE), 97218822Sdim K(NOINVERT), K(NOT), 98218822Sdim K(PLUGPLAY), K(POPUP), K(PRELOAD), K(PRODUCTVERSION), 99218822Sdim K(PURE), K(PUSHBOX), K(PUSHBUTTON), 100218822Sdim K(RADIOBUTTON), K(RCDATA), K(RTEXT), 101218822Sdim K(SCROLLBAR), K(SEPARATOR), K(SHIFT), K(STATE3), 102218822Sdim K(STRINGTABLE), K(STYLE), 103218822Sdim K(TOOLBAR), 104218822Sdim K(USERBUTTON), 105218822Sdim K(VALUE), { "VERSION", VERSIONK }, K(VERSIONINFO), 106218822Sdim K(VIRTKEY), K(VXD), 107218822Sdim { NULL, 0 }, 108218822Sdim}; 10938889Sjdp 110218822Sdim/* External input stream from resrc */ 111218822Sdimextern FILE *cpp_pipe; 11238889Sjdp 113218822Sdim/* Lexical scanner helpers. */ 114218822Sdimstatic int rclex_lastch = -1; 115218822Sdimstatic size_t rclex_tok_max = 0; 116218822Sdimstatic size_t rclex_tok_pos = 0; 117218822Sdimstatic char *rclex_tok = NULL; 11838889Sjdp 119218822Sdimstatic int 120218822Sdimrclex_translatekeyword (const char *key) 12138889Sjdp{ 122218822Sdim if (key && ISUPPER (key[0])) 123218822Sdim { 124218822Sdim const struct rclex_keywords *kw = &keywds[0]; 12538889Sjdp 126218822Sdim do 127218822Sdim { 128218822Sdim if (! strcmp (kw->name, key)) 129218822Sdim return kw->tok; 130218822Sdim ++kw; 131218822Sdim } 132218822Sdim while (kw->name != NULL); 133218822Sdim } 134218822Sdim return STRING; 13538889Sjdp} 13638889Sjdp 13738889Sjdp/* Handle a C preprocessor line. */ 13838889Sjdp 13938889Sjdpstatic void 140218822Sdimcpp_line (void) 14138889Sjdp{ 142218822Sdim const char *s = rclex_tok; 14338889Sjdp int line; 14438889Sjdp char *send, *fn; 145218822Sdim size_t len, mlen; 14638889Sjdp 14738889Sjdp ++s; 14892828Sobrien while (ISSPACE (*s)) 14938889Sjdp ++s; 15038889Sjdp 151218822Sdim /* Check for #pragma code_page ( DEFAULT | <nr>). */ 152218822Sdim len = strlen (s); 153218822Sdim mlen = strlen ("pragma"); 154218822Sdim if (len > mlen && memcmp (s, "pragma", mlen) == 0 && ISSPACE (s[mlen])) 155218822Sdim { 156218822Sdim const char *end; 157218822Sdim 158218822Sdim s += mlen + 1; 159218822Sdim while (ISSPACE (*s)) 160218822Sdim ++s; 161218822Sdim len = strlen (s); 162218822Sdim mlen = strlen ("code_page"); 163218822Sdim if (len <= mlen || memcmp (s, "code_page", mlen) != 0) 164218822Sdim /* FIXME: We ought to issue a warning message about an unrecognised pragma. */ 165218822Sdim return; 166218822Sdim s += mlen; 167218822Sdim while (ISSPACE (*s)) 168218822Sdim ++s; 169218822Sdim if (*s != '(') 170218822Sdim /* FIXME: We ought to issue an error message about a malformed pragma. */ 171218822Sdim return; 172218822Sdim ++s; 173218822Sdim while (ISSPACE (*s)) 174218822Sdim ++s; 175218822Sdim if (*s == 0 || (end = strchr (s, ')')) == NULL) 176218822Sdim /* FIXME: We ought to issue an error message about a malformed pragma. */ 177218822Sdim return; 178218822Sdim len = (size_t) (end - s); 179218822Sdim fn = xmalloc (len + 1); 180218822Sdim if (len) 181218822Sdim memcpy (fn, s, len); 182218822Sdim fn[len] = 0; 183218822Sdim while (len > 0 && (fn[len - 1] > 0 && fn[len - 1] <= 0x20)) 184218822Sdim fn[--len] = 0; 185218822Sdim if (! len || (len == strlen ("DEFAULT") && strcasecmp (fn, "DEFAULT") == 0)) 186218822Sdim wind_current_codepage = wind_default_codepage; 187218822Sdim else if (len > 0) 188218822Sdim { 189218822Sdim rc_uint_type ncp; 190218822Sdim 191218822Sdim if (fn[0] == '0' && (fn[1] == 'x' || fn[1] == 'X')) 192218822Sdim ncp = (rc_uint_type) strtol (fn + 2, NULL, 16); 193218822Sdim else 194218822Sdim ncp = (rc_uint_type) strtol (fn, NULL, 10); 195218822Sdim if (ncp == CP_UTF16 || ! unicode_is_valid_codepage (ncp)) 196218822Sdim fatal (_("invalid value specified for pragma code_page.\n")); 197218822Sdim wind_current_codepage = ncp; 198218822Sdim } 199218822Sdim free (fn); 200218822Sdim return; 201218822Sdim } 202218822Sdim 20338889Sjdp line = strtol (s, &send, 0); 20492828Sobrien if (*send != '\0' && ! ISSPACE (*send)) 20538889Sjdp return; 20638889Sjdp 20738889Sjdp /* Subtract 1 because we are about to count the newline. */ 20838889Sjdp rc_lineno = line - 1; 20938889Sjdp 21038889Sjdp s = send; 21192828Sobrien while (ISSPACE (*s)) 21238889Sjdp ++s; 21338889Sjdp 21438889Sjdp if (*s != '"') 21538889Sjdp return; 21638889Sjdp 21738889Sjdp ++s; 21838889Sjdp send = strchr (s, '"'); 21938889Sjdp if (send == NULL) 22038889Sjdp return; 22138889Sjdp 222218822Sdim fn = xmalloc (send - s + 1); 22338889Sjdp strncpy (fn, s, send - s); 22438889Sjdp fn[send - s] = '\0'; 22538889Sjdp 22638889Sjdp free (rc_filename); 22738889Sjdp rc_filename = fn; 22861843Sobrien 229218822Sdim if (! initial_fn) 23061843Sobrien { 23161843Sobrien initial_fn = xmalloc (strlen (fn) + 1); 23299461Sobrien strcpy (initial_fn, fn); 23361843Sobrien } 23461843Sobrien 23561843Sobrien /* Allow the initial file, regardless of name. Suppress all other 23699461Sobrien files if they end in ".h" (this allows included "*.rc"). */ 23761843Sobrien if (strcmp (initial_fn, fn) == 0 23861843Sobrien || strcmp (fn + strlen (fn) - 2, ".h") != 0) 23961843Sobrien suppress_cpp_data = 0; 24061843Sobrien else 24161843Sobrien suppress_cpp_data = 1; 24238889Sjdp} 24338889Sjdp 244218822Sdim/* Allocate a string of a given length. */ 245218822Sdim 246218822Sdimstatic char * 247218822Sdimget_string (int len) 248218822Sdim{ 249218822Sdim struct alloc_string *as; 250218822Sdim 251218822Sdim as = xmalloc (sizeof *as); 252218822Sdim as->s = xmalloc (len); 253218822Sdim 254218822Sdim as->next = strings; 255218822Sdim strings = as; 256218822Sdim 257218822Sdim return as->s; 258218822Sdim} 259218822Sdim 26038889Sjdp/* Handle a quoted string. The quotes are stripped. A pair of quotes 26138889Sjdp in a string are turned into a single quote. Adjacent strings are 26238889Sjdp merged separated by whitespace are merged, as in C. */ 26338889Sjdp 26438889Sjdpstatic char * 265218822Sdimhandle_quotes (rc_uint_type *len) 26638889Sjdp{ 267218822Sdim const char *input = rclex_tok; 26838889Sjdp char *ret, *s; 26938889Sjdp const char *t; 27038889Sjdp int ch; 271218822Sdim int num_xdigits; 27238889Sjdp 27338889Sjdp ret = get_string (strlen (input) + 1); 27438889Sjdp 27538889Sjdp s = ret; 27638889Sjdp t = input; 27738889Sjdp if (*t == '"') 27838889Sjdp ++t; 27938889Sjdp while (*t != '\0') 28038889Sjdp { 28138889Sjdp if (*t == '\\') 28238889Sjdp { 28338889Sjdp ++t; 28438889Sjdp switch (*t) 28538889Sjdp { 28638889Sjdp case '\0': 28738889Sjdp rcparse_warning ("backslash at end of string"); 28838889Sjdp break; 28938889Sjdp 29038889Sjdp case '\"': 29138889Sjdp rcparse_warning ("use \"\" to put \" in a string"); 292218822Sdim *s++ = '"'; 293218822Sdim ++t; 29438889Sjdp break; 29538889Sjdp 29638889Sjdp case 'a': 29799461Sobrien *s++ = ESCAPE_B; /* Strange, but true... */ 29838889Sjdp ++t; 29938889Sjdp break; 30038889Sjdp 30138889Sjdp case 'b': 30238889Sjdp *s++ = ESCAPE_B; 30338889Sjdp ++t; 30438889Sjdp break; 30538889Sjdp 30638889Sjdp case 'f': 30738889Sjdp *s++ = ESCAPE_F; 30838889Sjdp ++t; 30938889Sjdp break; 31038889Sjdp 31138889Sjdp case 'n': 31238889Sjdp *s++ = ESCAPE_N; 31338889Sjdp ++t; 31438889Sjdp break; 31538889Sjdp 31638889Sjdp case 'r': 31738889Sjdp *s++ = ESCAPE_R; 31838889Sjdp ++t; 31938889Sjdp break; 32038889Sjdp 32138889Sjdp case 't': 32238889Sjdp *s++ = ESCAPE_T; 32338889Sjdp ++t; 32438889Sjdp break; 32538889Sjdp 32638889Sjdp case 'v': 32738889Sjdp *s++ = ESCAPE_V; 32838889Sjdp ++t; 32938889Sjdp break; 33038889Sjdp 33138889Sjdp case '\\': 33238889Sjdp *s++ = *t++; 33338889Sjdp break; 33438889Sjdp 33538889Sjdp case '0': case '1': case '2': case '3': 33638889Sjdp case '4': case '5': case '6': case '7': 33738889Sjdp ch = *t - '0'; 33838889Sjdp ++t; 33938889Sjdp if (*t >= '0' && *t <= '7') 34038889Sjdp { 34138889Sjdp ch = (ch << 3) | (*t - '0'); 34238889Sjdp ++t; 34338889Sjdp if (*t >= '0' && *t <= '7') 34438889Sjdp { 34538889Sjdp ch = (ch << 3) | (*t - '0'); 34638889Sjdp ++t; 34738889Sjdp } 34838889Sjdp } 34938889Sjdp *s++ = ch; 35038889Sjdp break; 35138889Sjdp 352218822Sdim case 'x': case 'X': 35338889Sjdp ++t; 35438889Sjdp ch = 0; 355218822Sdim /* We only handle single byte chars here. Make sure 356218822Sdim we finish an escape sequence like "/xB0ABC" after 357218822Sdim the first two digits. */ 358218822Sdim num_xdigits = 2; 359218822Sdim while (num_xdigits--) 36038889Sjdp { 36138889Sjdp if (*t >= '0' && *t <= '9') 36238889Sjdp ch = (ch << 4) | (*t - '0'); 36338889Sjdp else if (*t >= 'a' && *t <= 'f') 36499461Sobrien ch = (ch << 4) | (*t - 'a' + 10); 36538889Sjdp else if (*t >= 'A' && *t <= 'F') 36699461Sobrien ch = (ch << 4) | (*t - 'A' + 10); 36738889Sjdp else 36838889Sjdp break; 36938889Sjdp ++t; 37038889Sjdp } 37138889Sjdp *s++ = ch; 37238889Sjdp break; 37338889Sjdp 37438889Sjdp default: 37538889Sjdp rcparse_warning ("unrecognized escape sequence"); 37638889Sjdp *s++ = '\\'; 37738889Sjdp *s++ = *t++; 37838889Sjdp break; 37938889Sjdp } 38038889Sjdp } 38138889Sjdp else if (*t != '"') 38238889Sjdp *s++ = *t++; 38338889Sjdp else if (t[1] == '\0') 38438889Sjdp break; 38538889Sjdp else if (t[1] == '"') 38638889Sjdp { 38738889Sjdp *s++ = '"'; 38838889Sjdp t += 2; 38938889Sjdp } 39038889Sjdp else 39138889Sjdp { 392218822Sdim rcparse_warning ("unexpected character after '\"'"); 39338889Sjdp ++t; 39492828Sobrien assert (ISSPACE (*t)); 39592828Sobrien while (ISSPACE (*t)) 396130561Sobrien { 397130561Sobrien if ((*t) == '\n') 398130561Sobrien ++rc_lineno; 399130561Sobrien ++t; 400130561Sobrien } 40138889Sjdp if (*t == '\0') 40238889Sjdp break; 40338889Sjdp assert (*t == '"'); 40438889Sjdp ++t; 40538889Sjdp } 40638889Sjdp } 40738889Sjdp 40838889Sjdp *s = '\0'; 40938889Sjdp 41038889Sjdp *len = s - ret; 41138889Sjdp 41238889Sjdp return ret; 41338889Sjdp} 41438889Sjdp 415218822Sdim/* Allocate a unicode string of a given length. */ 41638889Sjdp 417218822Sdimstatic unichar * 418218822Sdimget_unistring (int len) 41938889Sjdp{ 420218822Sdim return (unichar *) get_string (len * sizeof (unichar)); 421218822Sdim} 42238889Sjdp 423218822Sdim/* Handle a quoted unicode string. The quotes are stripped. A pair of quotes 424218822Sdim in a string are turned into a single quote. Adjacent strings are 425218822Sdim merged separated by whitespace are merged, as in C. */ 42638889Sjdp 427218822Sdimstatic unichar * 428218822Sdimhandle_uniquotes (rc_uint_type *len) 429218822Sdim{ 430218822Sdim const char *input = rclex_tok; 431218822Sdim unichar *ret, *s; 432218822Sdim const char *t; 433218822Sdim int ch; 434218822Sdim int num_xdigits; 43538889Sjdp 436218822Sdim ret = get_unistring (strlen (input) + 1); 437218822Sdim 438218822Sdim s = ret; 439218822Sdim t = input; 440218822Sdim if ((*t == 'L' || *t == 'l') && t[1] == '"') 441218822Sdim t += 2; 442218822Sdim else if (*t == '"') 443218822Sdim ++t; 444218822Sdim while (*t != '\0') 445218822Sdim { 446218822Sdim if (*t == '\\') 447218822Sdim { 448218822Sdim ++t; 449218822Sdim switch (*t) 450218822Sdim { 451218822Sdim case '\0': 452218822Sdim rcparse_warning ("backslash at end of string"); 453218822Sdim break; 454218822Sdim 455218822Sdim case '\"': 456218822Sdim rcparse_warning ("use \"\" to put \" in a string"); 457218822Sdim break; 458218822Sdim 459218822Sdim case 'a': 460218822Sdim *s++ = ESCAPE_B; /* Strange, but true... */ 461218822Sdim ++t; 462218822Sdim break; 463218822Sdim 464218822Sdim case 'b': 465218822Sdim *s++ = ESCAPE_B; 466218822Sdim ++t; 467218822Sdim break; 468218822Sdim 469218822Sdim case 'f': 470218822Sdim *s++ = ESCAPE_F; 471218822Sdim ++t; 472218822Sdim break; 473218822Sdim 474218822Sdim case 'n': 475218822Sdim *s++ = ESCAPE_N; 476218822Sdim ++t; 477218822Sdim break; 478218822Sdim 479218822Sdim case 'r': 480218822Sdim *s++ = ESCAPE_R; 481218822Sdim ++t; 482218822Sdim break; 483218822Sdim 484218822Sdim case 't': 485218822Sdim *s++ = ESCAPE_T; 486218822Sdim ++t; 487218822Sdim break; 488218822Sdim 489218822Sdim case 'v': 490218822Sdim *s++ = ESCAPE_V; 491218822Sdim ++t; 492218822Sdim break; 493218822Sdim 494218822Sdim case '\\': 495218822Sdim *s++ = (unichar) *t++; 496218822Sdim break; 497218822Sdim 498218822Sdim case '0': case '1': case '2': case '3': 499218822Sdim case '4': case '5': case '6': case '7': 500218822Sdim ch = *t - '0'; 501218822Sdim ++t; 502218822Sdim if (*t >= '0' && *t <= '7') 503218822Sdim { 504218822Sdim ch = (ch << 3) | (*t - '0'); 505218822Sdim ++t; 506218822Sdim if (*t >= '0' && *t <= '7') 507218822Sdim { 508218822Sdim ch = (ch << 3) | (*t - '0'); 509218822Sdim ++t; 510218822Sdim } 511218822Sdim } 512218822Sdim *s++ = (unichar) ch; 513218822Sdim break; 514218822Sdim 515218822Sdim case 'x': case 'X': 516218822Sdim ++t; 517218822Sdim ch = 0; 518218822Sdim /* We only handle two byte chars here. Make sure 519218822Sdim we finish an escape sequence like "/xB0ABC" after 520218822Sdim the first two digits. */ 521218822Sdim num_xdigits = 4; 522218822Sdim while (num_xdigits--) 523218822Sdim { 524218822Sdim if (*t >= '0' && *t <= '9') 525218822Sdim ch = (ch << 4) | (*t - '0'); 526218822Sdim else if (*t >= 'a' && *t <= 'f') 527218822Sdim ch = (ch << 4) | (*t - 'a' + 10); 528218822Sdim else if (*t >= 'A' && *t <= 'F') 529218822Sdim ch = (ch << 4) | (*t - 'A' + 10); 530218822Sdim else 531218822Sdim break; 532218822Sdim ++t; 533218822Sdim } 534218822Sdim *s++ = (unichar) ch; 535218822Sdim break; 536218822Sdim 537218822Sdim default: 538218822Sdim rcparse_warning ("unrecognized escape sequence"); 539218822Sdim *s++ = '\\'; 540218822Sdim *s++ = (unichar) *t++; 541218822Sdim break; 542218822Sdim } 543218822Sdim } 544218822Sdim else if (*t != '"') 545218822Sdim *s++ = (unichar) *t++; 546218822Sdim else if (t[1] == '\0') 547218822Sdim break; 548218822Sdim else if (t[1] == '"') 549218822Sdim { 550218822Sdim *s++ = '"'; 551218822Sdim t += 2; 552218822Sdim } 553218822Sdim else 554218822Sdim { 555218822Sdim ++t; 556218822Sdim assert (ISSPACE (*t)); 557218822Sdim while (ISSPACE (*t)) 558218822Sdim { 559218822Sdim if ((*t) == '\n') 560218822Sdim ++rc_lineno; 561218822Sdim ++t; 562218822Sdim } 563218822Sdim if (*t == '\0') 564218822Sdim break; 565218822Sdim assert (*t == '"'); 566218822Sdim ++t; 567218822Sdim } 568218822Sdim } 569218822Sdim 570218822Sdim *s = '\0'; 571218822Sdim 572218822Sdim *len = s - ret; 573218822Sdim 574218822Sdim return ret; 57538889Sjdp} 57638889Sjdp 57738889Sjdp/* Discard all the strings we have allocated. The parser calls this 57838889Sjdp when it no longer needs them. */ 57938889Sjdp 58038889Sjdpvoid 581130561Sobrienrcparse_discard_strings (void) 58238889Sjdp{ 58338889Sjdp struct alloc_string *as; 58438889Sjdp 58538889Sjdp as = strings; 58638889Sjdp while (as != NULL) 58738889Sjdp { 58838889Sjdp struct alloc_string *n; 58938889Sjdp 59038889Sjdp free (as->s); 59138889Sjdp n = as->next; 59238889Sjdp free (as); 59338889Sjdp as = n; 59438889Sjdp } 59538889Sjdp 59638889Sjdp strings = NULL; 59738889Sjdp} 59838889Sjdp 59938889Sjdp/* Enter rcdata mode. */ 60038889Sjdpvoid 601130561Sobrienrcparse_rcdata (void) 60238889Sjdp{ 60338889Sjdp rcdata_mode = 1; 60438889Sjdp} 60538889Sjdp 60638889Sjdp/* Go back to normal mode from rcdata mode. */ 60738889Sjdpvoid 608130561Sobrienrcparse_normal (void) 60938889Sjdp{ 61038889Sjdp rcdata_mode = 0; 61138889Sjdp} 612218822Sdim 613218822Sdimstatic void 614218822Sdimrclex_tok_add_char (int ch) 615218822Sdim{ 616218822Sdim if (! rclex_tok || rclex_tok_max <= rclex_tok_pos) 617218822Sdim { 618218822Sdim char *h = xmalloc (rclex_tok_max + 9); 619218822Sdim 620218822Sdim if (! h) 621218822Sdim abort (); 622218822Sdim if (rclex_tok) 623218822Sdim { 624218822Sdim memcpy (h, rclex_tok, rclex_tok_pos + 1); 625218822Sdim free (rclex_tok); 626218822Sdim } 627218822Sdim else 628218822Sdim rclex_tok_pos = 0; 629218822Sdim rclex_tok_max += 8; 630218822Sdim rclex_tok = h; 631218822Sdim } 632218822Sdim if (ch != -1) 633218822Sdim rclex_tok[rclex_tok_pos++] = (char) ch; 634218822Sdim rclex_tok[rclex_tok_pos] = 0; 635218822Sdim} 636218822Sdim 637218822Sdimstatic int 638218822Sdimrclex_readch (void) 639218822Sdim{ 640218822Sdim int r = -1; 641218822Sdim 642218822Sdim if ((r = rclex_lastch) != -1) 643218822Sdim rclex_lastch = -1; 644218822Sdim else 645218822Sdim { 646218822Sdim char ch; 647218822Sdim do 648218822Sdim { 649218822Sdim if (! cpp_pipe || feof (cpp_pipe) 650218822Sdim || fread (&ch, 1, 1,cpp_pipe) != 1) 651218822Sdim break; 652218822Sdim r = ((int) ch) & 0xff; 653218822Sdim } 654218822Sdim while (r == 0 || r == '\r'); 655218822Sdim } 656218822Sdim rclex_tok_add_char (r); 657218822Sdim return r; 658218822Sdim} 659218822Sdim 660218822Sdimstatic int 661218822Sdimrclex_peekch (void) 662218822Sdim{ 663218822Sdim int r; 664218822Sdim 665218822Sdim if ((r = rclex_lastch) == -1) 666218822Sdim { 667218822Sdim if ((r = rclex_readch ()) != -1) 668218822Sdim { 669218822Sdim rclex_lastch = r; 670218822Sdim if (rclex_tok_pos > 0) 671218822Sdim rclex_tok[--rclex_tok_pos] = 0; 672218822Sdim } 673218822Sdim } 674218822Sdim return r; 675218822Sdim} 676218822Sdim 677218822Sdimstatic void 678218822Sdimrclex_string (void) 679218822Sdim{ 680218822Sdim int c; 681218822Sdim 682218822Sdim while ((c = rclex_peekch ()) != -1) 683218822Sdim { 684218822Sdim if (c == '\n') 685218822Sdim break; 686218822Sdim if (c == '\\') 687218822Sdim { 688218822Sdim rclex_readch (); 689218822Sdim if ((c = rclex_peekch ()) == -1 || c == '\n') 690218822Sdim break; 691218822Sdim rclex_readch (); 692218822Sdim } 693218822Sdim else if (rclex_readch () == '"') 694218822Sdim { 695218822Sdim if (rclex_peekch () == '"') 696218822Sdim rclex_readch (); 697218822Sdim else 698218822Sdim break; 699218822Sdim } 700218822Sdim } 701218822Sdim} 702218822Sdim 703218822Sdimstatic rc_uint_type 704218822Sdimread_digit (int ch) 705218822Sdim{ 706218822Sdim rc_uint_type base = 10; 707218822Sdim rc_uint_type ret, val; 708218822Sdim int warned = 0; 709218822Sdim 710218822Sdim ret = 0; 711218822Sdim if (ch == '0') 712218822Sdim { 713218822Sdim base = 8; 714218822Sdim switch (rclex_peekch ()) 715218822Sdim { 716218822Sdim case 'o': case 'O': 717218822Sdim rclex_readch (); 718218822Sdim base = 8; 719218822Sdim break; 720218822Sdim 721218822Sdim case 'x': case 'X': 722218822Sdim rclex_readch (); 723218822Sdim base = 16; 724218822Sdim break; 725218822Sdim } 726218822Sdim } 727218822Sdim else 728218822Sdim ret = (rc_uint_type) (ch - '0'); 729218822Sdim while ((ch = rclex_peekch ()) != -1) 730218822Sdim { 731218822Sdim if (ISDIGIT (ch)) 732218822Sdim val = (rc_uint_type) (ch - '0'); 733218822Sdim else if (ch >= 'a' && ch <= 'f') 734218822Sdim val = (rc_uint_type) ((ch - 'a') + 10); 735218822Sdim else if (ch >= 'A' && ch <= 'F') 736218822Sdim val = (rc_uint_type) ((ch - 'A') + 10); 737218822Sdim else 738218822Sdim break; 739218822Sdim rclex_readch (); 740218822Sdim if (! warned && val >= base) 741218822Sdim { 742218822Sdim warned = 1; 743218822Sdim rcparse_warning ("digit exceeds base"); 744218822Sdim } 745218822Sdim ret *= base; 746218822Sdim ret += val; 747218822Sdim } 748218822Sdim return ret; 749218822Sdim} 750218822Sdim 751218822Sdim/* yyparser entry method. */ 752218822Sdim 753218822Sdimint 754218822Sdimyylex (void) 755218822Sdim{ 756218822Sdim char *s; 757218822Sdim unichar *us; 758218822Sdim rc_uint_type length; 759218822Sdim int ch; 760218822Sdim 761218822Sdim /* Make sure that rclex_tok is initialized. */ 762218822Sdim if (! rclex_tok) 763218822Sdim rclex_tok_add_char (-1); 764218822Sdim 765218822Sdim do 766218822Sdim { 767218822Sdim do 768218822Sdim { 769218822Sdim /* Clear token. */ 770218822Sdim rclex_tok_pos = 0; 771218822Sdim rclex_tok[0] = 0; 772218822Sdim 773218822Sdim if ((ch = rclex_readch ()) == -1) 774218822Sdim return -1; 775218822Sdim if (ch == '\n') 776218822Sdim ++rc_lineno; 777218822Sdim } 778218822Sdim while (ch <= 0x20); 779218822Sdim 780218822Sdim switch (ch) 781218822Sdim { 782218822Sdim case '#': 783218822Sdim while ((ch = rclex_peekch ()) != -1 && ch != '\n') 784218822Sdim rclex_readch (); 785218822Sdim cpp_line (); 786218822Sdim ch = IGNORED_TOKEN; 787218822Sdim break; 788218822Sdim 789218822Sdim case '{': 790218822Sdim ch = IGNORE_CPP (BEG); 791218822Sdim break; 792218822Sdim 793218822Sdim case '}': 794218822Sdim ch = IGNORE_CPP (END); 795218822Sdim break; 796218822Sdim 797218822Sdim case '0': case '1': case '2': case '3': case '4': 798218822Sdim case '5': case '6': case '7': case '8': case '9': 799218822Sdim yylval.i.val = read_digit (ch); 800218822Sdim yylval.i.dword = 0; 801218822Sdim switch (rclex_peekch ()) 802218822Sdim { 803218822Sdim case 'l': case 'L': 804218822Sdim rclex_readch (); 805218822Sdim yylval.i.dword = 1; 806218822Sdim break; 807218822Sdim } 808218822Sdim ch = IGNORE_CPP (NUMBER); 809218822Sdim break; 810218822Sdim case '"': 811218822Sdim rclex_string (); 812218822Sdim ch = IGNORE_CPP ((! rcdata_mode ? QUOTEDSTRING : SIZEDSTRING)); 813218822Sdim if (ch == IGNORED_TOKEN) 814218822Sdim break; 815218822Sdim s = handle_quotes (&length); 816218822Sdim if (! rcdata_mode) 817218822Sdim yylval.s = s; 818218822Sdim else 819218822Sdim { 820218822Sdim yylval.ss.length = length; 821218822Sdim yylval.ss.s = s; 822218822Sdim } 823218822Sdim break; 824218822Sdim case 'L': case 'l': 825218822Sdim if (rclex_peekch () == '"') 826218822Sdim { 827218822Sdim rclex_readch (); 828218822Sdim rclex_string (); 829218822Sdim ch = IGNORE_CPP ((! rcdata_mode ? QUOTEDUNISTRING : SIZEDUNISTRING)); 830218822Sdim if (ch == IGNORED_TOKEN) 831218822Sdim break; 832218822Sdim us = handle_uniquotes (&length); 833218822Sdim if (! rcdata_mode) 834218822Sdim yylval.uni = us; 835218822Sdim else 836218822Sdim { 837218822Sdim yylval.suni.length = length; 838218822Sdim yylval.suni.s = us; 839218822Sdim } 840218822Sdim break; 841218822Sdim } 842218822Sdim /* Fall through. */ 843218822Sdim default: 844218822Sdim if (ISIDST (ch) || ch=='$') 845218822Sdim { 846218822Sdim while ((ch = rclex_peekch ()) != -1 && (ISIDNUM (ch) || ch == '$' || ch == '.')) 847218822Sdim rclex_readch (); 848218822Sdim ch = IGNORE_CPP (rclex_translatekeyword (rclex_tok)); 849218822Sdim if (ch == STRING) 850218822Sdim { 851218822Sdim s = get_string (strlen (rclex_tok) + 1); 852218822Sdim strcpy (s, rclex_tok); 853218822Sdim yylval.s = s; 854218822Sdim } 855218822Sdim else if (ch == BLOCK) 856218822Sdim { 857218822Sdim const char *hs = NULL; 858218822Sdim 859218822Sdim switch (yylex ()) 860218822Sdim { 861218822Sdim case STRING: 862218822Sdim case QUOTEDSTRING: 863218822Sdim hs = yylval.s; 864218822Sdim break; 865218822Sdim case SIZEDSTRING: 866218822Sdim hs = yylval.s = yylval.ss.s; 867218822Sdim break; 868218822Sdim } 869218822Sdim if (! hs) 870218822Sdim { 871218822Sdim rcparse_warning ("BLOCK expects a string as argument."); 872218822Sdim ch = IGNORED_TOKEN; 873218822Sdim } 874218822Sdim else if (! strcmp (hs, "StringFileInfo")) 875218822Sdim ch = BLOCKSTRINGFILEINFO; 876218822Sdim else if (! strcmp (hs, "VarFileInfo")) 877218822Sdim ch = BLOCKVARFILEINFO; 878218822Sdim } 879218822Sdim break; 880218822Sdim } 881218822Sdim ch = IGNORE_CPP (ch); 882218822Sdim break; 883218822Sdim } 884218822Sdim } 885218822Sdim while (ch == IGNORED_TOKEN); 886218822Sdim 887218822Sdim return ch; 888218822Sdim} 889