Use C++ linker
[oweals/cde.git] / cde / programs / dtwm / WmResParse.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* 
24  * (c) Copyright 1989, 1990, 1991, 1992, 1993, 1994 OPEN SOFTWARE FOUNDATION, INC. 
25  * ALL RIGHTS RESERVED 
26 */ 
27 /* 
28  * Motif Release 1.2.4
29 */ 
30 #ifdef REV_INFO
31 #ifndef lint
32 static char rcsid[] = "$XConsortium: WmResParse.c /main/9 1996/11/01 10:17:34 drk $"
33 #endif
34 #endif
35 /*
36  * (c) Copyright 1987, 1988, 1989, 1990, 1993, 1994 Hewlett-Packard Company
37  * (c) Copyright 1993, 1994 International Business Machines Corp.
38  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
39  * (c) Copyright 1993, 1994 Novell, Inc.
40  */
41 /*
42  * (c) Copyright 1987, 1988 DIGITAL EQUIPMENT CORPORATION */
43 /*
44  * (c) Copyright 1988 MASSACHUSETTS INSTITUTE OF TECHNOLOGY */
45
46 /*
47  * Included Files:
48  */
49
50 #include "WmGlobal.h"
51 #include "WmResNames.h"
52 #ifdef WSM
53 #include <Dt/UserMsg.h>
54 #include <Dt/Connect.h>
55 #include <Tt/tt_c.h>
56 #endif /* WSM */
57 #ifdef PANELIST
58 #include "WmParse.h"
59 #include "WmParseP.h"
60 #include "WmPanelP.h"
61 #endif /* PANELIST */
62 #include "WmResource.h"
63
64 #include <Xm/VirtKeysP.h>
65
66 #include <X11/cursorfont.h>
67 #include <X11/keysym.h>
68 #include <X11/Xatom.h>
69 #include <ctype.h>
70
71 #include <locale.h>
72
73 #ifndef NO_MULTIBYTE
74 #include <stdlib.h>
75 #endif
76
77 #ifdef MOTIF_ONE_DOT_ONE
78 #include <stdio.h>
79 #include <pwd.h>
80 #else
81 #include <Xm/XmP.h>             /* for XmeGetHomeDirName */
82 #endif
83 #ifdef WSM
84 #include <signal.h>
85 #endif /* WSM */
86
87 /* maximum string lengths */
88
89 #define MAX_KEYSYM_STRLEN    100
90 #define MAX_EVENTTYPE_STRLEN  20
91 #define MAX_MODIFIER_STRLEN   20
92 #define MAX_CONTEXT_STRLEN    20
93 #define MAX_GROUP_STRLEN      20
94
95 #define min(a,b)        ((a)>(b) ? (b) : (a))
96
97 #define MAXLINE     (MAXWMPATH+1)
98
99 #define MBBSIZ      4096
100
101 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
102 # define PARSE_MENU_ITEMS(pSD, mSpec) ParseMenuItems(pSD, mSpec)
103 #else
104 # define PARSE_MENU_ITEMS(pSD, mSpec) ParseMenuItems(pSD)
105 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
106
107 /*
108  * include extern functions
109  */
110 #include "WmResParse.h"
111 #ifdef WSM
112 #include "WmWrkspace.h"
113 #endif /* WSM */
114 #include "WmError.h"
115 #include "WmFunction.h"
116 #include "WmImage.h"
117 #include "WmXSMP.h"
118
119 #ifdef MOTIF_ONE_DOT_ONE
120 extern char   *getenv ();
121 #endif
122 #ifdef PANELIST
123 # include <errno.h>
124 # ifdef X_NOT_STDC_ENV
125 extern int errno;
126 # endif
127 # define HOME_DT_WMRC    "/.dt/dtwmrc"
128 # define LANG_DT_WMRC    "/dtwmrc"
129 # define SYS_DT_WMRC     CDE_CONFIGURATION_TOP "/sys.dtwmrc"
130 #endif /* PANELIST */
131
132 /*
133  * Global Variables And Tables:
134  */
135 static char cfileName[MAXWMPATH+1];
136 #ifdef WSM
137 #ifndef NO_MESSAGE_CATALOG
138 char * pWarningStringFile;
139 char * pWarningStringLine;
140 #else
141 char pWarningStringFile[] = "%s: %s on line %d of configuration file %s\n";
142 char pWarningStringLine[] = "%s: %s on line %d of specification string\n";
143 #endif
144 #define cfileP  (wmGD.pWmPB->pFile)
145 #define parseP  (wmGD.pWmPB->pchNext)
146 #define line    (wmGD.pWmPB->pchLine)
147 #define linec   (wmGD.pWmPB->lineNumber)
148 #else  /* WSM */
149 static FILE *cfileP = NULL;   /* fopen'ed configuration file or NULL */
150 static unsigned char  line[MAXLINE+1]; /* line buffer */
151 static int   linec = 0;       /* line counter for parser */
152 static unsigned char *parseP = NULL;   /* pointer to parse string */
153 #endif /* WSM */
154
155
156 typedef struct {
157    char         *name;
158    unsigned int  mask;
159 } MaskTableEntry;
160
161 static MaskTableEntry modifierStrings[] = {
162
163     {"none",    None},
164     {"ctrl",    ControlMask},
165     {"shift",   ShiftMask},
166     {"alt",     Mod1Mask},
167     {"meta",    Mod1Mask},
168     {"lock",    LockMask},
169     {"mod1",    Mod1Mask},
170     {"mod2",    Mod2Mask},
171     {"mod3",    Mod3Mask},
172     {"mod4",    Mod4Mask},
173     {"mod5",    Mod5Mask},
174     {NULL,      (unsigned int)NULL},
175 };
176
177 #define ALT_INDEX 3
178 #define META_INDEX 4
179
180 typedef struct {
181    char         *event;
182    unsigned int  eventType;
183    Boolean       (*parseProc)();
184    unsigned int  closure;
185    Boolean       fClick;
186 } EventTableEntry;
187
188 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
189
190 # define CCI_USE_DEFAULT_NAME_TAG "DEFAULT_NAME"
191
192 String CCIEntryModifierNames[] = {
193   "none",
194   "inline",
195   "cascade",
196   "delimit",
197   "delimit_inline",
198   "delimit_cascade",
199   "exclude"
200 };
201
202 typedef enum {
203   NONE,             /* internal only. */
204   INLINE,           /* not supported. */
205   CASCADE,
206   DELIMIT,
207   DELIMIT_INLINE,   /* not supported. */
208   DELIMIT_CASCADE,
209   EXCLUDE
210 } CCIEntryModifier;
211
212 typedef struct _CCIFuncArg {
213   CCIEntryModifier mod;
214   String           cciEntry;
215 } CCIFuncArg;
216 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
217
218 #ifdef MOTIF_ONE_DOT_ONE
219 void GetHomeDirName(String  fileName);
220 #endif
221 #ifdef WSM
222 static String GetNetworkFileName (char *pchFile);
223 #endif /* WSM */
224 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
225 static MenuItem        *MakeSeparatorTemplate  (int);
226 static void ParseMenuItemName (unsigned char **linePP, MenuItem *menuItem);
227 static Boolean ParseClientCommand (unsigned char **linePP, MenuSpec *menuSpec,
228                                    MenuItem *menuItem, unsigned char *string,
229                                    Boolean *use_separators);
230 static void FixMenuItem (MenuSpec *menuSpec, MenuItem *menuItem);
231 static Boolean GetCCIModifier (String modString, CCIEntryModifier *mod);
232 static Boolean ParseWmFuncCCIArgs (unsigned char **linePP, 
233                                    WmFunction wmFunction, String *pArgs);
234 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
235 FILE *FopenConfigFile (void);
236 void SaveMenuAccelerators (WmScreenData *pSD, MenuSpec *newMenuSpec);
237 static void ParseMenuSet (WmScreenData *pSD, unsigned char *lineP);
238 MenuItem *ParseMwmMenuStr (WmScreenData *pSD, unsigned char *menuStr);
239 static MenuItem *ParseMenuItems (WmScreenData *pSD
240 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
241                                  , MenuSpec *menuSpec
242 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
243                                 );
244 static Boolean ParseWmLabel (WmScreenData *pSD, MenuItem *menuItem, 
245                              unsigned char *string);
246 static void ParseWmMnemonic (unsigned char **linePP, MenuItem *menuItem);
247 static Boolean ParseWmAccelerator (unsigned char **linePP, MenuItem *menuItem);
248 int ParseWmFunction (unsigned char **linePP, unsigned int res_spec, 
249                             WmFunction *pWmFunction);
250 #ifndef PANELIST
251 static Boolean ParseWmFuncMaybeStrArg (unsigned char **linePP, 
252                                        WmFunction wmFunction, String *pArgs);
253 #endif /* PANELIST */
254 static Boolean ParseWmFuncNoArg (unsigned char **linePP, WmFunction wmFunction,
255                                  String *pArgs);
256 #ifndef PANELIST
257 static Boolean ParseWmFuncStrArg (unsigned char **linePP, 
258                                   WmFunction wmFunction, String *pArgs);
259 #endif /* PANELIST */
260 void FreeMenuItem (MenuItem *menuItem);
261 static Boolean ParseWmFuncGrpArg (unsigned char **linePP, 
262                                   WmFunction wmFunction, GroupArg *pGroup);
263 static Boolean ParseWmFuncNbrArg (unsigned char **linePP, 
264                                   WmFunction wmFunction, 
265                                   unsigned long *pNumber);
266 void ParseButtonStr (WmScreenData *pSD, unsigned char *buttonStr);
267 static void ParseButtonSet (WmScreenData *pSD, unsigned char *lineP);
268 static Boolean ParseContext (unsigned char **linePP, Context *context, 
269                              Context *subContext);
270 void
271 ParseKeyStr (WmScreenData *pSD, unsigned char *keyStr);
272 static void ParseKeySet (WmScreenData *pSD, unsigned char *lineP);
273 Boolean ParseBtnEvent (unsigned char  **linePP,
274                        unsigned int *eventType,
275                        unsigned int *button,
276                        unsigned int *state,
277                        Boolean      *fClick);
278 Boolean ParseKeyEvent (unsigned char **linePP, unsigned int *eventType,
279                        KeyCode *keyCode,  unsigned int *state);
280 static Boolean ParseEvent (unsigned char **linePP, EventTableEntry *table,
281                            unsigned int *eventType, unsigned int *detail,
282                            unsigned int *state, Boolean *fClick);
283 static Boolean ParseModifiers(unsigned char **linePP, unsigned int *state);
284 static Boolean LookupModifier (unsigned char *name, unsigned int *valueP);
285 static Boolean ParseEventType (unsigned char **linePP, EventTableEntry *table,
286                                unsigned int *eventType, Cardinal *ix);
287 static Boolean ParseImmed (unsigned char **linePP, unsigned int closure,
288                            unsigned int  *detail);
289 static Boolean ParseKeySym (unsigned char **linePP, unsigned int closure,
290                             unsigned int *detail);
291 static unsigned int StrToNum(unsigned char *str);
292 static unsigned int StrToHex(unsigned char *str);
293 static unsigned int StrToOct(unsigned char *str);
294 void ScanAlphanumeric (unsigned char **linePP);
295 void ScanWhitespace(unsigned char  **linePP);
296 void ToLower (unsigned char  *string);
297 void
298 PWarning (char *message);
299 static void ProcessAccelText (unsigned char *startP, unsigned char *endP,
300                               unsigned char *destP);
301 void ProcessCommandLine (int argc,  char *argv[]);
302 static void ParseScreensArgument (int argc, char *argv[], int *pArgnum,
303                                   unsigned char *lineP);
304 void ProcessMotifBindings (void);
305 #ifdef PANELIST
306 static void ParseIncludeSet (WmScreenData *pSD, unsigned char *lineP);
307 static void ConfigStackInit (char *pchFileName);
308 static FILE *ConfigStackPush (unsigned char *pchFileName);
309 static void ConfigStackPop (void);
310 Boolean ParseWmFuncActionArg (unsigned char **linePP, 
311                                   WmFunction wmFunction, String *pArgs);
312 static void PreprocessConfigFile (void);
313 #endif /* PANELIST */
314
315 static EventTableEntry buttonEvents[] = {
316
317     {"btn1down",    ButtonPress,    ParseImmed,    SELECT_BUTTON,  FALSE},
318     {"btn1up",      ButtonRelease,  ParseImmed,    SELECT_BUTTON,  FALSE},
319     {"btn1click",   ButtonRelease,  ParseImmed,    SELECT_BUTTON,  TRUE},
320     {"btn1click2",  ButtonPress,    ParseImmed,    SELECT_BUTTON,  TRUE},
321     {"btn2down",    ButtonPress,    ParseImmed,    DMANIP_BUTTON,  FALSE},
322     {"btn2up",      ButtonRelease,  ParseImmed,    DMANIP_BUTTON,  FALSE},
323     {"btn2click",   ButtonRelease,  ParseImmed,    DMANIP_BUTTON,  TRUE},
324     {"btn2click2",  ButtonPress,    ParseImmed,    DMANIP_BUTTON,  TRUE},
325     {"btn3down",    ButtonPress,    ParseImmed,    BMENU_BUTTON,  FALSE},
326     {"btn3up",      ButtonRelease,  ParseImmed,    BMENU_BUTTON,  FALSE},
327     {"btn3click",   ButtonRelease,  ParseImmed,    BMENU_BUTTON,  TRUE},
328     {"btn3click2",  ButtonPress,    ParseImmed,    BMENU_BUTTON,  TRUE},
329     {"btn4down",    ButtonPress,    ParseImmed,    Button4,  FALSE},
330     {"btn4up",      ButtonRelease,  ParseImmed,    Button4,  FALSE},
331     {"btn4click",   ButtonRelease,  ParseImmed,    Button4,  TRUE},
332     {"btn4click2",  ButtonPress,    ParseImmed,    Button4,  TRUE},
333     {"btn5down",    ButtonPress,    ParseImmed,    Button5,  FALSE},
334     {"btn5up",      ButtonRelease,  ParseImmed,    Button5,  FALSE},
335     {"btn5click",   ButtonRelease,  ParseImmed,    Button5,  TRUE},
336     {"btn5click2",  ButtonPress,    ParseImmed,    Button5,  TRUE},
337     { NULL, (unsigned int)NULL, (Boolean(*)())NULL, (unsigned int)NULL, (Boolean)NULL}
338 };
339
340
341 static EventTableEntry keyEvents[] = {
342
343     {"key",         KeyPress,    ParseKeySym,    0,  FALSE},
344     { NULL, (unsigned int)NULL, (Boolean(*)())NULL, (unsigned int)NULL, (Boolean)NULL}
345 };
346
347 #ifdef PANELIST
348 typedef struct _ConfigFileStackEntry {
349     char                *fileName;
350     char                *tempName;
351     char                *cppName;
352     char                *wmgdConfigFile;
353     long                offset;
354     DtWmpParseBuf       *pWmPB;
355     struct _ConfigFileStackEntry        *pIncluder;
356     
357 } ConfigFileStackEntry;
358
359 static ConfigFileStackEntry *pConfigStack = NULL;
360 static ConfigFileStackEntry *pConfigStackTop = NULL;
361
362 #endif /* PANELIST */
363
364 unsigned int buttonModifierMasks[] = {
365     0,
366     SELECT_BUTTON_MASK,
367     DMANIP_BUTTON_MASK,
368     BMENU_BUTTON_MASK,
369     Button4Mask,
370     Button5Mask
371 };
372
373 /*
374  * FUNCTION PARSER TABLE (function names must be in alphabetic order)
375  */
376
377 typedef struct {
378    char         * funcName;
379    Context        greyedContext;
380    unsigned int   resource;
381    long           mgtMask;
382    WmFunction     wmFunction;
383    Boolean       (*parseProc)();
384 } FunctionTableEntry;
385
386
387 /*
388  * NOTE: New functions MUST be added in ALPHABETICAL order.  A binary search
389  *       is used to find the correct function name.
390  */
391
392 FunctionTableEntry functionTable[] = {
393 #ifdef WSM
394 #ifdef PANELIST
395     {"f.action",        0,
396                         CRS_ANY,
397                         0,
398                         F_Action,
399                         ParseWmFuncActionArg},
400 #else /* PANELIST */
401     {"f.action",        0,
402                         CRS_ANY,
403                         0,
404                         F_Action,
405                         ParseWmFuncStrArg},
406 #endif  /* PANELIST */
407 #endif /* WSM */
408     {"f.beep",          0,
409                         CRS_ANY,
410                         0,
411                         F_Beep,
412                         ParseWmFuncNoArg},
413 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
414     {"f.cci",           0,
415                         CRS_ANY,
416                         0,
417                         F_Nop,
418                         ParseWmFuncCCIArgs},
419 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
420     {"f.circle_down",   F_SUBCONTEXT_IB_IICON|F_SUBCONTEXT_IB_WICON,
421                         CRS_ANY,
422                         0,
423                         F_Circle_Down,
424                         ParseWmFuncGrpArg},
425     {"f.circle_up",     F_SUBCONTEXT_IB_IICON|F_SUBCONTEXT_IB_WICON,
426                         CRS_ANY,
427                         0,
428                         F_Circle_Up,
429                         ParseWmFuncGrpArg},
430 #ifdef WSM
431     {"f.create_workspace", 0,
432                         CRS_ANY,
433                         0,
434                         F_CreateWorkspace,
435                         ParseWmFuncNoArg},
436     {"f.delete_workspace", 0,
437                         CRS_ANY,
438                         0,
439                         F_DeleteWorkspace,
440                         ParseWmFuncNoArg},
441 #endif /* WSM */
442     {"f.exec",          0,
443                         CRS_ANY,
444                         0,
445                         F_Exec,
446                         ParseWmFuncStrArg},
447     {"f.focus_color",   F_SUBCONTEXT_IB_IICON|F_SUBCONTEXT_IB_WICON,
448                         CRS_ANY,
449                         0,
450                         F_Focus_Color,
451                         ParseWmFuncNoArg},
452     {"f.focus_key",     F_SUBCONTEXT_IB_IICON|F_SUBCONTEXT_IB_WICON,
453                         CRS_ANY,
454                         0,
455                         F_Focus_Key,
456                         ParseWmFuncNoArg},
457 #ifdef WSM
458     {"f.goto_workspace", 0,
459                         CRS_ANY,
460                         0,
461                         F_Goto_Workspace,
462                         ParseWmFuncStrArg},
463 #endif /* WSM */
464 #ifdef WSM
465     {"f.help",          0,
466                         CRS_ANY,
467                         0,
468                         F_Help,
469                         ParseWmFuncStrArg},  /* [helpvolume && helptopic] */
470     {"f.help_mode",     0,
471                         CRS_ANY,
472                         0,
473                         F_Help_Mode,
474                         ParseWmFuncNoArg},  /* for now */
475 #endif /* WSM */
476 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
477     {"f.invoke_command",
478                         0, CRS_ANY,
479                         0,
480                         F_InvokeCommand,
481                         ParseWmFuncStrArg},
482 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
483     {"f.kill",          F_CONTEXT_ROOT,
484                         CRS_ANY,
485                         MWM_FUNC_CLOSE,
486                         F_Kill,
487                         ParseWmFuncNoArg},
488     {"f.lower",         F_SUBCONTEXT_IB_IICON|F_SUBCONTEXT_IB_WICON,
489                         CRS_ANY,
490                         0,
491                         F_Lower,
492                         ParseWmFuncMaybeStrArg},
493 #ifdef WSM
494     {"f.marquee_selection",     
495                         F_CONTEXT_WINDOW|F_CONTEXT_ICON|F_SUBCONTEXT_IB_IICON,
496                         CRS_ANY,
497                         0,
498                         F_Marquee_Selection,
499                         ParseWmFuncNoArg},
500 #endif /* WSM */
501     {"f.maximize",      F_CONTEXT_ROOT|F_CONTEXT_MAXIMIZE|
502                                        F_SUBCONTEXT_IB_WICON,
503                         CRS_ANY,
504                         MWM_FUNC_MAXIMIZE,
505                         F_Maximize,
506                         ParseWmFuncNoArg},
507     {"f.menu",          0,
508                         CRS_ANY,
509                         0,
510                         F_Menu,
511                         ParseWmFuncStrArg},
512     {"f.minimize",      F_CONTEXT_ICON|F_CONTEXT_ROOT|F_SUBCONTEXT_IB_IICON,
513                         CRS_ANY,
514                         MWM_FUNC_MINIMIZE,
515                         F_Minimize,
516                         ParseWmFuncNoArg},
517     {"f.move",          F_CONTEXT_ROOT,
518                         CRS_ANY,
519                         MWM_FUNC_MOVE,
520                         F_Move,
521                         ParseWmFuncNoArg},
522     {"f.next_cmap",     0,
523                         CRS_ANY,
524                         0,
525                         F_Next_Cmap,
526                         ParseWmFuncNoArg},
527     {"f.next_key",      0,
528                         CRS_ANY,
529                         0,
530                         F_Next_Key,
531                         ParseWmFuncGrpArg},
532 #ifdef WSM
533     {"f.next_workspace",        0,
534                         CRS_ANY,
535                         0,
536                         F_Next_Workspace,
537                         ParseWmFuncNoArg},
538 #endif /* WSM */
539     {"f.nop",           F_CONTEXT_ROOT|F_CONTEXT_ICON|F_CONTEXT_WINDOW|
540                             F_SUBCONTEXT_IB_WICON | F_SUBCONTEXT_IB_IICON,
541                         CRS_ANY,
542                         0,
543                         F_Nop,
544                         ParseWmFuncNoArg},
545     {"f.normalize",     F_CONTEXT_ROOT|F_CONTEXT_NORMAL|F_SUBCONTEXT_IB_WICON,
546                         CRS_ANY,
547                         0,
548                         F_Normalize,
549                         ParseWmFuncNoArg},
550 #ifdef PANELIST
551     {"f.normalize_and_raise",
552                         F_CONTEXT_ROOT|F_CONTEXT_NORMAL,
553                         CRS_ANY,
554                         0,
555                         F_Normalize_And_Raise,
556                         ParseWmFuncMaybeStrArg},
557 #else /* PANELIST */
558     {"f.normalize_and_raise",
559                         F_CONTEXT_ROOT|F_CONTEXT_NORMAL,
560                         CRS_ANY,
561                         0,
562                         F_Normalize_And_Raise,
563                         ParseWmFuncNoArg},
564 #endif /* PANELIST */
565 #ifdef WSM
566     {"f.occupy_all", F_CONTEXT_ICONBOX|F_CONTEXT_ROOT,
567                         CRS_ANY,
568                         DtWM_FUNC_OCCUPY_WS,
569                         F_AddToAllWorkspaces,
570                         ParseWmFuncNoArg},
571 #endif /* WSM */
572     {"f.pack_icons",    0,
573                         CRS_ANY,
574                         0,
575                         F_Pack_Icons,
576                         ParseWmFuncNoArg},
577     {"f.pass_keys",     0,
578                         CRS_ANY,
579                         0,
580                         F_Pass_Key,
581                         ParseWmFuncNoArg},
582 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
583     {"f.post_rmenu",    0,
584                         CRS_KEY,
585                         0,
586                         F_Post_RMenu,
587                         ParseWmFuncNoArg},
588 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
589     {"f.post_wmenu",    0,
590                         CRS_BUTTON|CRS_KEY,
591                         0,
592                         F_Post_SMenu,
593                         ParseWmFuncNoArg},
594     {"f.prev_cmap",     0,
595                         CRS_ANY,
596                         0,
597                         F_Prev_Cmap,
598                         ParseWmFuncNoArg},
599     {"f.prev_key",      0,
600                         CRS_ANY,
601                         0,
602                         F_Prev_Key,
603                         ParseWmFuncGrpArg},
604 #ifdef WSM
605     {"f.prev_workspace",        0,
606                         CRS_ANY,
607                         0,
608                         F_Prev_Workspace,
609                         ParseWmFuncNoArg},
610 #endif /* WSM */
611     {"f.quit_mwm",      F_CONTEXT_ICON|F_CONTEXT_WINDOW,
612                         CRS_ANY,
613                         0,
614                         F_Quit_Mwm,
615                         ParseWmFuncNoArg},
616     {"f.raise",         F_SUBCONTEXT_IB_IICON|F_SUBCONTEXT_IB_WICON,
617                         CRS_ANY,
618                         0,
619                         F_Raise,
620                         ParseWmFuncMaybeStrArg},
621     {"f.raise_lower",   F_CONTEXT_ROOT |
622                                 F_SUBCONTEXT_IB_IICON|F_SUBCONTEXT_IB_WICON,
623                         CRS_ANY,
624                         0,
625                         F_Raise_Lower,
626                         ParseWmFuncNoArg},
627     {"f.refresh",       0,
628                         CRS_ANY,
629                         0,
630                         F_Refresh,
631                         ParseWmFuncNoArg},
632     {"f.refresh_win",   F_CONTEXT_ICON|F_CONTEXT_ROOT,
633                         CRS_ANY,
634                         0,
635                         F_Refresh_Win,
636                         ParseWmFuncNoArg},
637 #ifdef WSM
638     {"f.remove",        F_CONTEXT_ROOT,
639                         CRS_ANY,
640                         DtWM_FUNC_OCCUPY_WS,
641                         F_Remove,
642                         ParseWmFuncNoArg},
643 #endif /* WSM */
644     {"f.resize",        F_CONTEXT_ICON|F_CONTEXT_ROOT|
645                                  F_SUBCONTEXT_IB_IICON|F_SUBCONTEXT_IB_WICON,
646                         CRS_ANY,
647                         MWM_FUNC_RESIZE,
648                         F_Resize,
649                         ParseWmFuncNoArg},
650 #ifdef WSM
651     {"f.restart",       F_CONTEXT_ICON|F_CONTEXT_WINDOW,
652                         CRS_ANY,
653                         0,
654                         F_Restart,
655                         ParseWmFuncStrArg},
656 #else /* WSM */
657     {"f.restart",       F_CONTEXT_ICON|F_CONTEXT_WINDOW,
658                         CRS_ANY,
659                         0,
660                         F_Restart,
661                         ParseWmFuncNoArg},
662 #endif /* WSM */
663     {"f.restore",       F_CONTEXT_ROOT|F_CONTEXT_NORMAL|F_SUBCONTEXT_IB_WICON,
664                         CRS_ANY,
665                         0,
666                         F_Restore,
667                         ParseWmFuncNoArg},
668     {"f.restore_and_raise",
669                         F_CONTEXT_ROOT|F_CONTEXT_NORMAL,
670                         CRS_ANY,
671                         0,
672                         F_Restore_And_Raise,
673                         ParseWmFuncNoArg},
674     {"f.screen",        0,
675                         CRS_ANY,
676                         0,
677                         F_Screen,
678                         ParseWmFuncStrArg},
679     {"f.send_msg",      F_CONTEXT_ROOT,
680                         CRS_ANY,
681                         0,
682                         F_Send_Msg,
683                         ParseWmFuncNbrArg},
684     {"f.separator",     0,
685                         CRS_MENU,
686                         0,
687                         F_Separator,
688                         ParseWmFuncNoArg},
689     {"f.set_behavior",  0,
690                         CRS_ANY,
691                         0,
692                         F_Set_Behavior,
693                         ParseWmFuncNoArg},
694 #ifdef WSM
695     {"f.set_context",   0,
696                         CRS_ANY,
697                         0,
698                         F_Set_Context,
699                         ParseWmFuncNbrArg},
700 #endif /* WSM */
701     {"f.title",         0,
702                         CRS_MENU,
703                         0,
704                         F_Title,
705                         ParseWmFuncNoArg},
706 #if defined(PANELIST)
707     {"f.toggle_frontpanel", 0,
708                         CRS_ANY,
709                         0,
710                         F_Toggle_Front_Panel,
711                         ParseWmFuncNoArg},
712
713     {"f.version",       0,
714                         CRS_ANY,
715                         0,
716                         F_Version,
717                         ParseWmFuncNoArg},
718 #endif /* PANELIST */
719 #ifdef WSM
720
721 #ifdef OLD
722     {"f.workspace_presence",F_CONTEXT_ICON|F_CONTEXT_ROOT|F_CONTEXT_ICONBOX|
723                             F_SUBCONTEXT_IB_IICON|F_SUBCONTEXT_IB_WICON,
724 #endif /* OLD */
725     {"f.workspace_presence", F_CONTEXT_ROOT|F_CONTEXT_ICONBOX|
726                         F_SUBCONTEXT_IB_WICON,
727                         CRS_ANY,
728                         DtWM_FUNC_OCCUPY_WS,
729                         F_Workspace_Presence,
730                         ParseWmFuncNoArg},
731 #endif /* WSM */
732 #if defined(DEBUG) && defined(WSM)
733     {"f.zz_debug",      0,
734                         CRS_ANY,
735                         0,
736                         F_ZZ_Debug,
737                         ParseWmFuncStrArg},
738 #endif /* DEBUG */
739 };
740
741 /*
742  * NOTE: New functions MUST be added in ALPHABETICAL order.  A binary search
743  *       is used to find the correct function name.
744  */
745
746 #define WMFUNCTIONTABLESIZE (sizeof(functionTable)/sizeof(functionTable[0]))
747
748 /*
749  * Be sure to update these define, whenever adding/deleting a function.
750  */
751 #ifdef WSM
752 # if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
753 #  define F_CCI_INDEX  2
754 # endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
755 int F_ACTION_INDEX;
756 int F_EXEC_INDEX;
757 int F_NOP_INDEX;
758 #else  /* WSM */
759 # if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
760 #  define F_CCI_INDEX  1
761 #  define F_EXEC_INDEX 4
762 #  define F_NOP_INDEX 16
763 # else
764 #  define F_EXEC_INDEX 3
765 #  define F_NOP_INDEX 14
766 # endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
767 #endif /* WSM */
768 #ifdef WSM
769 \f
770 /******************************<->*************************************
771  *
772  *  void GetFunctionTableValues (int *execIndex, int *nopIndex, 
773  *                               int *actionIndex)
774  *
775  *  Description:
776  *  -----------
777  *  This routine dynamically computes the size of the functionTable[],
778  *  and the indices for key functions, such as f.exec, f.action, and
779  *  f.nop
780  *
781  *  Inputs:
782  *  ------
783  *  We are setting the values of F_EXEC_INDEX, F_ACTION_INDEX, 
784  *  and F_NOP_INDEX on a global level.  The addresses
785  *  for same are passed in.
786  * 
787  *  Outputs:
788  *  -------
789  *
790  *  Comments:
791  *  --------
792  *  This routine calls smaller routines for efficiency sake.
793  *
794  ******************************<->***********************************/
795 void
796 GetFunctionTableValues (int *execIndex, int *nopIndex,
797                     int *actionIndex)
798 {
799
800         GetExecIndex (WMFUNCTIONTABLESIZE, execIndex);
801
802         GetActionIndex (WMFUNCTIONTABLESIZE, actionIndex);
803
804         GetNopIndex (WMFUNCTIONTABLESIZE, nopIndex);
805
806 } /* END OF FUNCTION GetFunctionTableValues */
807
808
809 \f
810 /******************************<->*************************************
811  *
812
813  *
814  *  Description:
815  *  -----------
816
817  *
818  *  Inputs:
819  *  ------
820
821  *  Outputs:
822  *  -------
823  *
824  *  Comments:
825  *  --------
826  *
827  ******************************<->***********************************/
828
829 void
830 GetExecIndex (int tableSize, int *execIndex)
831 {
832         int i;
833
834         for (i = 0; i < (tableSize); i++)
835         {
836                 if (!(strcmp ("f.exec", functionTable[i].funcName)))
837                 {
838                         *execIndex = i;
839                         return;
840                 }
841                 else
842                 {
843                         *execIndex = 0;
844                 }
845         }
846 } /* END OF FUNCTION GetExecIndex */
847
848 \f
849 /******************************<->*************************************
850  *
851
852  *
853  *  Description:
854  *  -----------
855
856  *
857  *  Inputs:
858  *  ------
859
860  *  Outputs:
861  *  -------
862  *
863  *  Comments:
864  *  --------
865  *
866  ******************************<->***********************************/
867
868
869 void
870 GetActionIndex (int tableSize, int *actionIndex)
871 {
872         int i;
873
874         for (i = 0; i < (tableSize); i++)
875         {
876                 if (!(strcmp ("f.action", functionTable[i].funcName)))
877                 {
878                         *actionIndex = i;
879                         return;
880                 }
881                 else
882                 {
883                         *actionIndex = 0;
884                 }
885         }
886 } /* END OF FUNCTION GetActionIndex */
887
888
889 \f
890 /******************************<->*************************************
891  *
892
893  * 
894  *  Description:
895  *  -----------
896
897  *
898  *  Inputs:
899  *  ------
900
901  *  Outputs:
902  *  -------
903  *
904  *  Comments:
905  *  --------
906  *
907  ******************************<->***********************************/
908 void
909 GetNopIndex (int tableSize, int *nopIndex)
910 {
911         int i;
912
913         for (i = 0; i < (tableSize); i++)
914         {
915                 if (!(strcmp ("f.nop", functionTable[i].funcName)))
916                 {
917                         *nopIndex = i;
918                         return;
919                 }
920                 else
921                 {
922                         *nopIndex = 0;
923                 }
924         }
925 } /* END OF FUNCTION GetNopIndex */
926
927
928
929 \f
930 /*************************************<->*************************************
931  *
932  *  void
933  *  WmDtGetHelpArgs ()
934  *
935  *
936  *  Description:
937  *  -----------
938  *  Get Help Args
939
940  *
941  *  Inputs:
942  *  ------
943
944  * 
945  *  Outputs:
946  *  -------
947  *
948  *
949  *  Comments:
950  *  --------
951  *  None.
952  * 
953  *************************************<->***********************************/
954 void
955 WmDtGetHelpArgs(char *args, 
956                  unsigned char* volume, 
957                  unsigned char* topic, 
958                  int *argsCount)
959 {
960     unsigned char *string;
961     unsigned char *lineP;
962
963     cfileP = NULL;
964     linec = 0;
965     parseP = (unsigned char*) args;
966
967     if(GetNextLine () != NULL)
968     {
969         *argsCount = 0;
970         lineP = line;
971         if ((string = GetSmartSMString (&lineP)) != NULL)
972         {
973             *argsCount = *argsCount + 1;
974             strcpy ((char*)topic, (char*)string);
975         }
976
977         if ((string = GetSmartSMString (&lineP)) != NULL)
978         {
979             *argsCount = *argsCount + 1;
980             strcpy ((char*)volume, (char *)string);
981         }
982     }
983
984 } /* END OF FUNCTION WmDtGetHelpArgs */
985
986
987
988
989 \f
990 /******************************<->*************************************
991  *
992  *  void
993  *  ParseDtSessionHints (pSD, property)
994  *
995  *
996  *  Description:
997  *  -----------
998  *  This function parses a DtSessionHints string and returns a list of 
999  *  DtSessionItems array.  The string should have the syntax:
1000  *
1001
1002  *
1003  *
1004  *  Inputs:
1005  *  ------
1006  *  line = (global) line buffer
1007  *  pSD->rootWindow = default root window of display
1008  *
1009  * 
1010  *  Outputs:
1011  *  -------
1012  *  Return = 
1013  *
1014  *
1015  *  Comments:
1016  *  --------
1017  *  None.
1018  * 
1019  *************************************<->***********************************/
1020
1021 void 
1022 ParseDtSessionHints (WmScreenData *pSD, unsigned char *property)
1023 {
1024
1025     cfileP = NULL;
1026     linec = 0;
1027     parseP = property;
1028
1029     ParseSessionItems (pSD);
1030
1031 } /* END OF FUNCTION ParseDtSessionHints */
1032
1033 \f
1034 /*************************************<->*************************************
1035  *
1036  *  FindDtSessionMatch(commandArgc, commandArgv, pCD, pSD, pWorkSpaceList,
1037  *                      clientMachine)
1038  *
1039  *  Description:
1040  *  -----------
1041  *  Try to find a match for this client in the session hints.
1042  *  Set up client-session data.
1043  *
1044  *
1045  *  Inputs:
1046  *  ------
1047  *  commandArgc    -  argument count
1048  *  commandArgv    -  WM_COMMAND argument vector
1049  *  pCD            -  pointer to client data
1050  *  pSD            -  pointer to screen data
1051  *  pWorkspaceList -  pointer to a list of workspaces (to be returned)
1052  *  clientMachine  -  string for -host option in session hints
1053  *
1054  *  Outputs:
1055  *  -------
1056  *  *pCD            -  client data (may be modified)
1057  *  FindDtSessionMatch - returns True if a match for this client
1058  *                        was found in the session hints.
1059  *  *pWorkspaceList - list of workspaces this client should be put 
1060  *                    into.  (needs to be freed)
1061  *
1062  *
1063  *  Comments:
1064  *  --------
1065  *  Various pieces of client state (in pCD) are reset when a match
1066  *     is found.
1067  *
1068  *  The caller must free *pWorkspaceList when done.
1069  * 
1070  *************************************<->***********************************/
1071 Boolean FindDtSessionMatch(int commandArgc, char **commandArgv,
1072                             ClientData *pCD, WmScreenData *pSD,
1073                             char **pWorkSpaceList, char *clientMachine)
1074
1075 {
1076     int count, item;
1077     int relCount;
1078     int argNum;
1079     SessionGeom *sessionGeom;
1080
1081
1082     for (count = 0; count < pSD->totalSessionItems; count++)
1083     {
1084         if (!pSD->pDtSessionItems[count].processed &&
1085             pSD->pDtSessionItems[count].commandArgc == commandArgc)
1086         {
1087             if ((clientMachine) &&
1088                 (pSD->pDtSessionItems[count].clientMachine) &&
1089                 (strcmp(clientMachine, 
1090                         pSD->pDtSessionItems[count].clientMachine)))
1091             {
1092                 /*
1093                  * This item has clientMachine string but the 
1094                  * clientMachine does not match.
1095                  */
1096                 continue;
1097             }
1098             for (argNum = 0; argNum < commandArgc ; argNum++)
1099             {
1100                 if(strcmp(commandArgv[argNum],
1101                           pSD->pDtSessionItems[count].commandArgv[argNum]))
1102
1103                 {
1104                     /*
1105                      * One mismatch and we quit looking at this item.
1106                      * Decrement argNum so a mismatch on the last item
1107                      * will not look like a match below when comparing
1108                      * argNum == commandArgc
1109                      */
1110                     argNum--;
1111                     break;
1112                 }
1113             }           
1114             if (argNum == commandArgc)
1115             {
1116                 /*
1117                  * Made it through all strings so this is a match
1118                  */
1119                 
1120                 pSD->pDtSessionItems[count].processed = True;
1121                 pSD->remainingSessionItems --;
1122                 pCD->clientFlags |= SM_LAUNCHED;
1123                 
1124                 /*
1125                  * Free strings malloc'd for commandArgv for this item 
1126                  */
1127                 
1128                 for (relCount = 0; relCount < commandArgc; relCount++)
1129                 {
1130                     XtFree(pSD->pDtSessionItems[count].commandArgv[relCount]);
1131                 }
1132                 XtFree((char *)pSD->pDtSessionItems[count].commandArgv);
1133
1134                 if(pSD->pDtSessionItems[count].clientState)
1135                 {
1136                     pCD->clientState =
1137                         pSD->pDtSessionItems[count].clientState;
1138                     pCD->clientFlags |= SM_CLIENT_STATE;
1139                 }
1140                 
1141                 if(pSD->pDtSessionItems[count].sessionGeom)
1142                 {
1143                     sessionGeom = pSD->pDtSessionItems[count].sessionGeom;
1144                     if (sessionGeom->flags & XValue)
1145                     {
1146                         pCD->clientX = sessionGeom->clientX;
1147                         pCD->clientFlags |= SM_X;
1148                     }
1149                     if (sessionGeom->flags & YValue)
1150                     {
1151                         pCD->clientY = sessionGeom->clientY;
1152                         pCD->clientFlags |= SM_Y;
1153                     }
1154                     if (sessionGeom->flags & WidthValue)
1155                     {
1156                         pCD->clientWidth = sessionGeom->clientWidth;
1157                         pCD->clientFlags |= SM_WIDTH;
1158                     }
1159                     if (sessionGeom->flags & HeightValue)
1160                     {
1161                         pCD->clientHeight = sessionGeom->clientHeight;
1162                         pCD->clientFlags |= SM_HEIGHT;
1163                     }
1164
1165                     /*
1166                      * Free SessionGeom malloc'd space for this item 
1167                      */
1168                     
1169                     XtFree((char *)pSD->pDtSessionItems[count].sessionGeom); 
1170                 }
1171
1172                 if(pSD->pDtSessionItems[count].clientMachine)
1173                 {
1174                     /*
1175                      * Free clientMachine malloc'd space for this item 
1176                      */
1177                     
1178                     XtFree((char *)
1179                            pSD->pDtSessionItems[count].clientMachine); 
1180                     pSD->pDtSessionItems[count].clientMachine = NULL;
1181                 }
1182                 
1183                 
1184                 if(pSD->pDtSessionItems[count].workspaces)
1185                 {
1186                     /*
1187                      * The caller is responsible for freeing this
1188                      * data.
1189                      */
1190                     *pWorkSpaceList = pSD->pDtSessionItems[count].workspaces;
1191                 }
1192
1193
1194                 if(pSD->remainingSessionItems == 0)
1195                 {
1196                     /*
1197                      * Free the whole pSD->pDtSessionHints structure 
1198                      */
1199                     XtFree((char *)pSD->pDtSessionItems);
1200                 }
1201                 
1202                 return (True);
1203             }
1204
1205         } /* not processed and argc's are the same */
1206
1207     } /* for */
1208     
1209     return (False);
1210     
1211 } /* END OF FUNCTION FindDtSessionMatch */
1212
1213
1214
1215
1216 \f
1217 /*************************************<->*************************************
1218  *
1219  *  void
1220  *  ParseSessionItems (pSD)
1221  *
1222  *
1223  *  Description:
1224  *  -----------
1225  *  Parse session items
1226
1227  *
1228  *  Inputs:
1229  *  ------
1230  *  pSD    = pointer to screen data
1231  *  cfileP = (global) file pointer to  NULL
1232  *  line   = (global) line buffer
1233  *  linec  = (global) line count
1234  *  parseP = (global) parse string pointer if cfileP == NULL
1235  *  pSD->rootWindow = default root window of display
1236
1237  * 
1238  *  Outputs:
1239  *  -------
1240  *  linec  = (global) line count incremented
1241  *  parseP = (global) parse string pointer if cfileP == NULL
1242  *
1243  *
1244  *  Comments:
1245  *  --------
1246  *  None.
1247  * 
1248  *************************************<->***********************************/
1249
1250 void
1251 ParseSessionItems (WmScreenData *pSD)
1252 {
1253     unsigned char *string;
1254     unsigned char *lineP;
1255     int count;
1256
1257     
1258     /*
1259      * Parse property string
1260      */
1261
1262     
1263
1264     if(GetNextLine () != NULL)
1265     {
1266         pSD->totalSessionItems = atoi((char *)line);
1267         pSD->remainingSessionItems = pSD->totalSessionItems;
1268     }
1269     
1270
1271     if((pSD->totalSessionItems < 1) ||
1272        !GetSessionHintsInfo(pSD, pSD->totalSessionItems))
1273     {
1274         /*
1275          * No items or couldn't allocate space
1276          */
1277         return;
1278     }
1279     
1280     count = 0;
1281
1282     while ((count < pSD->totalSessionItems) && (GetNextLine () != NULL))
1283     {
1284
1285         lineP = line;
1286         while ((string = GetSmartSMString (&lineP)) != NULL)
1287         {
1288             if (!strcmp((char *)string, "-geometry"))
1289             {
1290                 /*
1291                  * Parse geometry if it is present
1292                  */
1293                 string = GetSmartSMString(&lineP);
1294                 ParseSessionGeometry (pSD, count, string);
1295             }
1296             
1297             else if (!strcmp((char *)string, "-state"))
1298             {
1299                 /*
1300                  * Parse the state if it is present
1301                  */
1302                 string = GetSmartSMString(&lineP);
1303                 ParseSessionClientState (pSD, count, string);
1304             }
1305
1306             else if (!strcmp((char *)string, "-workspaces"))        
1307             {
1308                 /*
1309                  * Parse the workspaces string if it is present
1310                  */
1311                 string = GetSmartSMString(&lineP);
1312                 ParseSessionWorkspaces (pSD, count, string);
1313             }       
1314
1315             else if (!strcmp((char *)string, "-cmd"))       
1316             {
1317                 /*
1318                  * Parse the command string if it is present
1319                  */
1320                 string = GetSmartSMString(&lineP);
1321                 ParseSessionCommand (pSD, count, &string);
1322             }
1323             
1324             else if (!strcmp((char *)string, "-host"))      
1325             {
1326                 /*
1327                  * Parse the host string if it is present
1328                  */
1329                 string = GetSmartSMString(&lineP);
1330                 ParseSessionHost (pSD, count, string);
1331             }
1332             
1333         } /* while GetSmartSMString */
1334         
1335         count++;
1336
1337     } /* while GetNextLine */
1338     
1339
1340
1341 } /* END OF FUNCTION ParseSessionItems */
1342
1343
1344 \f
1345 /*************************************<->*************************************
1346  *
1347  *  ParseSessionClientState (pSD, count, string);
1348  *
1349  *  Description:
1350  *  -----------
1351  *  Inputs:
1352  *  ------
1353  *  Outputs:
1354  *  -------
1355  *  Comments:
1356  *  --------
1357  *
1358  *************************************<->***********************************/
1359 void ParseSessionClientState (WmScreenData *pSD, int count,
1360                               unsigned char *string)
1361
1362
1363
1364 {
1365
1366     if(!strcmp((char *)string, "NormalState"))
1367     {
1368         pSD->pDtSessionItems[count].clientState = NORMAL_STATE;
1369     }
1370     else if(!strcmp((char *)string, "IconicState"))
1371     {
1372         pSD->pDtSessionItems[count].clientState = MINIMIZED_STATE;
1373     }
1374     
1375
1376 } /* END OF FUNCTION ParseSessionClientState */
1377
1378 \f
1379 /*************************************<->*************************************
1380  *
1381  *  ParseSessionGeometry (pSD, count, string)
1382  *
1383  *  Description:
1384  *  -----------
1385  *  Inputs:
1386  *  ------
1387  *  Outputs:
1388  *  -------
1389  *  Comments:
1390  *  --------
1391  *
1392  *************************************<->***********************************/
1393 void ParseSessionGeometry (WmScreenData *pSD, int count,
1394                            unsigned char *string)
1395
1396 {
1397     SessionGeom *pTmpSessionGeom;
1398     int mask /* = 0 */;
1399     int X, Y, width, height;
1400     X = Y = width = height = 0;
1401     
1402     /*
1403      *  XParseGeometry
1404      */
1405
1406     mask = XParseGeometry((char *)string, &X, &Y, (unsigned int *)&width, 
1407                           (unsigned int *)&height);
1408     if (mask)
1409     {
1410         /*
1411          * Allocate space for the geometry structure
1412          */
1413
1414         if ((pTmpSessionGeom = 
1415              (SessionGeom *)XtMalloc (sizeof (SessionGeom))) == NULL)
1416         {
1417             Warning (((char *)GETMESSAGE(60, 1, "Insufficient memory for session geometry item")));
1418             return;
1419
1420         }
1421
1422         pTmpSessionGeom->flags = mask;
1423         pTmpSessionGeom->clientX = X;
1424         pTmpSessionGeom->clientY = Y;
1425         pTmpSessionGeom->clientWidth = width;
1426         pTmpSessionGeom->clientHeight = height;
1427
1428         pSD->pDtSessionItems[count].sessionGeom = pTmpSessionGeom;
1429     }
1430     
1431 } /* END OF FUNCTION  ParseSessionGeometry */
1432
1433 \f
1434 /*************************************<->*************************************
1435  *
1436  * void
1437  * ParseSessionWorkspaces (pSD, count, string)
1438  *
1439  *  Description:
1440  *  -----------
1441  *  Inputs:
1442  *  ------
1443  *  Outputs:
1444  *  -------
1445  *  Comments:
1446  *  --------
1447  *
1448  *************************************<->***********************************/
1449 void ParseSessionWorkspaces (WmScreenData *pSD,  int count,
1450                              unsigned char *string)
1451
1452 {
1453
1454     /*
1455      * Allocate space for the workspaces string
1456      */
1457
1458     if ((pSD->pDtSessionItems[count].workspaces =
1459          (String)XtMalloc ((unsigned int) (strlen((char *)string) + 1))) == NULL)
1460     {
1461         Warning (((char *)GETMESSAGE(60, 2, "Insufficient memory for workspaces list in sesssion item")));
1462         return;
1463
1464     }
1465
1466     strcpy(pSD->pDtSessionItems[count].workspaces, (char *)string);
1467     
1468 } /* END OF FUNCTION ParseSessionWorkspaces */
1469
1470
1471 \f
1472 /*************************************<->*************************************
1473  *
1474  * void
1475  * ParseSessionCommand (pSD, count, string)
1476  *
1477  *  Description:
1478  *  -----------
1479  *  Inputs:
1480  *  ------
1481  *  Outputs:
1482  *  -------
1483  *  Comments:
1484  *  --------
1485  *
1486  *************************************<->***********************************/
1487 void ParseSessionCommand (WmScreenData *pSD,  int count,
1488                           unsigned char **commandString)
1489 {
1490 #define ARG_AMT 100
1491     int xindex;
1492     unsigned char **argv;
1493     int  argc = 0;
1494     int  iSizeArgv;
1495     
1496     unsigned char *string;
1497     
1498     argv = (unsigned char **) XtMalloc (ARG_AMT * sizeof(char *));
1499     iSizeArgv = ARG_AMT;
1500     
1501     while ((string = GetSmartSMString (commandString)) != NULL)
1502     {
1503         /*
1504          * Get pointers to strings in command line and count them
1505          */
1506         argv[argc] = string;
1507         argc ++;
1508
1509         if (argc >= iSizeArgv)
1510         {
1511             iSizeArgv += ARG_AMT;
1512             argv = (unsigned char **) 
1513                    XtRealloc ((char *)argv, (iSizeArgv * sizeof(char *)));
1514         }
1515     }
1516     if ((pSD->pDtSessionItems[count].commandArgv =
1517          (char **)XtMalloc ((argc) * sizeof(char * ))) == NULL)
1518     {
1519         /*
1520          * Allocate space for saved argv
1521          */
1522         
1523         Warning (((char *)GETMESSAGE(60, 3, "Insufficient memory for commandArgv array")));
1524     }
1525     else
1526     {
1527         pSD->pDtSessionItems[count].commandArgc = argc;
1528         for (xindex = 0; xindex < argc ; xindex++)
1529         {
1530             if ((pSD->pDtSessionItems[count].commandArgv[xindex] =
1531                  (String) XtMalloc
1532                  ((unsigned int) (strlen((char *)argv[xindex]) + 1))) == NULL)
1533             {
1534                 /*
1535                  * Allocate space for the next command segment.
1536                  */
1537                 Warning (((char *)GETMESSAGE(60, 4, "Insufficient memory for commandArgv item")));
1538             }
1539             else
1540             {
1541                 strcpy(pSD->pDtSessionItems[count].commandArgv[xindex],
1542                        (char *)argv[xindex]);
1543             }
1544         }
1545     }
1546
1547     XtFree ((char *) argv);
1548     
1549 } /* END OF FUNCTION ParseSessionCommand */
1550
1551
1552 \f
1553 /*************************************<->*************************************
1554  *
1555  * void
1556  * ParseSessionHost (pSD, count, string)
1557  *
1558  *  Description:
1559  *  -----------
1560  *  Inputs:
1561  *  ------
1562  *  Outputs:
1563  *  -------
1564  *  Comments:
1565  *  --------
1566  *
1567  *************************************<->***********************************/
1568 void ParseSessionHost (WmScreenData *pSD,  int count,
1569                              unsigned char *string)
1570
1571 {
1572
1573     /*
1574      * Allocate space for the workspaces string
1575      */
1576
1577     if ((pSD->pDtSessionItems[count].clientMachine =
1578          (String)XtMalloc ((unsigned int) (strlen((char *)string) + 1))) == 
1579         NULL)
1580     {
1581         Warning (((char *)GETMESSAGE(60, 38, 
1582                 "Insufficient memory for host name in sesssion item")));
1583         return;
1584     }
1585
1586     strcpy(pSD->pDtSessionItems[count].clientMachine, (char *)string);
1587     
1588 } /* END OF FUNCTION ParseSessionHost */
1589
1590
1591 \f
1592 /*************************************<->*************************************
1593  *
1594  *  GetSessionHintsInfo (pSD, numItems)
1595  *
1596  *  Description:
1597  *  -----------
1598  *  Inputs:
1599  *  ------
1600  *  Outputs:
1601  *  -------
1602  *  Comments:
1603  *  --------
1604  *
1605  *************************************<->***********************************/
1606 Boolean GetSessionHintsInfo (WmScreenData *pSD, long numItems)
1607
1608 {
1609    
1610     if ((pSD->pDtSessionItems =
1611          (DtSessionItem *)XtMalloc (numItems * sizeof (DtSessionItem)))
1612         == NULL)
1613     {
1614         Warning (((char *)GETMESSAGE(60, 5, "Insufficient memory for Dt Session Hints")));
1615         return(False);
1616     }
1617     
1618     memset ((char *)pSD->pDtSessionItems, NULL,
1619             numItems * sizeof (DtSessionItem));
1620
1621     return(True);
1622     
1623     
1624 } /* END OF FUNCTION  GetSessionHintsInfo  */ 
1625
1626
1627
1628 \f
1629 /*************************************<->*************************************
1630  *
1631  *  PeekAhead (currentChar, currentLev)
1632  *
1633  *
1634  *  Description:
1635  *  -----------
1636  *  Returns a new level value if this is a new nesting level of quoted string
1637  *  Otherwise it returns a zero
1638  *
1639  *
1640  *  Inputs:
1641  *  ------
1642  *  currentChar = current position in the string
1643  *  currentLev = current level of nesting
1644  *
1645  * 
1646  *  Outputs:
1647  *  -------
1648  *  Returns either a new level of nesting or zero if the character is copied in
1649  *
1650  *
1651  *  Comments:
1652  *  --------
1653  * 
1654  *************************************<->***********************************/
1655 unsigned int PeekAhead(unsigned char *currentChar,
1656                        unsigned int currentLev)
1657
1658
1659 {
1660     Boolean             done = False;
1661     unsigned int        tmpLev = 1;
1662 #ifndef NO_MULTIBYTE
1663     unsigned int        chlen;
1664
1665     while (((chlen = mblen ((char *)currentChar, MB_CUR_MAX)) > 0) &&
1666            (chlen == 1) && ((*currentChar == '"') || (*currentChar == '\\'))
1667            && (done == False))
1668     {
1669         currentChar++;
1670
1671         if(((chlen = mblen ((char *)currentChar, MB_CUR_MAX)) > 0) && (chlen == 1) &&
1672            ((*currentChar == '"') || (*currentChar == '\\')))
1673         {
1674             tmpLev++;
1675             if(*currentChar == '"')
1676             {
1677                 done = True;
1678             }
1679             else
1680             {
1681                 currentChar++;
1682             }
1683         }
1684     }
1685 #else
1686     while((*currentChar != NULL) && (done == False) &&
1687           ((*currentChar == '"') || (*currentChar == '\\')))
1688     {
1689         currentChar++;
1690         if((*currentChar != NULL) &&
1691            ((*currentChar == '"') || (*currentChar == '\\')))
1692         {
1693             tmpLev++;
1694             if(*currentChar == '"')
1695             {
1696                 done = True;
1697             }
1698             else
1699             {
1700                 currentChar++;
1701             }
1702         }
1703     }
1704 #endif /*NO_MULTIBYTE*/
1705
1706     /*
1707      * Figure out if this is truly a new level of nesting - else ignore it
1708      * This section probably could do some error checking and return -1
1709          * If so, change type of routine from unsigned int to int
1710      */
1711     if(done == True)
1712     {
1713         return(tmpLev);
1714     }
1715     else
1716     {
1717         return(0);
1718     }
1719 } /* END OF FUNCTION PeekAhead */
1720     
1721     
1722 #endif /* WSM */
1723
1724
1725 \f
1726 #ifdef MOTIF_ONE_DOT_ONE
1727 /*************************************<->*************************************
1728  *
1729  *  GetHomeDirName (fileName)
1730  *
1731  *  Description:
1732  *  -----------
1733  *  This function finds the "HOME" directory
1734  *
1735  *
1736  *  Inputs:
1737  *  ------
1738  *  fileName 
1739  *
1740  *  Outputs:
1741  *  -------
1742  *  fileName
1743  *
1744  *  Comments:
1745  *  --------
1746  * 
1747  *************************************<->***********************************/
1748 void GetHomeDirName(String  fileName)
1749 {
1750         int uid;
1751         struct passwd *pw;
1752         char *ptr = NULL;
1753
1754         if((ptr = getenv("HOME")) == NULL)
1755         {
1756             if((ptr = getenv("USER")) != NULL)
1757             {
1758                 pw = getpwnam(ptr);
1759             }
1760             else
1761             {
1762                 uid = getuid();
1763                 pw = getpwuid(uid);
1764             }
1765
1766             if (pw)
1767             {
1768                 ptr = pw->pw_dir;
1769             }
1770             else
1771             {
1772                 ptr = "";
1773             }
1774         }
1775         strcpy(fileName, ptr);
1776 }
1777 #endif
1778
1779 \f
1780 /*************************************<->*************************************
1781  *
1782  *  SyncModifierStrings (fileName)
1783  *
1784  *  Description:
1785  *  -----------
1786  *  This function updates modifierStrings table so that Mwm uses the correct
1787  *  modifier to keysym mapping.  Specifically, fix up the Alt and Meta bindings.
1788  *
1789  *  Inputs:
1790  *  ------
1791  *  fileName 
1792  *
1793  *  Outputs:
1794  *  -------
1795  *  fileName
1796  *
1797  *  Comments:
1798  *  --------
1799  * 
1800  *************************************<->***********************************/
1801 void SyncModifierStrings(void)
1802 {
1803     XModifierKeymap *map;
1804     int i, j, k = 0;
1805
1806     map = XGetModifierMapping (DISPLAY);
1807
1808     for (i = 0; i < 8; i++)
1809     {
1810         for (j = 0; j < map->max_keypermod; j++)
1811         {
1812             if (map->modifiermap[k])
1813             {
1814                 KeySym ks = XKeycodeToKeysym(DISPLAY, map->modifiermap[k], 0);
1815                 char *nm = XKeysymToString(ks);
1816
1817                 /* Compare, ignoring the trailing '_L' or '_R' in keysym */
1818                 if (nm && !strncmp("Alt", nm, 3))
1819                 {
1820                     modifierStrings[ALT_INDEX].mask = (1<<i);
1821                 }
1822                 else if (nm && !strncmp("Meta", nm, 4))
1823                 {
1824                     modifierStrings[META_INDEX].mask = (1<<i);
1825                 }
1826             }
1827             k++;
1828         }
1829     }
1830
1831     XFreeModifiermap(map);
1832 }
1833
1834
1835 \f
1836 /*************************************<->*************************************
1837  *
1838  *  ProcessWmFile ()
1839  *
1840  *
1841  *  Description:
1842  *  -----------
1843  *  This function reads the mwm resource description file and processes the
1844  *  resources that are described.
1845  *
1846  *
1847  *  Inputs:
1848  *  ------
1849  *  wmGD.bitmapDirectory = bitmapDirectory resource value
1850  *  pSD->buttonBindings = buttonBindings resource value
1851  *  wmGD.configFile = configuration file resource value
1852  *  pSD->keyBindings = keyBindings resource value
1853  *  wmGD.rootWindow = default root window of display
1854  *  HOME = environment variable for home directory
1855  *  functionTable = window manager function parse table
1856  *
1857  * 
1858  *  Outputs:
1859  *  -------
1860  *  wmGD.buttonSpecs = list of button binding specifications
1861  *  wmGD.keySpecs = list of key binding specification
1862  *  wmGD.menuSpecs = list of menu specifications
1863  * *wmGD.acceleratorMenuSpecs = initialized array of (MenuSpec *)
1864  *  wmGD.acceleratorMenuCount = 0
1865  *
1866  *
1867  *  Comments:
1868  *  --------
1869  * If there are more than MAXLINE characters on a line the excess characters
1870  * are truncated.
1871  * 
1872  *************************************<->***********************************/
1873 #define MENU_SPEC       "menu"
1874 #define BUTTON_SPEC     "buttons"
1875 #define KEY_SPEC        "keys"
1876 #ifdef PANELIST
1877 #define FRONT_PANEL_SPEC DTWM_FP_PANEL_OLD
1878 #define DROP_EFFECTS_SPEC   DTWM_FP_DROP_EFFECTS
1879 #define PANEL_SPEC      DTWM_FP_PANEL
1880 #define BOX_SPEC        DTWM_FP_BOX
1881 #define CONTROL_SPEC    DTWM_FP_CONTROL
1882 #define INCLUDE_SPEC    DTWM_FP_INCLUDE
1883 #define ANIMATION_SPEC  DTWM_FP_ANIMATION
1884 #define SWITCH_SPEC     DTWM_FP_SWITCH
1885
1886 void ProcessWmFile (WmScreenData *pSD, Boolean bNested)
1887
1888 #else /* PANELIST */
1889 void ProcessWmFile (WmScreenData *pSD)
1890 #endif /* PANELIST */
1891 {
1892     unsigned char *lineP;
1893     unsigned char *string;
1894     unsigned int   n;
1895     MenuSpec      *menuSpec;
1896 #ifdef PANELIST
1897     static Boolean conversionInProgress = False;
1898     Arg args[10];
1899     int argnum;
1900
1901     if (!bNested)
1902     {
1903 #endif /* PANELIST */
1904
1905     /*
1906      * Initialize global data values that are set based on data in
1907      * the mwm resource description file.
1908      */
1909
1910     pSD->buttonSpecs = NULL;
1911     pSD->keySpecs = NULL;
1912     pSD->menuSpecs = NULL;
1913
1914 #ifdef WSM
1915     /**** hhhhhhhhhhhh   ******/
1916     GetFunctionTableValues (&F_EXEC_INDEX, &F_NOP_INDEX, &F_ACTION_INDEX);
1917 #endif /* WSM */
1918     /*
1919      * Find and parse the default system menu string, if it exists.
1920      */
1921
1922     cfileP = NULL;
1923     linec = 0;
1924     if (((parseP = (unsigned char *) builtinSystemMenu) != NULL) && 
1925          (GetNextLine () != NULL))
1926     {
1927         lineP = line;
1928         ParseMenuSet (pSD, lineP);
1929     }
1930
1931     linec = 0;
1932     if (((parseP = (unsigned char *) builtinRootMenu) != NULL) && 
1933          (GetNextLine () != NULL))
1934     {
1935         lineP = line;
1936         ParseMenuSet (pSD, lineP);
1937     }
1938 #ifdef PANELIST
1939     if (wmGD.useFrontPanel &&  !wmGD.dtSD &&
1940         (XDefaultScreen (wmGD.display) == pSD->screen))
1941     {
1942         wmGD.dtSD = pSD;  /* only one per display */
1943     }
1944 #endif /* PANELIST */
1945
1946     /*
1947      * Find and associate a stream with the window manager resource 
1948      *   description file.
1949      */
1950
1951     if ((cfileP = FopenConfigFile ()) == NULL)
1952     {
1953         if (!wmGD.useStandardBehavior)
1954           Warning (((char *)GETMESSAGE(60, 6, "Cannot open configuration file")));
1955         return;
1956     }
1957
1958 #ifdef PANELIST 
1959     }  /* end if (!bNested) */
1960 #endif /* PANELIST */
1961     /*
1962      * Parse the information in the configuration file.
1963      * If there are more than MAXLINE characters on a line the excess are
1964      *   truncated.
1965      */
1966
1967     linec = 0;
1968     while ((GetNextLine () != NULL))  /* not EOF nor read error */
1969     {
1970         lineP = line;
1971         if ((*line == '!') || (string = GetString (&lineP)) == NULL)
1972         /* empty or comment line */
1973         {
1974             continue;
1975         }
1976
1977         ToLower (string);
1978         if (!strcmp ((char *)string, MENU_SPEC))
1979         {
1980             ParseMenuSet (pSD, lineP);
1981         }
1982         else if (!strcmp ((char *) string, BUTTON_SPEC))
1983         {
1984             ParseButtonSet (pSD, lineP);
1985         }
1986         else if (!strcmp ((char *) string, KEY_SPEC))
1987         {
1988             ParseKeySet (pSD, lineP);
1989         }
1990 #ifdef PANELIST
1991         else if (!strcmp ((char *)string, INCLUDE_SPEC))
1992         {
1993             ParseIncludeSet (pSD, lineP);
1994         }
1995 #endif /* PANELIST */
1996     }
1997
1998     fclose (cfileP);
1999
2000     /*
2001      * Create and initialize the pSD->acceleratorMenuSpecs array.
2002      * This assumes we create pointers to MenuSpecs within ProcessWmFile().
2003      * Set pSD->acceleratorMenuCount to 0.
2004      */
2005
2006     /* count the number of menu specifications */
2007     n = 0;
2008     menuSpec = pSD->menuSpecs;
2009     while (menuSpec)
2010     {
2011         n++;
2012         menuSpec = menuSpec->nextMenuSpec;
2013     }
2014
2015     /* allocate the array and initialize to zeros */
2016     pSD->acceleratorMenuSpecs = NULL;
2017     if (n)
2018     {
2019         pSD->acceleratorMenuSpecs = 
2020             (MenuSpec **) XtCalloc (n, sizeof (MenuSpec *));
2021         if (pSD->acceleratorMenuSpecs == NULL)
2022         {
2023             Warning (((char *)GETMESSAGE(60, 7, "Insufficient memory for menu accelerators")));
2024         }
2025     }
2026     pSD->acceleratorMenuCount = 0;
2027 } /* END OF FUNCTION ProcessWmFile */
2028
2029 /**** This function stolen from Xt/Intrinsic.c ****/
2030 /* The implementation of this routine is operating system dependent */
2031
2032 static char *ExtractLocaleName(lang)
2033     String      lang;
2034 {
2035
2036 #ifdef hpux      /* hpux-specific parsing of the locale string */
2037 #define MAXLOCALE       64      /* buffer size of locale name */
2038
2039     char           *start;
2040     char           *end;
2041     int             len;
2042     static char     buf[MAXLOCALE];
2043
2044     /*  If lang has a substring ":<category>;", extract <category>
2045      *  from the first such occurrence as the locale name.
2046      */
2047
2048     start = lang;
2049     if (start = strchr (lang, ':')) {
2050         start++;
2051         if (end = strchr (start, ';')) {
2052             len = end - start;
2053             strncpy(buf, start, len);
2054             *(buf + len) = '\0';
2055             lang = buf;
2056       }
2057     }
2058 #endif  /* hpux */
2059
2060     return lang;
2061 }
2062
2063 #ifdef WSM
2064 #define RC_CONFIG_SUBDIR                "/config/"
2065 #define RC_DEFAULT_CONFIG_SUBDIR        "/config/C"
2066 #endif /* WSM */
2067 \f
2068 /*************************************<->*************************************
2069  *
2070  *  FopenConfigFile ()
2071  *
2072  *
2073  *  Description:
2074  *  -----------
2075  *  This function searches for, opens, and associates a stream with the mwm 
2076  *  resource description file,
2077  *
2078  *
2079  *  Inputs:
2080  *  ------
2081  *  wmGD.configFile = configuration file resource value.
2082  *  HOME = environment variable for home directory
2083  *
2084  *
2085  *  Outputs:
2086  *  -------
2087  *  Return = If successful, a pointer to the FILE structure associated with 
2088  *           the configuration file.  Otherwise, NULL.
2089  *
2090  *
2091  *  Comments:
2092  *  --------
2093  *  None.
2094  * 
2095  *************************************<->***********************************/
2096 FILE *FopenConfigFile (void)
2097 {
2098
2099     char    *LANG, *LANGp;
2100     FILE    *fileP;
2101
2102 #ifndef MOTIF_ONE_DOT_ONE
2103     char *homeDir = XmeGetHomeDirName();
2104 #endif
2105 #ifdef PANELIST
2106     Boolean stackPushed;
2107 #endif /* PANELIST */
2108
2109     /*
2110      * Get the LANG environment variable
2111      * make copy since another call to getenv will blast the value.
2112      */
2113     LANGp = setlocale(LC_CTYPE, NULL);
2114
2115     /*
2116      * setlocale not guaranteed to return $LANG -- extract
2117      * something usable.
2118      */
2119     LANGp = ExtractLocaleName (LANGp);
2120
2121     if ((LANGp == NULL) || (strlen(LANGp) == 0))
2122       {
2123          LANG = NULL;
2124       }
2125     else
2126       {
2127          if ((LANG = (char *) XtMalloc(strlen(LANGp) +1)) == NULL)
2128            {
2129               PWarning (((char *)GETMESSAGE(60, 41, "Insufficient memory to get LANG environment variable.")));
2130               return(NULL);
2131            }
2132
2133          strcpy(LANG, LANGp);
2134       }
2135
2136
2137     /*
2138      * To get a name for the file first look at the value of the configFile
2139      * resource.  Interpret "~/.." as relative to the user's home directory.
2140      * Use the LANG variable if set and .mwmrc is in $HOME/$LANG/.mwmrc  
2141      */
2142
2143 #ifdef PANELIST
2144     if (pConfigStackTop && pConfigStackTop->tempName)
2145     {
2146         fileP = fopen (pConfigStackTop->tempName, "r");
2147         return (fileP);
2148     }
2149     stackPushed = (pConfigStackTop && (pConfigStackTop != pConfigStack));
2150     fileP = NULL;
2151     cfileName[0] = '\0';
2152 #endif /* PANELIST */
2153     if ((wmGD.configFile != NULL) && (wmGD.configFile[0] != '\0'))
2154     /* pointer to nonNULL string */
2155     {
2156         if ((wmGD.configFile[0] == '~') && (wmGD.configFile[1] == '/'))
2157         /* handle "~/..." */
2158         {
2159 #ifdef MOTIF_ONE_DOT_ONE
2160             GetHomeDirName(cfileName);
2161 #else
2162             strcpy (cfileName, homeDir);
2163 #endif
2164             if (LANG != NULL)
2165             {
2166                 strncat(cfileName, "/", MAXWMPATH-strlen(cfileName));
2167                 strncat(cfileName, LANG, MAXWMPATH-strlen(cfileName));
2168             }
2169             strncat(cfileName, &(wmGD.configFile[1]), MAXWMPATH-strlen(cfileName));
2170             if ((fileP = fopen (cfileName, "r")) != NULL)
2171             {
2172                 if (LANG != NULL) { 
2173                     XtFree(LANG); 
2174                     LANG = NULL; 
2175                 }
2176 #ifndef PANELIST
2177                 return (fileP);
2178 #endif /* PANELIST */
2179             }
2180             else
2181             {
2182                 /* 
2183                  * Just try $HOME/.mwmrc
2184                  */
2185 #ifdef MOTIF_ONE_DOT_ONE
2186                 GetHomeDirName(cfileName);
2187 #else
2188                 strcpy (cfileName, homeDir);
2189 #endif
2190                 strncat(cfileName, &(wmGD.configFile[1]), 
2191                         MAXWMPATH-strlen(cfileName));
2192                 if ((fileP = fopen (cfileName, "r")) != NULL)
2193                 {
2194                   if (LANG != NULL) {
2195                       XtFree(LANG);
2196                       LANG = NULL;
2197                   }
2198 #ifndef PANELIST
2199                   return (fileP);
2200 #endif /* PANELIST */
2201                 }
2202             }
2203
2204             
2205         }
2206         else
2207         /* relative to current directory or absolute */
2208         {
2209 #ifdef PANELIST
2210             char *pch;
2211
2212             pch = (char *) GetNetworkFileName (wmGD.configFile);
2213
2214             if ((fileP = fopen (pch, "r")) != NULL)
2215             {
2216                 strncpy (cfileName, pch, MAXWMPATH);
2217             }
2218             XtFree (pch);
2219   
2220           if ((fileP == NULL) && !stackPushed)
2221           {
2222 #endif  /* PANELIST  */
2223             if ((fileP = fopen (wmGD.configFile, "r")) != NULL)
2224               {
2225                 if (LANG != NULL) {
2226                     XtFree(LANG);
2227                     LANG = NULL;
2228                 }
2229                 return(fileP);
2230               }
2231 #ifdef PANELIST 
2232           }
2233           else if ((fileP == NULL) && stackPushed)
2234           {
2235                 strcpy (cfileName, wmGD.configFile);
2236           }
2237 #endif /* PANELIST */
2238         }
2239     }
2240 #ifdef PANELIST 
2241   if ((fileP == NULL) && !stackPushed)
2242   {
2243 #endif /* PANELIST */
2244
2245     /*
2246      * The configFile resource didn't do it for us.
2247      * First try HOME_MWMRC, then try SYS_MWMRC .
2248      */
2249
2250 #define HOME_MWMRC "/.mwmrc"
2251 #define SLASH_MWMRC "/system.mwmrc"
2252
2253 #ifdef MOTIF_ONE_DOT_ONE
2254     GetHomeDirName(cfileName);
2255 #else
2256     strcpy (cfileName, homeDir);
2257 #endif
2258
2259 #ifdef WSM
2260     if (MwmBehavior)
2261     {
2262         /*
2263          *
2264          *  Looking for $HOME/$LANG/.mwmrc
2265          *  --or--if $LANG is NULL
2266          *  Looking for $HOME/.mwmrc
2267          *
2268          */
2269         if (LANG != NULL)
2270         {
2271             strncat(cfileName, "/", MAXWMPATH-strlen(cfileName));
2272             strncat(cfileName, LANG, MAXWMPATH-strlen(cfileName));
2273         }
2274         strncat(cfileName, HOME_MWMRC, MAXWMPATH - strlen(cfileName));
2275     }
2276     else
2277     {
2278         /*
2279          *
2280          *  Looking for $HOME/.dt/$LANG/dtwmrc
2281          *
2282          *  --or--if $LANG is NULL--
2283          *
2284          *  Looking for $HOME/.dt/dtwmrc
2285          *
2286          */
2287         strncat(cfileName, "/.dt/", MAXWMPATH-strlen(cfileName));
2288
2289         if (LANG != NULL)
2290         {
2291             strncat(cfileName, LANG, MAXWMPATH-strlen(cfileName));
2292         }
2293         strncat(cfileName, LANG_DT_WMRC, MAXWMPATH - strlen(cfileName));
2294     }
2295 #else /* WSM */
2296     if (LANG != NULL)
2297     {
2298         strncat(cfileName, "/", MAXWMPATH-strlen(cfileName));
2299         strncat(cfileName, LANG, MAXWMPATH-strlen(cfileName));
2300     }
2301     strncat(cfileName, HOME_MWMRC, MAXWMPATH - strlen(cfileName));
2302 #endif /* WSM */
2303     if ((fileP = fopen (cfileName, "r")) != NULL)
2304     {
2305         if (LANG != NULL) {
2306             XtFree(LANG);
2307             LANG = NULL;
2308         }
2309 #ifndef PANELIST
2310         return (fileP);
2311 #endif /* PANELIST */
2312     }
2313     else
2314     {
2315         /* 
2316          * Just try $HOME/.mwmrc
2317          */
2318 #ifdef MOTIF_ONE_DOT_ONE
2319         GetHomeDirName(cfileName);
2320 #else
2321     strcpy (cfileName, homeDir);
2322 #endif
2323 #ifdef WSM
2324         if (MwmBehavior)
2325         {
2326             /* 
2327              * Just try $HOME/.mwmrc
2328              */
2329             strncat(cfileName, HOME_MWMRC, MAXWMPATH - strlen(cfileName));
2330         }
2331         else
2332         {
2333             /* 
2334              * Just try $HOME/.dt/dtwmrc
2335              */
2336             strncat(cfileName, HOME_DT_WMRC, MAXWMPATH - strlen(cfileName));
2337         }
2338 #else /* WSM */
2339         strncat(cfileName, HOME_MWMRC, MAXWMPATH - strlen(cfileName));
2340 #endif /* WSM */
2341         if ((fileP = fopen (cfileName, "r")) != NULL)
2342         {
2343           if (LANG != NULL) {
2344               XtFree(LANG);
2345               LANG = NULL;
2346           }
2347 #ifndef PANELIST
2348           return (fileP);
2349 #endif /* PANELIST */
2350         }
2351     }
2352 #ifdef PANELIST
2353   }
2354
2355 #define DTLIBDIR  CDE_INSTALLATION_TOP
2356 #define DTADMINDIR  CDE_CONFIGURATION_TOP
2357 #define SLASH_DT_WMRC "/sys.dtwmrc"
2358
2359   if ((fileP == NULL) && !stackPushed)
2360   {
2361     /* 
2362      * No home-based config file. Try the admin directory.
2363      */
2364     strcpy(cfileName, DTADMINDIR);
2365     strncat(cfileName, RC_CONFIG_SUBDIR, MAXWMPATH-strlen(cfileName));
2366     strncat(cfileName, LANG, MAXWMPATH-strlen(cfileName));
2367     strncat(cfileName, SLASH_DT_WMRC, MAXWMPATH - strlen(cfileName));
2368
2369     if (((fileP = fopen (cfileName, "r")) == NULL) && LANG && *LANG)
2370     {
2371         /* Try it with no LANG */
2372         strcpy(cfileName, DTADMINDIR);
2373         strncat(cfileName, RC_CONFIG_SUBDIR, MAXWMPATH-strlen(cfileName));
2374         strncat(cfileName, SLASH_DT_WMRC, MAXWMPATH - strlen(cfileName));
2375     }
2376
2377     if ((fileP = fopen (cfileName, "r")) != NULL)
2378     {
2379       XtFree(LANG);
2380       LANG = NULL;
2381     }
2382   }
2383
2384   if ((fileP == NULL) && !stackPushed)
2385   {
2386 #endif /* PANELIST */
2387
2388 #ifndef LIBDIR
2389 #define LIBDIR "/usr/lib/X11"
2390 #endif
2391     if (LANG != NULL)
2392     {
2393 #ifdef WSM
2394         if (MwmBehavior)
2395         {
2396             strcpy(cfileName, LIBDIR);
2397             strncat(cfileName, "/", MAXWMPATH-strlen(cfileName));
2398             strncat(cfileName, LANG, MAXWMPATH-strlen(cfileName));
2399             strncat(cfileName, SLASH_MWMRC, MAXWMPATH - strlen(cfileName));
2400         }
2401         else
2402         {
2403             strcpy(cfileName, DTLIBDIR);
2404             strncat(cfileName, RC_CONFIG_SUBDIR, MAXWMPATH-strlen(cfileName));
2405             strncat(cfileName, LANG, MAXWMPATH-strlen(cfileName));
2406             strncat(cfileName, SLASH_DT_WMRC, MAXWMPATH - strlen(cfileName));
2407         }
2408 #else /* WSM */
2409        /*
2410         * Try /$LANG/system.mwmrc within the install tree
2411         */
2412         strcpy(cfileName, LIBDIR);
2413         strncat(cfileName, "/", MAXWMPATH-strlen(cfileName));
2414         strncat(cfileName, LANG, MAXWMPATH-strlen(cfileName));
2415         strncat(cfileName, SLASH_MWMRC, MAXWMPATH - strlen(cfileName));
2416 #endif /* WSM */
2417         if ((fileP = fopen (cfileName, "r")) != NULL)
2418         {
2419           XtFree(LANG);
2420           LANG = NULL;
2421 #ifndef PANELIST
2422           return (fileP);
2423 #endif /* PANELIST */
2424         }
2425     }
2426
2427 #ifdef PANELIST
2428     if ((fileP == NULL) && !stackPushed)
2429     {
2430 #endif /* PANELIST */
2431 #ifdef WSM
2432     if (MwmBehavior)
2433     {
2434         strcpy(cfileName, LIBDIR);
2435         strncat(cfileName, SLASH_MWMRC, MAXWMPATH - strlen(cfileName));
2436 #ifdef PANELIST
2437         fileP = fopen (cfileName, "r");
2438 #else /* PANELIST */
2439         return (fopen (cfileName, "r"));
2440 #endif /* PANELIST */
2441     }
2442     else
2443     {
2444         strcpy(cfileName, DTLIBDIR);
2445         strncat(cfileName, RC_DEFAULT_CONFIG_SUBDIR, 
2446                                         MAXWMPATH - strlen(cfileName));
2447         strncat(cfileName, SLASH_DT_WMRC, MAXWMPATH - strlen(cfileName));
2448 #ifdef PANELIST
2449         fileP = fopen (cfileName, "r");
2450 #else /* PANELIST */
2451         return (fopen (cfileName, "r"));
2452 #endif /* PANELIST */
2453     }
2454 #else /* WSM */
2455     /*
2456      * Try /system.mwmrc within the install tree
2457      */
2458     strcpy(cfileName, LIBDIR);
2459     strncat(cfileName, SLASH_MWMRC, MAXWMPATH - strlen(cfileName));
2460
2461     if (LANG != NULL) 
2462     {
2463        XtFree(LANG);
2464        LANG = NULL;
2465     }
2466 #ifdef PANELIST
2467     strcpy(cfileName, cfileName);
2468     fileP = fopen (cfileName, "r");
2469 #else /* PANELIST */
2470     return (fopen (cfileName, "r"));
2471 #endif /* PANELIST */
2472 #endif /* WSM */
2473 #ifdef PANELIST
2474     }
2475   }
2476
2477     if (!fileP)
2478     {
2479         char *pch;
2480
2481         /*
2482          * handle "<host>:<path>" form of file name
2483          */
2484         pch = (char *) GetNetworkFileName (cfileName);
2485         if ((fileP = fopen (cfileName, "r")) != NULL)
2486         {
2487             strncpy (cfileName, pch, MAXWMPATH);
2488             XtFree (pch);
2489         }
2490
2491         /*
2492          * Either not "<host>:<path>" form or there was a
2493          * problem up above. This is the last attempt to 
2494          * open something.
2495          */
2496         if (!fileP)
2497         {
2498             fileP = fopen (cfileName, "r");
2499         }
2500     }
2501
2502     if (!pConfigStack)
2503     {
2504         ConfigStackInit (cfileName);
2505     }
2506
2507     if (wmGD.cppCommand && *wmGD.cppCommand)
2508     {
2509         /*
2510          *  Run the file through the C-preprocessor
2511          */
2512         PreprocessConfigFile ();
2513         if (pConfigStackTop->cppName)
2514         {
2515             /* open the result */
2516             fileP = fopen (pConfigStackTop->cppName, "r");
2517         }
2518     }
2519
2520     if (LANG != NULL) 
2521     {
2522         XtFree(LANG);
2523         LANG = NULL;
2524     }
2525     return (fileP);
2526 #endif /* PANELIST */
2527
2528 } /* END OF FUNCTION FopenConfigFile */
2529
2530 \f
2531 /*************************************<->*************************************
2532  *
2533  *  SaveMenuAccelerators (pSD, newMenuSpec)
2534  *
2535  *
2536  *  Description:
2537  *  -----------
2538  *  This function saves the MenuSpec pointer in pSD->acceleratorMenuSpecs.
2539  *
2540  *
2541  *  Inputs:
2542  *  ------
2543  *  newMenuSpec = pointer to MenuSpec to be saved.
2544  *  pSD->acceleratorMenuSpecs = 
2545  *  pSD->acceleratorMenuCount = 
2546  *
2547  *
2548  *  Outputs:
2549  *  -------
2550  *  pSD->acceleratorMenuSpecs = possibly updated
2551  *  pSD->acceleratorMenuCount = possibly updated
2552  *
2553  *
2554  *  Comments:
2555  *  --------
2556  *  We assume only MenuSpecs created within ProcessWmFile() are to be saved.
2557  *  Otherwise, we may cause override the limits of pSD->acceleratorMenuSpecs.
2558  * 
2559  *************************************<->***********************************/
2560
2561 void SaveMenuAccelerators (WmScreenData *pSD, MenuSpec *newMenuSpec)
2562 {
2563     MenuSpec  **pMenuSpec;
2564
2565     pMenuSpec = pSD->acceleratorMenuSpecs;
2566
2567     if (pMenuSpec == NULL) 
2568         return;
2569
2570     while ((*pMenuSpec != NULL) && (*pMenuSpec != newMenuSpec))
2571     {
2572         pMenuSpec++;
2573     }
2574
2575     if (*pMenuSpec == NULL)
2576     {
2577         *pMenuSpec = newMenuSpec;
2578         pSD->acceleratorMenuCount++;
2579     }
2580
2581 } /* END OF FUNCTION SaveMenuAccelerators */
2582
2583 \f
2584 /*************************************<->*************************************
2585  *
2586  *  ParseMenuSet (pSD, lineP)
2587  *
2588  *
2589  *  Description:
2590  *  -----------
2591  *  Menu pane specification found.  Parse the following syntax:
2592  *
2593  *          v
2594  *     Menu menu_pane_name
2595  *     {
2596  *       label  [mnemonic]  [accelerator]  function
2597  *       label  [mnemonic]  [accelerator]  function
2598  *                 ...
2599  *       label  [mnemonic]  [accelerator]  function
2600  *     }
2601  *
2602  *
2603  *  Inputs:
2604  *  ------
2605  *  cfileP = (global) file pointer to fopened configuration file or NULL
2606  *  lineP = pointer to menu name in line buffer
2607  *  line   = (global) line buffer
2608  *  linec  = (global) line count
2609  *  parseP = (global) parse string pointer if cfileP == NULL
2610  *  pSD->rootWindow = default root window of display
2611  *  wmGD.bitmapDirectory = bitmapDirectory resource value
2612  *  HOME = environment variable for home directory
2613  *
2614  * 
2615  *  Outputs:
2616  *  -------
2617  *  linec  = (global) line count incremented
2618  *  parseP = (global) parse string pointer if cfileP == NULL
2619  *  pSD->menuSpecs = list of menu specifications
2620  *
2621  *
2622  *  Comments:
2623  *  --------
2624  *  Skips unnamed menu specifications.
2625  *  This means custom menu specifications can be distinguished by NULL name.
2626  * 
2627  *************************************<->***********************************/
2628
2629 static void ParseMenuSet (WmScreenData *pSD, unsigned char *lineP)
2630 {
2631     unsigned char     *string;
2632     MenuSpec *menuSpec;
2633     
2634     /*
2635      * If menu name is NULL then skip this pane specification.
2636      */
2637
2638     if ((string = GetString (&lineP)) == NULL)
2639     {
2640         return;
2641     }
2642
2643     /*
2644      * Allocate space for the menu specification structure.
2645      */
2646
2647     if ((menuSpec = (MenuSpec *)XtMalloc (sizeof (MenuSpec))) == NULL)
2648     {
2649         PWarning (((char *)GETMESSAGE(60, 9, "Insufficient memory for menu")));
2650         return;
2651     }
2652     menuSpec->currentContext = 0;
2653     menuSpec->menuWidget = NULL;
2654     menuSpec->whichButton = SELECT_BUTTON;  /* Button1 selection default */
2655     menuSpec->menuItems = NULL;
2656     menuSpec->accelContext = 0;
2657     menuSpec->accelKeySpecs = NULL;
2658 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
2659     menuSpec->exclusions = NULL;
2660     menuSpec->clientLocal = FALSE;
2661 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
2662     menuSpec->nextMenuSpec = NULL;
2663
2664     /*
2665      * Allocate and fill space for the menu name.
2666      */
2667
2668     if ((menuSpec->name = 
2669          (String)XtMalloc ((unsigned int) (strlen ((char *)string) + 1))) 
2670          == NULL)
2671     {
2672         PWarning (((char *)GETMESSAGE(60, 10, "Insufficient memory for menu")));
2673         XtFree ((char *)menuSpec);
2674         return;
2675     }
2676     strcpy (menuSpec->name, (char *)string);
2677
2678     /* 
2679      * Add the empty structure to the head of the menu specification list.
2680      */
2681
2682     menuSpec->nextMenuSpec = pSD->menuSpecs;
2683     pSD->menuSpecs = menuSpec;
2684
2685     /*
2686      * Require leading '{' on the next line.
2687      */
2688
2689     while ((GetNextLine () != NULL))  /* not EOF nor read error */
2690     {
2691         lineP = line;
2692         ScanWhitespace(&lineP);
2693
2694         if ((lineP == NULL) || (*line == '!') || (*lineP == '\0') || (*lineP == '#'))
2695         /* ignore empty or comment line */
2696         {
2697             continue;
2698         }
2699
2700         if (*lineP == '{')
2701         /* found '{' */
2702         {
2703             break;
2704         }
2705
2706         /* not a '{' */
2707         PWarning (((char *)GETMESSAGE(60, 11, "Expected '{' after menu name")));
2708         return;
2709     }
2710
2711     /*
2712      * Found leading "{" or EOF.
2713      * Parse menu item specifications until "}" or EOF found.
2714      */
2715
2716     menuSpec->menuItems = PARSE_MENU_ITEMS (pSD, menuSpec);
2717
2718 } /* END OF FUNCTION ParseMenuSet */
2719
2720 \f
2721 /*************************************<->*************************************
2722  *
2723  *  MenuItem *
2724  *  ParseMwmMenuStr (pSD, menuStr)
2725  *
2726  *
2727  *  Description:
2728  *  -----------
2729  *  This function parses a WMW_MENU string and returns a list of 
2730  *  MenuItems structures.  The string should have the syntax:
2731  *
2732  *       label  [mnemonic]  [accelerator]  function
2733  *       label  [mnemonic]  [accelerator]  function
2734  *                 ...
2735  *       label  [mnemonic]  [accelerator]  function
2736  *
2737  *
2738  *  Inputs:
2739  *  ------
2740  *  line = (global) line buffer
2741  *  pSD->rootWindow = default root window of display
2742  *  wmGD.bitmapDirectory = bitmapDirectory resource value
2743  *  HOME = environment variable for home directory
2744  *  functionTable = window manager function parse table
2745  *
2746  * 
2747  *  Outputs:
2748  *  -------
2749  *  Return = list of MenuItem structures or NULL
2750  *
2751  *
2752  *  Comments:
2753  *  --------
2754  *  None.
2755  * 
2756  *************************************<->***********************************/
2757
2758 MenuItem *ParseMwmMenuStr (WmScreenData *pSD, unsigned char *menuStr)
2759 {
2760
2761     cfileP = NULL;
2762     linec = 0;
2763     parseP = menuStr;
2764
2765     return (PARSE_MENU_ITEMS (pSD, NULL));
2766
2767 } /* END OF FUNCTION ParseMwmMenuStr */
2768
2769 \f
2770 /*************************************<->*************************************
2771  *
2772  *  static MenuItem *
2773  *  ParseMenuItems (pSD, menuSpec)
2774  *
2775  *
2776  *  Description:
2777  *  -----------
2778  *  Parse menu item specifications:
2779  *
2780  *       label  [mnemonic]  [accelerator]  function
2781  *       label  [mnemonic]  [accelerator]  function
2782  *                 ...
2783  *       label  [mnemonic]  [accelerator]  function
2784  *     [}]
2785  *
2786  *
2787  *  Inputs:
2788  *  ------
2789  *  pSD    = pointer to screen data
2790  *  cfileP = (global) file pointer to fopened configuration file or NULL
2791  *  line   = (global) line buffer
2792  *  linec  = (global) line count
2793  *  parseP = (global) parse string pointer if cfileP == NULL
2794  *  pSD->rootWindow = default root window of display
2795  *  wmGD.bitmapDirectory = bitmapDirectory resource value
2796  *  HOME = environment variable for home directory
2797  *
2798  * 
2799  *  Outputs:
2800  *  -------
2801  *  linec  = (global) line count incremented
2802  *  parseP = (global) parse string pointer if cfileP == NULL
2803  *  Return = list of MenuItem structures or NULL
2804  *
2805  *
2806  *  Comments:
2807  *  --------
2808  *  None.
2809  * 
2810  *************************************<->***********************************/
2811
2812 static MenuItem *ParseMenuItems (WmScreenData *pSD
2813 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
2814                                  , MenuSpec *menuSpec
2815 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
2816                                 )
2817 {
2818     unsigned char *string;
2819     unsigned char *lineP;
2820     MenuItem      *firstMenuItem;
2821     MenuItem      *lastMenuItem;
2822     MenuItem      *menuItem;
2823     register int   ix;
2824 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
2825     Boolean        use_separators = False;
2826 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
2827     
2828     /*
2829      * Parse "label [mnemonic] [accelerator] function" or
2830      *       "<client command>[.<client command>]*"
2831      * lines until "}" or EOF found.
2832      */
2833
2834     firstMenuItem = lastMenuItem = NULL;
2835     while ((GetNextLine () != NULL))
2836     {
2837         lineP = line;
2838         if ((*line == '!') || (*line == '#') || (string = GetString (&lineP)) == NULL)
2839         /* ignore empty or comment lines */
2840         {
2841             continue;
2842         }
2843         if (*string == '}')  /* finished with menu set. */
2844         {
2845             break;
2846         }
2847
2848         /*
2849          * Allocate space for the menu item structure. 
2850          */
2851
2852         if ((menuItem = (MenuItem *)XtMalloc (sizeof (MenuItem))) == NULL)
2853         {
2854             PWarning (((char *)GETMESSAGE(60, 12, "Insufficient memory for menu item")));
2855             continue;
2856         }
2857         menuItem->nextMenuItem = NULL;
2858         menuItem->wmFunction = (WmFunction)NULL;
2859         menuItem->wmFuncArgs = NULL;
2860 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
2861         menuItem->clientCommandName = NULL;
2862         menuItem->clientCommandID = 0;
2863 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
2864
2865 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
2866         /*
2867          * Is this a simple menu item label or is it a
2868          * client command specification.
2869          */
2870
2871         if (IsClientCommand((String) string))
2872         {
2873             if (!ParseClientCommand(&lineP, menuSpec, menuItem, string,
2874                                     &use_separators))
2875             {
2876                 XtFree ((char *)menuItem);
2877                 continue;
2878             }
2879
2880             for (ix = 0; ix < WMFUNCTIONTABLESIZE - 1; ++ix)
2881               if (functionTable[ix].wmFunction == F_InvokeCommand)
2882                 break;
2883
2884             if (ix == WMFUNCTIONTABLESIZE - 1)
2885             {
2886                 ix = F_NOP_INDEX;
2887                 menuItem->wmFunction = F_Nop;
2888             }
2889             else menuItem->wmFunction = F_InvokeCommand;
2890         }
2891         else /* It must be a menu item label */
2892 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
2893         {
2894             /*
2895              * Parse the menu item label.
2896              */
2897             if (!ParseWmLabel (pSD, menuItem, string))
2898             {
2899                 XtFree ((char *)menuItem);
2900                 continue;
2901             }
2902         }
2903
2904         /*
2905          * Parse any menu function mnemonic.
2906          */
2907
2908         ParseWmMnemonic (&lineP, menuItem);
2909
2910         /*
2911          * Parse any menu function accelerator.
2912          */
2913
2914         if (!ParseWmAccelerator (&lineP, menuItem))
2915         {
2916             XtFree ((char *)menuItem);
2917             continue;
2918         }
2919         /*
2920          * Parse the menu function name if this is not a client
2921          * command. If it is a client command, then the wmFunction
2922          * field should already be set, as well as the ix variable,
2923          * but we do want to search for a menu item name that occupies
2924          * the same place as the function does for normal menu items.
2925          */
2926 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
2927         if (menuItem->wmFunction != NULL)
2928           ParseMenuItemName(&lineP, menuItem);
2929         else
2930 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
2931           ix = ParseWmFunction (&lineP, CRS_MENU, &menuItem->wmFunction);
2932
2933         /*
2934          * Determine context sensitivity and applicability mask.
2935          */
2936
2937         menuItem->greyedContext = functionTable[ix].greyedContext;
2938         menuItem->mgtMask = functionTable[ix].mgtMask;
2939 #ifdef PANELIST
2940         if ((menuItem->wmFunction == F_Toggle_Front_Panel) &&
2941             ((wmGD.useFrontPanel == False) ||
2942              (wmGD.dtSD != pSD)))
2943         {
2944             /*
2945              * disallow this function if there's no front
2946              * panel on this screen.
2947              */
2948             menuItem->greyedContext |= (F_CONTEXT_ALL           | 
2949                                        F_SUBCONTEXT_IB_WICON    | 
2950                                        F_SUBCONTEXT_IB_IICON);
2951         }
2952 #endif /* PANELIST */
2953
2954         /* 
2955          * Apply the function argument parser.
2956          */
2957         if (!(*(functionTable [ix].parseProc)) 
2958                    (&lineP, menuItem->wmFunction, &menuItem->wmFuncArgs))
2959         {
2960             FreeMenuItem (menuItem);
2961             continue;  /* skip this menu item */
2962         }
2963
2964 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
2965         /*
2966          * If we're working on the f.cci function, this will fix-up
2967          * the menuItem entries so that it appears that we read-in
2968          * an old-style client-command entry.  Eventually, the cci
2969          * handling should be changed to make use of the wmFuncArgs.
2970          * Note that if DEFAULT_NAME was specified as the label, it
2971          * is first set to NULL.
2972          * FixMenuItem needs menuSpec since this is when the EXCLUDE
2973          * items are stored.
2974          */
2975         if (ix == F_CCI_INDEX)
2976           {
2977             CCIEntryModifier mod = ((CCIFuncArg *)menuItem->wmFuncArgs)->mod;
2978
2979             /* first fix the label if needed. */
2980             if (!strcmp(menuItem->label, CCI_USE_DEFAULT_NAME_TAG))
2981               {
2982                 XtFree(menuItem->label);
2983                 menuItem->label = NULL;
2984               }
2985
2986             FixMenuItem(menuSpec, menuItem);
2987
2988             if (mod == DELIMIT || mod == DELIMIT_CASCADE || mod == DELIMIT_INLINE)
2989               use_separators = True;
2990           }
2991
2992         /*
2993          * If this menu item is supposed to be wrapped in separators,
2994          * then create a separator template before the menu item
2995          */
2996         if (use_separators)
2997         {
2998             MenuItem *separator = MakeSeparatorTemplate(TOP_SEPARATOR);
2999             if (lastMenuItem != NULL) lastMenuItem->nextMenuItem = separator;
3000             else                      firstMenuItem = separator;
3001             lastMenuItem = separator;
3002         }
3003 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
3004
3005         /*
3006          * Add this item to the menu specification.
3007          */
3008
3009         if (lastMenuItem != NULL)  /* not first */
3010         {
3011             lastMenuItem->nextMenuItem = menuItem;
3012         }
3013         else
3014         {
3015             firstMenuItem = menuItem;
3016         }
3017         lastMenuItem = menuItem;
3018
3019 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
3020         /* If this menu item is supposed to be wrapped in separators
3021          * then create a separator template after the menu item
3022          */
3023         if (use_separators)
3024         {
3025             MenuItem *separator = MakeSeparatorTemplate(BOTTOM_SEPARATOR);
3026             if (lastMenuItem != NULL) lastMenuItem->nextMenuItem = separator;
3027             else                      firstMenuItem = separator;
3028             lastMenuItem = separator;
3029         }
3030
3031         use_separators = FALSE;
3032 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
3033     }
3034
3035     return (firstMenuItem);
3036
3037 } /* END OF FUNCTION ParseMenuItems */
3038
3039
3040 \f
3041 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
3042 /*************************************<->*************************************
3043  *
3044  *  StoreExclusion (menuSpec, string)
3045  *
3046  *
3047  *  Description:
3048  *  -----------
3049  *  Store the exclusion string in the menuspec. The list of exclusion
3050  *  strings are used to determine whether an insertion should be disallowed.
3051  *
3052  *
3053  *  Inputs:
3054  *  ------
3055  *  menuSpec = the menu specification structure
3056  *  string   = exclusion client command string
3057  *
3058  * 
3059  *  Outputs:
3060  *  -------
3061  *  Return   = nothing
3062  *
3063  *  Comments:
3064  *  --------
3065  *
3066  *************************************<->***********************************/
3067
3068 static void StoreExclusion (MenuSpec *menuSpec, String string)
3069 {
3070     MenuExclusion *exclusion;
3071
3072     exclusion = (MenuExclusion *)XtMalloc(sizeof(MenuExclusion));
3073     exclusion->command_string = XtNewString(string);
3074
3075     /* We don't care what order the exclusions are in so stick it
3076        at the head of the list because it is easier. */
3077     exclusion->nextExclusion = menuSpec->exclusions;
3078     menuSpec->exclusions = exclusion;
3079 }
3080
3081 \f
3082 /*************************************<->*************************************
3083  *
3084  *  IsClientCommand (string)
3085  *
3086  *
3087  *  Description:
3088  *  -----------
3089  *  Determine whether the string is a client command by the prefix
3090  *  characters.
3091  *
3092  *
3093  *  Inputs:
3094  *  ------
3095  *  string   = possible client command string
3096  *
3097  * 
3098  *  Outputs:
3099  *  -------
3100  *  Return   = (Boolean) TRUE iff the string is a client command.
3101  *             Otherwise, FALSE is returned.
3102  *
3103  *
3104  *  Comments:
3105  *  --------
3106  *  This function simply checks what the first two or three characters of
3107  *  the string are. If they match the beginning of a client command
3108  *  specification, then TRUE is returned. This function does no go on to
3109  *  parse the rest of the specification. The legal client command beginning
3110  *  characters are:
3111  *
3112  *              characters:     meaning:
3113  *              -----------------------------------------------
3114  *                  <           simple client command beginning
3115  *                -><           forced cascade menu
3116  *                 =<           client command with separators
3117  *                 ~<           exclusion operator
3118  * 
3119  *  Assumes:
3120  *  --------
3121  *  There is no leading whitespace on the string
3122  *
3123  *************************************<->***********************************/
3124
3125 Boolean IsClientCommand (String string)
3126 {
3127     if ((mblen ((char *)string, MB_CUR_MAX) == 1 && *string == '<') ||
3128         (strncmp(string, "-><", 3) == 0) ||
3129         (strncmp(string, "=<", 2) == 0)  ||
3130         (strncmp(string, "=><", 3) == 0) ||
3131         (strncmp(string, "~<", 2) == 0))
3132       return(TRUE);
3133
3134     return(FALSE);
3135 }
3136
3137 \f
3138 /*************************************<->*************************************
3139  *
3140  *  ParseClientCommand (linePP, menuSpec, menuitem, string, use_separators)
3141  *
3142  *
3143  *  Description:
3144  *  -----------
3145  *  Parse the string and whatever is left of the line to verify whether
3146  *  correct syntax was used for a client command. Store the client command
3147  *  string in the menuitem, unless it is an exclusion. If it is an
3148  *  exclusion, then store the exclusion string in the menuSpec and return
3149  *  FALSE to indicate that the menuitem is no longer needed.
3150  *
3151  *
3152  *  Inputs:
3153  *  ------
3154  *  linePP   = pointer to current line buffer pointer.
3155  *  menuItem = pointer to MenuItem structure
3156  *  string   = first token of client command
3157  *
3158  * 
3159  *  Outputs:
3160  *  -------
3161  *  Return   = (Boolean) TRUE iff the line is a valid client command 
3162  *             that can used to match insertions.
3163  *             Otherwise, FALSE is returned meaning that the client
3164  *             command had incorrect syntax or it was an exclusion, in
3165  *             which case any useful information was stored in the
3166  *             menuSpec.
3167  *
3168  *
3169  *  Comments:
3170  *  --------
3171  *  This function parses the entire line to determine if correct
3172  *  syntax was used for the client command. We assume at this point
3173  *  that the line is a client command. We are just syntax checking.
3174  *  If the syntax is correct, the client command is stored in the
3175  *  menuitem structure, in the "label" field.
3176  *
3177  *  Valid syntax for a client command (single quoted characters are
3178  *  literals):
3179  *
3180  *  modifier  = { '->' | '=' | '~' }
3181  *  reference = '<' { name | '*' } '>'
3182  *  command   = [ modifier ] reference [ { modifier | '.' } reference ]*
3183  *  name      = alpha-numeric string, white space allowed
3184  *
3185  *  Assumes:
3186  *  --------
3187  *  There is no leading whitespace on the string argument
3188  *
3189  *************************************<->***********************************/
3190
3191 enum { PRS_NO_STATE, PRS_BEGIN, PRS_MODIFIER, PRS_REFERENCE,
3192        PRS_SEPARATOR, PRS_END, PRS_ERROR, PRS_MAX_STATES };
3193
3194 /* This table lists for each parse state, the legal states that can
3195    be moved to. Each list must end with a PRS_NO_STATE value to 
3196    terminate the list. */
3197 static int cmd_parse_table[PRS_END][PRS_END] =
3198 {
3199   /* PRS_NO_STATE */  { PRS_NO_STATE },
3200   /* PRS_BEGIN */     { PRS_MODIFIER, PRS_REFERENCE, PRS_NO_STATE },
3201   /* PRS_MODIFIER */  { PRS_REFERENCE, PRS_NO_STATE },
3202   /* PRS_REFERENCE */ { PRS_SEPARATOR, PRS_END, PRS_NO_STATE },
3203   /* PRS_SEPARATOR */ { PRS_REFERENCE, PRS_NO_STATE },
3204 };
3205
3206 static Boolean ParseClientCommand (unsigned char **linePP, MenuSpec *menuSpec,
3207                                    MenuItem *menuItem, unsigned char *string,
3208                                    Boolean *use_separators)
3209 {
3210     int token, linelen, i;
3211     int state = PRS_BEGIN;
3212     String stream, unchanged_stream, exclusion_text;
3213     Boolean return_val = FALSE;
3214     Boolean exclusion = FALSE; /* this will be set to TRUE if the client
3215                                   command was parsed to be an exclusion
3216                                   command. */
3217
3218     /* Construct one input stream out of the string and the linePP that
3219        we were given. */
3220     linelen = strlen((char *)string) + strlen((char *)*linePP) + 1;
3221     if ((unchanged_stream = stream = (String)
3222          XtMalloc((unsigned int)(sizeof(unsigned char) * linelen))) == NULL)
3223     {
3224         PWarning (((char *)GETMESSAGE(60, 42,
3225                     "Insufficient memory for menu item label")));
3226         return (FALSE);
3227     }
3228     strcpy(stream, (char *) string);
3229     strcat(stream, " ");
3230     strcat(stream, (char *) *linePP);
3231
3232     for (;;)
3233     {
3234         token = PRS_NO_STATE;
3235         while (token == PRS_NO_STATE)
3236         {
3237             if (mblen ((char *)stream, MB_CUR_MAX) > 1) {
3238               token = PRS_ERROR;
3239               continue;
3240             }
3241
3242             switch (*stream)
3243             {
3244               case '\0':
3245               case '\n':
3246                 /* We've reached the end of the stream. Return the
3247                    PRS_END token. */
3248                 token = PRS_END;
3249                 break;
3250               case '-':
3251                 /* This should be a cascade-force modifier */
3252                 ++stream;
3253                 if (mblen ((char *)stream, MB_CUR_MAX) > 1) {
3254                   token = PRS_ERROR;
3255                   continue;
3256                 }
3257                 if (*stream == '>')
3258                 {
3259                     ++stream; token = PRS_MODIFIER;
3260                 }
3261                 else token = PRS_ERROR;
3262                 break;
3263               case '=':
3264                 /* This is either a separators modifier or
3265                    a combination separators and cascade-force
3266                    modifier */
3267                 ++stream;
3268                 if (mblen ((char *)stream, MB_CUR_MAX) > 1) {
3269                   token = PRS_ERROR;
3270                   continue;
3271                 }
3272                 if (*stream == '>') ++stream;
3273                 token = PRS_MODIFIER;
3274                 *use_separators = TRUE;
3275                 break;
3276               case '~':
3277                 /* This is a exclude-command modifier */
3278                 ++stream; token = PRS_MODIFIER;
3279                 exclusion = TRUE;
3280                 /* Setup a pointer to the text following the ~ so
3281                    we can do matching later for exclusions. */
3282                 exclusion_text = stream;
3283                 break;
3284               case '<':
3285                 /* Skip the open bracket */
3286                 ++stream;
3287
3288                 /* This should be the beginning of a reference. First
3289                    skip any leading whitespace. */
3290                 if (mblen ((char *)stream, MB_CUR_MAX) > 1) {
3291                   token = PRS_ERROR;
3292                   continue;
3293                 }
3294                 while (mblen ((char *)stream, MB_CUR_MAX) == 1 && 
3295                        (*stream == ' ' || *stream == '\t')) 
3296                   ++stream;
3297
3298                 if (mblen ((char *)stream, MB_CUR_MAX) > 1) {
3299                   token = PRS_ERROR;
3300                   continue;
3301                 }
3302                 /* Now check for a reference name wild card or a
3303                    full reference name */
3304                 if (*stream == '*')
3305                   ++stream;
3306                 else
3307                 {
3308                     while (mblen ((char *)stream, MB_CUR_MAX) == 1 && 
3309                            (isalnum(*stream) || *stream == ' ' ||
3310                             *stream == '\t'  || *stream == '_' ))
3311                       ++stream;
3312                 }
3313                 
3314                 if (mblen ((char *)stream, MB_CUR_MAX) > 1) {
3315                   token = PRS_ERROR;
3316                   continue;
3317                 }
3318
3319                 /* Now skip past any trailing white space */
3320                 while (mblen ((char *)stream, MB_CUR_MAX) == 1 && 
3321                        (*stream == ' ' || *stream == '\t'))
3322                   ++stream;
3323
3324                 if (mblen ((char *)stream, MB_CUR_MAX) > 1) {
3325                   token = PRS_ERROR;
3326                   continue;
3327                 }
3328                 /* At this point, we should be looking at the close
3329                    of the reference */
3330                 if (*stream == '>')
3331                 {
3332                     token = PRS_REFERENCE;
3333                     ++stream;
3334                 }
3335                 else token = PRS_ERROR;
3336                 break;
3337               case '.':
3338                 /* This is a reference separator */
3339                 ++stream; token = PRS_SEPARATOR;
3340                 break;
3341               case ' ':
3342               case '\t':
3343                 /* The only place white space is allowed as at the
3344                    beginning of the line, after all the client command
3345                    text and within the delimiters of a REFERENCE. We
3346                    are guaranteed not to have whitespace at the 
3347                    beginning of the line by the time this function is
3348                    called. Also, the REFERENCE parsing above handles
3349                    all white space internal to the client command. Therefore,
3350                    since we are seeing white space, we must be at the
3351                    end of the client command. */
3352                 token = PRS_END;
3353                 break;
3354               default:
3355                 token = PRS_ERROR;
3356
3357             } /* end switch (*stream) */
3358         } /* end while (token == PRS_NO_STATE) */
3359
3360         /* If we got an error then just return an error */
3361         if (token == PRS_ERROR)
3362         {
3363             return_val = FALSE; break;
3364         }
3365         
3366         /* Check whether the token we got is a valid transition */
3367         for (i = 0; cmd_parse_table[state][i] != PRS_NO_STATE; ++i)
3368         {
3369             if (token == cmd_parse_table[state][i]) 
3370             {
3371                 /* It is a valid transition, so break out of the loop */
3372                 break;
3373             }
3374         }
3375         
3376         /* If i is not indexing the NO_STATE value in the parse_table,
3377            then the parse succeeded. Check if the new state is PRS_END.
3378            If so then we are done. If the state isn't the same as the
3379            current token, then we hit a parse error. */
3380         if (cmd_parse_table[state][i] != PRS_NO_STATE)
3381         {
3382             if (token == PRS_END)
3383             {
3384                 return_val = TRUE;
3385                 break;
3386             }
3387         }
3388         else 
3389         {
3390             /* parse error */
3391             return_val = FALSE;
3392             break;
3393         }
3394         
3395         /* The transition was valid so make the transition by
3396            setting the state to be the current token. */
3397         state = token; 
3398
3399     } /* end for (;;) */
3400
3401     /* If the return_val is TRUE, then the parse succeeded and we
3402        want to save the string we parsed into the label field of
3403        the menu item. */
3404     if (return_val == TRUE)
3405     {
3406         /* NULL terminate the string */
3407         *stream = '\0';
3408
3409         /* Check whether this client command was an exclusion. If not,
3410            then store the client command string in the menu item. */
3411         if (exclusion == TRUE)
3412         {
3413             /* Since the command was an exclusion, store the command
3414                string in the menuSpec and change the return value to
3415                FALSE. */
3416             StoreExclusion(menuSpec, exclusion_text);
3417             return_val = FALSE;
3418         }
3419         else
3420         {
3421             menuItem->label = XtNewString(unchanged_stream);
3422             menuItem->labelType = XmSTRING;
3423         }
3424     }
3425
3426     /* Free the string we allocated and return. */
3427     XtFree((char *)unchanged_stream);
3428
3429     return(return_val);
3430 }
3431 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
3432
3433 \f
3434 /*************************************<->*************************************
3435  *
3436  *  ParseWmLabel (pSD, menuItem, string)
3437  *
3438  *
3439  *  Description:
3440  *  -----------
3441  *  Parse a menu label string.
3442  *
3443  *
3444  *  Inputs:
3445  *  ------
3446  *  pSD      = pointer to screen data
3447  *  menuItem = pointer to MenuItem structure
3448  *  string   = label string
3449  *
3450  * 
3451  *  Outputs:
3452  *  -------
3453  *  menuItem->label
3454  *  menuItem->labelType
3455  *  menuItem->labelBitmapCache
3456  *  Return   = boolean, FALSE iff insufficient memory
3457  *
3458  *
3459  *  Comments:
3460  *  --------
3461  * We have two label types:  XmSTRING and XmPIXMAP
3462  * We allocate and fill the label field with string and set the type to 
3463  * XmSTRING.  If string = "@<bitmap_file>", and <bitmap_file> contains a
3464  * with which to build a label image we save the bitmap in the MenuItem 
3465  * structure and set the type to XmPIXMAP.
3466  * 
3467  *************************************<->***********************************/
3468
3469 static Boolean ParseWmLabel (WmScreenData *pSD, MenuItem *menuItem, 
3470                              unsigned char *string)
3471 {
3472
3473     /*
3474      * Allocate the label field and copy string.
3475      */
3476
3477     if ((menuItem->label = (String)
3478         XtMalloc ((unsigned int)(strlen ((char *)string) + 1))) == NULL)
3479     {
3480         PWarning (((char *)GETMESSAGE(60, 13, "Insufficient memory for menu item")));
3481         return (FALSE);
3482     }
3483
3484     strcpy (menuItem->label, (char *)string);
3485     menuItem->labelType = XmSTRING;
3486
3487     if (*string == '@')
3488     /*
3489      * Here:  string  = "@<bitmap file>"
3490      * Try to find the label bitmap in the bitmap cache or read the label 
3491      * bitmap file.
3492      */
3493     {
3494         string++;  /* skip "@" */
3495 #ifdef WSM
3496         if ((menuItem->labelBitmapIndex = GetBitmapIndex (pSD, 
3497                                            (char *)string, True)) >= 0)
3498 #else /* WSM */
3499         if ((menuItem->labelBitmapIndex = GetBitmapIndex (pSD, 
3500                                                (char *)string)) >= 0)
3501 #endif /* WSM */
3502         {
3503             menuItem->labelType = XmPIXMAP;
3504         }
3505     }
3506     return (TRUE);
3507
3508 } /* END OF FUNCTION ParseWmLabel */
3509
3510
3511 \f
3512 /*************************************<->*************************************
3513  *
3514  *  ParseWmMnemonic (linePP, menuItem)
3515  *
3516  *
3517  *  Description:
3518  *  -----------
3519  *  Parse an optional menu function mnemonic.
3520  *
3521  *
3522  *  Inputs:
3523  *  ------
3524  *  linePP   = pointer to current line buffer pointer.
3525  *  menuItem = pointer to MenuItem structure
3526  *
3527  * 
3528  *  Outputs:
3529  *  -------
3530  *  linePP   = pointer to revised line buffer pointer.
3531  *  menuItem->mnemonic = valid mnemonic character or NULL.
3532  *
3533  *
3534  *  Comments:
3535  *  --------
3536  *  None.
3537  * 
3538  *************************************<->***********************************/
3539
3540 static void ParseWmMnemonic (unsigned char **linePP, MenuItem *menuItem)
3541 {
3542     unsigned char *lineP = *linePP;
3543     unsigned char *mnemonic;
3544
3545     /*
3546      * Skip leading white space.
3547      */
3548     ScanWhitespace (&lineP);
3549     menuItem->mnemonic = (KeySym)NULL;
3550
3551     if (*lineP == '_')
3552     /* 
3553      * We have a mnemonic specification. 
3554      * Get the next string (we only use the first character).
3555      * If no string exists, the labelType is not XmSTRING, or does not contain 
3556      * the first character, then skip the string and return.
3557      * Otherwise, accept the first character as a mnemonic.
3558      */
3559     {
3560         KeySym ks;
3561         lineP++;
3562         mnemonic = GetString(&lineP);
3563
3564 #ifndef NO_MULTIBYTE
3565         if (menuItem->labelType == XmSTRING &&
3566             mnemonic != NULL &&
3567             (ks = XStringToKeysym((char *)mnemonic)) != NoSymbol &&
3568             strchr(menuItem->label, (char)(ks & 0xff)) != NULL)
3569         {
3570             menuItem->mnemonic = ks;
3571         }
3572 #else
3573         if ((mnemonic != NULL) &&
3574             (*mnemonic != '\0') &&
3575             (menuItem->labelType == XmSTRING) &&
3576             (strchr (menuItem->label, *mnemonic) != NULL))
3577         /* valid mnemonic */
3578         {
3579             menuItem->mnemonic = *mnemonic;
3580         }
3581 #endif
3582         else
3583         {
3584             PWarning (((char *)GETMESSAGE(60, 14, "Invalid mnemonic specification")));
3585         }
3586     }
3587
3588     *linePP = lineP;  /* consume any string */
3589
3590 } /* END OF FUNCTION ParseWmMnemonic */
3591
3592 \f
3593 /*************************************<->*************************************
3594  *
3595  *  ParseWmAccelerator (linePP, menuItem)
3596  *
3597  *
3598  *  Description:
3599  *  -----------
3600  *  Parse an optional menu function accelerator.
3601  *
3602  *
3603  *  Inputs:
3604  *  ------
3605  *  linePP   = pointer to current line buffer pointer.
3606  *  menuItem = pointer to MenuItem structure
3607  *
3608  * 
3609  *  Outputs:
3610  *  -------
3611  *  linePP   = pointer to revised line buffer pointer.
3612  *  menuItem->accelText = pointer to an accelerator string or NULL.
3613  *
3614  *
3615  *  Comments:
3616  *  --------
3617  *  None.
3618  * 
3619  *************************************<->***********************************/
3620
3621 static Boolean ParseWmAccelerator (unsigned char **linePP, MenuItem *menuItem)
3622 {
3623     unsigned char *lineP;
3624     String        string;
3625     unsigned int  eventType;
3626     unsigned int  state;
3627     KeyCode       keycode;
3628     Boolean       status;
3629
3630     menuItem->accelState = 0;
3631     menuItem->accelKeyCode = 0;
3632     menuItem->accelText = NULL;
3633     status = TRUE;
3634
3635     /*
3636      * If linePP contains NULL, then abort.
3637      */
3638     if (*linePP == (unsigned char *) NULL) return(FALSE);
3639
3640     /*
3641      * Skip leading white space.
3642      */
3643     ScanWhitespace (linePP);
3644     lineP = *linePP;
3645
3646     /*
3647      * If the second character is not ".", and an accelerator specification 
3648      * exists, then process and save the specification string.
3649      */
3650
3651     if ((*lineP != '\0') &&     /* something follows */
3652         (*lineP != '!')  &&     /* skip if we have the ! WmFunction */
3653 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
3654          /* skip label name for client command */
3655         ((*lineP != '"') || (menuItem->wmFunction != F_InvokeCommand)) &&
3656 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
3657         (*lineP != 'f')  &&
3658         (*(lineP+1) != '.'))    /* skip if we have f.xxx WmFunction */
3659     {
3660         if (ParseKeyEvent(&lineP, &eventType, &keycode, &state))
3661         {
3662             if ((string = (String) XtMalloc 
3663                  ((unsigned int) (lineP - *linePP + 1))) == NULL)
3664             {
3665                 PWarning (((char *)GETMESSAGE(60, 15, "Insufficient memory for accelerator specification")));
3666                 status = FALSE;
3667             }
3668             else
3669             /*
3670              * Save the accelerator state and keycode.
3671              * Process and save the accelerator text.
3672              */
3673             {
3674                 ProcessAccelText (*linePP, lineP, (unsigned char *) string);
3675                 menuItem->accelState = state;
3676                 menuItem->accelKeyCode = keycode;
3677                 menuItem->accelText = string;
3678             }
3679         }
3680         else
3681         {
3682             PWarning (((char *)GETMESSAGE(60, 16, "Invalid accelerator specification")));
3683             status = FALSE;
3684         }
3685
3686         *linePP = lineP;  /* consume the specification */
3687     }
3688
3689     return (status);
3690
3691 } /* END OF FUNCTION ParseWmAccelerator */
3692
3693 \f
3694 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
3695 /*************************************<->*************************************
3696  *
3697  *  ParseMenuItemName (linePP, menuItem)
3698  *
3699  *
3700  *  Description:
3701  *  -----------
3702  *  Parse a user defined client command menu item
3703  *
3704  *
3705  *  Inputs:
3706  *  ------
3707  *  linePP   = pointer to current line buffer pointer.
3708  *  menuItem = pointer to MenuItem structure
3709  *
3710  * 
3711  *  Outputs:
3712  *  -------
3713  *  menuItem->label will have menu item name appended to it
3714  *
3715  *  Comments:
3716  *  --------
3717  *  This function attempts to find a menu item label string at the end
3718  *  of the client command specification line. A menu item label string
3719  *  must be delimited by double quotes. If found, the label string is
3720  *  appended to the menuItem->label field, after being reallocated to
3721  *  accommodate the new space requirement.
3722  * 
3723  *************************************<->***********************************/
3724
3725 static void ParseMenuItemName (unsigned char **linePP, MenuItem *menuItem)
3726 {
3727     unsigned char *lineP, *endquote;
3728     int chlen;
3729
3730     /* Skip past any whitespace */
3731     ScanWhitespace (linePP);
3732     lineP = *linePP;
3733
3734     /* Look for a double quote */
3735     if (mblen ((char *)lineP, MB_CUR_MAX) == 1 && *lineP == '"')
3736     {
3737         /* Move past the first quote. */
3738         ++lineP;
3739
3740         endquote = lineP;
3741
3742         /* Search for closing quote */
3743         while (*endquote != '\0' &&
3744                (chlen = mblen ((char *)endquote, MB_CUR_MAX)) > 0 && 
3745                (chlen > 1 || *endquote != '"'))
3746         {
3747             /* If we ran off the end of the line, then just abort. Bad
3748                syntax. */
3749             if ((chlen == 1 && *endquote == '\n') || *endquote == '\0') return;
3750             endquote += chlen;
3751         }
3752         if (chlen < 0) return; /* invalid character */
3753
3754         /* Well, we have a valid menu item name. Store it in the 
3755            client command name field. Don't include the double quotes. */
3756         menuItem->clientCommandName =
3757           XtMalloc(sizeof(char) * (endquote - lineP) + 1);
3758         strncpy(menuItem->clientCommandName, (char *) lineP,
3759                 endquote - lineP);
3760         menuItem->clientCommandName[strlen(menuItem->clientCommandName)+1] = '\0';
3761     }
3762     else
3763     {
3764         /* If there was no double quote, then just advance to the end
3765            of the line. */
3766         while (*lineP != '\0' && 
3767                ((chlen = mblen ((char *)lineP, MB_CUR_MAX)) > 1 ||
3768                 *lineP != '\n'))
3769           lineP += chlen > 0 ? chlen : 1;
3770         *linePP = lineP;
3771     }
3772 }
3773 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
3774
3775 \f
3776 /*************************************<->*************************************
3777  *
3778  *  int
3779  *  ParseWmFunction (linePP, res_spec, pWmFunction)
3780  *
3781  *
3782  *  Description:
3783  *  -----------
3784  *  Parse a button, key, or menu function name and return its function table
3785  *  index.
3786  *
3787  *
3788  *  Inputs:
3789  *  ------
3790  *  linePP   = pointer to current line buffer pointer.
3791  *  res_spec = resource specification type (key, button, or menu).
3792  *  pWmFunction = pointer to window manager function destination.
3793  *  functionTable = window manager function parse table
3794  *
3795  * 
3796  *  Outputs:
3797  *  -------
3798  *  linePP   = pointer to revised line buffer pointer.
3799  *  pWmFunction = pointer to parsed window manager function.
3800  *  Return = function table index of parsed function.
3801  *
3802  *
3803  *  Comments:
3804  *  --------
3805  *  Uses F_Nop if the function name or resource type is invalid.
3806  * 
3807  *************************************<->***********************************/
3808
3809 int ParseWmFunction (unsigned char **linePP, unsigned int res_spec, 
3810                             WmFunction *pWmFunction)
3811 {
3812     unsigned char *lineP = *linePP;
3813     unsigned char *string;
3814     register int  low, mid, high, cmp;
3815
3816     /*
3817      * Skip leading white space.
3818      */
3819     ScanWhitespace (&lineP);
3820
3821     /* 
3822      * Have function string (may be NULL or a comment).
3823      * Handle the special case of '!' 
3824      */
3825
3826     if (*lineP == '!')
3827     {
3828         *linePP = ++lineP;
3829         *pWmFunction = F_Exec;
3830         return (F_EXEC_INDEX);
3831     }
3832
3833     /*
3834      * Identify the function corresponding to the specified name.
3835      * Try binary search of the window manager function parse table.
3836      * Assume f.nop if the function and resource type cannot be matched.
3837      * This handles NULL and comment strings, bad function names, and functions
3838      *   in inappropriate resource sets.
3839      */
3840     string = GetString (&lineP);
3841     *linePP = lineP;
3842
3843     if (string != NULL)
3844     {
3845         ToLower (string);
3846         low = 0;
3847         high = WMFUNCTIONTABLESIZE - 1;
3848
3849         while (low <= high)
3850         {
3851             mid = (low + high)/2;
3852             cmp = strcmp (functionTable[mid].funcName, (char *)string);
3853
3854             if (!cmp)
3855             /*
3856              * Function name match 
3857              * Require proper resource type for the function.
3858              */
3859             {
3860                 if (res_spec & functionTable[mid].resource)
3861                 {
3862                     *pWmFunction = functionTable[mid].wmFunction;
3863                     return (mid);
3864                 }
3865
3866                 /* invalid resource:  use F_Nop */
3867                 break;
3868             }
3869
3870             /*
3871              * Function name mismatch 
3872              */
3873             if (cmp > 0)
3874             {
3875                 high = mid - 1;
3876             }
3877             else
3878             {
3879                 low = mid + 1;
3880             }
3881         }
3882     }
3883
3884     /* 
3885      * Not found:  assume f.nop
3886      */
3887     *pWmFunction = F_Nop;
3888     return (F_NOP_INDEX);
3889
3890 } /* END OF FUNCTION ParseWmFunction */
3891
3892 \f
3893 /*************************************<->*************************************
3894  *
3895  *  ParseWmFuncMaybeStrArg (linePP, wmFunction, pArgs)
3896  *
3897  *
3898  *  Description:
3899  *  -----------
3900  *  Parses a window manager function with a null or string argument.
3901  *
3902  *
3903  *  Inputs:
3904  *  ------
3905  *  linePP   = pointer to current line buffer pointer.
3906  *  wmFunction = function (not used).
3907  *  pArgs = pointer to argument destination.
3908  *
3909  * 
3910  *  Outputs:
3911  *  -------
3912  *  linePP   = pointer to revised line buffer pointer.
3913  *  pArgs    = pointer to parsed argument string.
3914  *  Return   = FALSE iff insufficient memory
3915  *
3916  *
3917  *  Comments:
3918  *  --------
3919  *  Only used to parse arguments for F_Lower, F_Raise, and F_Raise_Lower.
3920  *  If it is used for any other function, be sure to change FreeMenuItem ()
3921  *  accordingly.
3922  * 
3923  *************************************<->***********************************/
3924
3925 #ifndef PANELIST
3926 static
3927 #endif 
3928 Boolean ParseWmFuncMaybeStrArg (unsigned char **linePP, 
3929                                        WmFunction wmFunction, String *pArgs)
3930 {
3931     unsigned char *string = *linePP;
3932     unsigned int  len;
3933
3934     ScanWhitespace (&string);
3935 /*
3936     if (*lineP == '-')
3937     {
3938         *linePP = ++lineP;
3939         return (ParseWmFuncStrArg (linePP, wmFunction, pArgs));
3940     }
3941 */
3942 #ifdef PANELIST
3943 #if 0
3944     else if (*lineP == '"' && *(lineP+1) == '-')
3945     {
3946         /* kill off '-' */
3947         strcpy ((char *) (lineP+1), (char *) (lineP+2));
3948         return (ParseWmFuncStrArg (linePP, wmFunction, pArgs));
3949     }
3950 #endif
3951 #endif /* PANELIST */
3952     if ((len = strlen ((char *)string)) != 0)
3953     {
3954         if ((*pArgs = (String)XtMalloc (len + 1)) == NULL)
3955         {
3956             PWarning (((char *)GETMESSAGE(60, 17, "Insufficient memory")));
3957             return (FALSE);
3958         }
3959         strcpy (*pArgs, (char *)string);
3960         return (TRUE);
3961     }
3962     else
3963     /* Do ParseWmFuncNoArg () */
3964     {
3965         *pArgs = NULL;
3966         return (TRUE);
3967     }
3968
3969 } /* END OF FUNCTION ParseWmFuncMaybeStrArg */
3970
3971 \f
3972 /*************************************<->*************************************
3973  *
3974  *  ParseWmFuncNoArg (linePP, wmFunction, pArgs)
3975  *
3976  *
3977  *  Description:
3978  *  -----------
3979  *  Parses a window manager function null argument.
3980  *
3981  *
3982  *  Inputs:
3983  *  ------
3984  *  linePP   = pointer to current line buffer pointer.
3985  *  wmFunction = function (not used).
3986  *  pArgs = pointer to argument destination.
3987  *
3988  * 
3989  *  Outputs:
3990  *  -------
3991  *  linePP   = unchanged
3992  *  pArgs    = NULL
3993  *  Return   = TRUE
3994  *
3995  *
3996  *  Comments:
3997  *  --------
3998  *  None.
3999  * 
4000  *************************************<->***********************************/
4001
4002 static Boolean ParseWmFuncNoArg (unsigned char **linePP, WmFunction wmFunction,
4003                                  String *pArgs)
4004 {
4005
4006     *pArgs = NULL;
4007     return (TRUE);
4008
4009 } /* END OF FUNCTION ParseWmFuncNoArg */
4010
4011 \f
4012 /*************************************<->*************************************
4013  *
4014  *  ParseWmFuncStrArg (linePP, wmFunction, pArgs)
4015  *
4016  *
4017  *  Description:
4018  *  -----------
4019  *  Parses a window manager function string argument.
4020  *
4021  *
4022  *  Inputs:
4023  *  ------
4024  *  linePP   = pointer to current line buffer pointer.
4025  *  wmFunction = function for which the argument string is intended.
4026  *  pArgs = pointer to argument string destination.
4027  *
4028  * 
4029  *  Outputs:
4030  *  -------
4031  *  linePP   = pointer to revised line buffer pointer.
4032  *  pArgs    = pointer to parsed argument string.
4033  *  Return   = FALSE iff insufficient memory
4034  *
4035  *
4036  *  Comments:
4037  *  --------
4038  *  Insures that an argument for F_Exec() ends in '&' .
4039  *  Only used to parse arguments for F_Exec, F_Menu, F_Lower, F_Raise, 
4040  *  F_Raise_Lower, and F_Screen.  If it is used for any other function, be
4041  *  sure to change FreeMenuItem () accordingly.
4042  * 
4043  *************************************<->***********************************/
4044
4045 #ifndef PANELIST
4046 static
4047 #endif
4048 Boolean ParseWmFuncStrArg (unsigned char **linePP, 
4049                                   WmFunction wmFunction, String *pArgs)
4050 {
4051     unsigned char *string;
4052     unsigned int  len;
4053 #ifndef NO_MULTIBYTE
4054     char *p;
4055     wchar_t last;
4056     char delim;
4057     wchar_t wdelim;
4058     int lastlen;
4059 #endif
4060
4061     if ((string = GetString (linePP)) != NULL)
4062     /* nonNULL string argument */
4063     {
4064         len = strlen ((char *)string);
4065         if ((*pArgs = (String)XtMalloc (len + 2)) == NULL)
4066         {
4067             PWarning (((char *)GETMESSAGE(60, 17, "Insufficient memory")));
4068             return (FALSE);
4069         }
4070         strcpy (*pArgs, (char *)string);
4071
4072         /*
4073          *  Insure that an argument for F_Exec ends in '&' .
4074          */
4075
4076 #ifndef NO_MULTIBYTE
4077         if ((wmFunction == F_Exec))
4078         {
4079             lastlen = 0;
4080             p = *pArgs;
4081             while (*p &&
4082                    ((len = mblen(p, MB_CUR_MAX)) > 0))
4083             {
4084                 mbtowc(&last, p, MB_CUR_MAX);
4085                 lastlen = len;
4086                 p += len;
4087             }
4088             delim = '&';
4089             mbtowc(&wdelim, &delim, MB_CUR_MAX);
4090             if (lastlen == 1 && last != wdelim)
4091             {
4092                 *p++ = '&';
4093                 *p   = '\0';
4094             }
4095         }
4096 #else
4097         if ((wmFunction == F_Exec) && ((*pArgs)[len - 1] != '&'))
4098         {
4099             (*pArgs)[len] = '&';
4100             (*pArgs)[len + 1] = '\0';
4101         }
4102 #endif
4103     }
4104     else
4105     /* NULL string argument */
4106     {
4107         *pArgs = NULL;
4108     }
4109
4110     return (TRUE);
4111
4112 } /* END OF FUNCTION ParseWmFuncStrArg */
4113
4114 \f
4115 /*************************************<->*************************************
4116  *
4117  *  FreeMenuItem (menuItem)
4118  *
4119  *
4120  *  Description:
4121  *  -----------
4122  *  This procedure destroys a MenuItem structure.
4123  *
4124  *
4125  *  Inputs:
4126  *  ------
4127  *  menuItem = to be destroyed.
4128  *
4129  * 
4130  *  Outputs:
4131  *  -------
4132  *  None.
4133  *
4134  *
4135  *  Comments:
4136  *  --------
4137  *  Assumes that ParseWmFuncStrArg () has parsed a menu item's function
4138  *  argument only for F_Exec, F_Menu, F_Lower, F_Raise, F_Raise_Lower, and
4139  *  F_Screen. If it is used for other functions, be sure to include them here!
4140  * 
4141  *************************************<->***********************************/
4142
4143 void FreeMenuItem (MenuItem *menuItem)
4144 {
4145     if (menuItem->label != NULL)
4146     {
4147         XtFree ((char *)menuItem->label);
4148     }
4149
4150     if (menuItem->accelText != NULL)
4151     {
4152         XtFree ((char *)menuItem->accelText);
4153     }
4154
4155     /*
4156      * If menuItem->wmFuncArgs is nonNULL, we assume that it is a string that
4157      * was malloc'ed in ParseWmFuncStrArg () and we free it now.
4158      */
4159     if ((menuItem->wmFuncArgs != NULL) &&
4160         ((menuItem->wmFunction == F_Exec)  || 
4161          (menuItem->wmFunction == F_Menu)  || 
4162          (menuItem->wmFunction == F_Lower) || 
4163          (menuItem->wmFunction == F_Raise) || 
4164          (menuItem->wmFunction == F_Raise_Lower) ||
4165          (menuItem->wmFunction == F_Screen)))
4166     {
4167         XtFree ((char *)menuItem->wmFuncArgs);
4168     }
4169
4170     XtFree ((char *)menuItem);
4171
4172 } /* END OF FUNCTION FreeMenuItem */
4173
4174
4175 \f
4176 /*************************************<->*************************************
4177  *
4178  *  ParseWmFuncGrpArg (linePP, wmFunction, pGroup)
4179  *
4180  *
4181  *  Description:
4182  *  -----------
4183  *  Parses a window manager function group argument.
4184  *
4185  *
4186  *  Inputs:
4187  *  ------
4188  *  linePP   = pointer to current line buffer pointer.
4189  *  wmFunction = function for which the group argument is intended.
4190  *  pGroup = pointer to group argument destination.
4191  *
4192  * 
4193  *  Outputs:
4194  *  -------
4195  *  linePP   = pointer to revised line buffer pointer.
4196  *  pGroup    = pointer to parsed group argument.
4197  *  Return   = FALSE iff invalid group argument.
4198  *
4199  *
4200  *  Comments:
4201  *  --------
4202  *  The only valid nonNULL arguments are "icon", "window", and "transient".
4203  * 
4204  *************************************<->***********************************/
4205
4206 static Boolean ParseWmFuncGrpArg (unsigned char **linePP, 
4207                                   WmFunction wmFunction, GroupArg *pGroup)
4208 {
4209     unsigned char  *lineP = *linePP;
4210     unsigned char  *startP;
4211     unsigned char   grpStr[MAX_GROUP_STRLEN+1];
4212     int    len;
4213
4214
4215     /*
4216      * Parse groups while each is followed by "|".
4217      */
4218
4219     *pGroup = 0;
4220     while (1)
4221     {
4222         /* 
4223          * Skip whitespace and find next group string.
4224          */
4225
4226         ScanWhitespace (&lineP);
4227         startP = lineP;
4228         ScanAlphanumeric (&lineP);
4229         if (startP == lineP)
4230         /* Group missing => use default or complain */
4231         {
4232             if (*pGroup)
4233             {
4234                 PWarning (((char *)GETMESSAGE(60, 18, "Missing group specification")));
4235                 return (FALSE);
4236             }
4237             else
4238             {
4239                 *pGroup = F_GROUP_DEFAULT;
4240                 break;
4241             }
4242         }
4243
4244         /*
4245          * Found a group string; compare it with valid groups.
4246          */
4247
4248         len = min (lineP - startP, MAX_GROUP_STRLEN);
4249         (void) strncpy ((char *)grpStr, (char *)startP, len);
4250         grpStr[len] = '\0';
4251         ToLower (grpStr);
4252
4253         if (!strcmp ("icon", (char *)grpStr))
4254         {
4255             *pGroup |= F_GROUP_ICON;
4256         }
4257         else if (!strcmp ("window", (char *)grpStr))
4258         {
4259             *pGroup |= F_GROUP_WINDOW;
4260         }
4261         else if (!strcmp ("transient", (char *)grpStr))
4262         {
4263             *pGroup |= F_GROUP_TRANSIENT;
4264         }
4265         else 
4266         /* Unknown group name */
4267         {
4268             PWarning (((char *)GETMESSAGE(60, 19, "Invalid group specification")));
4269             return (FALSE);
4270         }
4271
4272         /*
4273          *  Continue processing until the line is exhausted.
4274          *  Skip any '|' .
4275          */
4276
4277         ScanWhitespace (&lineP);
4278
4279         if (lineP == NULL || *lineP == '\0')
4280         {
4281             break; 
4282         }
4283         else if (*lineP == '|')
4284         {
4285             lineP++;
4286         }
4287     }
4288
4289     *linePP = lineP;
4290     return (TRUE);
4291
4292 } /* END OF FUNCTION ParseWmFuncGrpArg */
4293
4294
4295 \f
4296 /*************************************<->*************************************
4297  *
4298  *  ParseWmFuncNbrArg (linePP, wmFunction, pNumber)
4299  *
4300  *
4301  *  Description:
4302  *  -----------
4303  *  Parses a window manager function number argument.
4304  *
4305  *
4306  *  Inputs:
4307  *  ------
4308  *  linePP   = pointer to current line buffer pointer.
4309  *  wmFunction = function 
4310  *  pNumber = pointer to number argument destination.
4311  *
4312  * 
4313  *  Outputs:
4314  *  -------
4315  *  linePP   = pointer to revised line buffer pointer.
4316  *  pNumber  = pointer to parsed number argument.
4317  *  Return   = FALSE iff invalid number argument.
4318  *
4319  *
4320  *  Comments:
4321  *  --------
4322  *  None.
4323  * 
4324  *************************************<->***********************************/
4325
4326 static Boolean ParseWmFuncNbrArg (unsigned char **linePP, 
4327                                   WmFunction wmFunction, 
4328                                   unsigned long *pNumber)
4329 {
4330     int  val;
4331
4332     val = StrToNum (GetString (linePP));
4333     if (val == -1)
4334     {
4335         PWarning (((char *)GETMESSAGE(60, 20, "Invalid number specification")));
4336         *pNumber = 0;
4337         return (FALSE);
4338     }
4339
4340     *pNumber = val;
4341     return (TRUE);
4342
4343 } /* END OF FUNCTION ParseWmFuncNbrArg */
4344
4345 \f
4346 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
4347 /*************************************<->*************************************
4348  *
4349  *  ParseWmFuncCCIArgs (linePP, wmFunction, pArgs)
4350  *
4351  *
4352  *  Description:
4353  *  -----------
4354  *  Parses a Client-Command entry's arguments.
4355  *
4356  *
4357  *  Inputs:
4358  *  ------
4359  *  linePP   = pointer to current line buffer pointer.
4360  *  wmFunction = function for which the argument string is intended.
4361  *  pArgs = pointer to argument string destination.
4362  *
4363  * 
4364  *  Outputs:
4365  *  -------
4366  *  linePP   = pointer to revised line buffer pointer.
4367  *  pArgs    = pointer to parsed argument string.
4368  *  Return   = FALSE iff insufficient memory
4369  *
4370  *
4371  *  Comments:
4372  *  --------
4373  *  None.
4374  * 
4375  *************************************<->***********************************/
4376
4377 static Boolean ParseWmFuncCCIArgs (unsigned char **linePP, 
4378                                    WmFunction wmFunction, String *pArgs)
4379 {
4380   /*
4381    * Format:
4382    *    cci_func_args:
4383    *         cci_entry
4384    *         modifier cci_entry_list
4385    *
4386    *    cci_entry_list:
4387    *         cci_entry
4388    *         cci_entry . cci_entry
4389    *
4390    *    cci_entry:
4391    *         '<' cci_label '>'
4392    *
4393    *    cci_label:
4394    *         any combination of alpha and '_'
4395    */
4396
4397   CCIEntryModifier  mod;
4398   CCIFuncArg      *cciArg;
4399   unsigned char   *string;
4400
4401
4402   cciArg = XtNew(CCIFuncArg);
4403
4404   if ((string = GetString(linePP)) == NULL)
4405     {
4406       /* Error - no data for f.cci command. cci_entry_list is required. */
4407       fprintf(stderr, "Incorrect format for f.cci command.\n");
4408       return (FALSE);
4409     }
4410   else
4411     {
4412       /* check if no modifier was specified. */
4413       if (string[0] == '<')
4414         {
4415           cciArg->mod      = NONE;
4416           cciArg->cciEntry = XtNewString((char*)string);
4417         }
4418       else
4419         {
4420           if (! GetCCIModifier((String)string, &mod))
4421             {
4422               cciArg->mod      = NONE;
4423               cciArg->cciEntry = XtNewString("");
4424             }
4425           else
4426             {
4427               cciArg->mod = mod;
4428
4429               if ((string = GetString(linePP)) == NULL)
4430                 {
4431                   /* Found a modifier, but there's no cci_entry_list. */
4432                   fprintf(stderr, "Incorrect format for f.cci command.\n");
4433                   return(FALSE);
4434                 }
4435               else
4436                 {
4437                   cciArg->cciEntry = XtNewString((char*)string);
4438                 }
4439             }
4440         }
4441
4442       *pArgs = (String)cciArg;
4443     }
4444
4445   return(TRUE);
4446 } /* END OF FUNCTION ParseWmFuncCCIArgs */
4447 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
4448
4449 \f
4450 /*************************************<->*************************************
4451  *
4452  *  ParseButtonStr ()
4453  *
4454  *
4455  *  Description:
4456  *  -----------
4457  *  This function parses a button set specification string:
4458  *
4459  *     bindings_name
4460  *     {
4461  *       button   context   function
4462  *       button   context   function
4463  *                 ...
4464  *       button   context   function
4465  *     }
4466  *
4467  *
4468  *
4469  *  Inputs:
4470  *  ------
4471  *  pSD->buttonBindings = buttonBindings resource value
4472  *  functionTable = window manager function parse table
4473  *
4474  * 
4475  *  Outputs:
4476  *  -------
4477  *  pSD->buttonSpecs = list of button binding specifications.
4478  *
4479  *
4480  *  Comments:
4481  *  --------
4482  *  The button set specification name must match pSD->buttonBindings.
4483  * 
4484  *************************************<->***********************************/
4485
4486 void ParseButtonStr (WmScreenData *pSD, unsigned char *buttonStr)
4487 {
4488     unsigned char *lineP;
4489
4490     cfileP = NULL;
4491     linec = 0;
4492     if (((parseP = buttonStr) != NULL) && (GetNextLine () != NULL))
4493     {
4494         lineP = line;
4495         ParseButtonSet (pSD, lineP);
4496     }
4497
4498 } /* END OF FUNCTION ParseButtonStr */
4499
4500 \f
4501 /*************************************<->*************************************
4502  *
4503  *  ParseButtonSet (pSD, lineP)
4504  *
4505  *
4506  *  Description:
4507  *  -----------
4508  *  Button set specification found.  Parse the following syntax:
4509  *
4510  *             v
4511  *     Buttons bindings_name
4512  *     {
4513  *       button   context   function
4514  *       button   context   function
4515  *                 ...
4516  *       button   context   function
4517  *     }
4518  *
4519  *
4520  *  Inputs:
4521  *  ------
4522  *  cfileP = (global) file pointer to fopened configuration file or NULL
4523  *  line =  (global) line buffer
4524  *  lineP = pointer to current character in line buffer
4525  *  pSD->buttonBindings = buttonBindings resource value
4526  *
4527  * 
4528  *  Outputs:
4529  *  -------
4530  *  lineP = pointer to current character in line buffer
4531  *  pSD->buttonSpecs = list of button binding specifications.
4532  *
4533  *
4534  *  Comments:
4535  *  --------
4536  *  Skips unnamed button binding set and sets with names that don't match
4537  *  the buttonBindings resource.
4538  *  Skips bad button binding specifications.
4539  * 
4540  *************************************<->***********************************/
4541
4542 static void ParseButtonSet (WmScreenData *pSD, unsigned char *lineP)
4543 {
4544     unsigned char *string;
4545     ButtonSpec    *buttonSpec;
4546     ButtonSpec    *lastButtonSpec;
4547     int            ix;
4548     
4549     /*
4550      * Parse the button set bindings from the configuration file.
4551      * If either the button set name or buttonBindings resource is NULL or 
4552      *   they don't match, then skip this button specification.
4553      */
4554
4555     if (((string = GetString (&lineP)) == NULL) ||
4556         (pSD->buttonBindings == NULL) ||
4557         strcmp ((char *)string, pSD->buttonBindings))
4558     {
4559         return;
4560     }
4561
4562     /* 
4563      * Require leading '{' on the next line.
4564      */
4565     while ((GetNextLine () != NULL))  /* not EOF nor read error */
4566     {
4567         lineP = line;
4568         ScanWhitespace(&lineP);
4569
4570         if ((lineP == NULL) || (*line == '!') || (*lineP == '\0') || (*lineP == '#'))
4571         /* ignore empty or comment line */
4572         {
4573             continue;
4574         }
4575
4576         if (*lineP == '{')
4577         /* found '{' */
4578         {
4579             break;
4580         }
4581
4582         /* not a '{' */
4583         PWarning (((char *)GETMESSAGE(60, 21, "Expected '{' after button set name")));
4584         return;
4585     }
4586
4587     /*
4588      * Found leading "{" or EOF.
4589      * Prepare to accumulate button bindings by finding the end of
4590      *   the button specification list.
4591      * lastButtonSpec will be NULL only if no prior bindings exist.
4592      */
4593
4594     lastButtonSpec = pSD->buttonSpecs;
4595     if (lastButtonSpec != NULL)
4596     {
4597         while (lastButtonSpec->nextButtonSpec != NULL)
4598         {
4599             lastButtonSpec = (lastButtonSpec->nextButtonSpec);
4600         }
4601     }
4602
4603     /*
4604      * Parse "button context function"  until "}" or EOF found.
4605      * Skips bad button binding specifications.
4606      */
4607
4608     while ((GetNextLine () != NULL))  /* not EOF nor read error */
4609     {
4610         lineP = line;
4611         ScanWhitespace(&lineP);
4612         if ((lineP == NULL) || (*line == '!') || (*lineP == '\0') || (*lineP == '#'))
4613         /* ignore empty or comment lines */
4614         {
4615             continue;
4616         }
4617         if (*lineP == '}')  /* finished with button set */
4618         {
4619             break;
4620         }
4621
4622         /*
4623          * Allocate space for the button binding specification. 
4624          */
4625         if ((buttonSpec = (ButtonSpec *)XtMalloc (sizeof (ButtonSpec))) == NULL)
4626         {
4627             PWarning (((char *)GETMESSAGE(60, 22, "Insufficient memory for button specification")));
4628             continue;
4629         }
4630         buttonSpec->wmFunction = (WmFunction)NULL;
4631         buttonSpec->wmFuncArgs = NULL;
4632         buttonSpec->nextButtonSpec = NULL;
4633
4634         /*
4635          * Parse the button specification "button".
4636          */
4637         lineP = line;
4638         if (!ParseBtnEvent(&lineP,
4639                            &buttonSpec->eventType,
4640                            &buttonSpec->button,
4641                            &buttonSpec->state,
4642                            &buttonSpec->click))
4643         {
4644             PWarning (((char *)GETMESSAGE(60, 23, "Invalid button specification")));
4645             XtFree ((char *)buttonSpec);
4646             continue;  /* skip this button specification */
4647         }
4648
4649
4650         /*
4651          * Parse the button context.
4652          */
4653         if (!ParseContext(&lineP, &buttonSpec->context, 
4654                           &buttonSpec->subContext))
4655         {
4656             PWarning (((char *)GETMESSAGE(60, 24, "Invalid button context")));
4657             XtFree ((char *)buttonSpec);
4658             continue;  /* skip this button specification */
4659         }
4660
4661         /*
4662          * Parse the button function and any arguments.
4663          */
4664
4665         ix = ParseWmFunction (&lineP, CRS_BUTTON, &buttonSpec->wmFunction);
4666
4667         /*
4668          * remove any subContexts that don't apply to this function
4669          */
4670
4671         if ((functionTable[ix].greyedContext & F_SUBCONTEXT_IB_IICON) &&
4672             (buttonSpec->subContext & F_SUBCONTEXT_IB_IICON))
4673         {
4674             buttonSpec->subContext &= ~F_SUBCONTEXT_IB_IICON;
4675         }
4676
4677         if ((functionTable[ix].greyedContext & F_SUBCONTEXT_IB_WICON) &&
4678             (buttonSpec->subContext & F_SUBCONTEXT_IB_WICON))
4679         {
4680             buttonSpec->subContext &= ~F_SUBCONTEXT_IB_WICON;
4681         }
4682
4683         /*
4684          * Map Button3 menus to BMenu virtual button
4685          */
4686         if (buttonSpec->button == Button3 && 
4687            (buttonSpec->wmFunction == F_Menu ||
4688             buttonSpec->wmFunction == F_Post_SMenu)) {
4689
4690             buttonSpec->button = wmGD.bMenuButton;
4691         }
4692
4693         /* 
4694          * Apply the function argument parser.
4695          */
4696         if (!(*(functionTable [ix].parseProc)) 
4697                    (&lineP, buttonSpec->wmFunction, &buttonSpec->wmFuncArgs))
4698         {
4699             XtFree ((char *)buttonSpec);
4700             continue;  /* skip this button specification */
4701         }
4702
4703         /* 
4704          * Add the button specification to the button specification list.
4705          */
4706         if (lastButtonSpec != NULL)
4707         /* a prior specification exists */
4708         {
4709             lastButtonSpec->nextButtonSpec = buttonSpec;
4710         }
4711         else
4712         {
4713             pSD->buttonSpecs = buttonSpec;
4714         }
4715         lastButtonSpec = buttonSpec;
4716     }
4717
4718 } /* END OF FUNCTION ParseButtonSet */
4719
4720
4721 \f
4722 /*************************************<->*************************************
4723  *
4724  *  ParseContext (linePP, context, subContext)
4725  *
4726  *
4727  *  Description:
4728  *  -----------
4729  *  Parses a general context string.
4730  *
4731  *
4732  *  Inputs:
4733  *  ------
4734  *  linePP =  pointer to current line buffer pointer.
4735  * 
4736  *  Outputs:
4737  *  -------
4738  *  linePP =  pointer to revised line buffer pointer.
4739  *  context =    context field value
4740  *  subContext = subContext field value
4741  *  Return = (Boolean) true iff valid context string
4742  *
4743  *
4744  *  Comments:
4745  *  --------
4746  *  None.
4747  * 
4748  *************************************<->***********************************/
4749
4750 static Boolean ParseContext (unsigned char **linePP, Context *context, 
4751                              Context *subContext)
4752 {
4753     unsigned char   *lineP = *linePP;
4754     unsigned char   *startP;
4755     unsigned char    ctxStr[MAX_CONTEXT_STRLEN+1];
4756     int     len;
4757
4758     /*
4759      * Parse contexts while each is followed by "|".
4760      */
4761
4762     *context = 0;
4763     *subContext = 0;
4764     while (1) {
4765
4766         /* 
4767          * Skip whitespace and find next context string.
4768          */
4769         ScanWhitespace (&lineP);
4770         startP = lineP;
4771         ScanAlphanumeric (&lineP);
4772         if (startP == lineP)
4773         /* ERROR: Context missing */
4774         {
4775            return (FALSE);
4776         }
4777
4778         /*
4779          * Found nonNULL string; compare it with valid contexts.
4780          */
4781
4782         len = min(lineP - startP, MAX_CONTEXT_STRLEN);
4783         (void) strncpy ((char *)ctxStr, (char *)startP, len);
4784         ctxStr[len] = '\0';
4785         ToLower (ctxStr);
4786
4787         if (!strcmp ("root", (char *)ctxStr))
4788         {
4789             *context |= F_CONTEXT_ROOT;
4790             *subContext |= F_SUBCONTEXT_R_ALL;
4791         }
4792         else if (!strcmp ("icon", (char *)ctxStr))
4793         {
4794             *context |= (F_CONTEXT_ICON        |
4795                          F_CONTEXT_ICONBOX     |
4796                          F_SUBCONTEXT_IB_IICON | 
4797                          F_SUBCONTEXT_IB_WICON );
4798             *subContext |= (F_SUBCONTEXT_I_ALL    | 
4799                             F_SUBCONTEXT_IB_IICON | 
4800                             F_SUBCONTEXT_IB_WICON );
4801         }
4802         else if (!strcmp ("window", (char *)ctxStr))
4803         {
4804             *context |= F_CONTEXT_WINDOW;
4805             *subContext |= F_SUBCONTEXT_W_ALL;
4806         }
4807         else if (!strcmp ("frame", (char *)ctxStr))
4808         {
4809             *context |= F_CONTEXT_WINDOW;
4810             *subContext |= F_SUBCONTEXT_W_FRAME;
4811         }
4812         else if (!strcmp ("title", (char *)ctxStr))
4813         {
4814             *context |= F_CONTEXT_WINDOW;
4815             *subContext |= F_SUBCONTEXT_W_TITLE;
4816         }
4817         else if (!strcmp ("border", (char *)ctxStr))
4818         {
4819             *context |= F_CONTEXT_WINDOW;
4820             *subContext |= F_SUBCONTEXT_W_BORDER;
4821         }
4822         else if (!strcmp ("app", (char *)ctxStr))
4823         {
4824             *context |= F_CONTEXT_WINDOW;
4825             *subContext |= F_SUBCONTEXT_W_APP;
4826         }
4827 #ifdef WSM
4828         else if (!strcmp ("ifkey", (char *)ctxStr))
4829         {
4830             *context |= F_CONTEXT_IFKEY;
4831         }
4832 #endif /* WSM */
4833         else 
4834         /* Unknown context name */
4835         {
4836            return (FALSE);
4837         }
4838
4839         /* continue only if followed by '|' */
4840         ScanWhitespace (&lineP);
4841         if (*lineP != '|')
4842         {
4843             break; 
4844         }
4845         lineP++;
4846     }
4847
4848     *linePP = lineP;
4849     return (TRUE);
4850
4851 } /* END OF FUNCTION ParseContext */
4852
4853 \f
4854 /*************************************<->*************************************
4855  *
4856  *  ParseKeyStr ()
4857  *
4858  *
4859  *  Description:
4860  *  -----------
4861  *  This function parses a key set specification string:
4862  *
4863  *     bindings_name
4864  *     {
4865  *        key   context   function
4866  *        key   context   function
4867  *                     ...
4868  *        key   context   function
4869  *     }
4870  *
4871  *
4872  *  Inputs:
4873  *  ------
4874  *  pSD->keyBindings = keyBindings resource value
4875  *  functionTable = window manager function parse table
4876  *
4877  * 
4878  *  Outputs:
4879  *  -------
4880  *  pSD->keySpecs = list of key binding specification
4881  *
4882  *
4883  *  Comments:
4884  *  --------
4885  *  The key set specification name must match pSD->keyBindings.
4886  * 
4887  *************************************<->***********************************/
4888
4889 void
4890 ParseKeyStr (WmScreenData *pSD, unsigned char *keyStr)
4891 {
4892     unsigned char *lineP;
4893
4894     cfileP = NULL;
4895     linec = 0;
4896     if (((parseP = keyStr) != NULL) && (GetNextLine () != NULL))
4897     {
4898         lineP = line;
4899         ParseKeySet (pSD, lineP);
4900     }
4901
4902 } /* END OF FUNCTION ParseKeyStr */
4903
4904
4905 \f
4906 /*************************************<->*************************************
4907  *
4908  *  ParseKeySet (pSD, lineP)
4909  *
4910  *
4911  *  Description:
4912  *  -----------
4913  *  Key set specification found.  Parse the following syntax:
4914  *
4915  *          v
4916  *     Keys bindings_name
4917  *     {
4918  *        key   context   function
4919  *        key   context   function
4920  *                     ...
4921  *        key   context   function
4922  *     }
4923  *
4924  *
4925  *  Inputs:
4926  *  ------
4927  *  cfileP = (global) file pointer to fopened configuration file or NULL
4928  *  line =  (global) line buffer
4929  *  lineP = pointer to current character in line buffer
4930  *  pSD->keyBindings = keyBindings resource value
4931  *
4932  * 
4933  *  Outputs:
4934  *  -------
4935  *  lineP = pointer to current character in line buffer
4936  *  pSD->keySpecs = list of key binding specifications.
4937  *
4938  *
4939  *  Comments:
4940  *  --------
4941  *  Skips unnamed key binding set and sets with names that don't match the 
4942  *  keyBindings resource.
4943  *  Skips bad key binding specifications.
4944  * 
4945  *************************************<->***********************************/
4946
4947 static void ParseKeySet (WmScreenData *pSD, unsigned char *lineP)
4948 {
4949     unsigned char         *string;
4950     KeySpec      *keySpec;
4951     KeySpec      *lastKeySpec;
4952     unsigned int  eventType;
4953     int           ix;
4954 #ifdef WSM
4955     Boolean     bBadKey;
4956 #endif /* WSM */
4957     
4958     /*
4959      * Parse the key set bindings from the configuration file.
4960      * If either the key set name or keyBindings resource is NULL or they
4961      *   don't match then skip this key specification.
4962      */
4963
4964     if (((string = GetString (&lineP)) == NULL) ||
4965         (pSD->keyBindings == NULL) ||
4966         strcmp ((char *)string, pSD->keyBindings))
4967     {
4968         return;
4969     }
4970
4971     /*
4972      * Require leading '{' on next line.
4973      */
4974     while ((GetNextLine () != NULL))  /* not EOF nor read error */
4975     {
4976         lineP = line;
4977         ScanWhitespace(&lineP);
4978
4979         if ((lineP == NULL) || (*line == '!') || (*lineP == '\0') || (*lineP == '#'))
4980         /* ignore empty or comment line */
4981         {
4982             continue;
4983         }
4984
4985         if (*lineP == '{')
4986         /* found '{' */
4987         {
4988             break;
4989         }
4990
4991         /* not a '{' */
4992         PWarning (((char *)GETMESSAGE(60, 25, "Expected '{' after key set name")));
4993         return;
4994     }
4995
4996     /*
4997      * Found leading "{" or EOF.
4998      * Prepare to accumulate key bindings by finding the end of
4999      *   the key specification list.
5000      * lastKeySpec will be NULL only if no prior bindings exist.
5001      */
5002
5003     lastKeySpec = pSD->keySpecs;
5004     if (lastKeySpec != NULL)
5005     {
5006         while (lastKeySpec->nextKeySpec != NULL)
5007         {
5008             lastKeySpec = (lastKeySpec->nextKeySpec);
5009         }
5010     }
5011
5012     /*
5013      * Parse "key context function"  until "}" or EOF found.
5014      * Skip bad key bindings.
5015      */
5016
5017     while ((GetNextLine () != NULL))  /* not EOF nor read error */
5018     {
5019         lineP = line;
5020         ScanWhitespace (&lineP);
5021         if ((lineP == NULL) || (*line == '!') || (*lineP == '\0') || (*lineP == '#'))
5022         /* ignore empty or comment lines */
5023         {
5024             continue;
5025         }
5026         if (*lineP == '}')  /* finished with key set */
5027         {
5028             break;
5029         }
5030
5031         /*
5032          * Allocate space for the key specification.
5033          */
5034         if ((keySpec = (KeySpec *)XtMalloc (sizeof (KeySpec))) == NULL)
5035         {
5036             PWarning (((char *)GETMESSAGE(60, 26, "Insufficient memory for key specification")));
5037             continue;
5038         }
5039
5040         keySpec->wmFunction = (WmFunction)NULL;
5041         keySpec->wmFuncArgs = NULL;
5042         keySpec->nextKeySpec = NULL;
5043
5044         /*
5045          * Parse the key specification.
5046          */
5047 #ifdef WSM
5048         bBadKey = False;
5049 #endif /* WSM */
5050         if (!ParseKeyEvent(&lineP,
5051                            &eventType,
5052                            &keySpec->keycode,
5053                            &keySpec->state))
5054         {
5055 #ifdef WSM
5056             bBadKey = True;
5057 #else /* WSM */
5058             PWarning (((char *)GETMESSAGE(60, 27, "Invalid key specification")));
5059             XtFree ((char *)keySpec);
5060             continue;  /* skip this key specification */
5061 #endif /* WSM */
5062         }
5063
5064         /*
5065          * Parse the key context.
5066          *   Here lineP points to the candidate context string.
5067          */
5068
5069         if (!ParseContext(&lineP, &keySpec->context, 
5070                           &keySpec->subContext))
5071         {
5072 #ifdef WSM
5073             if (bBadKey)
5074                 PWarning (((char *)GETMESSAGE(60, 27, "Invalid key specification")));
5075 #endif /* WSM */
5076             PWarning (((char *)GETMESSAGE(60, 28, "Invalid key context")));
5077             XtFree ((char *)keySpec);
5078             continue;  /* skip this key specification */
5079         }
5080 #ifdef WSM
5081         if (bBadKey)
5082         {
5083             /*
5084              * Don't print an error message if this is a "hardware
5085              * available" binding.
5086              */
5087             if (!(keySpec->context & F_CONTEXT_IFKEY))
5088                 PWarning (((char *)GETMESSAGE(60, 27, "Invalid key specification")));
5089             XtFree ((char *)keySpec);
5090             continue;  /* skip this key specification */
5091         }
5092
5093         /*
5094          * This flag is only used for parsing, clear it so the
5095          * rest of the program doesn't see it.
5096          */
5097         keySpec->context &= ~F_CONTEXT_IFKEY;
5098 #endif /* WSM */
5099
5100
5101         /*
5102          * Parse the key function and any arguments.
5103          */
5104
5105         ix = ParseWmFunction (&lineP, CRS_KEY, &keySpec->wmFunction);
5106         
5107         /*
5108          * remove any subContexts that don't apply to this function
5109          */
5110         if ((functionTable[ix].greyedContext & F_SUBCONTEXT_IB_IICON) &&
5111             (keySpec->subContext & F_SUBCONTEXT_IB_IICON))
5112         {
5113             keySpec->subContext &= ~F_SUBCONTEXT_IB_IICON;
5114         }
5115
5116         if ((functionTable[ix].greyedContext & F_SUBCONTEXT_IB_WICON) &&
5117             (keySpec->subContext & F_SUBCONTEXT_IB_WICON))
5118         {
5119             keySpec->subContext &= ~F_SUBCONTEXT_IB_WICON;
5120         }
5121
5122         /* 
5123          * Apply the function argument parser.
5124          */
5125         if (!(*(functionTable [ix].parseProc)) 
5126                    (&lineP, keySpec->wmFunction, &keySpec->wmFuncArgs))
5127         {
5128             XtFree ((char *)keySpec);
5129             continue;  /* skip this key specification */
5130         }
5131
5132         /* 
5133          * Add the key specification to the key specification list. 
5134          */
5135         if (lastKeySpec != NULL)
5136         /* a prior specification exists */
5137         {
5138             lastKeySpec->nextKeySpec = keySpec;
5139         }
5140         else
5141         {
5142             pSD->keySpecs = keySpec;
5143         }
5144         lastKeySpec = keySpec;
5145     }
5146
5147 } /* END OF FUNCTION ParseKeySet */
5148
5149 #ifndef WSM
5150 \f
5151 /*************************************<->*************************************
5152  *
5153  *  GetNextLine ()
5154  *
5155  *
5156  *  Description:
5157  *  -----------
5158  *  Returns the next line from an fopened configuration file or a newline-
5159  *  embedded configuration string.
5160  *
5161  *
5162  *  Inputs:
5163  *  ------
5164  *  cfileP = (global) file pointer to fopened configuration file or NULL
5165  *  line   = (global) line buffer
5166  *  linec  = (global) line count
5167  *  parseP = (global) parse string pointer if cfileP == NULL
5168  *
5169  * 
5170  *  Outputs:
5171  *  -------
5172  *  line =    (global) next line 
5173  *  linec =   (global) line count incremented
5174  *  parseP =  (global) parse string pointer incremented
5175  *  Return =  line or NULL if file or string is exhausted.
5176  *
5177  *
5178  *  Comments:
5179  *  --------
5180  *  If there are more than MAXLINE characters on a line in the file cfileP the
5181  *  excess are truncated.  
5182  *  Assumes the line buffer is long enough for any parse string line.
5183  * 
5184  *************************************<->***********************************/
5185
5186 unsigned char *
5187 GetNextLine (void)
5188 {
5189     register unsigned char      *string;
5190     int                         len;
5191
5192 #ifndef NO_MULTIBYTE
5193     int   chlen;
5194     wchar_t last;
5195     wchar_t wdelim;
5196     char delim;
5197     int lastlen;
5198 #endif
5199
5200     if (cfileP != NULL)
5201     /* read fopened file */
5202     {
5203         if ((string = (unsigned char *) 
5204                       fgets ((char *)line, MAXLINE, cfileP)) != NULL)
5205         {
5206 #ifndef NO_MULTIBYTE
5207
5208             lastlen = 0;
5209             while (*string &&
5210                    ((len = mblen((char *)string, MB_CUR_MAX)) > 0))
5211             {
5212                 mbtowc(&last, (char *)string, MB_CUR_MAX);
5213                 lastlen = len;
5214                 string += len;
5215             }
5216             delim = '\\';
5217             mbtowc(&wdelim, &delim, MB_CUR_MAX);
5218             if (lastlen == 1 && last == wdelim)
5219             {
5220                 do
5221                 {
5222                     if (!fgets((char *)string, MAXLINE - (string - line), cfileP))
5223                         break;
5224
5225                     lastlen = 0;
5226                     while (*string &&
5227                            ((len = mblen((char *)string, MB_CUR_MAX)) > 0))
5228                     {
5229                         mbtowc(&last, (char *)string, MB_CUR_MAX);
5230                         lastlen = len;
5231                         string += len;
5232                     }
5233                     linec++;
5234                 }
5235                 while (lastlen == 1 && last == wdelim);
5236             }
5237             string = line;
5238 #else
5239             len = strlen((char *)string) - 2;
5240             if ((len > 0) && string[len] == '\\')
5241             {
5242                 do {
5243                     string = &string[len];
5244                     if (fgets((char *)string, 
5245                               MAXLINE - (string-line), cfileP) == NULL)
5246                        break;
5247                     len = strlen((char *)string) - 2;
5248                     linec++;
5249                 } while ((len >= 0) && string[len] == '\\');
5250                 string = line;
5251             }
5252 #endif
5253         }
5254     }
5255     else if ((parseP != NULL) && (*parseP != '\0'))
5256     /* read parse string */
5257     {
5258         string = line;
5259 #ifndef NO_MULTIBYTE
5260         while ((*parseP != '\0') &&
5261                ((chlen = mblen ((char *)parseP, MB_CUR_MAX)) > 0) &&
5262                (*parseP != '\n'))
5263         /* copy all but NULL and newlines to line buffer */
5264         {
5265             while (chlen--)
5266             {
5267                 *(string++) = *(parseP++);
5268             }
5269         }
5270 #else
5271         while ((*parseP != '\0') && (*parseP != '\n'))
5272         /* copy all but end-of-line and newlines to line buffer */
5273         {
5274             *(string++) = *(parseP++);
5275         }
5276 #endif
5277         *string = '\0';
5278         if (*parseP == '\n')
5279         {
5280             parseP++;
5281         }
5282     }
5283     else
5284     {
5285         string = NULL;
5286     }
5287
5288     linec++;
5289     return (string);
5290
5291 } /* END OF FUNCTION GetNextLine */
5292 #endif /* WSM */
5293
5294 #ifndef PANELIST
5295 \f
5296 #ifdef WSM
5297 /*************************************<->*************************************
5298  *
5299  *  GetStringC (linePP, SmBehavior)
5300  *
5301  *
5302  *  Description:
5303  *  -----------
5304  *  Returns the next quoted or whitespace-terminated nonquoted string in the
5305  *  line buffer.
5306  *  Additional functionality added to GetString in that anything in a
5307  *  quoted string is considered sacred and nothing will be stripped from
5308  *  the middle of a quoted string.
5309  *
5310  *
5311  *  Inputs:
5312  *  ------
5313  *  linePP =  pointer to current line buffer pointer.
5314  *  SmBehavior = flag that enables parsing session manager hints
5315  *               if True.
5316  *
5317  * 
5318  *  Outputs:
5319  *  -------
5320  *  linePP =  pointer to revised line buffer pointer.
5321  *  Return =  string 
5322  *
5323  *
5324  *  Comments:
5325  *  --------
5326  *  May alter the line buffer contents.
5327  *  Handles quoted strings and characters, removing trailing whitespace from
5328  *  quoted strings.
5329  *  Returns NULL string if the line is empty or is a comment.
5330  *  Code stolen from dtmwm.
5331  * 
5332  *************************************<->***********************************/
5333 #else /* WSM */
5334 /*************************************<->*************************************
5335  *
5336  *  GetString (linePP)
5337  *
5338  *
5339  *  Description:
5340  *  -----------
5341  *  Returns the next quoted or whitespace-terminated nonquoted string in the
5342  *  line buffer.
5343  *
5344  *
5345  *  Inputs:
5346  *  ------
5347  *  linePP =  pointer to current line buffer pointer.
5348  *
5349  * 
5350  *  Outputs:
5351  *  -------
5352  *  linePP =  pointer to revised line buffer pointer.
5353  *  Return =  string 
5354  *
5355  *
5356  *  Comments:
5357  *  --------
5358  *  May alter the line buffer contents.
5359  *  Handles quoted strings and characters, removing trailing whitespace from
5360  *  quoted strings.
5361  *  Returns NULL string if the line is empty or is a comment.
5362  * 
5363  *************************************<->***********************************/
5364 #endif /* WSM */
5365
5366 #ifdef WSM
5367 unsigned char *GetStringC (unsigned char **linePP, Boolean SmBehavior)
5368 #else /* WSM */
5369 unsigned char *GetString (unsigned char **linePP)
5370 #endif /* WSM */
5371 {
5372     unsigned char *lineP = *linePP;
5373     unsigned char *endP;
5374     unsigned char *curP;
5375     unsigned char *lnwsP;
5376 #ifdef WSM
5377     unsigned int  level = 0, checkLev, i, quoteLevel[10];
5378 #endif /* WSM */
5379 #ifndef NO_MULTIBYTE
5380     int            chlen;
5381
5382     /* get rid of leading white space */
5383     ScanWhitespace (&lineP);
5384
5385     /*
5386      * Return NULL if line is empty, a comment, or invalid.
5387      */
5388 #ifdef WSM
5389     if (
5390         *lineP == '\0' ||
5391         ((chlen = mblen ((char *)lineP, MB_CUR_MAX)) < 1) ||
5392         ((chlen == 1) && ((*lineP == '!') || 
5393                           ((!SmBehavior) && (*lineP == '#'))))
5394        )
5395 #else /* WSM */
5396     if (
5397         *lineP == '\0' ||
5398         ((chlen = mblen ((char *)lineP, MB_CUR_MAX)) < 1) ||
5399         ((chlen > 0) && ((*lineP == '!') || (*lineP == '#')))
5400        )
5401 #endif /* WSM */
5402     {
5403         *linePP = lineP;
5404         return (NULL);
5405     }
5406
5407     if ((chlen == 1) && (*lineP == '"'))
5408     /* Quoted string */
5409     {
5410 #ifdef WSM
5411         quoteLevel[level] = 1;  
5412 #endif /* WSM */
5413         /*
5414          * Start beyond double quote and find the end of the quoted string.
5415          * '\' quotes the next character.
5416          * Otherwise,  matching double quote or NULL terminates the string.
5417          *
5418          * We use lnwsP to point to the last non-whitespace character in the
5419          * quoted string.  When we have found the end of the quoted string,
5420          * increment lnwsP and if lnwsP < endP, write NULL into *lnwsP.
5421          * This removes any trailing whitespace without overwriting the 
5422          * matching quote, needed later.  If the quoted string was all 
5423          * whitespace, then this will write a NULL at the beginning of the 
5424          * string that will be returned -- OK.
5425          */
5426         lnwsP = lineP++;                /* lnwsP points to first '"' */
5427         curP = endP = lineP;            /* other pointers point beyond */
5428
5429         while ((*endP = *curP) &&
5430                ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0) &&
5431                ((chlen > 1) || (*curP != '"')))
5432         /* Haven't found matching quote yet.
5433          * First byte of next character has been copied to endP.
5434          */
5435         {
5436             curP++;
5437             if ((chlen == 1) && (*endP == '\\') && 
5438                 ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0))
5439             /* character quote:
5440              * copy first byte of quoted nonNULL character down.
5441              * point curP to next byte
5442              */
5443             {
5444 #ifdef WSM
5445                 if (SmBehavior)
5446                 {
5447                     /*
5448                      * Check to see if this is a quoted quote - if it is
5449                      * strip off a level - if not - it's sacred leave it alone
5450                      */
5451                     checkLev = PeekAhead((curP - 1), quoteLevel[level]);
5452                     if(checkLev > 0)
5453                     {
5454                         if(quoteLevel[level] <= checkLev)
5455                         {
5456                             level--;
5457                         }
5458                         else
5459                         {
5460                             level++;
5461                             quoteLevel[level] = checkLev;
5462                         }
5463                         
5464                         for(i = 0;i < (checkLev - 2);i++)
5465                         {
5466                             *endP++ = *curP++;curP++;
5467                         }
5468                         *endP = *curP++;
5469                     }
5470                 }
5471                 else 
5472                 {
5473 #endif /* WSM */
5474                 *endP = *curP++;
5475 #ifdef WSM
5476                 }
5477 #endif /* WSM */
5478             }
5479
5480             if (chlen == 1)
5481             /* Singlebyte character:  character copy finished. */
5482             {
5483                 if (isspace (*endP))
5484                 /* whitespace character:  leave lnwsP unchanged. */
5485                 {
5486                     endP++;
5487                 }
5488                 else
5489                 /* non-whitespace character:  point lnwsP to it. */
5490                 {
5491                     lnwsP = endP++;
5492                 }
5493             }
5494             else if (chlen > 1)
5495             /* Multibyte (nonwhitespace) character:  point lnwsP to it.
5496              * Finish character byte copy.
5497              */
5498             {
5499                 lnwsP = endP++;
5500                 while (--chlen)
5501                 {
5502                     *endP++ = *curP++;
5503                     lnwsP++;
5504                 }
5505             }
5506         }
5507 #else
5508
5509     /* get rid of leading white space */
5510     ScanWhitespace (&lineP);
5511
5512 #ifdef WSM
5513     /* Return NULL if line is empty, whitespace, or begins with a comment. */
5514     if ((lineP == NULL || *lineP == '\0') ||
5515         (!SmBehavior && (*lineP == '#')))
5516 #else /* WSM */
5517     /* Return NULL if line is empty, whitespace, or begins with a comment. */
5518     if ((lineP == NULL) || (*lineP == '\0') || (*lineP == '#'))
5519 #endif /* WSM */
5520     {
5521         *linePP = lineP;
5522         return (NULL);
5523     }
5524
5525     if (*lineP == '"')
5526     /* Quoted string */
5527     {
5528 #ifdef WSM
5529         quoteLevel[level] = 1;  
5530 #endif /* WSM */
5531         /*
5532          * Start beyond double quote and find the end of the quoted string.
5533          * '\' quotes the next character.
5534          * Otherwise,  matching double quote or NULL terminates the string.
5535          *
5536          * We use lnwsP to point to the last non-whitespace character in the
5537          * quoted string.  When we have found the end of the quoted string,
5538          * increment lnwsP and if lnwsP < endP, write NULL into *lnwsP.
5539          * This removes any trailing whitespace without overwriting the 
5540          * matching quote, needed later.  If the quoted string was all 
5541          * whitespace, then this will write a NULL at the beginning of the 
5542          * string that will be returned -- OK.
5543          */
5544         lnwsP = lineP++;                /* lnwsP points to first '"' */
5545         curP = endP = lineP;            /* other pointers point beyond */
5546
5547         while ((*endP = *curP) && (*endP != '"'))
5548         /* haven't found matching quote yet */
5549         {
5550             /* point curP to next character */
5551             curP++;
5552             if ((*endP == '\\') && (*curP != '\0'))
5553             /* shift quoted nonNULL character down and curP ahead */
5554             {
5555 #ifdef WSM
5556                 if (SmBehavior)
5557                 {
5558                     /*
5559                      * Check to see if this is a quoted quote - if it is
5560                      * strip off a level - if not - it's sacred leave it alone
5561                      */
5562                     checkLev = PeekAhead((curP - 1), quoteLevel[level]);
5563                     if(checkLev > 0)
5564                     {
5565                         if(quoteLevel[level] <= checkLev)
5566                         {
5567                             level--;
5568                         }
5569                         else
5570                         {
5571                             level++;
5572                             quoteLevel[level] = checkLev;
5573                         }
5574                         
5575                         for(i = 0;i < (checkLev - 2);i++)
5576                         {
5577                             *endP++ = *curP++;curP++;
5578                         }
5579                         *endP = *curP++;
5580                     }
5581                 }
5582                 else 
5583                 {
5584 #endif /* WSM */
5585                 *endP = *curP++;
5586 #ifdef WSM
5587                 }
5588 #endif /* WSM */
5589             }
5590             if (isspace (*endP))
5591             /* whitespace character:  leave lnwsP unchanged. */
5592             {
5593                 endP++;
5594             }
5595             else
5596             /* non-whitespace character:  point lnwsP to it. */
5597             {
5598                 lnwsP = endP++;
5599             }
5600         }
5601 #endif
5602
5603         /*
5604          *  Found matching quote or NULL.  
5605          *  NULL out any trailing whitespace.
5606          */
5607
5608         lnwsP++;
5609         if (lnwsP < endP)
5610         {
5611             *lnwsP = '\0';
5612         }
5613     }
5614
5615     else
5616     /* Unquoted string */
5617     {
5618         /* 
5619          * Find the end of the nonquoted string.
5620          * '\' quotes the next character.
5621          * Otherwise,  whitespace, end-of-line, or '#' terminates the string.
5622          */
5623         curP = endP = lineP;
5624
5625 #ifndef NO_MULTIBYTE
5626 #ifdef WSM
5627         while ((*endP = *curP) &&
5628                ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0) &&
5629                ((chlen > 1) || (!isspace (*curP) && 
5630                                 (SmBehavior || (*curP != '#')))))
5631 #else /* WSM */
5632         while ((*endP = *curP) &&
5633                ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0) &&
5634                ((chlen > 1) || (!isspace (*curP) && (*curP != '#'))))
5635 #endif /* WSM */
5636         /* Haven't found whitespace or '#' yet.
5637          * First byte of next character has been copied to endP.
5638          */
5639         {
5640             curP++;
5641             if ((chlen == 1) && (*endP == '\\') && 
5642                 ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0))
5643             /* character quote:
5644              * copy first byte of quoted nonNULL character down.
5645              * point curP to next byte
5646              */
5647             {
5648                 *endP = *curP++;
5649             }
5650             endP++;
5651             if (chlen > 1)
5652             /* Multibyte character:  finish character copy. */
5653             {
5654                 while (--chlen)
5655                 {
5656                     *endP++ = *curP++;
5657                 }
5658             }
5659         }
5660 #else
5661 #ifdef WSM
5662         while ((*endP = *curP) && !isspace (*endP) && 
5663                                         (SmBehavior || (*endP != '#')))
5664 #else /* WSM */
5665         while ((*endP = *curP) && !isspace (*endP) && (*endP != '#'))
5666 #endif /* WSM */
5667         {
5668             /* point curP to next character */
5669             curP++;
5670             if ((*endP == '\\') && (*curP != '\0'))
5671             /* shift quoted nonNULL character down and curP ahead */
5672             {
5673                 *endP = *curP++;
5674             }
5675             endP++;
5676         }
5677 #endif
5678     }
5679
5680     /*
5681      * Three cases for *endP:
5682      *   '#' --> write NULL over # and point to NULL
5683      *   whitespace or
5684      *     matching quote -> write end-of-line over char and point beyond
5685      *   NULL -> point to NULL 
5686      */
5687
5688 #ifdef WSM
5689     if (!SmBehavior && (*endP == '#'))
5690 #else /* WSM */
5691     if (*endP == '#')
5692 #endif /* WSM */
5693     {
5694         *endP = '\0';       /* write '\0' over '#' */
5695         *linePP = endP;     /* point to '\0' */
5696     }
5697     else if (*endP != '\0')
5698     {
5699         *endP = '\0';       /* write NULL over terminator */
5700         *linePP = ++curP;   /* point beyond terminator */
5701     }
5702     else
5703     {
5704         *linePP = endP;
5705     }
5706     return ((unsigned char *)lineP);
5707
5708 } /* END OF FUNCTION GetString */
5709 #endif /* PANELIST */
5710
5711
5712 \f
5713 /*************************************<->*************************************
5714  *
5715  *  ParseBtnEvent (linePP, eventType, button, state, fClick)
5716  *
5717  *
5718  *  Description:
5719  *  -----------
5720  *  Parse a button event specification.
5721  *
5722  *
5723  *  Inputs:
5724  *  ------
5725  *  linePP =          pointer to current line buffer pointer
5726  *  buttonEvents =    (global) button event parse table
5727  *  modifierStrings = (global) modifier string/mask table
5728  *
5729  * 
5730  *  Outputs:
5731  *  -------
5732  *  linePP =    pointer to revised line buffer pointer.
5733  *  eventType = type of event
5734  *  button =    parsed button number
5735  *  state =     composite modifier mask
5736  *  fClick =    is click?
5737  *
5738  *  Return = (Boolean) true iff valid button event specification
5739  * 
5740  *
5741  *  Comments:
5742  *  --------
5743  *  None.
5744  * 
5745  *************************************<->***********************************/
5746
5747 Boolean ParseBtnEvent (unsigned char  **linePP,
5748                        unsigned int *eventType,
5749                        unsigned int *button,
5750                        unsigned int *state,
5751                        Boolean      *fClick)
5752 {
5753     if (!ParseEvent (linePP, buttonEvents, eventType, button, state, fClick))
5754     {
5755        return (FALSE);
5756     }
5757
5758     /* 
5759      * The following is a fix for an X11 deficiency in regards to 
5760      * modifiers in grabs.
5761      */
5762     if (*eventType == ButtonRelease)
5763     {
5764         /* the button that is going up will always be in the modifiers... */
5765         *state |= buttonModifierMasks[*button];
5766     }
5767
5768     return (TRUE);
5769
5770 } /* END OF FUNCTION ParseBtnEvent */
5771
5772
5773 \f
5774 /*************************************<->*************************************
5775  *
5776  *  ParseKeyEvent (linePP, eventType, keyCode, state)
5777  *
5778  *
5779  *  Description:
5780  *  -----------
5781  *  Parse a key event specification.
5782  *
5783  *
5784  *  Inputs:
5785  *  ------
5786  *  linePP =          pointer to current line buffer pointer
5787  *  keyEvents =       (global) key event parse table
5788  *  modifierStrings = (global) modifier string/mask table
5789  *
5790  * 
5791  *  Outputs:
5792  *  -------
5793  *  linePP =    pointer to revised line buffer pointer.
5794  *  eventType = type of event
5795  *  keyCode =   parsed KeyCode
5796  *  state =     composite modifier mask
5797  *
5798  *  Return = (Boolean) true iff valid key event specification
5799  * 
5800  *
5801  *  Comments:
5802  *  --------
5803  *  None.
5804  * 
5805  *************************************<->***********************************/
5806
5807 Boolean ParseKeyEvent (unsigned char **linePP, unsigned int *eventType,
5808                        KeyCode *keyCode,  unsigned int *state)
5809
5810
5811 {
5812     Boolean      fClick;
5813     unsigned int keySym = 0;
5814
5815     if (!ParseEvent (linePP, keyEvents, eventType, &keySym, state, &fClick))
5816     {
5817        return (FALSE);
5818     }
5819
5820     /* 
5821      * Here keySym is a KeySym.  Convert it to a KeyCode.
5822      * KeyCode will be set to 0 if keySym is not defined for any KeyCode
5823      *  (e.g. 0x001).
5824      */
5825
5826     *keyCode = XKeysymToKeycode(DISPLAY, (KeySym) keySym);
5827
5828     if (*keyCode == 0)
5829     {
5830         if (keySym == XK_F9)
5831         {
5832             keySym = XK_KP_F1;
5833         }
5834         else if (keySym == XK_F10)
5835         {
5836             keySym = XK_KP_F2;
5837         }
5838         else if (keySym == XK_F11)
5839         {
5840             keySym = XK_KP_F3;
5841         }
5842         else if (keySym == XK_F12)
5843         {
5844             keySym = XK_KP_F4;
5845         }
5846         *keyCode = XKeysymToKeycode(DISPLAY, (KeySym) keySym);
5847     }
5848
5849     return (*keyCode != 0);
5850
5851 } /* END OF FUNCTION ParseKeyEvent */
5852
5853 \f
5854 /*************************************<->*************************************
5855  *
5856  *  ParseEvent (linePP, table, eventType, detail, state, fClick)
5857  *
5858  *
5859  *  Description:
5860  *  -----------
5861  *  Parse an event specification.
5862  *
5863  *
5864  *  Inputs:
5865  *  ------
5866  *  linePP =          pointer to current line buffer pointer.
5867  *  table =           event parse table
5868  *  modifierStrings = (global) modifier string/mask table
5869  *
5870  * 
5871  *  Outputs:
5872  *  -------
5873  *  linePP =    pointer to revised line buffer pointer.
5874  *  eventType = type of event
5875  *  detail =    dependent upon parse table detail procedure and closure
5876  *  state =     composite modifier mask
5877  *  fClick =    click flag
5878  *
5879  *  Return = (Boolean) true iff valid event specification
5880  *
5881  *  Comments:
5882  *  --------
5883  *  None.
5884  * 
5885  *************************************<->***********************************/
5886
5887 static Boolean ParseEvent (unsigned char **linePP, EventTableEntry *table,
5888                            unsigned int *eventType, unsigned int *detail,
5889                            unsigned int *state, Boolean *fClick)
5890 {
5891     unsigned char    *lineP = *linePP;
5892     Cardinal ix;
5893     Boolean  status;
5894  
5895     /* Parse the modifiers */
5896     if (!ParseModifiers (&lineP, state) || *lineP != '<')
5897     {
5898        return (FALSE);
5899     }
5900     lineP++;  /* skip '<' */
5901
5902     /* Parse the event type */
5903     if (!ParseEventType (&lineP, table, eventType, &ix) || *lineP != '>') 
5904     {
5905        return (FALSE);
5906     }
5907     lineP++;  /* skip '>' */
5908
5909     /*
5910      *  Compute detail and fClick.
5911      *  Status will be False for a invalid KeySym name.
5912      */
5913     status = (*(table[ix].parseProc))(&lineP, table[ix].closure, detail);
5914     *fClick = table[ix].fClick;
5915
5916     if (status)
5917     {
5918         *linePP = lineP;
5919     }
5920     return (status);
5921
5922 } /* END OF FUNCTION ParseEvent */
5923
5924
5925 \f
5926 /*************************************<->*************************************
5927  *
5928  *  ParseModifiers(linePP, state)
5929  *
5930  *
5931  *  Description:
5932  *  -----------
5933  *  Parses a modifier specification.
5934  *
5935  *
5936  *  Inputs:
5937  *  ------
5938  *  linePP = pointer to current line buffer pointer.
5939  *  modifierStrings = (global) modifier string/mask table
5940  *
5941  * 
5942  *  Outputs:
5943  *  -------
5944  *  linePP =    pointer to revised line buffer pointer.
5945  *  state  = composite modifier mask
5946  *  Return = (Boolean) true iff valid modifier name
5947  *
5948  *
5949  *  Comments:
5950  *  --------
5951  *  If successful, will be followed by NULL or '<'.
5952  * 
5953  *************************************<->***********************************/
5954
5955 static Boolean ParseModifiers(unsigned char **linePP, unsigned int *state)
5956 {
5957     unsigned char         *lineP = *linePP;
5958     unsigned char         *startP;
5959     unsigned char          modStr[MAX_MODIFIER_STRLEN+1];
5960     Boolean       fNot;
5961     unsigned int  maskBit;
5962     int           len;
5963
5964     *state = 0;
5965  
5966     /*
5967      * Parse modifiers until the event specifier is encountered.
5968      */
5969
5970     ScanWhitespace (&lineP);
5971     while ((*lineP != '\0') && (*lineP != '<'))
5972     {
5973         if (*lineP == '~') 
5974         {
5975             fNot = TRUE;
5976             lineP++;
5977         }
5978         else 
5979         {
5980             fNot = FALSE;
5981         }
5982
5983         startP = lineP;
5984         ScanAlphanumeric (&lineP);
5985         if (startP == lineP)
5986         /* ERROR: Modifier or '<' missing */
5987         {
5988             return (FALSE);
5989         }
5990         len = min(lineP - startP, MAX_MODIFIER_STRLEN);
5991         (void) strncpy ((char *)modStr, (char *)startP, len);
5992         modStr[len] = '\0';
5993
5994         if (!LookupModifier (modStr, &maskBit))
5995         /* Unknown modifier name */
5996         {
5997             return (FALSE);
5998         }
5999
6000         if (fNot) 
6001         {
6002             *state &= ~maskBit;
6003         }
6004         else 
6005         {
6006             *state |= maskBit;
6007         }
6008         ScanWhitespace(&lineP);
6009     }
6010
6011     *linePP = lineP;
6012     return (TRUE);  /* must have '<' or NULL following */
6013
6014 } /* END OF FUNCTION ParseModifiers */
6015
6016 \f
6017 /*************************************<->*************************************
6018  *
6019  *  LookupModifier (name, valueP)
6020  *
6021  *
6022  *  Description:
6023  *  -----------
6024  *  Return the modifier mask for the provided modifier name.
6025  *
6026  *
6027  *  Inputs:
6028  *  ------
6029  *  name = modifier string
6030  *  modifierStrings = modifier string/mask table
6031  *
6032  * 
6033  *  Outputs:
6034  *  -------
6035  *  valueP = modifier mask
6036  *  Return = (Boolean) true iff valid modifier name
6037  *
6038  *
6039  *  Comments:
6040  *  --------
6041  *  None.
6042  * 
6043  *************************************<->***********************************/
6044
6045 static Boolean LookupModifier (unsigned char *name, unsigned int *valueP)
6046 {
6047     register int i;
6048
6049     if (name != NULL)
6050     {
6051         ToLower (name);
6052         for (i=0; modifierStrings[i].name != NULL; i++)
6053         {
6054             if (!strcmp (modifierStrings[i].name, (char *)name))
6055             {
6056                 *valueP = modifierStrings[i].mask;
6057                 return (TRUE);
6058             }
6059         }
6060     }
6061
6062     return (FALSE);
6063
6064 } /* END OF FUNCTION LookupModifier */
6065
6066 \f
6067 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
6068 /*************************************<->*************************************
6069  *
6070  *  GetCCIModifier (modString, mod)
6071  *
6072  *
6073  *  Description:
6074  *  -----------
6075  *  Return the cci modifier corresponding to the specified string
6076  *
6077  *
6078  *  Inputs:
6079  *  ------
6080  *  modString = cci modifier string; may be null
6081  *
6082  * 
6083  *  Outputs:
6084  *  -------
6085  *  mod    = cci modifier.
6086  *  Return = (Boolean) true iff valid modifier string
6087  *
6088  *
6089  *  Comments:
6090  *  --------
6091  *  None.
6092  * 
6093  *************************************<->***********************************/
6094
6095 static Boolean GetCCIModifier (String modString, CCIEntryModifier *mod)
6096 {
6097   CCIEntryModifier i;
6098
6099
6100   if (modString != NULL)
6101     {
6102       ToLower ((unsigned char *)modString);
6103       for (i=NONE; i<=EXCLUDE; i++)
6104         {
6105           if (!strcmp (CCIEntryModifierNames[i], modString))
6106             {
6107               *mod = i;
6108               return (TRUE);
6109             }
6110         }
6111     }
6112
6113     return (FALSE);
6114
6115 } /* END OF FUNCTION GetCCIModifier */
6116
6117 \f
6118 /*************************************<->*************************************
6119  *
6120  *  FixMenuItem (menuSpec, menuItem)
6121  *
6122  *
6123  *  Description:
6124  *  -----------
6125  *  Fix-up the menuItem so that it appears an old-style cci command was
6126  *  read from the .mwmrc file
6127  *
6128  *
6129  *  Inputs:
6130  *  ------
6131  *  menuItem = the menu item structure
6132  *  menuSpec = the menu specification structure
6133  *
6134  * 
6135  *  Outputs:
6136  *  -------
6137  *  menuItem = the fixed-up menuitem
6138  *  menuSpec = the fixed-up menu specification structure if EXCLUDE found
6139  *  Return   = nothing
6140  *
6141  *  Comments:
6142  *  --------
6143  *
6144  *************************************<->***********************************/
6145
6146 static void FixMenuItem (MenuSpec *menuSpec, MenuItem *menuItem)
6147 {
6148   String      tmp;
6149   CCIFuncArg *cciArg;
6150   
6151
6152   if (menuItem == NULL)
6153     return;
6154
6155   cciArg = (CCIFuncArg *)menuItem->wmFuncArgs;
6156
6157   menuItem->clientCommandName = menuItem->label;
6158   menuItem->label = cciArg->cciEntry;
6159
6160   /*
6161    * Fix-up the label to handle the modifier.
6162    */
6163
6164   switch (cciArg->mod)
6165     {
6166     case NONE:
6167       break;
6168
6169     case INLINE:
6170       break;
6171
6172     case CASCADE:
6173       /* -> */
6174       tmp = (String) XtMalloc(strlen(menuItem->label) + 3);
6175       sprintf(tmp, "->%s", menuItem->label);
6176       XtFree(menuItem->label);
6177       menuItem->label = tmp;
6178       break;
6179
6180     case DELIMIT:
6181       /* = */
6182       tmp = (String) XtMalloc(strlen(menuItem->label) + 2);
6183       sprintf(tmp, "=%s", menuItem->label);
6184       XtFree(menuItem->label);
6185       menuItem->label = tmp;
6186       break;
6187
6188     case DELIMIT_INLINE:
6189       break;
6190
6191     case DELIMIT_CASCADE:
6192       /* => */
6193       tmp = (String) XtMalloc(strlen(menuItem->label) + 3);
6194       sprintf(tmp, "=>%s", menuItem->label);
6195       XtFree(menuItem->label);
6196       menuItem->label = tmp;
6197       break;
6198
6199     case EXCLUDE:
6200       /* ~ */
6201       StoreExclusion(menuSpec, menuItem->label);
6202
6203       tmp = (String) XtMalloc(strlen(menuItem->label) + 2);
6204       sprintf(tmp, "~%s", menuItem->label);
6205       XtFree(menuItem->label);
6206       menuItem->label = tmp;
6207       break;
6208     }
6209 }
6210 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
6211
6212 \f
6213 /*************************************<->*************************************
6214  *
6215  *  ParseEventType(linePP, table, eventType, ix)
6216  *
6217  *
6218  *  Description:
6219  *  -----------
6220  *  Parses the event type string.
6221  *
6222  *
6223  *  Inputs:
6224  *  ------
6225  *  linePP = pointer to current line buffer pointer.
6226  *  table =  event parse table
6227  *
6228  * 
6229  *  Outputs:
6230  *  -------
6231  *  linePP = pointer to revised line buffer pointer.
6232  *  eventType = type of event
6233  *  ix = table index for matched event
6234  *
6235  *  Return = (Boolean) true iff valid event
6236  *
6237  *
6238  *  Comments:
6239  *  --------
6240  *  None.
6241  * 
6242  *************************************<->***********************************/
6243
6244 static Boolean ParseEventType (unsigned char **linePP, EventTableEntry *table,
6245                                unsigned int *eventType, Cardinal *ix)
6246 {
6247     unsigned char *lineP = *linePP;
6248     unsigned char *startP = *linePP;
6249     unsigned char eventTypeStr[MAX_EVENTTYPE_STRLEN+1];
6250     register int  len;
6251
6252     /* Parse out the event string */
6253     ScanAlphanumeric (&lineP);
6254
6255     /*
6256      * Attempt to match the parsed event against our supported event set.
6257      */
6258
6259     if (startP != lineP)
6260     {
6261         len = min (lineP - startP, MAX_EVENTTYPE_STRLEN);
6262         (void) strncpy ((char *)eventTypeStr, (char *)startP, len);
6263         eventTypeStr[len] = '\0';
6264         ToLower (eventTypeStr);
6265
6266         for (len = 0; table[len].event != NULL; len++)
6267             if (!strcmp (table[len].event, (char *)eventTypeStr))
6268             {
6269                *ix = len;
6270                *eventType = table[*ix].eventType;
6271                *linePP = lineP;
6272                return (TRUE); 
6273             }
6274     }
6275
6276     /* Unknown event specified */
6277     return (FALSE);
6278
6279 } /* END OF FUNCTION ParseEventType */
6280
6281 \f
6282 /*************************************<->*************************************
6283  *
6284  *  ParseImmed (linePP, closure, detail)
6285  *
6286  *
6287  *  Description:
6288  *  -----------
6289  *  Button event detail procedure.
6290  *
6291  *
6292  *  Inputs:
6293  *  ------
6294  *  linePP =  not used
6295  *  closure = table entry
6296  *
6297  * 
6298  *  Outputs:
6299  *  -------
6300  *  detail = pointer to closure
6301  *
6302  *  Return = TRUE
6303  *
6304  *
6305  *  Comments:
6306  *  --------
6307  *  None.
6308  * 
6309  *************************************<->***********************************/
6310
6311 static Boolean ParseImmed (unsigned char **linePP, unsigned int closure,
6312                            unsigned int  *detail)
6313 {
6314     *detail = closure;
6315     return (TRUE);
6316
6317 } /* END OF FUNCTION ParseImmed */
6318
6319 \f
6320 /*************************************<->*************************************
6321  *
6322  *  ParseKeySym (linePP, closure, detail)
6323  *
6324  *
6325  *  Description:
6326  *  -----------
6327  *  Key event detail procedure.  Parses a KeySym string.
6328  *
6329  *
6330  *  Inputs:
6331  *  ------
6332  *  linePP = pointer to current line buffer pointer
6333  *
6334  *  closure = not used.
6335  *
6336  * 
6337  *  Outputs:
6338  *  -------
6339  *  linePP = pointer to revised line buffer pointer
6340  *  detail = pointer to parsed KeySym
6341  *
6342  *  Return = (Boolean) true iff valid KeySym string
6343  *
6344  *
6345  *  Comments:
6346  *  --------
6347  *  None.
6348  * 
6349  *************************************<->***********************************/
6350
6351 static Boolean ParseKeySym (unsigned char **linePP, unsigned int closure,
6352                             unsigned int *detail)
6353 {
6354     unsigned char *lineP = *linePP;
6355     unsigned char *startP;
6356     char           keySymName[MAX_KEYSYM_STRLEN+1];
6357     int            len;
6358 #ifndef NO_MULTIBYTE
6359     int            chlen;
6360 #endif
6361
6362     ScanWhitespace (&lineP);
6363     startP = lineP;
6364
6365 #ifndef NO_MULTIBYTE
6366     while (*lineP &&
6367            ((chlen = mblen ((char *)lineP, MB_CUR_MAX)) > 0) &&
6368            ((chlen > 1) ||
6369            (!isspace (*lineP) && *lineP != ',' && *lineP != ':')))
6370     {
6371         /* Skip next character */
6372         lineP += chlen;
6373     }
6374 #else
6375     while (*lineP && !isspace (*lineP) && *lineP != ',' && *lineP != ':' )
6376     {
6377         /* Skip next character */
6378         lineP++;
6379     }
6380 #endif
6381
6382     len = min (lineP - startP, MAX_KEYSYM_STRLEN);
6383     (void) strncpy (keySymName, (char *)startP, len);
6384     keySymName[len] = '\0';
6385
6386 #ifndef NO_MULTIBYTE
6387     if ((*detail = XStringToKeysym(keySymName)) == NoSymbol &&
6388          (mblen (keySymName, MB_CUR_MAX) == 1))
6389 #else
6390     if ((*detail = XStringToKeysym(keySymName)) == NoSymbol)
6391 #endif
6392     {
6393         if (!isdigit (keySymName[0]) ||
6394             ((*detail = StrToNum ((unsigned char *)&keySymName[0])) == -1))
6395         {
6396             *detail = NoSymbol;
6397             return (FALSE);
6398         }
6399     }
6400     *linePP = lineP;
6401     return (TRUE);
6402
6403 } /* END OF FUNCTION ParseKeySym */
6404
6405
6406 \f
6407 /*************************************<->*************************************
6408  *
6409  *  StrToNum(str)
6410  *
6411  *
6412  *  Description:
6413  *  -----------
6414  *  Converts a string to an unsigned hexadecimal, decimal, or octal integer.
6415  *
6416  *
6417  *  Inputs:
6418  *  ------
6419  *  str = character string
6420  *
6421  * 
6422  *  Outputs:
6423  *  -------
6424  *  Return = unsigned integer 
6425  *
6426  *
6427  *  Comments:
6428  *  --------
6429  *  None.
6430  * 
6431  *************************************<->***********************************/
6432
6433 static unsigned int StrToNum(unsigned char *str)
6434 {
6435     unsigned char c;
6436     unsigned int  val = 0;
6437
6438     if (*str == '0')
6439     {
6440         str++;
6441         if (*str == 'x' || *str == 'X')
6442         {
6443             return (StrToHex(++str));
6444         }
6445         return (StrToOct(str));
6446     }
6447
6448     while ((c = *str) != '\0')
6449     {
6450         if ('0' <= c && c <= '9')
6451         {
6452             val = val*10+c-'0';
6453         }
6454         else
6455         {
6456             return (-1);
6457         }
6458         str++;
6459     }
6460
6461     return (val);
6462
6463 } /* END OF FUNCTION StrToNum */
6464
6465
6466 \f
6467 /*************************************<->*************************************
6468  *
6469
6470  *
6471  *
6472  *  Description:
6473  *  -----------
6474  *
6475  *  Inputs:
6476  *  ------
6477  *
6478  * 
6479  *  Outputs:
6480  *  -------
6481  *
6482  *  Comments:
6483  *  --------
6484  *  None.
6485  * 
6486  *************************************<->***********************************/
6487
6488 static unsigned int StrToHex(unsigned char *str)
6489 {
6490     unsigned char c;
6491     unsigned int  val = 0;
6492
6493     while ((c = *str) != '\0')
6494     {
6495         if ('0' <= c && c <= '9')
6496         {
6497             val = val*16+c-'0';
6498         }
6499         else if ('a' <= c && c <= 'f')
6500         {
6501             val = val*16+c-'a'+10;
6502         }
6503         else if ('A' <= c && c <= 'F')
6504         {
6505             val = val*16+c-'A'+10;
6506         }
6507         else
6508         {
6509             return (-1);
6510         }
6511         str++;
6512     }
6513
6514     return (val);
6515
6516 } /* END OF FUNCTION StrToHex */
6517
6518
6519 \f
6520 /*************************************<->*************************************
6521  *
6522
6523  *
6524  *
6525  *  Description:
6526  *  -----------
6527  *
6528  *  Inputs:
6529  *  ------
6530  *
6531  * 
6532  *  Outputs:
6533  *  -------
6534  *
6535  *  Comments:
6536  *  --------
6537  *  None.
6538  * 
6539  *************************************<->***********************************/
6540
6541 static unsigned int StrToOct(unsigned char *str)
6542 {
6543     unsigned char c;
6544     unsigned int  val = 0;
6545
6546     while ((c = *str) != '\0')
6547     {
6548         if ('0' <= c && c <= '7')
6549         {
6550             val = val*8+c-'0';
6551         }
6552         else
6553         {
6554             return (-1);
6555         }
6556         str++;
6557     }
6558
6559     return (val);
6560
6561 } /* END OF FUNCTION StrToOct */
6562
6563
6564 \f
6565 /*************************************<->*************************************
6566  *
6567  *  ScanAlphanumeric (linePP)
6568  *
6569  *
6570  *  Description:
6571  *  -----------
6572  *  Scan string until a non-alphanumeric character is encountered.
6573  *
6574  *
6575  *  Inputs:
6576  *  ------
6577  *  linePP = nonNULL pointer to current line buffer pointer
6578  *
6579  * 
6580  *  Outputs:
6581  *  -------
6582  *  linePP = nonNULL pointer to revised line buffer pointer
6583  *
6584  *
6585  *  Comments:
6586  *  --------
6587  *  Assumes linePP is nonNULL
6588  * 
6589  *************************************<->***********************************/
6590
6591 void ScanAlphanumeric (unsigned char **linePP)
6592 {
6593 #ifndef NO_MULTIBYTE
6594     int            chlen;
6595
6596     while (*linePP &&
6597            ((chlen = mblen ((char *) *linePP, MB_CUR_MAX)) > 0) &&
6598            ((chlen > 1) || isalnum (**linePP)))
6599     {
6600         (*linePP) += chlen;
6601     }
6602 #else
6603     while (*linePP && isalnum (**linePP))
6604     {
6605         (*linePP)++;
6606     }
6607 #endif
6608
6609 } /* END OF FUNCTION ScanAlphanumeric */
6610
6611
6612 #ifndef WSM
6613 \f
6614 /*************************************<->*************************************
6615  *
6616  *  ScanWhitespace(linePP)
6617  *
6618  *
6619  *  Description:
6620  *  -----------
6621  *  Scan the string, skipping over all white space characters.
6622  *
6623  *
6624  *  Inputs:
6625  *  ------
6626  *  linePP = nonNULL pointer to current line buffer pointer
6627  *
6628  * 
6629  *  Outputs:
6630  *  -------
6631  *  linePP = nonNULL pointer to revised line buffer pointer
6632  *
6633  *
6634  *  Comments:
6635  *  --------
6636  *  Assumes linePP is nonNULL
6637  * 
6638  *************************************<->***********************************/
6639
6640 void ScanWhitespace(unsigned char  **linePP)
6641 {
6642 #ifndef NO_MULTIBYTE
6643     while (*linePP && (mblen ((char *)*linePP, MB_CUR_MAX) == 1) && isspace (**linePP))
6644 #else
6645     while (*linePP && isspace (**linePP))
6646 #endif
6647     {
6648         (*linePP)++;
6649     }
6650
6651 } /* END OF FUNCTION ScanWhitespace */
6652 #endif /* not WSM */
6653
6654 #ifndef WSM
6655 \f
6656 /*************************************<->*************************************
6657  *
6658  *  ToLower (string)
6659  *
6660  *
6661  *  Description:
6662  *  -----------
6663  *  Lower all characters in a string.
6664  *
6665  *
6666  *  Inputs:
6667  *  ------
6668  *  string = NULL-terminated character string or NULL
6669  *
6670  * 
6671  *  Outputs:
6672  *  -------
6673  *  string = NULL-terminated lower case character string or NULL
6674  *
6675  *
6676  *  Comments:
6677  *  --------
6678  *  None.
6679  * 
6680  *************************************<->***********************************/
6681
6682 void ToLower (unsigned char  *string)
6683 {
6684     unsigned char *pch = string;
6685 #ifndef NO_MULTIBYTE
6686     int            chlen;
6687
6688     while (*pch && ((chlen = mblen ((char *)pch, MB_CUR_MAX)) > 0))
6689     {
6690         if ((chlen == 1) && (isupper (*pch)))
6691         {
6692             *pch = tolower(*pch);
6693         }
6694         pch += chlen;
6695     }
6696 #else
6697     while (*pch != '\0')
6698     {
6699         if (isupper (*pch))
6700         {
6701             *pch = tolower(*pch);
6702         }
6703         pch++;
6704     }
6705 #endif
6706
6707 } /* END OF FUNCTION ToLower */
6708 #endif  /* WSM */
6709
6710 \f
6711 /*************************************<->*************************************
6712  *
6713  *  PWarning (message)
6714  *
6715  *
6716  *  Description:
6717  *  -----------
6718  *  This function lists a resource description parse message to stderr.
6719  *
6720  *
6721  *  Inputs:
6722  *  ------
6723  *  message = pointer to a message string
6724  *  cfileP  = (global) file pointer to fopened configuration file or NULL
6725  *  linec   = (global) line counter
6726  * 
6727  *************************************<->***********************************/
6728
6729 void
6730 PWarning (char *message)
6731 {
6732
6733 #ifdef WSM
6734     char pch[MAXWMPATH+1];
6735     String sMessage;
6736     char *pchFile;
6737
6738     sMessage = XtNewString ((String) message);
6739     if (cfileP != NULL)
6740     {
6741         if (pConfigStackTop->fileName)
6742         {
6743             pchFile = pConfigStackTop->fileName;
6744         }
6745         else 
6746         {
6747             pchFile = wmGD.configFile;
6748         }
6749
6750         sprintf (pch, pWarningStringFile,
6751                      GETMESSAGE(20,1,"Workspace Manager"), 
6752                      sMessage, linec, pchFile);
6753     }
6754     else
6755     {
6756         sprintf (pch, pWarningStringLine,
6757                      GETMESSAGE(20,1,"Workspace Manager"), 
6758                      sMessage, linec);
6759     }
6760     _DtSimpleError (wmGD.mwmName, DtIgnore, NULL, pch, NULL);
6761     XtFree (sMessage);
6762 #else /* WSM */
6763     if (cfileP != NULL)
6764     {
6765         fprintf (stderr, ((char *)GETMESSAGE(60, 33, "%s: %s on line %d of configuration file %s\n")),
6766                  wmGD.mwmName, message, linec,
6767                  wmGD.configFile ? wmGD.configFile : cfileName);
6768     }
6769     else
6770     {
6771         fprintf (stderr, ((char *)GETMESSAGE(60, 34, "%s: %s on line %d of specification string\n")),
6772                      wmGD.mwmName, message, linec);
6773     }
6774     fflush (stderr);
6775 #endif /* WSM */
6776
6777
6778 } /* END OF FUNCTION PWarning */
6779
6780 #ifdef WSM
6781 /*
6782  * Key substitution table entry
6783  */
6784
6785 typedef struct _keySubs
6786 {
6787     unsigned char *     pchFrom;
6788     int                 lenFrom;
6789     unsigned char *     pchTo;
6790 } KeySub;
6791
6792 \f
6793 /*************************************<->*************************************
6794  *
6795  *  InitKeySubs (ppKeySubs, pNumKeySubs)
6796  *
6797  *
6798  *  Description:
6799  *  -----------
6800  *  Initialize key label substitutions used in acclerator text
6801  *
6802  *
6803  *  Inputs:
6804  *  ------
6805  *  ppKeySubs   = ptr to key substitution table ptr
6806  *  pNumKeySubs = ptr to number of key substitutions
6807  *
6808  * 
6809  *  Outputs:
6810  *  -------
6811  *  *ppKeySubs          = ptr to key substitution table 
6812  *  *pNumKeySubs        = number of substitutions found
6813  *
6814  *  Comments:
6815  *  --------
6816  *  *ppKeySubs is allocated with XtMalloc in a complicated way.
6817  *  If this ever needs to be freed, a function to free it needs to
6818  *  be written.
6819  * 
6820  *************************************<->***********************************/
6821
6822 static void InitKeySubs (
6823     KeySub      **ppKeySubs,
6824     int         *pNumKeySubs)
6825 {
6826     int numKS;
6827     KeySub *pKS;
6828     KeySub *pKSret;
6829     unsigned char *pch0;
6830     unsigned char *pch1;
6831     int len;
6832 #ifndef NO_MULTIBYTE
6833     int         chlen;
6834 #endif 
6835
6836     pch0 = (unsigned char *)GETMESSAGE(60, 40, "");
6837
6838     if ((pch0 == NULL) || (*pch0 == '\0'))
6839     {
6840         *ppKeySubs = NULL;
6841         *pNumKeySubs = 0;
6842         return;
6843     }
6844
6845     pKSret = NULL;
6846     numKS = 0;
6847
6848     while (*pch0 != '\0')
6849     {
6850         ScanWhitespace (&pch0);
6851         if (*pch0 == '\0') break;
6852
6853         /* 
6854          * allocate space for next key sub 
6855          */
6856         if (pKSret == NULL)
6857         {
6858             pKSret = (KeySub *) XtMalloc (1*sizeof(KeySub));
6859         }
6860         else
6861         {
6862             pKSret = (KeySub *) XtRealloc ((char *)pKSret, 
6863                                            (numKS+1)*sizeof(KeySub));
6864         }
6865         pKS = &pKSret[numKS];
6866
6867         /* get "from" string */
6868         pch1 = pch0;
6869 #ifndef NO_MULTIBYTE
6870         while (*pch1 && ((chlen = mblen ((char *)pch1, MB_CUR_MAX)) > 0))
6871         {
6872             if ((chlen == 1) && (*pch1 == ' '))
6873             {
6874                 break;
6875             }
6876             pch1 += chlen;
6877         }
6878 #else /* NO_MULTIBYTE */
6879         while (*pch1 && (*pch1 != ' ')) pch1++;
6880 #endif /* NO_MULTIBYTE */
6881         pKS->lenFrom = pch1 - pch0;
6882         if (pKS->lenFrom < 1) 
6883         {
6884             /*
6885              * no "from" string
6886              */
6887             break;
6888         }
6889         pKS->pchFrom = (unsigned char *) XtMalloc (1+pKS->lenFrom);
6890         memcpy (pKS->pchFrom, pch0, pKS->lenFrom);
6891         pKS->pchFrom[pKS->lenFrom] = '\0';
6892
6893         /* get "to" string */
6894         ScanWhitespace (&pch1);
6895         pch0 = pch1;
6896
6897 #ifndef NO_MULTIBYTE
6898         while (*pch1 && ((chlen = mblen ((char *)pch1, MB_CUR_MAX)) > 0))
6899         {
6900             if ((chlen == 1) && (*pch1 == ' '))
6901             {
6902                 break;
6903             }
6904             pch1 += chlen;
6905         }
6906 #else /* NO_MULTIBYTE */
6907         while (*pch1 && (*pch1 != ' ')) pch1++;
6908 #endif /* NO_MULTIBYTE */
6909
6910         len = pch1 - pch0;
6911         if (len < 1)
6912         {
6913             /*
6914              * Invalid format, "from" string with no "to" string.
6915              */
6916             break;
6917         }
6918         pKS->pchTo = (unsigned char *) XtMalloc (1+len);
6919         memcpy (pKS->pchTo, pch0, len);
6920         pKS->pchTo[len] = '\0';
6921
6922         /* advance cursor */
6923         pch0 = pch1;
6924
6925         /* got one, bump the counter */
6926         numKS++; 
6927     }
6928
6929     *ppKeySubs = pKSret;
6930     *pNumKeySubs = numKS;
6931 }
6932
6933 #endif /* WSM */
6934 \f
6935 /*************************************<->*************************************
6936  *
6937  *  ProcessAccelText (startP, endP, destP)
6938  *
6939  *
6940  *  Description:
6941  *  -----------
6942  *  Process accelerator text and copy into string.
6943  *
6944  *
6945  *  Inputs:
6946  *  ------
6947  *  startP = pointer to start of valid accelerator specification
6948  *  endP =   pointer past end of accelerator specification
6949  *  destP =  pointer to destination buffer
6950  *
6951  * 
6952  *  Outputs:
6953  *  -------
6954  *  Destination buffer has processed accelerator text.
6955  *
6956  *  Comments:
6957  *  --------
6958  *  None.
6959  * 
6960  *************************************<->***********************************/
6961
6962 static void ProcessAccelText (unsigned char *startP, unsigned char *endP,
6963                               unsigned char *destP)
6964 {
6965 #ifndef NO_MULTIBYTE
6966     int   chlen;
6967 #endif
6968 #ifdef WSM
6969     static Boolean      bAccelInit = False;
6970     static KeySub       *pKeySub;
6971     static int          numKeySubs;
6972     unsigned char *     pchFirst;
6973     unsigned char *     pchSub;
6974     int                 lenSub;
6975     int                 i;
6976
6977     if (!bAccelInit)
6978     {
6979         InitKeySubs (&pKeySub, &numKeySubs);
6980         bAccelInit = True;
6981     }
6982 #endif /* WSM */
6983
6984     /*
6985      * Copy modifiers
6986      */
6987
6988     ScanWhitespace (&startP);
6989
6990     while (*startP != '<')
6991     {
6992         if (*startP == '~') 
6993         {
6994             *destP++ = *startP++;
6995         }
6996 #ifdef WSM
6997         pchFirst = startP;
6998 #endif /* WSM */
6999
7000 #ifndef NO_MULTIBYTE
7001         while (*startP &&
7002                (((chlen = mblen ((char *)startP, MB_CUR_MAX)) > 1)
7003                 || isalnum (*startP)))
7004         {
7005             while (chlen--)
7006             {
7007 #ifdef WSM
7008                 startP++;
7009
7010 #else /* WSM */
7011                 *destP++ = *startP++;
7012 #endif /* WSM */
7013             }
7014         }
7015 #else
7016         while (isalnum (*startP))
7017         {
7018 #ifdef WSM
7019                 startP++;
7020 #else /* WSM */
7021             *destP++ = *startP++;
7022 #endif /* WSM */
7023         }
7024 #endif
7025 #ifdef WSM
7026         /* find substitution */
7027         pchSub = NULL;
7028         lenSub = 0;
7029
7030         for (i=0; i<numKeySubs; i++)
7031         {
7032             if ((pKeySub[i].lenFrom == startP-pchFirst) &&
7033                 (!strncasecmp ((char *)pKeySub[i].pchFrom, (char *)pchFirst, 
7034                                 pKeySub[i].lenFrom)))
7035             {
7036                 pchSub = pKeySub[i].pchTo;
7037                 lenSub = strlen((char *)pchSub);
7038                 break;
7039             }
7040
7041         }
7042
7043         if ((pchSub != NULL) && (lenSub > 0))
7044         {
7045             memcpy (destP, pchSub, lenSub);
7046             destP += lenSub;
7047         }
7048         else
7049         {
7050             memcpy (destP, pchFirst, startP-pchFirst);
7051             destP += startP-pchFirst;
7052         }
7053 #endif /* WSM */
7054         *destP++ = '+';
7055
7056         ScanWhitespace (&startP);
7057     }
7058
7059     /*
7060      * Skip the key event type.
7061      */
7062     startP++;  /* skip '<' */
7063     while (*startP != '>')
7064     {
7065 #ifndef NO_MULTIBYTE
7066         startP += mblen ((char *)startP, MB_CUR_MAX);
7067 #else
7068         startP++;
7069 #endif
7070     }
7071     startP++;  /* skip '>' */
7072
7073     /*
7074      * Copy the KeySym string.
7075      */
7076
7077     ScanWhitespace (&startP);
7078     while (startP != endP)
7079     {
7080         *destP++ = *startP++;
7081     }
7082     *destP = '\0';
7083
7084 } /* END OF FUNCTION ProcessAccelText */
7085
7086
7087 \f
7088 /*************************************<->*************************************
7089  *
7090  *  ProcessCommandLine (argc, argv)
7091  *
7092  *
7093  *  Description:
7094  *  -----------
7095  *  This function looks for and processes mwm options in the command line
7096  *
7097  *  Inputs:
7098  *  ------
7099  *  argc =   argument count.
7100  *  argv =   argument vector.
7101  *
7102  * 
7103  *  Outputs:
7104  *  -------
7105  *  Changes global data to based on command line options recognized
7106  *
7107  *
7108  *************************************<->***********************************/
7109 #define SCREENS_OPT             "-screens"
7110 #define MULTI_SCREEN_OPT        "-multiscreen"
7111
7112 void ProcessCommandLine (int argc,  char *argv[])
7113 {
7114     unsigned char *string;
7115     int argnum;
7116     unsigned char *lineP;
7117
7118     for (argnum = 1; argnum < argc; argnum++)
7119     {
7120         lineP = (unsigned char *) argv[argnum];
7121         if ((string = GetString (&lineP)) == NULL) 
7122         /* empty or comment line */
7123         {
7124             continue;
7125         }
7126         if (!strcmp((char *)string, MULTI_SCREEN_OPT))
7127         {
7128             wmGD.multiScreen = True;
7129             wmGD.numScreens = ScreenCount (DISPLAY);
7130         }
7131         else if (!strcmp((char *)string, SCREENS_OPT))
7132         {
7133             argnum++;           /* skip to next arg */
7134             ParseScreensArgument (argc, argv, &argnum, lineP);
7135         }
7136     }
7137
7138 } /* END OF FUNCTION ProcessCommandLine */
7139
7140 \f
7141 /*************************************<->*************************************
7142  *
7143  *  ParseScreensArgument (argc, argv, pArgnum, lineP)
7144  *
7145  *
7146  *  Description:
7147  *  -----------
7148  *  This function processes the ``-screens'' command line argument
7149  *
7150  *  Inputs:
7151  *  ------
7152  *  argc =   argument count.
7153  *  argv =   argument vector.
7154  *  pArgnum = pointer to argument number where processing left off
7155  *  lineP  = pointer into argv[*pArgnum] where processing left off
7156  *
7157  * 
7158  *  Outputs:
7159  *  -------
7160  *  Changes global data to based on command line options recognized
7161  *      + wmGD.screenNames
7162  *      + wmGD.numScreens
7163  *  Assumes default screenNames are already in place
7164  *
7165  *************************************<->***********************************/
7166
7167 static void ParseScreensArgument (int argc, char *argv[], int *pArgnum,
7168                                   unsigned char *lineP)
7169 {
7170     unsigned char *string;
7171     int sNum = 0;
7172     int lastLen;
7173     int nameCount = 0;
7174
7175     for (; (*pArgnum < argc) && (sNum < ScreenCount(DISPLAY)); 
7176                                             (*pArgnum)++, sNum++)
7177     {
7178         lineP = (unsigned char *)argv[*pArgnum];
7179         if (*argv[*pArgnum] == '"')
7180         {
7181             /*
7182              * if Quote, use GetString to strip it
7183              */
7184             if ((string = GetString (&lineP)) == NULL) 
7185                 /* empty or comment line */
7186             {
7187                 continue;
7188             }
7189         }
7190         else 
7191         {
7192             string = (unsigned char *)argv[*pArgnum];
7193             if (*string == '-')
7194             {
7195                 /* another option, end of screens names */
7196                 break;
7197             }
7198         }
7199         
7200         if (!(wmGD.screenNames[sNum] = (unsigned char *) 
7201               XtRealloc ((char*)wmGD.screenNames[sNum], 
7202                          1 + strlen((char *)string))))
7203         {
7204             Warning (((char *)GETMESSAGE(60, 31, "Insufficient memory for screen names")));
7205             ExitWM(WM_ERROR_EXIT_VALUE);
7206         }
7207         else 
7208         {
7209             strcpy((char *)wmGD.screenNames[sNum], (char *)string);
7210             nameCount++;
7211         }
7212     }
7213
7214     (*pArgnum)--;
7215
7216     /*
7217      * remaining screens (if any) get first name specified 
7218      */
7219     if (nameCount > 0)
7220     {
7221         lastLen = 1 + strlen((char *)wmGD.screenNames[0]);
7222         for (; sNum < ScreenCount(DISPLAY); sNum++)
7223         {
7224             if (!(wmGD.screenNames[sNum] = (unsigned char *) 
7225                 XtRealloc ((char*)wmGD.screenNames[sNum], lastLen)))
7226             {
7227                 Warning (((char *)GETMESSAGE(60, 32, "Insufficient memory for screen names")));
7228                 ExitWM(WM_ERROR_EXIT_VALUE);
7229             }
7230             else 
7231             {
7232                 strcpy((char *)wmGD.screenNames[sNum], 
7233                        (char *)wmGD.screenNames[0]);
7234             }
7235         }
7236     }
7237
7238 } /* END OF FUNCTION ParseScreensArgument */
7239
7240 \f
7241 /*************************************<->*************************************
7242  *
7243  *  ProcessMotifBindings ()
7244  *
7245  *
7246  *  Description:
7247  *  -----------
7248  *  This function is used retrieve the motif input bindings
7249  *  and put them into a property on the root window.
7250  *
7251  *
7252  *************************************<->***********************************/
7253 void ProcessMotifBindings (void)
7254 {
7255     char           fileName[MAXWMPATH+1];
7256     char          *bindings = NULL;
7257 #ifndef MOTIF_ONE_DOT_ONE
7258     char          *homeDir = XmeGetHomeDirName();
7259 #else
7260     FILE          *fileP;
7261 #endif
7262
7263     /*
7264      *  Look in the user's home directory for .motifbind
7265      */
7266
7267 #ifdef MOTIF_ONE_DOT_ONE
7268     GetHomeDirName(fileName);
7269 #else
7270     strcpy (fileName, homeDir);
7271 #endif
7272     strncat(fileName, "/", MAXWMPATH-strlen(fileName));
7273     strncat(fileName, MOTIF_BINDINGS_FILE, MAXWMPATH-strlen(fileName));
7274
7275 #ifdef MOTIF_ONE_DOT_ONE
7276     if ((fileP = fopen (fileName, "r")) != NULL)
7277     {
7278         unsigned char   buffer[MBBSIZ];
7279         int             count;
7280         Boolean         first = True;
7281         int             mode = PropModeReplace;
7282         Window          propWindow;
7283
7284         /*
7285          * Get the atom for the property.
7286          */
7287         wmGD.xa_MOTIF_BINDINGS =
7288                 XInternAtom (DISPLAY, _XA_MOTIF_BINDINGS, False);
7289
7290         /*
7291          * The property goes on the root window of screen zero
7292          */
7293         propWindow = RootWindow(DISPLAY, 0);
7294
7295         /*
7296          * Copy file contents to property on root window of screen 0.
7297          */
7298         while ( (count=fread((char *) &buffer[0], 1, MBBSIZ, fileP)) > 0)
7299         {
7300             XChangeProperty (DISPLAY, propWindow, wmGD.xa_MOTIF_BINDINGS,
7301                                 XA_STRING, 8, mode,
7302                                 &buffer[0], count);
7303
7304             if (first)
7305             {
7306                 first = False;
7307                 mode = PropModeAppend;
7308             }
7309         }
7310     }
7311
7312 #else
7313     XDeleteProperty (DISPLAY, RootWindow (DISPLAY, 0),
7314                 XInternAtom (DISPLAY, "_MOTIF_BINDINGS", False));
7315     XDeleteProperty (DISPLAY, RootWindow (DISPLAY, 0),
7316                 XInternAtom (DISPLAY, "_MOTIF_DEFAULT_BINDINGS", False));
7317
7318     if (_XmVirtKeysLoadFileBindings (fileName, &bindings) == True) {
7319         XChangeProperty (DISPLAY, RootWindow(DISPLAY, 0),
7320                 XInternAtom (DISPLAY, "_MOTIF_BINDINGS", False),
7321                 XA_STRING, 8, PropModeReplace,
7322                 (unsigned char *)bindings, strlen(bindings));
7323     }
7324     else {
7325         _XmVirtKeysLoadFallbackBindings (DISPLAY, &bindings);
7326     }
7327     XtFree (bindings);
7328 #endif
7329 } /* END OF FUNCTION ProcessMotifBindings */
7330
7331 #ifdef PANELIST
7332 \f
7333 /*************************************<->*************************************
7334  *
7335  *  void
7336  *  ParseWmFunctionArg (linePP, ix, wmFunc, ppArg, sClientName)
7337  *
7338  *
7339  *  Description:
7340  *  -----------
7341  *  Parse the function arguments for a window manager function.
7342  *
7343  *
7344  *  Inputs:
7345  *  ------
7346  *  linePP   = pointer to line buffer pointer (contains string arg).
7347  *  ix = window manager function index (returned by ParseWmFunction)
7348  *  pWmFunction = pointer to window manager function destination.
7349  *  ppArg = ptr to argument pointer.
7350  *  sClientName = string name of client 
7351  *
7352  *
7353  *  Outputs:
7354  *  -------
7355  *  *ppArg = arg to pass to window manager function when invoking.
7356  *  Return = true on succes, false on some kind of parse error
7357  *
7358  *
7359  *  Comments:
7360  *  --------
7361  *  functionTable (window manager function table) is indexed with ix
7362  *  to get parsing info.
7363  *
7364  *  This function may malloc memory for the returned arg.
7365  *
7366  *  The sClientName is needed for starting some hpterm-based push_recall
7367  *  clients. It needs to be passed into the action so the hpterm gets
7368  *  named appropriately.
7369  * 
7370  *************************************<->***********************************/
7371
7372 Boolean
7373 ParseWmFunctionArg (
7374                 unsigned char **linePP,
7375                 int ix, 
7376                 WmFunction wmFunc, 
7377                 void **ppArg,
7378                 String sClientName,
7379                 String sTitle)
7380 {
7381     unsigned char *lineP = *linePP;
7382     Boolean bValidArg = True;
7383     unsigned char *str = NULL;
7384
7385     /*
7386      * If this is (possibly) a string argument, put it 
7387      * in quotes so that it will be parsed properly.
7388      */
7389     if ((functionTable[ix].parseProc == ParseWmFuncStrArg) ||
7390         (functionTable[ix].parseProc == ParseWmFuncMaybeStrArg))
7391     {
7392         if (lineP && *lineP != '"')
7393         {
7394             /*
7395              * not in quotes, repackage it, escaping the appropriate
7396              * characters.
7397              */
7398             str = _DtWmParseMakeQuotedString (lineP);
7399             if (str)
7400             {
7401                 lineP = str;
7402             }
7403         }
7404     }
7405
7406     /* 
7407      * Apply the function argument parser.
7408      */
7409     if ((functionTable[ix].wmFunction != wmFunc) ||
7410         !(*(functionTable [ix].parseProc)) (&lineP, wmFunc, ppArg))
7411     {
7412         bValidArg = False;
7413     }
7414
7415     /*
7416      * Add the exec parms if this is an f.action
7417      */
7418     if ((wmFunc == F_Action) && ppArg && *ppArg)
7419     {
7420         WmActionArg *pAP = (WmActionArg *) *ppArg;
7421         int totLen = 0;
7422
7423         /*
7424          * allocate more than enough string space to copy 
7425          * strings and intervening spaces.
7426          */
7427         if (sClientName && *sClientName)
7428         {
7429             /* length of: "name=" + sClientName + NULL */
7430             totLen += 5 + strlen(sClientName) + 1;
7431         }
7432         if (sTitle && *sTitle)
7433         {
7434             /* length of: "," + "title=" + sTitle + NULL */
7435             totLen += 1 + 6 + strlen(sTitle) + 1;
7436         }
7437
7438         if (totLen > 0)
7439         {
7440             pAP->szExecParms = (String) XtMalloc (totLen);
7441             /* start with empty string */
7442             pAP->szExecParms[0] = '\0'; 
7443
7444             if (sClientName && *sClientName)
7445             {
7446                 strcat (pAP->szExecParms, "name=");
7447                 strcat (pAP->szExecParms, sClientName);
7448             }
7449             if (sTitle && *sTitle)
7450             {
7451                 if (pAP->szExecParms[0] != '\0')
7452                 {
7453                     strcat (pAP->szExecParms, ",");
7454                 }
7455                 strcat (pAP->szExecParms, "title=");
7456                 strcat (pAP->szExecParms, sTitle);
7457             }
7458         }
7459     }
7460
7461     if (str)
7462     {
7463         XtFree ((char *) str);
7464     }
7465
7466     return (bValidArg);
7467
7468 } /* END OF FUNCTION ParseWmFunctionArg */
7469
7470 \f
7471 /*************************************<->*************************************
7472  *
7473  *  SystemCmd (pchCmd)
7474  *
7475  *
7476  *  Description:
7477  *  -----------
7478  *  This function fiddles with our signal handling and calls the
7479  *  system() function to invoke a unix command.
7480  *
7481  *
7482  *  Inputs:
7483  *  ------
7484  *  pchCmd = string with the command we want to exec.
7485  *
7486  *  Outputs:
7487  *  -------
7488  *
7489  *
7490  *  Comments:
7491  *  --------
7492  *  The system() command is touchy about the SIGCLD behavior. Restore
7493  *  the default SIGCLD handler during the time we run system().
7494  * 
7495  *************************************<->***********************************/
7496
7497 void
7498 SystemCmd (char *pchCmd)
7499 {
7500     struct sigaction sa;
7501     struct sigaction osa;
7502
7503     (void) sigemptyset(&sa.sa_mask);
7504     sa.sa_flags = 0;
7505     sa.sa_handler = SIG_DFL;
7506
7507     (void) sigaction (SIGCLD, &sa, &osa);
7508
7509     system (pchCmd);
7510
7511     (void) sigaction (SIGCLD, &osa, (struct sigaction *) 0);
7512 }
7513
7514
7515 \f
7516 /*************************************<->*************************************
7517  *
7518  *  DeleteTempConfigFileIfAny ()
7519  *
7520  *
7521  *  Description:
7522  *  -----------
7523  *  This function deletes the temporary config file used to process 
7524  *  old dtwmrc syntax.
7525  *
7526  *
7527  *  Inputs:
7528  *  ------
7529  *
7530  *
7531  *  Outputs:
7532  *  -------
7533  *
7534  *
7535  *  Comments:
7536  *  --------
7537  * 
7538  *************************************<->***********************************/
7539
7540 void
7541 DeleteTempConfigFileIfAny (void)
7542 {
7543     char pchCmd[MAXWMPATH+1];
7544
7545     if (pConfigStackTop->tempName)
7546     {
7547         strcpy (pchCmd, "/bin/rm ");
7548         strcat (pchCmd, pConfigStackTop->tempName);
7549         SystemCmd (pchCmd);
7550         XtFree ((char *) pConfigStackTop->tempName);
7551         pConfigStackTop->tempName = NULL;
7552     }
7553     if (pConfigStackTop->cppName)
7554     {
7555         strcpy (pchCmd, "/bin/rm ");
7556         strcat (pchCmd, pConfigStackTop->cppName);
7557         SystemCmd (pchCmd);
7558         XtFree ((char *) pConfigStackTop->cppName);
7559         pConfigStackTop->cppName = NULL;
7560     }
7561 }
7562
7563 \f
7564 /*************************************<->*************************************
7565  *
7566  *  ParseIncludeSet (pSD, lineP)
7567  *
7568  *
7569  *  Description:
7570  *  -----------
7571  *
7572  *
7573  *  Inputs:
7574  *  ------
7575  *  cfileP = (global) file pointer to fopened configuration file or NULL
7576  *  lineP = pointer to line buffer
7577  *  line   = (global) line buffer
7578  *  linec  = (global) line count
7579  *  parseP = (global) parse string pointer if cfileP == NULL
7580  *  pSD->rootWindow = default root window of display
7581  * 
7582  *  Outputs:
7583  *  -------
7584  *  linec  = (global) line count incremented
7585  *  parseP = (global) parse string pointer if cfileP == NULL
7586  *
7587  *
7588  *  Comments:
7589  *  --------
7590  * 
7591  *************************************<->***********************************/
7592
7593 static void ParseIncludeSet (WmScreenData *pSD, unsigned char *lineP) 
7594 {
7595     unsigned char     *string;
7596     unsigned char     *pchName;
7597
7598     /*
7599      * Require leading '{' on the next line.
7600      */
7601
7602     while ((GetNextLine () != NULL))  /* not EOF nor read error */
7603     {
7604         lineP = line;
7605         ScanWhitespace(&lineP);
7606
7607         if ((lineP == NULL) || (*line == '!') || (*lineP == '\0') || (*lineP == '#'))
7608         /* ignore empty or comment line */
7609         {
7610             continue;
7611         }
7612
7613         if (*lineP == '{')
7614         /* found '{' */
7615         {
7616             break;
7617         }
7618
7619         /* not a '{' */
7620         PWarning (((char *)GETMESSAGE(60, 37, "Expected '{'")));
7621         return;
7622     }
7623
7624     /*
7625      * Found leading "{" or EOF.
7626      * Parse include files until "}" or EOF found.
7627      */
7628     while ((GetNextLine () != NULL))
7629     {
7630         lineP = line;
7631         if ((*line == '!') || (string = GetString (&lineP)) == NULL)
7632         /* ignore empty or comment lines */
7633         {
7634             continue;
7635         }
7636         if (*string == '}')  /* finished with set. */
7637         {
7638             break;
7639         }
7640         pchName = _DtWmParseFilenameExpand (string);
7641         if (pchName && ConfigStackPush (pchName))
7642         {
7643             ProcessWmFile (pSD, True /* nested */);
7644             ConfigStackPop ();
7645             XtFree ((char *) pchName);
7646         }
7647
7648     }
7649
7650 }
7651
7652
7653 \f
7654 /*************************************<->*************************************
7655  *
7656  *  ConfigStackInit (pchFileName)
7657  *
7658  *
7659  *  Description:
7660  *  -----------
7661  *  Initializes the config file processing stack
7662  *
7663  *  Inputs:
7664  *  ------
7665  *  pchFileName = name of new file to start parsing
7666  * 
7667  *  Outputs:
7668  *  -------
7669  *
7670  *
7671  *  Comments:
7672  *  --------
7673  * 
7674  *************************************<->***********************************/
7675
7676 static void ConfigStackInit (char *pchFileName)
7677 {
7678
7679     pConfigStack  = XtNew (ConfigFileStackEntry);
7680
7681     if (pConfigStack)
7682     {
7683         pConfigStackTop = pConfigStack;
7684         pConfigStackTop->fileName = XtNewString (pchFileName);
7685         pConfigStackTop->tempName = NULL;
7686         pConfigStackTop->cppName = NULL;
7687         pConfigStackTop->offset = 0;
7688         pConfigStackTop->pWmPB = wmGD.pWmPB;
7689         pConfigStackTop->wmgdConfigFile = wmGD.configFile;
7690         pConfigStackTop->pIncluder = NULL;
7691
7692     }
7693     else
7694     {
7695         sprintf ((char *)wmGD.tmpBuffer,
7696             (char *)GETMESSAGE(60,36,"Insufficient memory to process included file: %s"), 
7697             pchFileName);
7698         Warning ((char *)wmGD.tmpBuffer);
7699     }
7700 }
7701
7702 \f
7703 /*************************************<->*************************************
7704  *
7705  *  ConfigStackPush (pchFileName)
7706  *
7707  *
7708  *  Description:
7709  *  -----------
7710  *  Open an included config file
7711  *
7712  *  Inputs:
7713  *  ------
7714  *  pchFileName = name of new file to start parsing
7715  *  wmGD.pWmPB = global parse buffer (pickle this)
7716  * 
7717  *  Outputs:
7718  *  -------
7719  *  wmGD.pWmPB = global parse buffer (new one for new file)
7720  *  return = FILE * to open file or NULL
7721  *
7722  *
7723  *  Comments:
7724  *  --------
7725  * 
7726  *************************************<->***********************************/
7727
7728 static FILE *
7729 ConfigStackPush (unsigned char *pchFileName)
7730 {
7731     ConfigFileStackEntry *pEntry;
7732     FILE *pNewFile = NULL;
7733
7734     pEntry = XtNew (ConfigFileStackEntry);
7735     if (pEntry)
7736     {
7737         /* save off state of current config file */
7738         pConfigStackTop->offset = ftell (cfileP);
7739         pConfigStackTop->pWmPB = wmGD.pWmPB;
7740         fclose (cfileP);
7741
7742         /* set up state of new config file */
7743         pEntry->fileName = XtNewString ((char *)pchFileName);
7744         pEntry->tempName = NULL;
7745         pEntry->cppName = NULL;
7746         pEntry->wmgdConfigFile = (String) pEntry->fileName;
7747
7748         /* set globals for new config file */
7749         wmGD.pWmPB = _DtWmParseNewBuf ();
7750         wmGD.configFile = pEntry->wmgdConfigFile;
7751
7752         /* put new entry onto stack */
7753         pEntry->pIncluder = pConfigStackTop;
7754         pConfigStackTop = pEntry;
7755
7756         /* open the file */
7757         pNewFile = cfileP = FopenConfigFile();
7758
7759         if (!pNewFile)
7760         {
7761             /* file open failed! back out */
7762             ConfigStackPop ();
7763         }
7764     }
7765     else
7766     {
7767         sprintf ((char *)wmGD.tmpBuffer,
7768             (char *)GETMESSAGE(60,36,"Insufficient memory to process included file: %s"), 
7769             pchFileName);
7770         Warning ((char *)wmGD.tmpBuffer);
7771     }
7772
7773     return (pNewFile);
7774 }
7775
7776
7777 \f
7778 /*************************************<->*************************************
7779  *
7780  *  ConfigStackPop ()
7781  *
7782  *
7783  *  Description:
7784  *  -----------
7785  *
7786  *
7787  *  Inputs:
7788  *  ------
7789  *  pchFileName = name of new file to start parsing
7790  *  wmGD.pWmPB = global parse buffer (pickle this)
7791  * 
7792  *  Outputs:
7793  *  -------
7794  *  wmGD.pWmPB = global parse buffer (new one for new file)
7795  *
7796  *
7797  *  Comments:
7798  *  --------
7799  *  assumes cfileP is closed already
7800  * 
7801  *************************************<->***********************************/
7802
7803 static void ConfigStackPop (void)
7804 {
7805     Boolean error = False;
7806     ConfigFileStackEntry *pPrev;
7807     char pchCmd[MAXWMPATH+1];
7808
7809     if (pConfigStackTop != pConfigStack)
7810     {
7811         pPrev = pConfigStackTop->pIncluder;
7812
7813         _DtWmParseDestroyBuf (wmGD.pWmPB);
7814         if (pConfigStackTop->tempName)
7815         {
7816             XtFree (pConfigStackTop->tempName);
7817         }
7818         if (pConfigStackTop->cppName)
7819         {
7820             strcpy (pchCmd, "/bin/rm "); 
7821             strcat (pchCmd, pConfigStackTop->cppName); 
7822             SystemCmd (pchCmd);
7823             XtFree ((char *) pConfigStackTop->cppName);
7824             pConfigStackTop->cppName = NULL;
7825         }
7826         if (pConfigStackTop->fileName)
7827         {
7828             XtFree (pConfigStackTop->fileName);
7829         }
7830
7831         wmGD.pWmPB = pPrev->pWmPB;
7832         wmGD.configFile = pPrev->wmgdConfigFile;
7833         if (pPrev->tempName)
7834         {
7835             cfileP = fopen (pPrev->tempName, "r");
7836         }
7837         else if (pPrev->cppName)
7838         {
7839             cfileP = fopen (pPrev->cppName, "r");
7840         }
7841         else
7842         {
7843             cfileP = fopen (pPrev->fileName, "r");
7844         }
7845         if (cfileP) 
7846         {
7847             fseek (cfileP, pPrev->offset, 0);
7848         }
7849         else
7850         {
7851             char msg[MAXWMPATH+1];
7852
7853             sprintf(msg, ((char *)GETMESSAGE(60, 39, 
7854                             "Could not reopen configuration file %s")),
7855                 pPrev->fileName);
7856             Warning (msg);
7857         }
7858
7859         XtFree ((char *)pConfigStackTop);
7860         pConfigStackTop = pPrev;
7861     }
7862 }
7863
7864 \f
7865 /*************************************<->*************************************
7866  *
7867  *  ParseWmFuncActionArg (linePP, wmFunction, pArgs)
7868  *
7869  *
7870  *  Description:
7871  *  -----------
7872  *  Parses a window manager f.action argument
7873  *
7874  *
7875  *  Inputs:
7876  *  ------
7877  *  linePP   = pointer to current line buffer pointer.
7878  *  wmFunction = function for which the argument string is intended.
7879  *  pArgs = pointer to argument destination.
7880  *
7881  * 
7882  *  Outputs:
7883  *  -------
7884  *  linePP   = pointer to revised line buffer pointer.
7885  *  pArgs    = pointer to parsed argument.
7886  *  Return   = FALSE iff insufficient memory
7887  *
7888  *
7889  *  Comments:
7890  *  --------
7891  * 
7892  *************************************<->***********************************/
7893
7894 Boolean ParseWmFuncActionArg (unsigned char **linePP, 
7895                                   WmFunction wmFunction, String *pArgs)
7896 {
7897 #define WM_ACTION_ARG_INCREMENT 5
7898 #define WM_ACTION_ARG_PAD       256
7899     unsigned char *string;
7900     char *pch;
7901     WmActionArg *pAP;
7902     int iArgSz;
7903
7904     pAP = XtNew (WmActionArg);
7905     if (pAP && (string = GetString (linePP)) != NULL)
7906     {
7907         /* Got action name */
7908         pAP->actionName = XtNewString ((char *) string);
7909
7910         /* Get action arguments, if any */
7911         if (pAP->aap = (DtActionArg *) 
7912                 XtMalloc (WM_ACTION_ARG_INCREMENT * sizeof (DtActionArg)))
7913         {
7914             iArgSz = WM_ACTION_ARG_INCREMENT;
7915             pAP->numArgs = 0;
7916
7917             while ((string = GetString (linePP)) != NULL)
7918             {
7919                if (pAP->aap[pAP->numArgs].u.file.name = (char *)
7920                        XtMalloc(1 + strlen((char *)string)))
7921                {
7922                    pAP->aap[pAP->numArgs].argClass = DtACTION_FILE;
7923
7924                    /* format the action argument */
7925                    pch = pAP->aap[pAP->numArgs].u.file.name;
7926
7927                    /* 
7928                     * Expand environment variable
7929                     */
7930                    if (string[0] == '$')
7931                    {
7932                        string = (unsigned char *) getenv ((char *)&string[1]);
7933                        if (!string)
7934                        {
7935                            break;
7936                        }
7937                        else
7938                        {
7939                            /*
7940                             * Make sure there's room for the new
7941                             * string.
7942                             */
7943                            pch = (char *) 
7944                              XtRealloc (pch, (1+strlen((char *)string)));
7945                            pAP->aap[pAP->numArgs].u.file.name = pch;
7946                        }
7947                    }
7948
7949                    /* !!! No host name processing is done!!! */
7950
7951                    strcpy (pch, (char *)string);
7952
7953                    pAP->numArgs++;
7954                    if (pAP->numArgs == iArgSz)
7955                    {
7956                        /* need to increase our array space */
7957                        iArgSz += WM_ACTION_ARG_INCREMENT;
7958                        pAP->aap = (DtActionArg *) 
7959                            XtRealloc((char *)pAP->aap,
7960                                      (iArgSz * sizeof (DtActionArg)));
7961                        if (!pAP->aap)
7962                        {
7963                            break; /* out of memory */
7964                        }
7965                    }
7966                }
7967                else
7968                {
7969                    break; /* out of memory */
7970                }
7971             }
7972
7973         }
7974         pAP->szExecParms = NULL;
7975         *pArgs = (String) pAP;
7976     }
7977     else
7978     /* NULL string argument */
7979     {
7980         *pArgs = NULL;
7981     }
7982
7983     return (TRUE);
7984
7985 } /* END OF FUNCTION ParseWmFuncActionArg */
7986
7987
7988 #endif /* PANELIST */
7989 #ifdef WSM
7990 \f
7991 /*************************************<->*************************************
7992  *
7993  *  PreprocessConfigFile (pSD)
7994  *
7995  *
7996  *  Description:
7997  *  -----------
7998  *  This function runs the configuration file through the C
7999  *  preprocessor
8000  *
8001  *
8002  *  Inputs:
8003  *  ------
8004  *  pSD = ptr to screen data
8005  *
8006  *  Outputs:
8007  *  -------
8008  *
8009  *
8010  *  Comments:
8011  *  --------
8012  * 
8013  *************************************<->***********************************/
8014
8015 static void
8016 PreprocessConfigFile (void)
8017 {
8018 #define CPP_NAME_SIZE   ((L_tmpnam)+1)
8019     char pchCmd[MAXWMPATH+1];
8020
8021     if (wmGD.cppCommand && *wmGD.cppCommand)
8022     {
8023         /*
8024          * Generate a temp file name.
8025          */
8026         pConfigStackTop->cppName = XtMalloc (CPP_NAME_SIZE * sizeof(char));
8027         if (pConfigStackTop->cppName)
8028         {
8029             (void) tmpnam (pConfigStackTop->cppName);
8030
8031             /*
8032              * Build up the command line.
8033              */
8034             strcpy (pchCmd, wmGD.cppCommand);
8035             strcat (pchCmd, " ");
8036             strcat (pchCmd, pConfigStackTop->fileName);
8037             strcat (pchCmd, " ");
8038             strcat (pchCmd, pConfigStackTop->cppName);
8039
8040             /*
8041              * Run the config file through the converter program
8042              * and send the output to a temp file. 
8043              */
8044             SystemCmd (pchCmd);
8045         }
8046     }
8047 }
8048
8049 \f
8050 /*************************************<->*************************************
8051  *
8052  *  GetNetworkFileName (char *pchFile)
8053  *
8054  *
8055  *  Description:
8056  *  -----------
8057  *  This function returns a local representation for a network
8058  *  file. 
8059  *
8060  *
8061  *  Inputs:
8062  *  ------
8063  *  pchFile     - pointer to file name of form [<host>:]<path>
8064  *
8065  *  Return:
8066  *  -------
8067  *  String      - ptr to allocated string of local file name. If input
8068  *                is not a network file, the a copy of pchFile is returned.
8069  *
8070  *
8071  *  Comments:
8072  *  --------
8073  *  returned file name should be freed with XtFree().
8074  * 
8075  *************************************<->***********************************/
8076
8077 static String
8078 GetNetworkFileName (char *pchFile)
8079 {
8080     char *pch;
8081     char *host_part; 
8082     char *file_part; 
8083     char *netfile;
8084     char *sName = NULL;
8085     char *pchName = NULL;
8086     int count;
8087     char **pchTok;
8088     String sReturn = NULL;
8089     char *homeDir;
8090     int len;
8091
8092
8093     pch = strchr (pchFile, ':');
8094
8095     if (pch)
8096     {
8097         /*
8098          * Expand special chars and find matching file.
8099          */
8100         pchTok = (char **)shellscan (pchFile, &count, 0);
8101
8102         if ((count == 1) || (count == 2))
8103         {
8104             /* one match found */
8105             host_part = pchTok[0];
8106         }
8107         else if (count > 2)
8108         {
8109             /* several matches found, pick one */
8110             host_part = pchTok[1];
8111         }
8112         else
8113         {
8114             host_part = NULL;
8115         }
8116
8117         if (host_part != NULL)
8118         {
8119             pch = strchr (host_part, ':');
8120             if (pch)
8121             {
8122                 /* 
8123                  * copy the string so we don't munge data
8124                  * inside shellscan 
8125                  */
8126                 host_part = sName = XtNewString ((String) host_part);
8127                 pch = strchr (sName, ':');
8128
8129                 /*
8130                  * separate the host and file parts of the
8131                  * file name
8132                  */
8133                 *pch = '\0';
8134                 file_part = pch+1;
8135             }
8136             else
8137             {
8138                 /*
8139                  * The colon went away. Hmm...
8140                  */
8141                 file_part = host_part;
8142                 host_part = NULL;
8143             }
8144
8145             if ((mblen(file_part, MB_CUR_MAX) == 1) && 
8146                 (mblen(file_part+1, MB_CUR_MAX) == 1) &&
8147                 (*file_part == '~') &&
8148                 (*(file_part+1) == '/'))
8149             {
8150                 /*
8151                  * Replace '~' with $HOME
8152                  */
8153                 homeDir = XmeGetHomeDirName();
8154                 len = strlen (host_part) + 1 +
8155                       strlen (homeDir) + strlen (file_part) + 1;
8156                 pch = (char *) XtMalloc (len);
8157                 strcpy (pch, sName);
8158                 host_part = pch;
8159                 pch += strlen (pch) + 1;
8160                 strcpy (pch, homeDir);
8161                 strcat (pch, file_part+1);
8162                 file_part = pch;
8163                 XtFree (sName);
8164                 sName = host_part;
8165             }
8166         }
8167         else
8168         {
8169             /*
8170              * shellscan had a problem with the file name.
8171              * just operate on the name as-is.
8172              * temporarily replace ':' with a NULL 
8173              */
8174             host_part = sName = XtNewString ((String) pchFile);
8175             pch = strchr (sName, ':');
8176             *pch = '\0';
8177             host_part = pchFile;
8178             file_part = pch+1;
8179         }
8180
8181         /* convert to canonical host/file name */
8182         netfile = (char *) 
8183                     tt_host_file_netfile (host_part, file_part);
8184         if (tt_pointer_error (netfile) == TT_OK)
8185         {
8186             /* convert to local file name equivalent */
8187             pchName = tt_netfile_file (netfile);
8188
8189             if (tt_pointer_error (pchName) == TT_OK)
8190             {
8191                 sReturn = XtNewString ((String) pchName);
8192                 tt_free ((char *)pchName);
8193             }
8194             tt_free (netfile);
8195         }
8196
8197         if (sName)
8198         {
8199             XtFree ((char *)sName);
8200         }
8201     }
8202
8203     if (sReturn == NULL)
8204     {
8205         if ((mblen(pchFile, MB_CUR_MAX) == 1) && 
8206             (mblen(pchFile+1, MB_CUR_MAX) == 1) &&
8207             (*pchFile == '~') &&
8208             (*(pchFile+1) == '/'))
8209         {
8210             /*
8211              * Replace '~' with $HOME
8212              */
8213             homeDir = XmeGetHomeDirName();
8214             len = strlen (homeDir) + strlen (pchFile) + 1;
8215             sReturn = (char *) XtMalloc (len);
8216             strcpy (sReturn, homeDir);
8217             strcat (sReturn, pchFile+1);
8218         }
8219         else
8220         {
8221             sReturn = XtNewString ((String) pchFile);
8222         }
8223     }
8224
8225     return (sReturn);
8226 }
8227 /****************************   eof    ***************************/
8228 #endif /* WSM */
8229
8230 \f
8231 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
8232 /*************************************<->*************************************
8233  *
8234  *  SetGreyedContextAndMgtMask (menuItem, wmFunction)
8235  *
8236  *
8237  *  Description:
8238  *  -----------
8239  *  This function sets up the greyed context and management mask
8240  *  for a menu item based on the menu function passed in.
8241  *
8242  *  Inputs:
8243  *  ------
8244  *  menuItem   = the menu item to be set up 
8245  *  wmFunction = the menu function to find in the function table
8246  *               to determine how to set up the relevant fields
8247  * 
8248  *  Outputs:
8249  *  -------
8250  *  The menuItem will have its greyed context and management mask fields
8251  *  set appropriately. If the given function cannot be found, the fields
8252  *  will be set to the appropriate values as if the function were F_Nop.
8253  *  Return = True if the function could be found. False otherwise.
8254  *
8255  *************************************<->***********************************/
8256
8257 Boolean SetGreyedContextAndMgtMask (MenuItem *menuItem,
8258                                     WmFunction wmFunction)
8259 {
8260     int ix;
8261
8262     for (ix = 0; ix < WMFUNCTIONTABLESIZE - 1; ++ix)
8263     {
8264         if (functionTable[ix].wmFunction == wmFunction)
8265         {
8266             /* Success! The function was found. Set up the
8267                values and get the heck out of here. */
8268             menuItem->greyedContext = functionTable[ix].greyedContext;
8269             menuItem->mgtMask = functionTable[ix].mgtMask;
8270             return(True);
8271         }
8272     }
8273
8274     /* We couldn't find the given command in the function table.
8275        Set up the values as if the F_Nop function were found
8276        and return False. */
8277     menuItem->greyedContext = functionTable[F_NOP_INDEX].greyedContext;
8278     menuItem->mgtMask = functionTable[F_NOP_INDEX].mgtMask;
8279     return(False);
8280 }
8281
8282
8283 \f
8284 /*************************************<->*************************************
8285  *
8286  *  MakeSeparatorTemplate ()
8287  *
8288  *
8289  *  Description:
8290  *  -----------
8291  *
8292  *  Inputs:
8293  *  ------
8294  * 
8295  *  Outputs:
8296  *  -------
8297  *
8298  *************************************<->***********************************/
8299 static
8300 MenuItem *MakeSeparatorTemplate (int position)
8301 {
8302     MenuItem *item;
8303
8304     item = (MenuItem *)XtMalloc(sizeof(MenuItem));
8305
8306     /* We use the labelType to determine where this separator is positioned
8307        relative to the client command(s) it is surrounding, i.e. TOP or
8308        BOTTOM */
8309     item->labelType = position;
8310     /* Make it look like a client command: */
8311     item->label = XtNewString("<label-template>");
8312     item->labelBitmapIndex = -1;
8313     item->mnemonic = (KeySym) 0;
8314     item->accelState = 0;
8315     item->accelKeyCode = (KeyCode) NULL;
8316     item->accelText = (String) NULL;
8317     item->wmFunction = (WmFunction) F_Separator;
8318     item->wmFuncArgs = (String) NULL;
8319     item->greyedContext = 0;
8320     item->mgtMask = 0;
8321     item->clientCommandName = (String) NULL;
8322     item->nextMenuItem = (MenuItem *) NULL;
8323
8324     return(item);
8325 }
8326 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */