1 %{
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 
6 #include "../config.h"
7 #include "zmachine.h"
8 #include "rc.h"
9 #include "rcp.h"
10 #include "hash.h"
11 
12 #define YYERROR_VERBOSE 1
13 
14 extern int _rc_line;
15 extern hash rc_hash;
16 
17 extern void rc_error(char*);
18 extern int  rc_lex(void);
19 
20 int rc_merging = 0;
21 
22 #define EMPTY_GAME(x) x.fg_col = -1; x.bg_col = -1; x.interpreter = -1; x.revision = -1; x.name = NULL; x.fonts = NULL; x.n_fonts = -1; x.colours = NULL; x.n_colours = -1; x.gamedir = x.savedir = x.sounds = x.graphics = NULL; x.xsize = x.ysize = -1; x.antialias = -1;
23 
merge_games(const rc_game * a,const rc_game * b)24 static inline rc_game merge_games(const rc_game* a, const rc_game* b)
25 {
26   rc_game r;
27 
28   if (a->fg_col == -1)
29 	r.fg_col = b->fg_col;
30   else
31     r.fg_col = a->fg_col;
32   if (a->bg_col == -1)
33 	r.bg_col = b->bg_col;
34   else
35     r.bg_col = a->bg_col;
36 
37   if (a->interpreter == -1)
38     r.interpreter = b->interpreter;
39   else
40     r.interpreter = a->interpreter;
41 
42   if (a->antialias == -1)
43     r.antialias = b->antialias;
44   else
45     r.antialias = a->antialias;
46 
47   if (a->revision == -1)
48     r.revision = b->revision;
49   else
50     r.revision = a->revision;
51 
52   if (a->name == NULL)
53     r.name = b->name;
54   else
55     r.name = a->name;
56 
57   if (a->fonts == NULL)
58     {
59       r.fonts = b->fonts;
60       r.n_fonts = b->n_fonts;
61     }
62   else if (b->fonts == NULL)
63     {
64       r.fonts = a->fonts;
65       r.n_fonts = a->n_fonts;
66     }
67   else
68     {
69       int x;
70 
71       r.n_fonts = a->n_fonts + b->n_fonts;
72       r.fonts = malloc(r.n_fonts*sizeof(rc_font));
73 
74       for (x=0; x<a->n_fonts; x++)
75       	r.fonts[x] = a->fonts[x];
76       for (x=0; x<b->n_fonts; x++)
77         r.fonts[x+a->n_fonts] = b->fonts[x];
78 
79       free(a->fonts);
80       free(b->fonts);
81     }
82 
83   if (a->colours == NULL)
84     {
85       r.colours   = b->colours;
86       r.n_colours = b->n_colours;
87     }
88   else if (b->colours == NULL)
89     {
90       r.colours   = a->colours;
91       r.n_colours = a->n_colours;
92     }
93   else
94     rc_error("Can only have one set of colours per block");
95 
96   if (a->gamedir == NULL)
97     r.gamedir = b->gamedir;
98   else
99     r.gamedir = a->gamedir;
100 
101   if (a->savedir == NULL)
102     r.savedir = b->savedir;
103   else
104     r.savedir = a->savedir;
105 
106   if (a->sounds == NULL)
107     r.sounds = b->sounds;
108   else
109     r.sounds = a->sounds;
110   if (a->graphics == NULL)
111     r.graphics = b->graphics;
112   else
113     r.graphics = a->graphics;
114 
115   if (a->xsize == -1)
116     r.xsize = b->xsize;
117   else
118     r.xsize = a->xsize;
119   if (a->ysize == -1)
120     r.ysize = b->ysize;
121   else
122     r.ysize = a->ysize;
123 
124   return r;
125 }
126 %}
127 
128 %union {
129   char*       str;
130   int         num;
131   char        chr;
132 
133   rc_font     font;
134   rc_game     game;
135   rc_colour   col;
136   stringlist* slist;
137 }
138 
139 %token DEFAULT
140 %token INTERPRETER
141 %token REVISION
142 %token FONT
143 %token COLOURS
144 %token GAME
145 %token ROMAN
146 %token BOLD
147 %token ITALIC
148 %token FIXED
149 %token SYMBOLIC
150 %token GAMEDIR
151 %token SAVEDIR
152 %token SOUNDS
153 %token GRAPHICS
154 %token SIZE
155 %token ANTIALIAS
156 %token YES
157 %token NO
158 
159 %token <str> GAMEID
160 %token <num> NUMBER
161 %token <str> STRING
162 %token <chr> CHARACTER
163 
164 %type <col>   ColourDefn
165 %type <game>  ColourList
166 %type <slist> RevisionList
167 %type <slist> GoodRevisionList
168 %type <num>   FontQual
169 %type <num>   FontDefn
170 %type <font>  FontType
171 %type <game>  RCOption
172 %type <game>  RCOptionList
173 %type <game>  RCBlock
174 %type <num>   YesOrNo
175 
176 %{
check_collision(char * ourid,char * name)177 static int check_collision(char* ourid, char* name)
178 {
179   rc_game* game;
180 
181   game = hash_get(rc_hash, ourid, strlen(ourid));
182   if (game != NULL && strcmp(name, game->name) != 0)
183     {
184       if (!rc_merging)
185 	zmachine_info("Namespace collision: identifier '%s' (for game '%s') already used for game '%s'", ourid, name, game->name);
186       return 0;
187     }
188 
189   return 1;
190 }
191 %}
192 
193 %%
194 
195 RCFile:		  RCDefn
196 		| RCFile RCDefn
197 		;
198 
199 RCDefn:		  DEFAULT STRING RCBlock
200 		    {
201 		      rc_game* game;
202 
203 		      if (!rc_merging)
204 			{
205 			  game = malloc(sizeof(rc_game));
206 			  *game = $3;
207 			  game->name = $2;
208 			  hash_store(rc_hash,
209 				     (unsigned char*)"default",
210 				     7,
211 				     game);
212 			}
213 		    }
214 		| DEFAULT RCBlock
215 		    {
216 		      rc_game* game;
217 
218 		      if (!rc_merging)
219 			{
220 			  game = malloc(sizeof(rc_game));
221 			  *game = $2;
222 			  game->name = "%s";
223 			  hash_store(rc_hash,
224 				     (unsigned char*)"default",
225 				     7,
226 				     game);
227 			}
228 
229 		    }
230 		| GAME STRING RevisionList
231 		    {
232 		      if ($3 != NULL)
233 		        {
234 		          rc_game* game;
235 		          stringlist* next;
236 
237 		          game = malloc(sizeof(rc_game));
238 		          EMPTY_GAME((*game));
239 		          game->name = $2;
240 
241 		          next = $3;
242 		          while (next != NULL)
243 		            {
244 			      if (check_collision(next->string, game->name))
245 			        {
246 			          hash_store(rc_hash,
247 					     (unsigned char*)next->string,
248 					     strlen(next->string),
249 					     game);
250 			        }
251 			      next = next->next;
252 	                    }
253 			}
254 		      else
255 		        {
256 		          zmachine_info(".zoomrc has erroneous entry for game '%s' (line %i)", $2, _rc_line);
257 			}
258 		    }
259 		| GAME STRING RevisionList RCBlock
260 		    {
261 		      if ($3 != NULL)
262 		        {
263 		          rc_game* game;
264 		          stringlist* next;
265 
266 		          game = malloc(sizeof(rc_game));
267 		          *game = $4;
268 		          game->name = $2;
269 
270 		          next = $3;
271 		          while (next != NULL)
272 		            {
273 			      if (check_collision(next->string, game->name))
274 			        {
275 			          hash_store(rc_hash,
276 					     (unsigned char*)next->string,
277 					     strlen(next->string),
278 					     game);
279 			        }
280 			      next = next->next;
281 	                    }
282 		        }
283 		      else
284 		        {
285 		          zmachine_info(".zoomrc has erroneous entry for game '%s' (line %i)", $2, _rc_line);
286 			}
287 		    }
288 		;
289 
290 RCBlock:	  '{' RCOptionList '}'
291 		    {
292 		      $$ = $2;
293 		    }
294                 | '{' '}'
295                     {
296 		      EMPTY_GAME($$);
297                     }
298 		| '{' ErrorList
299 		    {
300 		      yyerrok;
301 		      zmachine_info(".zoomrc options block ending at line %i makes no sense", _rc_line);
302 		      EMPTY_GAME($$);
303 		    }
304 		| '{' RCOptionList ErrorList
305 		    {
306 		      yyerrok;
307 		      $$ = $2;
308 
309 		      zmachine_info(".zoomrc options block at line %i has syntax errors", _rc_line);
310 		    }
311 		;
312 
313 RCOptionList:	  RCOption
314 		| RCOptionList RCOption
315 		    {
316 		      $$ = merge_games(&$1, &$2);
317 		    }
318 		;
319 
320 YesOrNo:	  YES { $$ = 1; }
321 		| NO  { $$ = 0; }
322 		;
323 
324 RCOption:	  INTERPRETER NUMBER
325 		    {
326 		      EMPTY_GAME($$);
327 		      $$.interpreter = $2;
328 		    }
329                 | ANTIALIAS YesOrNo
330 		    {
331 		      EMPTY_GAME($$);
332 		      $$.antialias = $2;
333 		    }
334 		| REVISION CHARACTER
335 		    {
336 		      EMPTY_GAME($$);
337 		      $$.revision = $2;
338 		    }
339 		| FONT NUMBER STRING FontType
340 		    {
341 		      EMPTY_GAME($$);
342 		      $$.fonts = malloc(sizeof(rc_font));
343 		      $$.n_fonts = 1;
344 		      $$.fonts[0] = $4;
345 
346 		      $$.fonts[0].name = $3;
347 		      $$.fonts[0].num  = $2;
348 		    }
349 		| COLOURS ColourList
350 		    {
351 		      $$ = $2;
352 		    }
353                 | GAMEDIR STRING
354 		    {
355 		      EMPTY_GAME($$);
356 		      $$.gamedir = $2;
357 		    }
358                 | SAVEDIR STRING
359 		    {
360 		      EMPTY_GAME($$);
361 		      $$.savedir = $2;
362 		    }
363 		| SOUNDS STRING
364 		    {
365 		      EMPTY_GAME($$);
366 		      $$.sounds = $2;
367 		    }
368 		| GRAPHICS STRING
369 		    {
370 		      EMPTY_GAME($$);
371 		      $$.graphics = $2;
372 		    }
373 		| SIZE NUMBER ',' NUMBER
374 		    {
375 		      EMPTY_GAME($$);
376 		      $$.xsize = $2;
377 		      $$.ysize = $4;
378 		    }
379 		;
380 
381 FontType:	  FontDefn
382 		    {
383 		      $$.name = NULL;
384 		      $$.attributes[0] = $1;
385 		      $$.n_attr = 1;
386 		      $$.num = 0;
387 		    }
388 		| FontType ',' FontDefn
389 		    {
390 		      $$ = $1;
391 		      $$.n_attr++;
392 		      $$.attributes[$$.n_attr-1] = $3;
393 		    }
394 		;
395 
396 FontDefn:	  FontQual
397 		    {
398 		      $$ = $1;
399 		    }
400 		| FontDefn '-' FontQual
401 		    {
402 		      $$ = $1|$3;
403 		    }
404 		;
405 
406 FontQual:	  ROMAN    { $$ = 0; }
407 		| BOLD     { $$ = 1; }
408 		| ITALIC   { $$ = 2; }
409 		| FIXED    { $$ = 4; }
410                 | SYMBOLIC { $$ = 8; }
411 		;
412 
413 ColourList:	  ColourDefn
414 		    {
415 		      EMPTY_GAME($$);
416 		      $$.colours = malloc(sizeof(rc_colour));
417 		      $$.colours[0] = $1;
418 		      $$.n_colours = 1;
419 		    }
420 		| ColourList ',' ColourDefn
421 		    {
422 		      $$ = $1;
423 		      $$.n_colours++;
424 		      $$.colours = realloc($$.colours,
425 				           sizeof(rc_colour)*$$.n_colours);
426 		      $$.colours[$$.n_colours-1]=$3;
427 		    }
428 		;
429 
430 ColourDefn:	  '(' NUMBER ',' NUMBER ',' NUMBER ')'
431 		    {
432 		      $$.r = $2&0xff;
433 		      $$.g = $4&0xff;
434 		      $$.b = $6&0xff;
435 		    }
436 		;
437 
438 RevisionList:	  GoodRevisionList
439 		| BadRevisionList
440 		    { $$ = NULL; }
441 		;
442 
443 BadRevisionList:  ErrorList
444 		    { yyerrok; }
445 		;
446 
447 GoodRevisionList: GAMEID
448 		    {
449 		      $$ = malloc(sizeof(stringlist));
450 		      $$->next = NULL;
451 		      $$->string = $1;
452 		    }
453 		| RevisionList ',' GAMEID
454 		    {
455 		      if ($1 == NULL)
456 		        {
457 		          $$ = NULL;
458 			}
459 	              else
460 		        {
461 		          $$ = malloc(sizeof(stringlist));
462 		          $$->next = $1;
463 		          $$->string = $3;
464 			}
465 		    }
466 		;
467 
468 ErrorList:	  error '}' { yyerrok; }
469 		;
470 
471 %%
472