1 %{
2 /**
3  *
4  * $Id: mwmparse.y,v 1.1 2004/08/28 19:27:39 dannybackx Exp $
5  *
6  * Copyright (C) 1995 Free Software Foundation, Inc.
7  * Copyright (C) 1995-2002 LessTif Development Team
8  *
9  * This file is part of the GNU LessTif Library.
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Library General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Library General Public License for more details.
20  *
21  * You should have received a copy of the GNU Library General Public
22  * License along with this library; if not, write to the Free
23  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  *
25  **/
26 
27 #include "LTconfig.h"
28 
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <string.h>
33 #ifdef HAVE_FCNTL_H
34 #include <fcntl.h>
35 #endif
36 #ifdef HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif
39 #ifdef HAVE_SYS_TYPES_H
40 #include <sys/types.h>
41 #endif
42 #ifdef HAVE_SYS_STAT_H
43 #include <sys/stat.h>
44 #else
45 #error "you lose (I don't know how to fix this)"
46 #endif
47 #include <X11/Xfuncs.h>
48 
49 #include <Xm/Xm.h>
50 #include <Xm/MwmUtil.h>
51 
52 #include "mwm.h"
53 
54 
55 extern int yydebug;
56 extern int yylex(void);
57 
58 static int num_items;
59 static MenuRoot *cur_menu;
60 static ScreenInfo *pscr;
61 static Boolean skip_test;
62 static Boolean button_bind_match;
63 static Boolean button_bind_found;
64 static Boolean key_bind_match;
65 static Boolean key_bind_found;
66 
67 /*
68  * this must be here for the parser
69  */
70 static int lineno;
71 
72 %}
73 %token  ALT_TOK
74 	APP_TOK
75 	BACK_TOK
76 	BORDER_TOK
77 	BTN1_CLICK2_TOK
78 	BTN1_CLICK_TOK
79 	BTN1_DOWN_TOK
80 	BTN1_UP_TOK
81 	BTN2_CLICK2_TOK
82 	BTN2_CLICK_TOK
83 	BTN2_DOWN_TOK
84 	BTN2_UP_TOK
85 	BTN3_CLICK2_TOK
86 	BTN3_CLICK_TOK
87 	BTN3_DOWN_TOK
88 	BTN3_UP_TOK
89 	BTN4_CLICK2_TOK
90 	BTN4_CLICK_TOK
91 	BTN4_DOWN_TOK
92 	BTN4_UP_TOK
93 	BTN5_CLICK2_TOK
94 	BTN5_CLICK_TOK
95 	BTN5_DOWN_TOK
96 	BTN5_UP_TOK
97 	BUTTONS_TOK
98 	CTRL_TOK
99 	FBEEP_TOK
100 	FCIRCLE_DOWN_TOK
101 	FCIRCLE_UP_TOK
102 	FEXEC_TOK
103 	FFOCUS_COLOR_TOK
104 	FFOCUS_KEY_TOK
105 	FKILL_TOK
106 	FLOWER_TOK
107 	FMAXIMIZE_TOK
108 	FMENU_TOK
109 	FMINIMIZE_TOK
110 	FMOVE_TOK
111 	FNEXT_CMAP_TOK
112 	FNEXT_KEY_TOK
113 	FNOP_TOK
114 	FNORMALIZE_TOK
115 	FNORMANDRAISE_TOK
116 	FPACK_ICONS_TOK
117 	FPASS_KEYS_TOK
118 	FPOST_WMENU_TOK
119 	FPREV_CMAP_TOK
120 	FPREV_KEY_TOK
121 	FQUIT_MWM_TOK
122 	FRAISE_LOWER_TOK
123 	FRAISE_TOK
124 	FRAME_TOK
125 	FREE_FAMILY_TOK
126 	FREFRESH_TOK
127 	FREFRESH_WIN_TOK
128 	FRESIZE_TOK
129 	FRESTART_TOK
130 	FRESTOREANDRAISE_TOK
131 	FRESTORE_TOK
132 	FSCREEN_TOK
133 	FSEND_MSG_TOK
134 	FSEPARATOR_TOK
135 	FSET_BEHAVIOR_TOK
136 	FTITLE_TOK
137 	FWINDOWLIST_TOK
138 	FDESK_TOK
139 	FTOGGLE_PAGE_TOK
140 	FGOTO_PAGE_TOK
141 	ICON_TOK
142 	KEY_TOK
143 	KEYS_TOK
144 	LOCK_TOK
145 	MENU_TOK
146 	MENUB_TOK
147 	MINIMIZEB_TOK
148 	MAXIMIZEB_TOK
149 	MOD1_TOK
150 	MOD2_TOK
151 	MOD3_TOK
152 	MOD4_TOK
153 	MOD5_TOK
154 	NEXT_TOK
155 	PREV_TOK
156 	ROOT_TOK
157 	SHIFT_TOK
158 	TITLE_TOK
159 	TRANSIENT_TOK
160 	WINDOW_TOK
161 	WITHIN_TOK
162 	STRING_TOK
163 
164 %type <string>
165 	STRING_TOK
166 
167 %type <number>
168 	FCIRCLE_DOWN_TOK
169 	FCIRCLE_UP_TOK
170 	FEXEC_TOK
171 	FFOCUS_COLOR_TOK
172 	FFOCUS_KEY_TOK
173 	FKILL_TOK
174 	FLOWER_TOK
175 	FMAXIMIZE_TOK
176 	FMENU_TOK
177 	FMINIMIZE_TOK
178 	FMOVE_TOK
179 	FNEXT_CMAP_TOK
180 	FNEXT_KEY_TOK
181 	FNOP_TOK
182 	FNORMALIZE_TOK
183 	FNORMANDRAISE_TOK
184 	FPACK_ICONS_TOK
185 	FPASS_KEYS_TOK
186 	FPOST_WMENU_TOK
187 	FPREV_CMAP_TOK
188 	FPREV_KEY_TOK
189 	FQUIT_MWM_TOK
190 	FRAISE_LOWER_TOK
191 	FRAISE_TOK
192 	FRAME_TOK
193 	FREE_FAMILY_TOK
194 	FREFRESH_TOK
195 	FREFRESH_WIN_TOK
196 	FRESIZE_TOK
197 	FRESTART_TOK
198 	FRESTOREANDRAISE_TOK
199 	FRESTORE_TOK
200 	FSCREEN_TOK
201 	FSEND_MSG_TOK
202 	FSEPARATOR_TOK
203 	FSET_BEHAVIOR_TOK
204 	FTITLE_TOK
205 	ICON_TOK
206 
207 %type <string>
208 	bitmap_file
209 	string
210 
211 %type <label>
212 	label
213 
214 %type <number>
215 	context
216 	object
217 
218 %type <function>
219 	function
220 
221 %type <modifiers>
222 	modifier_name
223 	modifier_list
224 
225 %type <hotkey>
226 	key
227 
228 %union {
229     char	*string;
230     int		number;
231     KeySym	key;
232     struct {
233 	int func;
234 	char *arg;
235     } function;
236     struct {
237 	int type;
238 	char *string;
239     } label;
240     long	modifiers;
241     struct {
242 	int button;
243 	int event;
244 	int count;
245 	int modifiers;
246     } button;
247     struct {
248 	int modifiers;
249 	KeySym key;
250     } hotkey;
251 };
252 
253 %%
254 res_file:		res_file binding
255 	|
256 ;
257 
258 binding:		button_bindings
259 	|		key_bindings
260 	|		menu_bindings
261 ;
262 
263 button_bindings:	BUTTONS_TOK string
264 			{
265 			    if (!skip_test) {
266 				if (button_bind_found == False) {
267 				    if (strcmp($2, pscr->button_bindings) == 0)
268 					button_bind_match = True;
269 				    else
270 					button_bind_match = False;
271 				}
272 				else if (strcmp($2, pscr->button_bindings) == 0) {
273 				    yyerror("Ignoring duplicate button bindings");
274 				    button_bind_match = False;
275 				}
276 				else
277 				    button_bind_match = False;
278 			    }
279 			    else
280 				button_bind_match = True;
281 			}
282 			'{' button_list '}'
283 ;
284 
285 button_list:		button_list button_binding
286 	|		error
287 			{
288 			    yyerror("Invalid button binding");
289 			    yyerrok;
290 			    yyclearin;
291 			}
292 	|
293 ;
294 
295 button_binding:		button context function
296 			{
297 			    int contexts = $<number>2;
298 			    int mods, func;
299 			    MenuItem *mi = NULL;
300 			    MouseButton *temp = NULL, *ptr;
301 
302 			    if (!button_bind_match)
303 				break;
304 
305 			    mods = $<button>1.modifiers;
306 			    if ((contexts & C_WINDOW) &&
307 				(((mods == 0) || mods == AnyModifier))) {
308 			        pscr->buttons2grab &= ~($<button>1.button);
309 			    }
310 
311 			    func = $<function>3.func;
312 
313 			    if ((func == F_EXEC) ||
314 				(func == F_RESTART) ||
315 			        (func == F_CIRCULATE_UP) ||
316 				(func == F_CIRCULATE_DOWN) ||
317 			        (func == F_WARP)) {
318 			        mi = (MenuItem *)XtMalloc(sizeof(MenuItem));
319 
320 			        mi->next = (MenuItem *) NULL;
321 			        mi->prev = (MenuItem *) NULL;
322 			        if ((func == F_EXEC) || (func == F_RESTART)) {
323 			            mi->item = XtNewString("DOIT");
324 			            mi->action = $<function>3.arg;
325 			        }
326 			        else {
327 			            mi->item = XtNewString("DONT DOIT");
328 			            mi->action = $<function>3.arg;
329 			        }
330 				mi->item2 = "";
331 			        mi->state = 0;
332 			        mi->func = func;
333 			        mi->strlen = strlen(mi->item);
334 				mi->strlen2 = 0;
335 			        mi->val1 = 0;
336 			        mi->val2 = 0;
337 			        mi->val1_unit = 1;
338 			        mi->val2_unit = 1;
339 			    }
340 
341 			    temp = pscr->buttons;
342 			    pscr->buttons =
343 				(MouseButton *)XtMalloc(sizeof(MouseButton));
344 			    pscr->buttons->func = func;
345 			    if (func == F_POPUP)
346 				pscr->buttons->menu = (MenuRoot *)$<function>3.arg;
347 			    else if (func == F_W_POPUP)
348 				pscr->buttons->menu = (MenuRoot *)DEFAULT_WIN_MENU_NAME;
349 			    else
350 				pscr->buttons->menu = NULL;
351 			    pscr->buttons->item = mi;
352 			    pscr->buttons->button =
353 				ffs($<button>1.button) - 8;
354 			    pscr->buttons->context = contexts;
355 			    pscr->buttons->modifier = mods;
356 			    pscr->buttons->mask = $<button>1.event;
357 			    pscr->buttons->count = $<button>1.count;
358 			    pscr->buttons->val1 = 0;
359 			    pscr->buttons->val2 = 0;
360 			    pscr->buttons->val1_unit = pscr->d_width;
361 			    pscr->buttons->val2_unit = pscr->d_height;
362 
363 			    /* if duplicate, skip second */
364 			    for (ptr = temp;
365 				 ptr != NULL;
366 				 ptr = ptr->next) {
367                               /* If everything is the same except for having
368                                   func's F_POPUP and F_WINDOWLIST, the
369                                   second is a duplicate */
370                                if (((ptr->func == F_POPUP ||
371                                      ptr->func == F_WINDOWLIST) &&
372                                     (pscr->buttons->func == F_POPUP ||
373                                      pscr->buttons->func == F_WINDOWLIST)) &&
374 				    ptr->modifier == pscr->buttons->modifier &&
375 				    ptr->mask == pscr->buttons->mask &&
376                                    ptr->count == pscr->buttons->count &&
377                                    ptr->context == pscr->buttons->context &&
378                                    ptr->button  == pscr->buttons->button) {
379 
380                                    XtFree((char *)pscr->buttons);
381                                    pscr->buttons = temp;
382                                    break;
383                                }
384 
385                                if (ptr->func == pscr->buttons->func &&
386                                    ptr->modifier == pscr->buttons->modifier &&
387                                    ptr->mask == pscr->buttons->mask &&
388                                    ptr->count == pscr->buttons->count &&
389                                    ptr->button == pscr->buttons->button) {
390 				    ptr->context |= pscr->buttons->context;
391 				    XtFree((char *)pscr->buttons);
392 				    pscr->buttons = temp;
393 				    break;
394 				}
395 			    }
396 			    if (ptr == NULL)
397 				pscr->buttons->next = temp;
398 			}
399 ;
400 
401 key_bindings:		KEYS_TOK string
402 			{
403 			    if (!skip_test) {
404 				if (key_bind_found == False) {
405 				    if (strcmp($2, pscr->key_bindings) == 0)
406 					key_bind_match = True;
407 				    else
408 					key_bind_match = False;
409 				}
410 				else if (strcmp($2, pscr->key_bindings) == 0) {
411 				    yyerror("Ignoring duplicate key bindings");
412 					key_bind_match = False;
413 				}
414 				else
415 				    key_bind_match = False;
416 			    }
417 			    else
418 				key_bind_match = True;
419 			}
420 			'{' key_list '}'
421 ;
422 
423 key_list:		key_list key_binding
424 	|		error
425 			{
426 			    yyerror("Invalid key binding");
427 			    yyerrok;
428 			    yyclearin;
429 			}
430 	|
431 ;
432 
433 key_binding:		key context function
434 			{
435 			    FuncKey        *tmp = NULL;
436 			    KeySym          keysym;
437 			    KeyCode         keycode;
438 			    int             i, min, max;
439 			    int func, contexts;
440 			    char *ptr;
441 
442 			    if (!key_bind_match)
443 				break;
444 
445 			    ptr = $<function>3.arg;
446 			    func = $<function>3.func;
447 			    contexts = $<number>2;
448 
449 			    /*
450 			     * Don't let a 0 keycode go through, since that
451 			     * means AnyKey to the XGrabKey call in GrabKeys().
452 			     */
453 			    keysym = $<hotkey>1.key;
454 			    if (keysym == 0)
455 				break;
456 			    if ((keycode = XKeysymToKeycode(dpy, $<hotkey>1.key)) == 0)
457 				break;
458 
459 			    XDisplayKeycodes(dpy, &min, &max);
460 			    for (i = min; i <= max; i++) {
461 				if (XKeycodeToKeysym(dpy, i, 0) == keysym) {
462 				    tmp = (FuncKey *)XtMalloc(sizeof(FuncKey));
463 				    tmp->next = pscr->keys;
464 				    pscr->keys = tmp;
465 
466 				    tmp->name = "HOTKEY";
467 				    tmp->keycode = i;
468 				    tmp->cont = contexts;
469 				    tmp->mods = $<hotkey>1.modifiers;
470 				    tmp->func = func;
471 				    if (func == F_W_POPUP)
472 					tmp->action = DEFAULT_WIN_MENU_NAME;
473 				    else
474 					tmp->action = ptr;
475 				    tmp->val1 = 0;
476 				    tmp->val2 = 0;
477 				    tmp->val1_unit = pscr->d_width;
478 				    tmp->val2_unit = pscr->d_height;
479 				    tmp->menu = NULL;
480 				}
481 			    }
482 			}
483 ;
484 
485 menu_bindings:		MENU_TOK string
486 			{
487 			    num_items = 0;
488 			    cur_menu = MENU_Create($<string>2);
489 			}
490 			'{' item_list '}'
491 			{
492 			    MENU_Add(pscr, cur_menu);
493 			}
494 ;
495 
496 item_list:		item_list item_binding
497 	|		error
498 			{
499 			    yyerror("Invalid menu item");
500 			    yyerrok;
501 			    yyclearin;
502 			}
503 	|
504 ;
505 
506 item_binding:		label mnemonic accelerator function
507 			{
508 			    MenuItem *tmp;
509 			    int width, width2;
510 			    FuncKey        *tmpk = NULL;
511 			    KeySym          keysym;
512 			    KeyCode         keycode;
513 			    int             i, min, max;
514 			    int func, contexts;
515 			    char *ptr, *acc;
516 
517 			    tmp = (MenuItem *)XtCalloc(1, sizeof(MenuItem));
518 			    if (cur_menu->first == NULL) {
519 				cur_menu->first = tmp;
520 				tmp->prev = NULL;
521 				tmp->next = NULL;
522 			    }
523 			    else {
524 				cur_menu->last->next = tmp;
525 				tmp->prev = cur_menu->last;
526 			    }
527 			    cur_menu->last = tmp;
528 			    cur_menu->items++;
529 
530 			    if ($<function>4.func == F_NOP)
531 				tmp->item = "";
532 			    else
533 				tmp->item = $<label>1.string;
534 			    tmp->item2 = "";
535 			    MENU_FindHotKey(tmp, $<key>2);
536 			    if (strcmp(tmp->item, "no-label") == 0)
537 				tmp->strlen = 0;
538 			    else
539 				tmp->strlen = strlen(tmp->item);
540 
541 			    tmp->action = $<function>4.arg;
542 			    tmp->next = NULL;
543 			    tmp->state = 0;
544 			    tmp->func = $<function>4.func;
545 			    tmp->val1 = 0;
546 			    tmp->val2 = 0;
547 			    tmp->val1_unit = pscr->d_width;
548 			    tmp->val2_unit = pscr->d_height;
549 
550 			    width = XTextWidth(pscr->components[MWM_MENU].font,
551 					       tmp->item, tmp->strlen);
552 			    if (tmp->func == F_POPUP)
553 			        width += 15;
554 			    if (width <= 0)
555 			        width = 1;
556 			    if (width > cur_menu->width)
557 			        cur_menu->width = width;
558 
559 			    ptr = $<function>4.arg;
560 			    func = $<function>4.func;
561 			    contexts = C_WINDOW|C_ICON|C_FRAME|C_TITLE|C_LALL|C_RALL;
562 
563 			    /*
564 			     * Don't let a 0 keycode go through, since that
565 			     * means AnyKey to the XGrabKey call in GrabKeys().
566 			     */
567 			    keysym = $<hotkey>3.key;
568 			    if (keysym == 0)
569 				break;
570 			    if ((keycode = XKeysymToKeycode(dpy, $<hotkey>3.key)) == 0)
571 				break;
572 
573 			    acc = MENU_AcceleratorString(pscr,
574 							 $<hotkey>3.key,
575 							 $<hotkey>3.modifiers);
576 			    if (strlen(acc)) {
577 				tmp->item2 = XtNewString(acc);
578 				tmp->strlen2 = strlen(acc);
579 				width2 = XTextWidth(pscr->components[MWM_MENU].font,
580 						    tmp->item2, tmp->strlen2);
581 				if (width2 > cur_menu->width2)
582 				    cur_menu->width2 = width2;
583 			    }
584 
585 			    XDisplayKeycodes(dpy, &min, &max);
586 			    for (i = min; i <= max; i++) {
587 				if (XKeycodeToKeysym(dpy, i, 0) == keysym) {
588 				    tmpk = (FuncKey *)XtMalloc(sizeof(FuncKey));
589 				    tmpk->next = pscr->keys;
590 				    pscr->keys = tmpk;
591 
592 				    tmpk->name = "HOTKEY";
593 				    tmpk->keycode = i;
594 				    tmpk->cont = contexts;
595 				    tmpk->mods = $<hotkey>3.modifiers;
596 				    tmpk->func = func;
597 				    tmpk->action = ptr;
598 				    tmpk->val1 = 0;
599 				    tmpk->val2 = 0;
600 				    tmpk->val1_unit = pscr->d_width;
601 				    tmpk->val2_unit = pscr->d_height;
602 				    tmpk->menu = NULL;
603 				}
604 			    }
605 			}
606 ;
607 
608 accelerator:		key
609 			{ $<hotkey>$ = $<hotkey>1; }
610 	|
611 			{ $<hotkey>$.modifiers = 0; $<hotkey>$.key = 0; }
612 ;
613 
614 context:		context '|' object
615 			{ $<number>$ = $1 | $3; }
616 	|		object
617 			{ $<number>$ = $1; }
618 ;
619 
620 object:			ROOT_TOK
621 			{ $<number>$ = C_ROOT; }
622 	|		ICON_TOK
623 			{ $<number>$ = C_ICON; }
624 	|		MENUB_TOK
625 			{ $<number>$ = C_MENUB; }
626 	|		MINIMIZEB_TOK
627 			{ $<number>$ = C_MINIMIZEB; }
628 	|		MAXIMIZEB_TOK
629 			{ $<number>$ = C_MAXIMIZEB; }
630 	|		WINDOW_TOK
631 			{ $<number>$ = C_WINDOW|C_FRAME|C_TITLE|C_LALL|C_RALL|C_ICON; }
632 	|		TITLE_TOK
633 			{ $<number>$ = C_TITLE; }
634 	|		FRAME_TOK
635 			{ $<number>$ = C_FRAME|C_TITLE|C_LALL|C_RALL; }
636 	|		BORDER_TOK
637 			{ $<number>$ = C_FRAME; }
638 	|		APP_TOK
639 			{ $<number>$ = C_WINDOW; }
640 	|		error
641 			{ yyerror("Invalid context"); $<number>$ = 0; }
642 ;
643 
644 button:			modifier_list '<' button_event_name '>'
645 			{
646 			    $<button>$ = $<button>3;
647 			    $<button>$.modifiers = $1;
648 			}
649 	|		'<' button_event_name '>'
650 			{
651 			    $<button>$ = $<button>2;
652 			    $<button>$.modifiers = 0;
653 			}
654 ;
655 
656 key:			modifier_list '<' KEY_TOK '>' STRING_TOK
657 			{
658 			    $<hotkey>$.modifiers = $<modifiers>1;
659 			    $<hotkey>$.key = XStringToKeysym($<string>5);
660 			}
661 	|		'<' KEY_TOK '>' STRING_TOK
662 			{
663 			    $<hotkey>$.modifiers = 0;
664 			    $<hotkey>$.key = XStringToKeysym($<string>4);
665 			}
666 ;
667 
668 modifier_list:		modifier_list modifier_name
669 			{ $<modifiers>$ = $1 | $2; }
670 	|		modifier_name
671 			{ $<modifiers>$ = $1; }
672 ;
673 
674 modifier_name:		CTRL_TOK
675 			{ $<modifiers>$ = ControlMask; }
676 	|		SHIFT_TOK
677 			{ $<modifiers>$ = ShiftMask; }
678 	|		ALT_TOK
679 			{ $<modifiers>$ = pscr->alt_mask; }
680 	|		LOCK_TOK
681 			{ $<modifiers>$ = LockMask; }
682 	|		MOD1_TOK
683 			{ $<modifiers>$ = Mod1Mask; }
684 	|		MOD2_TOK
685 			{ $<modifiers>$ = Mod2Mask; }
686 	|		MOD3_TOK
687 			{ $<modifiers>$ = Mod3Mask; }
688 	|		MOD4_TOK
689 			{ $<modifiers>$ = Mod4Mask; }
690 	|		MOD5_TOK
691 			{ $<modifiers>$ = Mod5Mask; }
692 ;
693 
694 button_event_name:	BTN1_DOWN_TOK
695 			{
696 			    $<button>$.button = Button1Mask;
697 			    $<button>$.event = ButtonPressMask;
698 			    $<button>$.count = 0;
699 			}
700 	|		BTN1_UP_TOK
701 			{
702 			    $<button>$.button = Button1Mask;
703 			    $<button>$.event = ButtonReleaseMask;
704 			    $<button>$.count = 0;
705 			}
706 	|		BTN1_CLICK_TOK
707 			{
708 			    $<button>$.button = Button1Mask;
709 			    $<button>$.event = ButtonPressMask|ButtonReleaseMask;
710 			    $<button>$.count = 1;
711 			}
712 	|		BTN1_CLICK2_TOK
713 			{
714 			    $<button>$.button = Button1Mask;
715 			    $<button>$.event = ButtonPressMask|ButtonReleaseMask;
716 			    $<button>$.count = 2;
717 			}
718 	|		BTN2_DOWN_TOK
719 			{
720 			    $<button>$.button = Button2Mask;
721 			    $<button>$.event = ButtonPressMask;
722 			    $<button>$.count = 0;
723 			}
724 	|		BTN2_UP_TOK
725 			{
726 			    $<button>$.button = Button2Mask;
727 			    $<button>$.event = ButtonReleaseMask;
728 			    $<button>$.count = 0;
729 			}
730 	|		BTN2_CLICK_TOK
731 			{
732 			    $<button>$.button = Button2Mask;
733 			    $<button>$.event = ButtonPressMask|ButtonReleaseMask;
734 			    $<button>$.count = 1;
735 			}
736 	|		BTN2_CLICK2_TOK
737 			{
738 			    $<button>$.button = Button2Mask;
739 			    $<button>$.event = ButtonPressMask|ButtonReleaseMask;
740 			    $<button>$.count = 2;
741 			}
742 	|		BTN3_DOWN_TOK
743 			{
744 			    $<button>$.button = Button3Mask;
745 			    $<button>$.event = ButtonPressMask;
746 			    $<button>$.count = 0;
747 			}
748 	|		BTN3_UP_TOK
749 			{
750 			    $<button>$.button = Button3Mask;
751 			    $<button>$.event = ButtonReleaseMask;
752 			    $<button>$.count = 0;
753 			}
754 	|		BTN3_CLICK_TOK
755 			{
756 			    $<button>$.button = Button3Mask;
757 			    $<button>$.event = ButtonPressMask|ButtonReleaseMask;
758 			    $<button>$.count = 1;
759 			}
760 	|		BTN3_CLICK2_TOK
761 			{
762 			    $<button>$.button = Button3Mask;
763 			    $<button>$.event = ButtonPressMask|ButtonReleaseMask;
764 			    $<button>$.count = 2;
765 			}
766 	|		BTN4_DOWN_TOK
767 			{
768 			    $<button>$.button = Button4Mask;
769 			    $<button>$.event = ButtonPressMask;
770 			    $<button>$.count = 0;
771 			}
772 	|		BTN4_UP_TOK
773 			{
774 			    $<button>$.button = Button4Mask;
775 			    $<button>$.event = ButtonReleaseMask;
776 			    $<button>$.count = 0;
777 			}
778 	|		BTN4_CLICK_TOK
779 			{
780 			    $<button>$.button = Button4Mask;
781 			    $<button>$.event = ButtonPressMask|ButtonReleaseMask;
782 			    $<button>$.count = 1;
783 			}
784 	|		BTN4_CLICK2_TOK
785 			{
786 			    $<button>$.button = Button4Mask;
787 			    $<button>$.event = ButtonPressMask|ButtonReleaseMask;
788 			    $<button>$.count = 2;
789 			}
790 	|		BTN5_DOWN_TOK
791 			{
792 			    $<button>$.button = Button5Mask;
793 			    $<button>$.event = ButtonPressMask;
794 			    $<button>$.count = 0;
795 			}
796 	|		BTN5_UP_TOK
797 			{
798 			    $<button>$.button = Button5Mask;
799 			    $<button>$.event = ButtonReleaseMask;
800 			    $<button>$.count = 0;
801 			}
802 	|		BTN5_CLICK_TOK
803 			{
804 			    $<button>$.button = Button5Mask;
805 			    $<button>$.event = ButtonPressMask|ButtonReleaseMask;
806 			    $<button>$.count = 1;
807 			}
808 	|		BTN5_CLICK2_TOK
809 			{
810 			    $<button>$.button = Button5Mask;
811 			    $<button>$.event = ButtonPressMask|ButtonReleaseMask;
812 			    $<button>$.count = 2;
813 			}
814 	|		error
815 			{
816 			    yyerror("Invalid button event name");
817 			    $<button>$.button = 0;
818 			    $<button>$.event = 0;
819 			    $<button>$.count = 0;
820 			}
821 ;
822 
823 label:			string
824 			{ $<label>$.type = IS_STRING; $<label>$.string = $1; }
825 	|		bitmap_file
826 			{ $<label>$.type = IS_BITMAP; $<label>$.string = $1; }
827 	|		error
828 			{
829 			    yyerror("Invalid label");
830 			    $<label>$.type = IS_STRING;
831 			    $<label>$.string = "";
832 			}
833 ;
834 
835 bitmap_file:		'@' string
836 			{ $<string>$ = $2; }
837 ;
838 
839 mnemonic:		'_' string
840 			{
841 			    if (strlen($<string>2) != 1) {
842 				yyerror("Invalid mnemonic specification");
843 				$<key>$ = 0;
844 			    }
845 			    else {
846 				$<key>$ = XStringToKeysym($<string>2);
847 			    }
848 			}
849 	|
850 			{ $<key>$ = 0; }
851 ;
852 
853 function:		FBEEP_TOK
854 			{
855 			    $<function>$.func = F_BEEP;
856 			    $<function>$.arg = "";
857 			}
858 	|		FCIRCLE_DOWN_TOK optional_arg
859 			{
860 			    $<function>$.func = F_CIRCULATE_DOWN;
861 			    $<function>$.arg = $<string>2;
862 			}
863 	|		FCIRCLE_UP_TOK optional_arg
864 			{
865 			    $<function>$.func = F_CIRCULATE_UP;
866 			    $<function>$.arg = $<string>2;
867 			}
868 	|		FEXEC_TOK string
869 			{
870 			    $<function>$.func = F_EXEC;
871 			    $<function>$.arg = $<string>2;
872 			}
873 	|		'!' string
874 			{
875 			    $<function>$.func = F_EXEC;
876 			    $<function>$.arg = $<string>2;
877 			}
878 	|		FFOCUS_COLOR_TOK
879 			{
880 			    $<function>$.func = F_FOCUS_COLOR;
881 			    $<function>$.arg = "";
882 			}
883 	|		FFOCUS_KEY_TOK
884 			{
885 			    $<function>$.func = F_FOCUS_KEY;
886 			    $<function>$.arg = "";
887 			}
888 	|		FKILL_TOK
889 			{
890 			    $<function>$.func = F_CLOSE;
891 			    $<function>$.arg = "";
892 			}
893 	|		FLOWER_TOK optional_arg
894 			{
895 			    $<function>$.func = F_LOWER;
896 			    $<function>$.arg = $<string>2;
897 			}
898 	|		FMAXIMIZE_TOK
899 			{
900 			    $<function>$.func = F_MAXIMIZE;
901 			    $<function>$.arg = "";
902 			}
903 	|		FMENU_TOK string
904 			{
905 			    $<function>$.func = F_POPUP;
906 			    $<function>$.arg = $<string>2;
907 			}
908 	|		FMINIMIZE_TOK
909 			{
910 			    $<function>$.func = F_ICONIFY;
911 			    $<function>$.arg = "";
912 			}
913 	|		FMOVE_TOK
914 			{
915 			    $<function>$.func = F_MOVE;
916 			    $<function>$.arg = "";
917 			}
918 	|		FNEXT_CMAP_TOK
919 			{
920 			    $<function>$.func = F_NEXT_CMAP;
921 			    $<function>$.arg = "";
922 			}
923 	|		FNEXT_KEY_TOK optional_arg
924 			{
925 			    $<function>$.func = F_NEXT_KEY;
926 			    $<function>$.arg = $<string>2;
927 			}
928 	|		FNOP_TOK
929 			{
930 			    $<function>$.func = F_NOP;
931 			    $<function>$.arg = "";
932 			}
933 	|		FNORMALIZE_TOK
934 			{
935 			    $<function>$.func = F_NORMALIZE;
936 			    $<function>$.arg = "";
937 			}
938 	|		FNORMANDRAISE_TOK
939 			{
940 			    $<function>$.func = F_NORM_AND_RAISE;
941 			    $<function>$.arg = "";
942 			}
943 	|		FPACK_ICONS_TOK
944 			{
945 			    $<function>$.func = F_PACK_ICONS;
946 			    $<function>$.arg = "";
947 			}
948 	|		FPASS_KEYS_TOK
949 			{
950 			    $<function>$.func = F_PASS_KEYS;
951 			    $<function>$.arg = "";
952 			}
953 	|		FPOST_WMENU_TOK
954 			{
955 			    $<function>$.func = F_W_POPUP;
956 			    $<function>$.arg = "";
957 			}
958 	|		FPREV_CMAP_TOK
959 			{
960 			    $<function>$.func = F_PREV_CMAP;
961 			    $<function>$.arg = "";
962 			}
963 	|		FPREV_KEY_TOK optional_arg
964 			{
965 			    $<function>$.func = F_PREV_KEY;
966 			    $<function>$.arg = $<string>2;
967 			}
968 	|		FQUIT_MWM_TOK
969 			{
970 			    $<function>$.func = F_QUIT;
971 			    $<function>$.arg = "";
972 			}
973 	|		FRAISE_TOK optional_arg
974 			{
975 			    $<function>$.func = F_RAISE;
976 			    $<function>$.arg = $<string>2;
977 			}
978 	|		FRAISE_LOWER_TOK optional_arg
979 			{
980 			    $<function>$.func = F_RAISELOWER;
981 			    $<function>$.arg = $<string>2;
982 			}
983 	|		FREFRESH_TOK
984 			{
985 			    $<function>$.func = F_REFRESH;
986 			    $<function>$.arg = "";
987 			}
988 	|		FREFRESH_WIN_TOK
989 			{
990 			    $<function>$.func = F_REFRESH_WIN;
991 			    $<function>$.arg = "";
992 			}
993 	|		FRESIZE_TOK
994 			{
995 			    $<function>$.func = F_RESIZE;
996 			    $<function>$.arg = "";
997 			}
998 	|		FRESTORE_TOK
999 			{
1000 			    $<function>$.func = F_ICONIFY;
1001 			    $<function>$.arg = "";
1002 			}
1003 	|		FRESTOREANDRAISE_TOK
1004 			{
1005 			    $<function>$.func = F_RESTORE_AND_RAISE;
1006 			    $<function>$.arg = "";
1007 			}
1008 	|		FRESTART_TOK optional_arg
1009 			{
1010 			    $<function>$.func = F_RESTART;
1011 			    $<function>$.arg = $<string>2;
1012 			}
1013 	|		FSCREEN_TOK optional_arg
1014 			{
1015 			    $<function>$.func = F_SCREEN;
1016 			    $<function>$.arg = $<string>2;
1017 			}
1018 	|		FSEND_MSG_TOK string
1019 			{
1020 			    $<function>$.func = F_SEND_MSG;
1021 			    $<function>$.arg = $<string>2;
1022 			}
1023 	|		FSEPARATOR_TOK
1024 			{
1025 			    $<function>$.func = F_NOP;
1026 			    $<function>$.arg = "";
1027 			}
1028 	|		FSET_BEHAVIOR_TOK
1029 			{
1030 			    $<function>$.func = F_SET_BEHAVIOR;
1031 			    $<function>$.arg = "";
1032 			}
1033 	|		FTITLE_TOK
1034 			{
1035 			    $<function>$.func = F_TITLE;
1036 			    $<function>$.arg = "";
1037 			}
1038 	|		FWINDOWLIST_TOK
1039 			{
1040 			    $<function>$.func = F_WINDOWLIST;
1041 			    $<function>$.arg = "";
1042 			}
1043 	|		error
1044 			{
1045 			    yyerror("Invalid mnemonic, accelerator, or function");
1046 			    $<function>$.func = F_NOP;
1047 			    $<function>$.arg = "";
1048 			}
1049 ;
1050 
1051 optional_arg:		arg
1052 			{ $<string>$ = $<string>1; }
1053 	|
1054 			{ $<string>$ = ""; }
1055 ;
1056 
1057 arg:			'-' string
1058 			{ $<string>$ = $<string>2; }
1059 	|		ROOT_TOK
1060 			{ $<string>$ = "ROOT"; }
1061 	|		WINDOW_TOK
1062 			{ $<string>$ = "WINDOW"; }
1063 	|		TRANSIENT_TOK
1064 			{ $<string>$ = "TRANSIENT"; }
1065 	|		ICON_TOK
1066 			{ $<string>$ = "ICON"; }
1067 	|		WITHIN_TOK
1068 			{ $<string>$ = "WITHIN"; }
1069 	|		FREE_FAMILY_TOK
1070 			{ $<string>$ = "FREE_FAMILY"; }
1071 	|		NEXT_TOK
1072 			{ $<string>$ = "NEXT"; }
1073 	|		PREV_TOK
1074 			{ $<string>$ = "PREV"; }
1075 	|		BACK_TOK
1076 			{ $<string>$ = "BACK"; }
1077 ;
1078 string:			STRING_TOK
1079 			{ $<string>$ = $<string>1; }
1080 ;
1081 %%
1082 
1083 /*
1084  * these to variables are used by the parser to control input
1085  */
1086 #define MAX_UNGET	1024
1087 static const char *curpos;
1088 static const char *endpos;
1089 static const char *input_buf;
1090 static char unget[MAX_UNGET];
1091 static int upos = 0;
1092 
1093 static char *_MwmRootMenu = DEFAULT_MWM_ROOT_MENU;
1094 static char *_MwmKeyBindings = DEFAULT_MWM_KEY_BINDINGS;
1095 static char *_MwmWindowMenu = DEFAULT_MWM_WINDOW_MENU;
1096 static char *_MwmBehaviorKey = MWM_BEHAVIOR_KEY_BINDINGS;
1097 static char *_MwmBuiltinButtonBindings = BUILTIN_MWM_BUTTON_BINDINGS;
1098 static char *_MwmBuiltinMenuButtonBindings = BUILTIN_MENU_BUTTON_BINDINGS;
1099 static char *_MwmBuiltinKillButtonBindings = BUILTIN_KILL_BUTTON_BINDINGS;
1100 static char *_MwmBuiltinIconButtonBindings = BUILTIN_ICON_BUTTON_BINDINGS;
1101 
1102 void
yyerror(const char * fmt,...)1103 yyerror(const char *fmt, ...) {
1104     va_list arg_list;
1105 
1106     va_start(arg_list, fmt);
1107     vfprintf(stderr, fmt, arg_list);
1108     va_end(arg_list);
1109     fprintf(stderr, " at line %d\n", lineno);
1110 }
1111 
1112 
1113 char
mwm_getc(void)1114 mwm_getc(void) {
1115     char c;
1116 
1117     if (upos) {
1118 	upos--;
1119 	c = unget[upos];
1120 	if (c == '\n')
1121 	    lineno++;
1122 	return c;
1123     }
1124     if (curpos >= endpos)
1125 	return 0;
1126     else if (*curpos == 0) {
1127 	curpos++;
1128 	return 0;
1129     }
1130     c = *curpos;
1131     curpos++;
1132     if (c == '\n')
1133 	lineno++;
1134     return c;
1135 }
1136 
1137 
1138 void
mwm_putc(char c)1139 mwm_putc(char c) {
1140     printf("OUTPUT: %c\n", c);
1141 }
1142 
1143 
1144 void
mwm_unputc(char c)1145 mwm_unputc(char c) {
1146     if (upos == MAX_UNGET) {
1147 	yyerror("Lexer can't back up anymore.\n");
1148 	return;
1149     }
1150     if (c == '\n')
1151 	lineno--;
1152     unget[upos] = c;
1153     upos++;
1154 }
1155 
1156 
1157 int
PARSE_buf(ScreenInfo * scr,char * buffer)1158 PARSE_buf(ScreenInfo *scr, char *buffer) {
1159     pscr = scr;
1160     lineno = 1;
1161     curpos = input_buf = buffer;
1162     endpos = input_buf + strlen(input_buf);
1163     upos = 0;
1164     return yyparse();
1165 }
1166 
1167 
1168 static void
do_standard(ScreenInfo * scr)1169 do_standard(ScreenInfo *scr)
1170 {
1171     skip_test = True;
1172 
1173     PARSE_buf(scr, _MwmRootMenu);
1174     PARSE_buf(scr, _MwmWindowMenu);
1175     PARSE_buf(scr, _MwmKeyBindings);
1176     PARSE_buf(scr, _MwmBehaviorKey);
1177 
1178     /* a certain amount seems to be expected as builtin */
1179     PARSE_buf(scr, _MwmBuiltinButtonBindings);
1180     if (Mwm.w_menu_button_click)
1181 	PARSE_buf(scr, _MwmBuiltinMenuButtonBindings);
1182     if (Mwm.w_menu_button_click_2)
1183 	PARSE_buf(scr, _MwmBuiltinKillButtonBindings);
1184     if (Mwm.icon_click)
1185 	PARSE_buf(scr, _MwmBuiltinIconButtonBindings);
1186 
1187     PROP_SetBehavior(scr, False);
1188 }
1189 
1190 
1191 static void
do_custom(ScreenInfo * scr)1192 do_custom(ScreenInfo *scr)
1193 {
1194     char *configfile, *ptr;
1195     int fd;
1196 
1197     configfile=find_config_file();
1198     if (configfile==NULL)
1199     {
1200 	yyerror("Cannot find configuration file.  "
1201 		"Using builtin defaults.\n", configfile);
1202 	do_standard(scr);
1203 	return;
1204     }
1205 
1206 #ifdef __EMX__
1207     if ((fd = open(configfile, O_RDONLY|O_TEXT)) < 0)
1208 #else
1209     if ((fd = open(configfile, O_RDONLY)) < 0)
1210 #endif
1211     {
1212 	yyerror("Cannot open configuration file '%s'.  "
1213 		"Using builtin defaults.\n", configfile);
1214 	do_standard(scr);
1215     }
1216     else {
1217 	int bytes_read, statrc;
1218 	struct stat st;
1219 
1220 	if (debugging)
1221  	   fprintf(stderr, "Reading configuration from '%s'\n", configfile);
1222 
1223 	statrc=stat(configfile, &st);
1224 	ptr = XtMalloc(st.st_size + 1);
1225 	bytes_read=read(fd, ptr, st.st_size);
1226 	close(fd);
1227 
1228 	skip_test = False;
1229 	ptr[bytes_read] = '\0';
1230 	PARSE_buf(scr, ptr);
1231 
1232 	/* a certain amount seems to be expected as builtin */
1233 	skip_test = True;
1234 
1235 	PARSE_buf(scr, _MwmBuiltinButtonBindings);
1236 	if (Mwm.w_menu_button_click)
1237 	PARSE_buf(scr, _MwmBuiltinMenuButtonBindings);
1238 	if (Mwm.w_menu_button_click_2)
1239 	PARSE_buf(scr, _MwmBuiltinKillButtonBindings);
1240 	if (Mwm.icon_click)
1241 	PARSE_buf(scr, _MwmBuiltinIconButtonBindings);
1242 
1243 	PROP_SetBehavior(scr, True);
1244 
1245 	XtFree(ptr);
1246     }
1247 
1248     XtFree(configfile);
1249 }
1250 
1251 void
PARSE_mwmrc(ScreenInfo * scr)1252 PARSE_mwmrc(ScreenInfo *scr) {
1253     int flag;
1254 
1255     key_bind_found = False;
1256     button_bind_found = False;
1257     key_bind_match = False;
1258     button_bind_match = False;
1259 
1260     if ((flag = PROP_GetBehavior(scr)) & MWM_INFO_STARTUP_CUSTOM) {
1261 	if (debugging)
1262 	    printf("parsing custom file.\n");
1263 	do_custom(scr);
1264     }
1265     else if (flag & MWM_INFO_STARTUP_STANDARD) {
1266 	if (debugging)
1267 	    printf("parsing standard bindings.\n");
1268 	do_standard(scr);
1269     }
1270     else {
1271 	if (debugging)
1272 	    printf("parsing custom file by default.\n");
1273 	do_custom(scr);
1274     }
1275 
1276     return;
1277 }
1278