1 /*
2 * windres.c
3 *
4 * Copyright (c) 2013, Frank Fesevur <ffes(at)users.sourceforge.net>
5 *
6 * This source code is released for free distribution under the terms of the
7 * GNU General Public License version 2 or (at your option) any later version.
8 *
9 * This module contains functions for generating tags for Windows Resource files.
10 */
11
12 #include "general.h"
13
14 #include <string.h>
15 #include <ctype.h>
16
17 #include "parse.h"
18 #include "read.h"
19 #include "routines.h"
20
21 static int _blockDepth = 0;
22
23 typedef enum _WindResKinds
24 {
25 K_NONE = -1,
26 K_DIALOG,
27 K_MENU,
28 K_ICON,
29 K_BITMAP,
30 K_CURSOR,
31 K_FONT,
32 K_VERSION,
33 K_ACCELERATORS
34 } ResKind;
35
36 static kindDefinition ResKinds [] = {
37 { true, 'd', "dialog", "dialogs" },
38 { true, 'm', "menu", "menus" },
39 { true, 'i', "icon", "icons" },
40 { true, 'b', "bitmap", "bitmaps" },
41 { true, 'c', "cursor", "cursors" },
42 { true, 'f', "font", "fonts" },
43 { true, 'v', "version", "versions" },
44 { true, 'a', "accelerators", "accelerators" }
45 };
46
47 typedef enum _WindResParserState
48 {
49 P_STATE_NONE,
50 P_STATE_IN_COMMENT,
51 P_STATE_IN_STATEMENTS, /* Between first line of item and BEGIN/{ */
52 P_STATE_IN_BLOCK, /* In a BEGIN/END or {/} block */
53 P_STATE_AT_END
54 } ResParserState;
55
makeResTag(vString * name,ResKind kind)56 static void makeResTag(vString *name, ResKind kind)
57 {
58 vStringStripTrailing(name);
59 makeSimpleTag(name, kind);
60 vStringClear(name);
61 }
62
parseResDefinition(const unsigned char * line)63 static ResParserState parseResDefinition(const unsigned char *line)
64 {
65 ResParserState state = P_STATE_NONE;
66 vString *name, *type;
67
68 name = vStringNew();
69 while (*line && !isspace((int) *line))
70 {
71 vStringPut(name, (int) *line);
72 line++;
73 }
74
75 while (*line && isspace((int) *line))
76 line++;
77
78 type = vStringNew();
79 while (*line && !isspace((int) *line))
80 {
81 vStringPut(type, (int) *line);
82 line++;
83 }
84
85 if (strcmp(vStringValue(type), "DIALOG") == 0 || strcmp(vStringValue(type), "DIALOGEX") == 0)
86 {
87 makeResTag(name, K_DIALOG);
88 state = P_STATE_IN_STATEMENTS;
89 }
90 else if (strcmp(vStringValue(type), "MENU") == 0 || strcmp(vStringValue(type), "MENUEX") == 0)
91 {
92 makeResTag(name, K_MENU);
93 state = P_STATE_IN_STATEMENTS;
94 }
95 else if (strcmp(vStringValue(type), "VERSIONINFO") == 0)
96 {
97 makeResTag(name, K_VERSION);
98 state = P_STATE_IN_STATEMENTS;
99 }
100 else if (strcmp(vStringValue(type), "ACCELERATORS") == 0)
101 {
102 makeResTag(name, K_ACCELERATORS);
103 state = P_STATE_IN_STATEMENTS;
104 }
105 else if (strcmp(vStringValue(type), "ICON") == 0)
106 {
107 makeResTag(name, K_ICON);
108 state = P_STATE_NONE;
109 }
110 else if (strcmp(vStringValue(type), "CURSOR") == 0)
111 {
112 makeResTag(name, K_CURSOR);
113 state = P_STATE_NONE;
114 }
115 else if (strcmp(vStringValue(type), "BITMAP") == 0)
116 {
117 makeResTag(name, K_BITMAP);
118 state = P_STATE_NONE;
119 }
120 else if (strcmp(vStringValue(type), "FONT") == 0)
121 {
122 makeResTag(name, K_FONT);
123 state = P_STATE_NONE;
124 }
125
126 vStringDelete(name);
127 vStringDelete(type);
128
129 return state;
130 }
131
parseResLine(const unsigned char * line,ResParserState state)132 static ResParserState parseResLine(const unsigned char *line, ResParserState state)
133 {
134 while (*line != '\0') /* readLineFromInputFile returns NULL terminated strings */
135 {
136 while (isspace((int) *line))
137 line++;
138
139 switch (state)
140 {
141 case P_STATE_NONE:
142 {
143 /* C-styled # line (#include, #define, etc), ignore rest of line */
144 if (*line == '#')
145 {
146 return P_STATE_NONE;
147 }
148 /* single line comment, ignore rest of line */
149 else if (*line == '/' && line[1] == '/')
150 {
151 return P_STATE_NONE;
152 }
153 /* multi-line comment */
154 else if( *line == '/' && line[1] == '*' )
155 {
156 state = P_STATE_IN_COMMENT;
157 }
158 else if (isalnum((int) *line))
159 {
160 return parseResDefinition(line);
161 }
162 break;
163 }
164 case P_STATE_IN_COMMENT:
165 {
166 if (*line == '*' && line[1] == '/')
167 state = P_STATE_NONE;
168 break;
169 }
170 case P_STATE_IN_STATEMENTS:
171 {
172 /* First BEGIN block */
173 if (*line == '{' || strcmp((const char *) line, "BEGIN") == 0)
174 {
175 _blockDepth = 1;
176 return P_STATE_IN_BLOCK;
177 }
178 break;
179 }
180 case P_STATE_IN_BLOCK:
181 {
182 /* Nested BEGIN blocks? */
183 if (*line == '{' || strcmp((const char *) line, "BEGIN") == 0)
184 {
185 _blockDepth++;
186 }
187 else if (*line == '}' || strcmp((const char *) line, "END") == 0)
188 {
189 if (_blockDepth == 1)
190 return P_STATE_NONE;
191 else
192 _blockDepth--;
193 }
194 break;
195 }
196 case P_STATE_AT_END:
197 {
198 return state;
199 }
200 }
201 if (line == NULL)
202 return P_STATE_AT_END;
203 line++;
204 }
205
206 return state;
207 }
208
findResTags(void)209 static void findResTags(void)
210 {
211 const unsigned char *line;
212 ResParserState state = P_STATE_NONE;
213 _blockDepth = 0;
214
215 while ((line = readLineFromInputFile()) != NULL)
216 {
217 state = parseResLine(line, state);
218 if (state == P_STATE_AT_END)
219 return;
220 }
221 }
222
223 /* parser definition */
WindResParser(void)224 extern parserDefinition* WindResParser(void)
225 {
226 static const char *const extensions [] = { "rc", NULL };
227 parserDefinition* def = parserNew("WindRes");
228 def->kindTable = ResKinds;
229 def->kindCount = ARRAY_SIZE(ResKinds);
230 def->extensions = extensions;
231 def->parser = findResTags;
232 return def;
233 }
234