1999-09-04 Steve Chamberlain <sac@pobox.com>
[deliverable/binutils-gdb.git] / binutils / rcparse.y
index 56c6db86a63ed9395316b8d75d1186cb5d756697..03cbbdc5b67e194bc894f96c364a0f0400a43c5f 100644 (file)
@@ -1,5 +1,5 @@
 %{ /* rcparse.y -- parser for Windows rc files
-   Copyright 1997 Free Software Foundation, Inc.
+   Copyright 1997, 1998 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
    This file is part of GNU Binutils.
 #include "libiberty.h"
 #include "windres.h"
 
-/* The current language.  The default is U.S. English.  */
+#include <ctype.h>
 
-static unsigned short language = 0x409;
+/* The current language.  */
+
+static unsigned short language;
 
 /* The resource information during a sub statement.  */
 
@@ -60,7 +62,12 @@ static unsigned long class;
   struct accelerator *pacc;
   struct dialog_control *dialog_control;
   struct menuitem *menuitem;
-  struct rcdata_data *rcdata;
+  struct
+  {
+    struct rcdata_item *first;
+    struct rcdata_item *last;
+  } rcdata;
+  struct rcdata_item *rcdata_item;
   struct stringtable_data *stringtable;
   struct fixed_versioninfo *fixver;
   struct ver_info *verinfo;
@@ -81,7 +88,12 @@ static unsigned long class;
   } i;
   unsigned long il;
   unsigned short is;
-  char *s;
+  const char *s;
+  struct
+  {
+    unsigned long length;
+    const char *s;
+  } ss;
 };
 
 %token BEG END
@@ -95,7 +107,7 @@ static unsigned long class;
 %token BEDIT HEDIT IEDIT
 %token FONT
 %token ICON
-%token LANGUAGE CHARACTERISTICS VERSION
+%token LANGUAGE CHARACTERISTICS VERSIONK
 %token MENU MENUEX MENUITEM SEPARATOR POPUP CHECKED GRAYED HELP INACTIVE
 %token MENUBARBREAK MENUBREAK
 %token MESSAGETABLE
@@ -109,12 +121,15 @@ static unsigned long class;
 %token NOT
 %token <s> QUOTEDSTRING STRING
 %token <i> NUMBER
+%token <ss> SIZEDSTRING
+%token IGNORED_TOKEN
 
 %type <pacc> acc_entries
 %type <acc> acc_entry acc_event
 %type <dialog_control> control control_params
 %type <menuitem> menuitems menuitem menuexitems menuexitem
-%type <rcdata> optrcdata_data rcdata_data opt_control_data
+%type <rcdata> optrcdata_data optrcdata_data_int rcdata_data
+%type <rcdata_item> opt_control_data
 %type <fixver> fixedverinfo
 %type <verinfo> verblocks
 %type <verstring> vervals
@@ -139,20 +154,28 @@ static unsigned long class;
 
 input:
          /* empty */
-       | input accelerator
-       | input bitmap
-       | input cursor
-       | input dialog
-       | input font
-       | input icon
-       | input language
-       | input menu
-       | input menuex
-       | input messagetable
-       | input rcdata
-       | input stringtable
-       | input user
-       | input versioninfo
+       | input newcmd accelerator
+       | input newcmd bitmap
+       | input newcmd cursor
+       | input newcmd dialog
+       | input newcmd font
+       | input newcmd icon
+       | input newcmd language
+       | input newcmd menu
+       | input newcmd menuex
+       | input newcmd messagetable
+       | input newcmd rcdata
+       | input newcmd stringtable
+       | input newcmd user
+       | input newcmd versioninfo
+       | input newcmd IGNORED_TOKEN
+       ;
+
+newcmd:
+         /* empty */
+         {
+           rcparse_discard_strings ();
+         }
        ;
 
 /* Accelerator resources.  */
@@ -173,7 +196,7 @@ acc_entries:
          {
            struct accelerator *a;
 
-           a = (struct accelerator *) xmalloc (sizeof *a);
+           a = (struct accelerator *) res_alloc (sizeof *a);
            *a = $2;
            if ($1 == NULL)
              $$ = a;
@@ -200,29 +223,37 @@ acc_entry:
            $$ = $1;
            $$.id = $2;
            $$.flags |= $4;
+           if (($$.flags & ACC_VIRTKEY) == 0
+               && ($$.flags & (ACC_SHIFT | ACC_CONTROL | ACC_ALT)) != 0)
+             rcparse_warning (_("inappropriate modifiers for non-VIRTKEY"));
          }
        ;
 
 acc_event:
          QUOTEDSTRING
          {
-           char *s = $1;
+           const char *s = $1;
+           char ch;
 
+           $$.next = NULL;
            $$.id = 0;
-           if (*s != '^')
+           ch = *s;
+           if (ch != '^')
              $$.flags = 0;
            else
              {
-               $$.flags = ACC_CONTROL;
+               $$.flags = ACC_CONTROL | ACC_VIRTKEY;
                ++s;
+               ch = *s;
+               ch = toupper ((unsigned char) ch);
              }
-           $$.key = *s;
+           $$.key = ch;
            if (s[1] != '\0')
-             rcparse_warning ("accelerator should only be one character");
-           free (s);
+             rcparse_warning (_("accelerator should only be one character"));
          }
        | posnumexpr
          {
+           $$.next = NULL;
            $$.flags = 0;
            $$.id = 0;
            $$.key = $1;
@@ -238,6 +269,11 @@ acc_options:
          {
            $$ = $1 | $3;
          }
+       /* I've had one report that the comma is optional.  */
+       | acc_options acc_option
+         {
+           $$ = $1 | $2;
+         }
        ;
 
 acc_option:
@@ -274,7 +310,6 @@ bitmap:
          id BITMAP memflags_move file_name
          {
            define_bitmap ($1, &$3, $4);
-           free ($4);
          }
        ;
 
@@ -284,7 +319,6 @@ cursor:
          id CURSOR memflags_move_discard file_name
          {
            define_cursor ($1, &$3, $4);
-           free ($4);
          }
        ;
 
@@ -301,6 +335,8 @@ dialog:
              dialog.height = $8;
              dialog.style = WS_POPUP | WS_BORDER | WS_SYSMENU;
              dialog.exstyle = $4;
+             dialog.menu.named = 1;
+             dialog.class.named = 1;
              dialog.font = NULL;
              dialog.ex = NULL;
              dialog.controls = NULL;
@@ -320,9 +356,11 @@ dialog:
              dialog.height = $8;
              dialog.style = WS_POPUP | WS_BORDER | WS_SYSMENU;
              dialog.exstyle = $4;
+             dialog.menu.named = 1;
+             dialog.class.named = 1;
              dialog.font = NULL;
              dialog.ex = ((struct dialog_ex *)
-                          xmalloc (sizeof (struct dialog_ex)));
+                          res_alloc (sizeof (struct dialog_ex)));
              memset (dialog.ex, 0, sizeof (struct dialog_ex));
              dialog.controls = NULL;
              sub_res_info = $3;
@@ -341,9 +379,11 @@ dialog:
              dialog.height = $8;
              dialog.style = WS_POPUP | WS_BORDER | WS_SYSMENU;
              dialog.exstyle = $4;
+             dialog.menu.named = 1;
+             dialog.class.named = 1;
              dialog.font = NULL;
              dialog.ex = ((struct dialog_ex *)
-                          xmalloc (sizeof (struct dialog_ex)));
+                          res_alloc (sizeof (struct dialog_ex)));
              memset (dialog.ex, 0, sizeof (struct dialog_ex));
              dialog.ex->help = $9;
              dialog.controls = NULL;
@@ -370,14 +410,14 @@ styles:
          /* empty */
        | styles CAPTION QUOTEDSTRING
          {
-           dialog.caption = $3;
+           unicode_from_ascii ((int *) NULL, &dialog.caption, $3);
          }
        | styles CLASS id
          {
            dialog.class = $3;
          }
        | styles STYLE
-           { style = dialog.style }
+           { style = dialog.style; }
            styleexpr
          {
            dialog.style = style;
@@ -388,15 +428,17 @@ styles:
          }
        | styles FONT numexpr ',' QUOTEDSTRING
          {
+           dialog.style |= DS_SETFONT;
            dialog.pointsize = $3;
-           dialog.font = $5;
+           unicode_from_ascii ((int *) NULL, &dialog.font, $5);
          }
        | styles FONT numexpr ',' QUOTEDSTRING cnumexpr cnumexpr
          {
+           dialog.style |= DS_SETFONT;
            dialog.pointsize = $3;
-           dialog.font = $5;
+           unicode_from_ascii ((int *) NULL, &dialog.font, $5);
            if (dialog.ex == NULL)
-             rcparse_warning ("extended FONT requires DIALOGEX");
+             rcparse_warning (_("extended FONT requires DIALOGEX"));
            else
              {
                dialog.ex->weight = $6;
@@ -415,7 +457,7 @@ styles:
          {
            sub_res_info.language = $3 | ($4 << 8);
          }
-       | styles VERSION numexpr
+       | styles VERSIONK numexpr
          {
            sub_res_info.version = $3;
          }
@@ -474,7 +516,7 @@ control:
          {
            $$ = $3;
            if (dialog.ex == NULL)
-             rcparse_warning ("IEDIT requires DIALOGEX");
+             rcparse_warning (_("IEDIT requires DIALOGEX"));
            res_string_to_id (&$$->class, "BEDIT");
          }
        | CHECKBOX
@@ -504,7 +546,7 @@ control:
            if ($11 != NULL)
              {
                if (dialog.ex == NULL)
-                 rcparse_warning ("control data requires DIALOGEX");
+                 rcparse_warning (_("control data requires DIALOGEX"));
                $$->data = $11;
              }
          }
@@ -513,10 +555,34 @@ control:
          {
            $$ = define_control ($2, $3, $6, $7, $8, $9, $4, style, $10);
            if (dialog.ex == NULL)
-             rcparse_warning ("help ID requires DIALOGEX");
+             rcparse_warning (_("help ID requires DIALOGEX"));
            $$->help = $11;
            $$->data = $12;
          }
+       | CONTROL optstringc numexpr ',' QUOTEDSTRING control_styleexpr
+           cnumexpr cnumexpr cnumexpr cnumexpr optcnumexpr opt_control_data
+         {
+           $$ = define_control ($2, $3, $7, $8, $9, $10, 0, style, $11);
+           if ($12 != NULL)
+             {
+               if (dialog.ex == NULL)
+                 rcparse_warning ("control data requires DIALOGEX");
+               $$->data = $12;
+             }
+           $$->class.named = 1;
+           unicode_from_ascii(&$$->class.u.n.length, &$$->class.u.n.name, $5);
+         }
+       | CONTROL optstringc numexpr ',' QUOTEDSTRING control_styleexpr
+           cnumexpr cnumexpr cnumexpr cnumexpr cnumexpr cnumexpr opt_control_data
+         {
+           $$ = define_control ($2, $3, $7, $8, $9, $10, 0, style, $11);
+           if (dialog.ex == NULL)
+             rcparse_warning ("help ID requires DIALOGEX");
+           $$->help = $12;
+           $$->data = $13;
+           $$->class.named = 1;
+           unicode_from_ascii(&$$->class.u.n.length, &$$->class.u.n.name, $5);
+         }
        | CTEXT
            {
              default_style = SS_CENTER | WS_GROUP;
@@ -567,7 +633,7 @@ control:
          {
            $$ = $3;
            if (dialog.ex == NULL)
-             rcparse_warning ("IEDIT requires DIALOGEX");
+             rcparse_warning (_("IEDIT requires DIALOGEX"));
            res_string_to_id (&$$->class, "HEDIT");
          }
        | ICON optstringc numexpr cnumexpr cnumexpr opt_control_data
@@ -577,7 +643,7 @@ control:
            if ($6 != NULL)
              {
                if (dialog.ex == NULL)
-                 rcparse_warning ("control data requires DIALOGEX");
+                 rcparse_warning (_("control data requires DIALOGEX"));
                $$->data = $6;
              }
          }
@@ -589,7 +655,7 @@ control:
            if ($10 != NULL)
              {
                if (dialog.ex == NULL)
-                 rcparse_warning ("control data requires DIALOGEX");
+                 rcparse_warning (_("control data requires DIALOGEX"));
                $$->data = $10;
              }
          }
@@ -599,7 +665,7 @@ control:
            $$ = define_control ($2, $3, $4, $5, $6, $7, CTL_STATIC,
                                 style, $9);
            if (dialog.ex == NULL)
-             rcparse_warning ("help ID requires DIALOGEX");
+             rcparse_warning (_("help ID requires DIALOGEX"));
            $$->help = $10;
            $$->data = $11;
          }
@@ -613,7 +679,7 @@ control:
          {
            $$ = $3;
            if (dialog.ex == NULL)
-             rcparse_warning ("IEDIT requires DIALOGEX");
+             rcparse_warning (_("IEDIT requires DIALOGEX"));
            res_string_to_id (&$$->class, "IEDIT");
          }
        | LISTBOX
@@ -698,7 +764,7 @@ control:
          }
        | USERBUTTON QUOTEDSTRING ',' numexpr ',' numexpr ',' numexpr ','
            numexpr ',' numexpr ',' 
-           { style = WS_CHILD | WS_VISIBLE }
+           { style = WS_CHILD | WS_VISIBLE; }
            styleexpr optcnumexpr
          {
            $$ = define_control ($2, $4, $6, $8, $10, $12, CTL_BUTTON,
@@ -722,7 +788,7 @@ control_params:
            if ($7 != NULL)
              {
                if (dialog.ex == NULL)
-                 rcparse_warning ("control data requires DIALOGEX");
+                 rcparse_warning (_("control data requires DIALOGEX"));
                $$->data = $7;
              }
          }
@@ -733,7 +799,7 @@ control_params:
            if ($9 != NULL)
              {
                if (dialog.ex == NULL)
-                 rcparse_warning ("control data requires DIALOGEX");
+                 rcparse_warning (_("control data requires DIALOGEX"));
                $$->data = $9;
              }
          }
@@ -742,7 +808,7 @@ control_params:
          {
            $$ = define_control ($1, $2, $3, $4, $5, $6, class, style, $8);
            if (dialog.ex == NULL)
-             rcparse_warning ("help ID requires DIALOGEX");
+             rcparse_warning (_("help ID requires DIALOGEX"));
            $$->help = $9;
            $$->data = $10;
          }
@@ -766,7 +832,7 @@ opt_control_data:
          }
        | BEG optrcdata_data END
          {
-           $$ = $2;
+           $$ = $2.first;
          }
        ;
 
@@ -796,7 +862,6 @@ font:
          id FONT memflags_move_discard file_name
          {
            define_font ($1, &$3, $4);
-           free ($4);
          }
        ;
 
@@ -806,7 +871,6 @@ icon:
          id ICON memflags_move_discard file_name
          {
            define_icon ($1, &$3, $4);
-           free ($4);
          }
        ;
 
@@ -950,6 +1014,10 @@ menuexitem:
          {
            $$ = define_menuitem ($2, $3, $4, $5, 0, NULL);
          }
+       | MENUITEM SEPARATOR
+         {
+           $$ = define_menuitem (NULL, 0, 0, 0, 0, NULL);
+         }
        | POPUP QUOTEDSTRING BEG menuexitems END
          {
            $$ = define_menuitem ($2, 0, 0, 0, 0, $4);
@@ -975,7 +1043,6 @@ messagetable:
          id MESSAGETABLE memflags_move file_name
          {
            define_messagetable ($1, &$3, $4);
-           free ($4);
          }
        ;
 
@@ -984,14 +1051,29 @@ messagetable:
 rcdata:
          id RCDATA suboptions BEG optrcdata_data END
          {
-           define_rcdata ($1, &$3, $5);
+           define_rcdata ($1, &$3, $5.first);
          }
        ;
 
+/* We use a different lexing algorithm, because rcdata strings may
+   contain embedded null bytes, and we need to know the length to use.  */
+
 optrcdata_data:
+         {
+           rcparse_rcdata ();
+         }
+         optrcdata_data_int
+         {
+           rcparse_normal ();
+           $$ = $2;
+         }
+       ;
+
+optrcdata_data_int:
          /* empty */
          {
-           $$ = NULL;
+           $$.first = NULL;
+           $$.last = NULL;
          }
        | rcdata_data
          {
@@ -1000,21 +1082,39 @@ optrcdata_data:
        ;
 
 rcdata_data:
-         QUOTEDSTRING
+         SIZEDSTRING
          {
-           $$ = append_rcdata_string (NULL, $1);
+           struct rcdata_item *ri;
+
+           ri = define_rcdata_string ($1.s, $1.length);
+           $$.first = ri;
+           $$.last = ri;
          }
        | sizednumexpr
          {
-           $$ = append_rcdata_number (NULL, $1.val, $1.dword);
+           struct rcdata_item *ri;
+
+           ri = define_rcdata_number ($1.val, $1.dword);
+           $$.first = ri;
+           $$.last = ri;
          }
-       | rcdata_data ',' QUOTEDSTRING
+       | rcdata_data ',' SIZEDSTRING
          {
-           $$ = append_rcdata_string ($1, $3);
+           struct rcdata_item *ri;
+
+           ri = define_rcdata_string ($3.s, $3.length);
+           $$.first = $1.first;
+           $1.last->next = ri;
+           $$.last = ri;
          }
        | rcdata_data ',' sizednumexpr
          {
-           $$ = append_rcdata_number ($1, $3.val, $3.dword);
+           struct rcdata_item *ri;
+
+           ri = define_rcdata_number ($3.val, $3.dword);
+           $$.first = $1.first;
+           $1.last->next = ri;
+           $$.last = ri;
          }
        ;
 
@@ -1042,14 +1142,13 @@ string_data:
    file_name case to keep the parser happy.  */
 
 user:
-         id id suboptions BEG rcdata_data END
+         id id suboptions BEG optrcdata_data END
          {
-           define_user_data ($1, $2, &$3, $5);
+           define_user_data ($1, $2, &$3, $5.first);
          }
        | id id suboptions file_name
          {
            define_user_file ($1, $2, &$3, $4);
-           free ($4);
          }
        ;
 
@@ -1066,7 +1165,7 @@ fixedverinfo:
          /* empty */
          {
            $$ = ((struct fixed_versioninfo *)
-                 xmalloc (sizeof (struct fixed_versioninfo)));
+                 res_alloc (sizeof (struct fixed_versioninfo)));
            memset ($$, 0, sizeof (struct fixed_versioninfo));
          }
        | fixedverinfo FILEVERSION numexpr cnumexpr cnumexpr cnumexpr
@@ -1161,8 +1260,15 @@ id:
          }
        | STRING
          {
-           res_string_to_id (&$$, $1);
-           free ($1);
+           char *copy, *s;
+
+           /* It seems that resource ID's are forced to upper case.  */
+           copy = xstrdup ($1);
+           for (s = copy; *s != '\0'; s++)
+             if (islower ((unsigned char) *s))
+               *s = toupper ((unsigned char) *s);
+           res_string_to_id (&$$, copy);
+           free (copy);
          }
        ;
 
@@ -1193,7 +1299,7 @@ suboptions:
            $$ = $1;
            $$.language = $3 | ($4 << 8);
          }
-       | suboptions VERSION numexpr
+       | suboptions VERSIONK numexpr
          {
            $$ = $1;
            $$.version = $3;
@@ -1226,7 +1332,7 @@ memflags_move:
            $$.language = language;
            $$.memflags = MEMFLAG_MOVEABLE;
          }
-       | memflags_move_discard memflag
+       | memflags_move memflag
          {
            $$ = $1;
            $$.memflags |= $2.on;
This page took 0.032047 seconds and 4 git commands to generate.