eh, make ’em volatile, this is not time-critical code anyway
[alioth/magicpoint.git] / grammar.y
1 %{
2 /*
3  * Copyright (C) 1997 and 1998 WIDE Project.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the project nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 /*
30  * partly derived from lbl libpcap source code, which has the following
31  * copyright notice:
32  */
33 /*
34  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996
35  *      The Regents of the University of California.  All rights reserved.
36  *
37  * Redistribution and use in source and binary forms, with or without
38  * modification, are permitted provided that: (1) source code distributions
39  * retain the above copyright notice and this paragraph in its entirety, (2)
40  * distributions including binary code include the above copyright notice and
41  * this paragraph in its entirety in the documentation or other materials
42  * provided with the distribution, and (3) all advertising materials mentioning
43  * features or use of this software display the following acknowledgement:
44  * ``This product includes software developed by the University of California,
45  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
46  * the University nor the names of its contributors may be used to endorse
47  * or promote products derived from this software without specific prior
48  * written permission.
49  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
50  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
51  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
52  *
53  */
54
55 #define IN_GRAMMAR_Y
56 #include "mgp.h"
57 #include <stdarg.h>
58
59 int yylex(void);
60
61 int n_errors = 0;
62 struct ctrl *yyroot;
63 char *yyfilename;
64 int yylineno;
65
66 void
67 yyerror(const char *msg, ...)
68 {
69         va_list ap;
70         va_start(ap, msg);
71         ++n_errors;
72         fprintf(stderr, "%s:%d: error: ", yyfilename, yylineno);
73         vfprintf(stderr, msg, ap);
74         fprintf(stderr, "\n");
75         va_end(ap);
76 }
77
78 static void yywarn(const char *msg, ...)
79 #if HAVE_ATTRIBUTE_FORMAT
80     __attribute__((__format__(__printf__, 1, 2)))
81 #endif
82     ;
83
84 static void
85 yywarn(const char *msg, ...)
86 {
87         va_list ap;
88         va_start(ap, msg);
89         fprintf(stderr, "%s:%d: warning: ", yyfilename, yylineno);
90         vfprintf(stderr, msg, ap);
91         fprintf(stderr, "\n");
92         va_end(ap);
93 }
94
95 static struct ctrl *
96 gen_void(int op)
97 {
98         struct ctrl *ct;
99
100         if (!(ct = ctlalloc1(op))) {
101                 yyerror("cannot allocate void node");
102                 return ct;
103         }
104         return ct;
105 }
106
107 static struct ctrl *
108 gen_double_int(int op, int v)
109 {
110         struct ctrl *ct;
111
112         if (!(ct = ctlalloc1(op))) {
113                 yyerror("cannot allocate double node");
114                 return ct;
115         }
116         ct->ctf_value = (double)v;
117         return ct;
118 }
119
120 static struct ctrl *
121 gen_double(int op, double v)
122 {
123         struct ctrl *ct;
124
125         if (!(ct = ctlalloc1(op))) {
126                 yyerror("cannot allocate double node");
127                 return ct;
128         }
129         ct->ctf_value = v;
130         return ct;
131 }
132
133 static struct ctrl *
134 gen_int(int op, int v)
135 {
136         struct ctrl *ct;
137
138         if (!(ct = ctlalloc1(op))) {
139                 yyerror("cannot allocate integer node");
140                 return ct;
141         }
142         ct->cti_value = v;
143         return ct;
144 }
145
146 static struct ctrl *
147 gen_int3(int op, int v1, int v2, int v3)
148 {
149         struct ctrl *ct;
150
151         if (!(ct = ctlalloc1(op))) {
152                 yyerror("cannot allocate integer3 node");
153                 return ct;
154         }
155         ct->cti3_value1 = v1;
156         ct->cti3_value2 = v2;
157         ct->cti3_value3 = v3;
158         return ct;
159 }
160
161 static struct ctrl *
162 gen_str(int op, const char *str)
163 {
164         struct ctrl *ct;
165
166         if (!(ct = ctlalloc1(op))) {
167                 yyerror("cannot allocate str1 node");
168                 return ct;
169         }
170         ct->ctc_value = strdup(str);
171         return ct;
172 }
173
174 static struct ctrl *
175 gen_str2(int op, const char *str1, const char *str2)
176 {
177         struct ctrl *ct;
178
179         if (!(ct = ctlalloc1(op))) {
180                 yyerror("cannot allocate str2 node");
181                 return ct;
182         }
183         ct->ctc2_value1 = strdup(str1);
184         ct->ctc2_value2 = strdup(str2);
185         return ct;
186 }
187
188 static struct ctrl *
189 gen_color(int op, char *color)
190 {
191         struct ctrl *ct;
192
193         if (!(ct = ctlalloc1(op))) {
194                 yyerror("cannot allocate colour node");
195                 return ct;
196         }
197         if (get_color(color, &ct->ctl_value) < 0)
198                 yyerror("cannot allocate colour \"%s\"", color);
199         return ct;
200 }
201
202 static struct ctrl *
203 gen_bgrad(int w, int h, int colors, int dir, int zoomflg, struct ctrl *extra)
204 {
205         struct ctrl *ct;
206         struct ctrl *p;
207         int siz;
208
209         if (!(ct = ctlalloc1(CTL_BGRAD))) {
210                 yyerror("cannot allocate node (op=BGRAD)");
211                 return ct;
212         }
213         ct->ctd_width = w;
214         ct->ctd_height = h;
215         ct->ctd_numcolor = colors;
216         ct->ctd_dir = dir;
217         ct->ctd_zoomflag = zoomflg;
218
219         /* process color list. */
220         siz = ct->ctd_g_colors = 0;
221         for (p = extra; p; p = p->ct_next)
222                 siz++;
223         if (siz <= 2) {
224                 ct->ct_val.ctrl_grad.colors =
225                         malloc(3 * sizeof(struct gcolor *));
226         } else {
227                 ct->ct_val.ctrl_grad.colors =
228                         malloc((siz + 1) * sizeof(struct gcolor *));
229         }
230         if (!ct->ct_val.ctrl_grad.colors) {
231                 yyerror("cannot allocate color table");
232                 return ct;
233         }
234
235         ct->ctd_g_colors = 2;
236         ct->ct_val.ctrl_grad.colors[0] = name2gcolor(DEFAULT_GRADSTART);
237         ct->ct_val.ctrl_grad.colors[1] = name2gcolor(DEFAULT_GRADEND);
238         switch (siz) {
239         case 0:
240                 break;
241         case 1:
242                 ct->ct_val.ctrl_grad.colors[0] = name2gcolor(extra->ctc_value);
243                 break;
244         default:
245                 ct->ctd_g_colors = siz;
246                 siz = 0;
247                 for (p = extra; p; p = p->ct_next) {
248                         ct->ct_val.ctrl_grad.colors[siz] =
249                                 name2gcolor(p->ctc_value);
250                         siz++;
251                 }
252         }
253
254         /* normalize */
255         if (ct->ctd_dir < 0) {  /*circle*/
256                 ct->ctd_mode = 1;
257                 ct->ctd_dir = abs(ct->ctd_dir);
258         } else                  /*linear*/
259                 ct->ctd_mode = 0;
260         while (ct->ctd_dir < 0)
261                 ct->ctd_dir += 360;
262         ct->ctd_dir %= 360;
263         if (ct->ctd_width <= 0)
264                 ct->ctd_width = 100;
265         if (ct->ctd_height <= 0)
266                 ct->ctd_height = 100;
267
268         if (extra)
269                 ctlfree(extra);
270
271         return ct;
272 }
273
274 static struct ctrl *
275 gen_newimage(struct ctrl *arg)
276 {
277         struct ctrl *p;
278         struct ctrl *ct;
279
280         if (!(ct = ctlalloc1(CTL_IMAGE))) {
281                 yyerror("cannot allocate node (op=IMAGE)");
282                 return ct;
283         }
284
285         /* default setting */
286         ct->ctm_ximagesize = 100;
287         ct->ctm_yimagesize = 100;
288         ct->ctm_zoomflag = Z_NORMAL | (Z_NORMAL << Z_YSHIFT);
289         ct->ctm_raise = 0;
290         ct->ctm_rotate = 0;
291         ct->ctm_zoomonclk = 0;
292
293         for (p = arg; p; p = p->ct_next) {
294                 if (p->ctc_value[0] != '-')
295                         break;
296
297                 if (strcmp(p->ctc_value, "-colors") == 0 && p->ct_next) {
298                         p = p->ct_next;
299                         ct->ctm_numcolor = atoi(p->ctc_value);
300                 } else if (strcmp(p->ctc_value, "-xysize") == 0
301                         && p->ct_next && p->ct_next->ct_next) {
302                         p = p->ct_next;
303                         ct->ctm_ximagesize = atoi(p->ctc_value);
304                         p = p->ct_next;
305                         ct->ctm_yimagesize = atoi(p->ctc_value);
306                         ct->ctm_zoomflag = Z_ABSOLUTE | (Z_ABSOLUTE << Z_YSHIFT);
307                 } else if (strcmp(p->ctc_value, "-zoom") == 0 && p->ct_next) {
308                         p = p->ct_next;
309                         ct->ctm_ximagesize = atoi(p->ctc_value);
310                         ct->ctm_yimagesize = atoi(p->ctc_value);
311                         ct->ctm_zoomflag = Z_NORMAL | (Z_NORMAL << Z_YSHIFT);
312                 } else if (strcmp(p->ctc_value, "-xyzoom") == 0
313                         && p->ct_next && p->ct_next->ct_next) {
314                         p = p->ct_next;
315                         ct->ctm_ximagesize = atoi(p->ctc_value);
316                         p = p->ct_next;
317                         ct->ctm_yimagesize = atoi(p->ctc_value);
318                         ct->ctm_zoomflag = Z_NORMAL | (Z_NORMAL << Z_YSHIFT);
319                 } else if (strcmp(p->ctc_value, "-scrzoom") == 0 && p->ct_next) {
320                         p = p->ct_next;
321                         ct->ctm_ximagesize = atoi(p->ctc_value);
322                         ct->ctm_yimagesize = atoi(p->ctc_value);
323                         ct->ctm_zoomflag = Z_SCREEN | (Z_SCREEN << Z_YSHIFT);
324                 } else if (strcmp(p->ctc_value, "-xscrzoom") == 0 && p->ct_next) {
325                         p = p->ct_next;
326                         ct->ctm_ximagesize = atoi(p->ctc_value);
327                         ct->ctm_yimagesize = 100;
328                         ct->ctm_zoomflag = Z_SCREEN | (Z_OBEY << Z_YSHIFT);
329                 } else if (strcmp(p->ctc_value, "-yscrzoom") == 0 && p->ct_next) {
330                         p = p->ct_next;
331                         ct->ctm_ximagesize = 100;
332                         ct->ctm_yimagesize = atoi(p->ctc_value);
333                         ct->ctm_zoomflag = Z_OBEY | (Z_SCREEN << Z_YSHIFT);
334                 } else if (strcmp(p->ctc_value, "-xyscrzoom") == 0
335                         && p->ct_next && p->ct_next->ct_next) {
336                         p = p->ct_next;
337                         ct->ctm_ximagesize = atoi(p->ctc_value);
338                         p = p->ct_next;
339                         ct->ctm_yimagesize = atoi(p->ctc_value);
340                         ct->ctm_zoomflag = Z_SCREEN | (Z_SCREEN << Z_YSHIFT);
341                 } else if (strcmp(p->ctc_value, "-raise") == 0 && p->ct_next) {
342                         p = p->ct_next;
343                         ct->ctm_raise = atoi(p->ctc_value);
344                 } else if (strcmp(p->ctc_value, "-rotate") == 0 && p->ct_next) {
345                         p = p->ct_next;
346                         ct->ctm_rotate = atoi(p->ctc_value);
347                 } else if (strcmp(p->ctc_value, "-zoomonclk") == 0 && p->ct_next) {
348                         p = p->ct_next;
349                         ct->ctm_zoomonclk = atoi(p->ctc_value);
350                 } else {
351                         yyerror("invalid argument %s specified for newimage",
352                                 p->ctc_value);
353                         return ct;
354                 }
355         }
356
357         if (!p) {
358                 yyerror("no filename specified to newimage");
359                 return ct;
360         }
361
362         if (p->ct_next) {
363                 yyerror("multiple filename specified to newimage");
364                 return ct;
365         }
366
367         ct->ctm_fname = p->ctc_value;
368         chkfile(ct->ctm_fname);
369         return ct;
370 }
371
372 static struct ctrl *
373 gen_image(int op, char *fname, int colors, int xsiz, int ysiz, int zoomflg)
374 {
375         struct ctrl *ct;
376
377         if (!(ct = ctlalloc1(op))) {
378                 yyerror("cannot allocate node (op=IMAGE)");
379                 return ct;
380         }
381         ct->ctm_fname = fname;
382         ct->ctm_numcolor = colors;
383         ct->ctm_ximagesize = xsiz;
384         ct->ctm_yimagesize = ysiz;
385         switch (zoomflg) {
386         case 0:
387                 ct->ctm_zoomflag = 0;
388                 if (ct->ctm_ximagesize == 0) {
389                         ct->ctm_ximagesize = 100;
390                         ct->ctm_zoomflag |= Z_NORMAL;
391                 } else
392                         ct->ctm_zoomflag |= Z_SCREEN;
393                 if (ct->ctm_yimagesize == 0) {
394                         ct->ctm_yimagesize = 100;
395                         ct->ctm_zoomflag |= (Z_NORMAL << Z_YSHIFT);
396                 } else
397                         ct->ctm_zoomflag |= (Z_SCREEN << Z_YSHIFT);
398                 break;
399         case 1:
400                 ct->ctm_zoomflag = Z_NORMAL | (Z_NORMAL << Z_YSHIFT);
401                 break;
402         case 2:
403                 ct->ctm_zoomflag = Z_SCREEN0 | (Z_SCREEN0 << Z_YSHIFT);
404                 break;
405         }
406         chkfile(ct->ctm_fname);
407         return ct;
408 }
409
410 static struct ctrl *
411 gen_bar(const char *color, int thick, int start, int len)
412 {
413         struct ctrl *ct;
414
415         if (!(ct = ctlalloc1(CTL_BAR))) {
416                 yyerror("cannot allocate node (op=BAR)");
417                 return ct;
418         }
419         if (get_color(color, &ct->ctb_color) < 0)
420                 yyerror("cannot allocate colour %s", color);
421
422         /* normalise */
423
424         if (thick < 0)
425                 ct->ctb_width = 0;
426         else if (thick > 1000)
427                 ct->ctb_width = 1000;
428         else
429                 ct->ctb_width = thick;
430
431         if (start < 0)
432                 ct->ctb_start = 0;
433         else if (start > 100)
434                 ct->ctb_start = 100;
435         else
436                 ct->ctb_start = start;
437
438         if ((ct->ctb_start + len) > 100)
439                 ct->ctb_length = 100 - ct->ctb_start;
440         else
441                 ct->ctb_length = len;
442
443         return ct;
444 }
445
446 static struct ctrl *
447 gen_icon(char *n, char *color, int siz)
448 {
449         struct ctrl *ct;
450
451         if (!(ct = ctlalloc1(CTL_ICON))) {
452                 yyerror("cannot allocate node (op=ICON)");
453                 return ct;
454         }
455         ct->ctic_value = n;
456         if (get_color(color, &ct->ctic_color) < 0)
457                 yyerror("cannot allocate colour %s", color);
458         ct->ctic_size = siz;
459         return ct;
460 }
461
462 static struct ctrl *
463 gen_pcache(int flag, int mode, int effect, int value)
464 {
465         struct ctrl *ct;
466
467         if (!(ct = ctlalloc1(CTL_PCACHE))) {
468                 yyerror("cannot allocate node (op=PCACHE)");
469                 return ct;
470         }
471         ct->ctch_flag = flag;
472         ct->ctch_mode = mode;
473         ct->ctch_effect = effect;
474         ct->ctch_value = value;
475
476         return ct;
477 }
478
479 static struct ctrl *
480 gen_valign(char *align)
481 {
482         struct ctrl *ct;
483
484         if (!(ct = ctlalloc1(CTL_VALIGN))) {
485                 yyerror("cannot allocate node (op=VALIGN)");
486                 return ct;
487         }
488         if (!strcmp(align, "center"))
489                 ct->cti_value = VL_CENTER;
490         else {
491                 if (!strcmp(align, "top"))
492                         ct->cti_value = VL_TOP;
493                 else {
494                         if (!strcmp(align, "bottom"))
495                                 ct->cti_value = VL_BOTTOM;
496                         else {
497                                 yyerror("%%valign not center|top|bottom");
498                                 ctlfree(ct);
499                                 return NULL;
500                         }
501                 }
502         }
503         return ct;
504 }
505
506 static struct ctrl *
507 gen_area(int width, int height, int xoff, int yoff)
508 {
509         struct ctrl *ct;
510
511         if (!(ct = ctlalloc1(CTL_AREA))) {
512                 yyerror("cannot allocate node (op=AREA)");
513                 return ct;
514         }
515         if (width < 0 || width > 100)
516                 width = 100;
517         if (height < 0 || height > 100)
518                 height = 100;
519         if (xoff < 0)
520                 xoff = (100 - width) / 2;
521         else if (width + xoff > 100)
522                 xoff = 100 - width;
523         if (yoff < 0)
524                 yoff = (100 - height) / 2;
525 #ifdef notdef   /* mgp doesn't check overflow in y axis, anyway. */
526         else if (height + yoff > 100)
527                 yoff = 100 - height;
528 #endif
529         ct->ctar_width = width;
530         ct->ctar_height = height;
531         ct->ctar_xoff = xoff;
532         ct->ctar_yoff = yoff;
533         return ct;
534 }
535
536 static struct ctrl *
537 gen_argsfromstr(int op, char *str, int flag)
538 {
539         struct ctrl *ct;
540         unsigned int siz;
541         char **h;
542
543         if (!(ct = ctlalloc1(op))) {
544                 yyerror("cannot allocate args node");
545                 return ct;
546         }
547
548         ct->cta_argc = 0;
549         ct->cta_argv = malloc((siz = 16) * sizeof(char *));     /*initial siz*/
550         ct->cta_flag = flag;
551         if (!ct->cta_argv) {
552                 yyerror("cannot allocate args table");
553                 return ct;
554         }
555         for (h = (char **)ct->cta_argv;
556              (*h = strsep((char **)&str, " "));
557              /*none*/) {
558                 if (**h != '\0') {
559                         h++;
560                         ct->cta_argc++;
561                         if (siz < ct->cta_argc + 2) {
562                                 siz *= 2;
563                                 ct->cta_argv = realloc(ct->cta_argv,
564                                         siz * sizeof(char *));
565                                 if (!ct->cta_argv) {
566                                         yyerror("cannot allocate args table");
567                                         return ct;
568                                 }
569                         }
570                 }
571         }
572         ct->cta_argv[ct->cta_argc] = NULL;
573
574         return ct;
575 }
576
577 static void
578 check_xfont(const char *seed, const char *registry)
579 {
580         int hyphen;
581         const char *p;
582
583         hyphen = 0;
584         for (p = seed; *p; p++) {
585                 if (*p == '-')
586                         hyphen++;
587         }
588         switch (hyphen) {
589         case 0:
590         case 1:
591         case 2:
592         case XLFD_HYPHEN:
593                 break;
594         default:
595                 yyerror("invalid XFONT seed <%s>", seed);
596                 break;
597         }
598
599         hyphen = 0;
600         for (p = registry; *p; p++) {
601                 if (*p == '-')
602                         hyphen++;
603         }
604         switch (hyphen) {
605         case 0:
606         case 1:
607                 break;
608         default:
609                 yyerror("invalid XFONT registry <%s>", registry);
610                 break;
611         }
612 }
613
614 %}
615
616 %union {
617         int i;
618         double d;
619         char *s;
620         struct ctrl *ct;
621 }
622
623 %token COMMA NUM DOUBLE ID STR WINSIZ
624 %token KW_NOOP KW_DEFAULT KW_TAB KW_SIZE KW_FORE KW_BACK KW_LEFT KW_CENTER
625 %token KW_RIGHT KW_SHRINK KW_LCUTIN KW_RCUTIN KW_CONT KW_NODEF KW_XFONT
626 %token KW_IMAGE KW_BIMAGE KW_PAGE KW_HGAP KW_VGAP KW_GAP KW_PAUSE
627 %token KW_PREFIX KW_AGAIN KW_CCOLOR KW_BAR KW_INCLUDE KW_BGRAD KW_TEXT
628 %token KW_LINESTART KW_LINEEND KW_MARK KW_SYSTEM KW_FILTER KW_ENDFILTER
629 %token KW_QUALITY KW_ICON KW_LEFTFILL KW_XSYSTEM KW_TSYSTEM
630 %token KW_DEFFONT KW_FONT KW_NEWIMAGE KW_PSFONT
631 %token KW_CHARSET KW_PCACHE KW_VALIGN KW_AREA
632 %token KW_OPAQUE KW_SUP KW_SUB KW_SETSUP KW_TITLE
633
634 %type <ct> toplevel
635 %type <ct> line defaultline tabline shellline deffontline
636 %type <ct> cmd defaultcmd tabcmd  deffontcmd
637 %type <ct> nid args arg
638 %type <i> NUM
639 %type <d> DOUBLE
640 %type <s> ID STR WINSIZ STRorID
641
642 %%
643 toplevel: line                  { yyroot = $$; }
644         | defaultline           { yyroot = $$; }
645         | tabline               { yyroot = $$; }
646         | shellline             { yyroot = $$; }
647         | deffontline           { yyroot = $$; }
648         ;
649 line:     cmd                   { $$ = $1; }
650         | cmd COMMA line        { $$ = $1; $$->ct_next = $3; }
651         ;
652 defaultline: defaultcmd line    { $$ = $1; $$->ct_next = $2; }
653         ;
654 tabline: tabcmd line            { $$ = $1; $$->ct_next = $2; }
655         ;
656 deffontline: deffontcmd line    { $$ = $1; $$->ct_next = $2; }
657         ;
658 STRorID:  STR
659         | ID                    { yywarn("\"%s\" should be quoted", $1); }
660         ;
661 shellline:
662           KW_SYSTEM STR NUM     { $$ = gen_argsfromstr(CTL_SYSTEM, $2, $3); }
663         | KW_SYSTEM STR         { $$ = gen_argsfromstr(CTL_SYSTEM, $2, 0); }
664         | KW_XSYSTEM STR NUM    { $$ = gen_argsfromstr(CTL_XSYSTEM, $2, $3); }
665         | KW_XSYSTEM STR        { $$ = gen_argsfromstr(CTL_XSYSTEM, $2, 0); }
666         | KW_TSYSTEM STR NUM    { $$ = gen_argsfromstr(CTL_TSYSTEM, $2, $3); }
667         | KW_TSYSTEM STR        { $$ = gen_argsfromstr(CTL_TSYSTEM, $2, 0); }
668         | KW_FILTER STR         { $$ = gen_argsfromstr(CTL_FILTER, $2, 0); }
669         | KW_ENDFILTER          { $$ = gen_void(CTL_ENDFILTER); }
670         ;
671 nid:      STRorID       { $$ = gen_str(CTL_NOOP, $1); }
672         | STRorID nid   { $$ = gen_str(CTL_NOOP, $1); $$->ct_next = $2; }
673         ;
674 args:     arg           { $$ = $1; }
675         | arg args      { $$ = $1; $$->ct_next = $2; }
676         ;
677 arg:      STR           { $$ = gen_str(CTL_NOOP, $1); }
678         | ID            { $$ = gen_str(CTL_NOOP, $1); }
679         | NUM           { char buf[30];
680                           snprintf(buf, sizeof(buf), "%d", $1);
681                           $$ = gen_str(CTL_NOOP, buf);
682                         }
683         ;
684 cmd:      KW_NOOP       { $$ = gen_void(CTL_NOOP); }
685         | KW_LEFT       { $$ = gen_void(CTL_LEFT); }
686         | KW_LEFTFILL   { $$ = gen_void(CTL_LEFTFILL); }
687         | KW_RIGHT      { $$ = gen_void(CTL_RIGHT); }
688         | KW_CENTER     { $$ = gen_void(CTL_CENTER); }
689         | KW_SHRINK     { $$ = gen_void(CTL_SHRINK); }
690         | KW_LCUTIN     { $$ = gen_void(CTL_LCUTIN); }
691         | KW_RCUTIN     { $$ = gen_void(CTL_RCUTIN); }
692         | KW_CONT       { $$ = gen_void(CTL_CONT); }
693         | KW_NODEF      { $$ = gen_void(CTL_NODEF); }
694         | KW_PAUSE      { $$ = gen_int(CTL_PAUSE, 0); }
695         | KW_AGAIN      { $$ = gen_void(CTL_AGAIN); }
696         | KW_MARK       { $$ = gen_void(CTL_MARK); }
697         | KW_PAGE       { $$ = gen_void(CTL_PAGE); }
698         | KW_SETSUP NUM NUM NUM { $$ = gen_int3(CTL_SETSUP, $2, $3, $4); }
699         | KW_SUP        { $$ = gen_void(CTL_SUP); }
700         | KW_SUB        { $$ = gen_void(CTL_SUB); }
701         | KW_SIZE NUM   { $$ = gen_double_int(CTL_SIZE, $2); }
702         | KW_SIZE DOUBLE        { $$ = gen_double(CTL_SIZE, $2); }
703         | KW_HGAP NUM   { $$ = gen_int(CTL_HGAP, $2); }
704         | KW_VGAP NUM   { $$ = gen_int(CTL_VGAP, $2); }
705         | KW_GAP NUM    { $$ = gen_int(CTL_GAP, $2); }
706         | KW_QUALITY NUM
707                         { if (!quality_flag)
708                                 $$ = gen_int(CTL_QUALITY, $2);
709                           else
710                                 $$ = ctlalloc1(CTL_NOOP);
711                         }
712         | KW_FORE STRorID       { $$ = gen_color(CTL_FORE, $2); }
713         | KW_BACK STRorID       { $$ = gen_color(CTL_BACK, $2); }
714         | KW_CCOLOR STRorID     { $$ = gen_color(CTL_CCOLOR, $2); }
715         | KW_BGRAD NUM NUM NUM NUM NUM nid
716                         { $$ = gen_bgrad($2, $3, $4, $5, $6, $7); }
717         | KW_BGRAD NUM NUM NUM NUM NUM
718                         { $$ = gen_bgrad($2, $3, $4, $5, $6,
719                                 (struct ctrl *)NULL);
720                         }
721         | KW_BGRAD NUM NUM NUM NUM
722                         { $$ = gen_bgrad($2, $3, $4, $5, 1,
723                                 (struct ctrl *)NULL);
724                         }
725         | KW_BGRAD NUM NUM NUM
726                         { $$ = gen_bgrad($2, $3, $4, 0, 1,
727                                 (struct ctrl *)NULL);
728                         }
729         | KW_BGRAD NUM NUM
730                         { $$ = gen_bgrad($2, $3, DEFAULT_GRADCOLORS, 0, 1,
731                                         (struct ctrl *)NULL);
732                         }
733         | KW_BGRAD NUM  { $$ = gen_bgrad($2, 100, DEFAULT_GRADCOLORS, 0, 1,
734                                         (struct ctrl *)NULL);
735                         }
736         | KW_BGRAD      { $$ = gen_bgrad(100, 100, DEFAULT_GRADCOLORS, 0, 1,
737                                         (struct ctrl *)NULL);
738                         }
739         | KW_XFONT STRorID
740                         { char *p;
741                           if (strncmp($2, "medium", 6) == 0
742                            || strncmp($2, "bold", 4) == 0) {
743                                 /* for backward compatibility */
744                                 p = malloc(strlen($2) + 1 + 6);
745                                 sprintf(p, "times-%s", $2);
746                           } else
747                                 p = $2;
748                           check_xfont(p, "iso8859-1"); /* lexical check */
749                           $$ = gen_str2(CTL_XFONT2, p, "iso8859-1");
750                         }
751         | KW_XFONT STRorID STRorID
752                         { check_xfont($2, $3);  /* lexical check */
753                           $$ = gen_str2(CTL_XFONT2, $2, $3);
754                         }
755         | KW_BIMAGE STRorID     { $$ = gen_image(CTL_BIMAGE, $2, 0, 0, 0, 0); }
756         | KW_BIMAGE STRorID WINSIZ
757                         { int x, y;
758                           x = atoi($3); y = atoi(strchr($3, 'x') + 1);
759                           $$ = gen_image(CTL_BIMAGE, $2, 0, x, y, 2);
760                         }
761         | KW_PSFONT STRorID     {
762                                         $$ = gen_str2(CTL_PSFONT, $2, "iso8859-1");
763                                 }
764         | KW_INCLUDE STRorID    { $$ = gen_str(CTL_INCLUDE, $2); }
765         | KW_PREFIX ID  { char *p;
766                           $$ = gen_str(CTL_PREFIX, $2);
767                           for (p = $$->ctc_value; *p; p++) {
768                                 if (*p == '_') *p = ' ';
769                           }
770                         }
771         | KW_PREFIX STR { $$ = gen_str(CTL_PREFIX, $2); }
772         | KW_PREFIX NUM { $$ = gen_double_int(CTL_PREFIXN, $2); }
773         | KW_PREFIX DOUBLE      { $$ = gen_double(CTL_PREFIXN, $2); }
774         | KW_NEWIMAGE args
775                         { $$ = gen_newimage($2); }
776         | KW_IMAGE STRorID WINSIZ
777                         { int x, y;
778                           x = atoi($3); y = atoi(strchr($3, 'x') + 1);
779                           $$ = gen_image(CTL_IMAGE, $2, 0, x, y, 2);
780                         }
781         | KW_IMAGE STRorID NUM WINSIZ
782                         { int x, y;
783                           x = atoi($4); y = atoi(strchr($4, 'x') + 1);
784                           $$ = gen_image(CTL_IMAGE, $2, $3, x, y, 2);
785                         }
786         | KW_IMAGE STRorID NUM NUM NUM NUM
787                         { $$ = gen_image(CTL_IMAGE, $2, $3, $4, $5, $6 ? 1 : 0); }
788         | KW_IMAGE STRorID NUM NUM NUM
789                         { $$ = gen_image(CTL_IMAGE, $2, $3, $4, $5, 0); }
790         | KW_IMAGE STRorID NUM NUM
791                         { $$ = gen_image(CTL_IMAGE, $2, $3, $4, 0, 0); }
792         | KW_IMAGE STRorID NUM
793                         { $$ = gen_image(CTL_IMAGE, $2, $3, 0, 0, 0); }
794         | KW_IMAGE STRorID      { $$ = gen_image(CTL_IMAGE, $2, 0, 0, 0, 0); }
795         | KW_BAR STRorID NUM NUM NUM
796                         { $$ = gen_bar($2, $3, $4, $5); }
797         | KW_BAR STRorID NUM NUM
798                         { $$ = gen_bar($2, $3, $4, 100); }
799         | KW_BAR STRorID NUM    { $$ = gen_bar($2, $3, 0, 100); }
800         | KW_BAR STRorID        { $$ = gen_bar($2, 10, 0, 100); }
801         | KW_BAR        { $$ = gen_bar("black", 10, 0, 100); }
802         | KW_ICON STR STRorID NUM
803                         { $$ = gen_icon($2, $3, $4); }
804         | KW_ICON ID STRorID NUM
805                         { $$ = gen_icon($2, $3, $4); }
806         | KW_FONT STR   { $$ = gen_str(CTL_FONT, $2); }
807         | KW_TITLE STR  { $$ = gen_str(CTL_TITLE, $2); }
808         | KW_TEXT STR   { $$ = gen_str(CTL_TEXT, $2); } /*easter egg*/
809         | KW_CHARSET STR        { $$ = gen_str(CTL_CHARSET, $2); }
810         | KW_AREA NUM NUM { $$ = gen_area($2, $3, -1, -1); }
811         | KW_AREA NUM NUM NUM NUM { $$ = gen_area($2, $3, $4, $5); }
812         | KW_PCACHE NUM NUM NUM NUM
813                         { $$ = gen_pcache($2, $3, $4, $5); }
814         | KW_PCACHE NUM
815                         { $$ = gen_pcache($2, 0, 0, 0); }
816         | KW_VALIGN STRorID     {
817                         $$ = gen_valign($2);
818         }
819         | KW_OPAQUE NUM { $$ = gen_int(CTL_OPAQUE, $2); }
820         ;
821 tabcmd:   KW_TAB NUM    { $$ = gen_int(CTL_TAB, $2); }
822         | KW_TAB ID     { $$ = gen_str(CTL_TAB, $2); }
823         ;
824 defaultcmd: KW_DEFAULT NUM
825                         { $$ = gen_int(CTL_DEFAULT, $2); }
826         ;
827 deffontcmd: KW_DEFFONT STR
828                         { $$ = gen_str(CTL_DEFFONT, $2); }
829         ;
830 %%