1: /*************************************************************
2: * Program: CMENU Menu Compiler
3: * Module: cmenu1.c
4: * Menu Compiler:
5: * Main and Utility Functions
6: * Written by: Leor Zolman, 7/91
7: *************************************************************/
8:
g: #define MASTER
10: #include "cmenu.h"
11: #include "ccmenu.h"
12:
13: #include <string.h>
14:
15: #if__STDC__
16: # include <stdarg.h>
17: #else
18: include <varargs.h>
19: #endif
20:
21: int main(argc,argv)
22: int argc;
23: char **argv;
24: {
25: register i;
26:
27: printf('CMENU Menu Compiler v%s\n", VERSION);
28: if (argc < 2)
29: {
30: puts("usage: cmenu <menu-source-file(s)>\n");
31: return 0;
32: }
33:
34: for (i = 1; i <argc; i++)
35: if (dofile(argv[i]) == ERROR) /* process source files */
36: return 1;
37: return 0;
38: }
39:
40: /************************************************************
41: * dofile():
42: * Process a single .mnu source file
43: ************************************************************/
44:
45: int dofile(name)
46: char *name;
47: {
48: register i;
49: char *cp;
50:
51: if ((cp = strstr(name, ".mnu")) ||
52: (cp = strstr(name, ".MNU")))
53: *cp = '\0';
54:
55: strcpy(src_name, name);
56: strcat(src_name, ".mnu");
57: strcpy(obj_name, name);
58:
59: if ((fp = fopen(src_name, "r")) == NULL)
60: return fprintf(stderr, "Can't open %s\n", src_name);
61:
62: n_menus = 0;
63 lineno = 1;
64: in_menu = FALSE;
65: fatal = FALSE;
66:
67: /* Main processing loop. Read a token and process it,
68: * until end of file is reached:
69: */
70:
71: while ((token = gettok(fp)) != T_EOF)
72: {
73: if (!in_menu && token != T_MENU)
74: {
75: error("Each menu must begin with the Menu keyword");
76: break;
77: }
78: if ((*keywords[token].t_func)() == ERROR)
79: if (fatal) /* If fatal error, exit loop */
80: break;
81: }
82:
83: fclose(fp);
84:
85: if (!n_menus)
86: return error("No menus defined");
87:
88: if (in_menu)
89: {
90: if (n_items)
91: itemcheck();
92: error("Menu definition missing \"Endmenu\" statement");
93: }
94:
95: for (i = 0; i < n_menus; i++) /* check for undefined */
96: if (!MInfo[i].Processed) /* "lmenu" references */
97: {
98: printf("Local Menu \"%s\" is undefined.\n",
99: MInfo[i] .Name);
100: err_flag = TRUE;
101: }
102:
103: if (err_flag)
104: return ERROR;
105:
106: if (write_file() == ERROR)
107: return ERROR;
108: return OK;
109: }
110:
111:
112: /***********************************************************
113: * create_menu():
114: * Construct a new menu information structure and
115: * return it (by value).
116: * Set fatal to TRUE if can't create.
117: ***********************************************************/
118:
119: MINFO create_menu(name)
120: char *name;
121: {
122: MINFO mi;
123:
124: if (n_menus == MAX_MENUS)
125: fatalerr("Maximum # of menus (%d) exceeded", MAX_MENUS);
126: else
127: {
128: strcpy(mi_Name, name);
129: mi.Processed = FALSE;
130: }
131: return mi;
132: }
133:
134:
135: /***********************************************************
136: * find_menu():
137: * Search the Menu Info table for a named local menu.
138: * If found:
139: * Return a pointer to the entry if found, and set
140: * global variable menu_num to the menu's index
141: * else:
142: * return NULL
143: ***********************************************************/
144:
145: MINFO *find_menu(name)
146: char *name;
147: {
148: int i;
149:
150: for (i = 0; i < n_menus; i++)
151: if (!strcmp(MInfo[i].Name, name))
152: {
153: menu_num = i;
154: return &MInfo[i];
155: }
156: return NULL;
157: }
158:
159:
160: /***********************************************************
161: * create_item(): Allocate space for Item Info structure,
162: * Initialize it and return a pointer to the structure
163: * Return NULL if there was a creation error.
164: ***********************************************************/
165:
166: IINFO *create_item(name)
167: char *name;
168: {
169: IINFO *IIp;
170: ITEM *Ip;
171:
172: if (n_items == MAX_ITEMS)
173: {
174: fatalerr("Max. # of items (%d) exceeded", MAX_ITEMS);
175: return NULL;
176: }
177:
178: if ((IIp =(IINFO*) malloc(sizeof(IINFO))) == NULL)
179: {
180: fatalerr("Out of memory");
181: NULL;
182: }
183:
184: strcpy(IIp->Name, name);
185: Ip = &IIp->Item;
186: Ip->acttyp = ACT_NONE;
187: Ip->pre_clear = Ip->post_clear = Ip->prompt = DEFAULT;
188: Ip->nextcode = DEFAULT;
189: Ip->nextitem = Ip->lmenunum = 0;
190: *Ip->text = *Ip->path = *Ip->action = *Ip->help = '\0';
191: return IIp;
192: }
193:
194:
195: /***********************************************************
196: * find_item():
197: * Search the Item Info table for a named item in the
198: * currently active menu definition.
199: * If item name found:
200: * Set item_num to the index value of the Item,
201: * Return a pointer to the entry
202: * else:
203: * return NULL
204: ***********************************************************/
205:
206: IINFO *find_item(name)
207: char *name;
208: {
209: int i;
210:
211: for (i = 0; i < n_items; i++)
212: if (!strcmp(MIp->Items[i]->Name, name))
213: {
214: item_num = i;
215: return MIp->Items[i];
216: }
217: return NULL;
218: }
219:
220:
221: /***********************************************************
222: * itemcheck():
223: * Check the currently active item to make sure
224: * both a Text and an Action clause have been
225: * explicitly given.
226: ***********************************************************/
227:
228: Void itemcheck()
229: {
230: if (!*Ip->text)
231: error("No TEXT clause found for current item");
232: if (Ip->acttyp == ACT_NONE)
233: error("No ACTION clause found for current item");
234: }
235:
236:
237: /***********************************************************
238: * write_file():
239: * Write menu object file to disk, ready for
240: * execution via menu.
241: * Menu object file format:
242: * --------------------------------
243: * <count> (integer count of # of menus in file)
244: * MENU 1 (MENU structure for 1st Menu)
245: * ITEM 1
246: * ITEM 2
247: * ...
248: * ITEM n_items
249: * MENU 2 (MENU structure for 2nd Menu)
250: * ...
251: * .
252: * .
253: * .
254: * MENU <count> (MENU structure for final Menu)
255: * ...
256: * --------------------------------
257: *
258: ***********************************************************/
259:
260: int write_file()
261: {
262: int i,j;
263:
264: strcat(obj_name, ".mnc");
265:
266: if ((fp = fopen(obj_name, "wb")) == NULL)
267: {
268: fprintf(stderr,
269: "Cannot open %s for writing.\n", obj_name);
270: return ERROR;
271: }
272:
273: if (fwrite((Void *)&n_menus, sizeof n_menus, 1, fp) != 1)
274: {
275: fprintf(stderr,
276: "Error writing menu count to %s\n", obj_name);
277: return ERROR;
278: }
279:
280: for (i = 0; i < n_menus; i++)
281: {
282: Mp = &MInfo[i].Menu;
283: if (fwrite((Void *) Mp, sizeof (MENU), 1, fp) != 1)
284: {
285: fprintf(stderr,
286: "Error writing to %s\n", obj_name);
287: return ERROR;
288: }
289:
290: for (j = 0; j < Mp->nitems; j++)
291: {
292: if (fwrite((Void *) &MInfo[i].Items[j]->Item,
293: sizeof (ITEM), 1, fp) != 1)
294: {
295: fprintf(stderr,
296: "Error writing to %s\n", obj_name);
297: return ERROR;
298: }
299: free(MInfo[i].Items[j]);
300: }
301: }
302: printf("Menu object file %s written.\n", obj_name);
303: return OK;
304: }
305:
306:
307: /***********************************************************
308: * warning():
309: * Display a warning message, preceded by source
310: * file name and line number, supporting format
311: * conversions.
312: ***********************************************************/
313:
314: #if_STDC_ /* ANSI variable-#-of-args method: */
315: int warning(char *fmt, ...)
316: {
317: va_list arglist;
318: va_start(arglist, fmt);
319:
320: #else /* old "varargs" method: */
321: int warning(fmt, va_alist)
322: char *fmt;
323: va_dcl
324: {
325: va_list arglist;
326: va_start(arglist);
327: #endif
328: /* the rest is the same, ANSI or varargs: */
329:
330: fprintf(stderr, "%s (%d): ", src_name, lineno);
331: vfprintf(stderr, fmt, arglist);
332: va_end(arglist);
333: fprintf(stderr, "\n");
334: return OK;
335: }
336:
337:
338: /***********************************************************
339: * error():
340: * Display an error message, preceded by source
341: * file name and line number, supporting format
342: * conversions.
343: ***********************************************************/
344:
345: #if__STDC__ /* ANSI variable-#-of-args method: */
346: int error(char *fmt, ...)
347: {
348: va_list arglist;
349: va_start(arglist, fmt);
350:
351: #else /* old "varargs" method: */
352: int error(fmt, va_alist)
353: char *fmt;
354: va_dcl
355: {
356: va_list arglist;
357: va_start(arglist);
358: #endif
359:
360: /* the rest is the same, ANSI or varargs: */
361:
362: fprintf(stderr, "%s (%d): ", src_name, lineno);
363: vfprintf(stderr, fmt, arglist);
364: va_end(arglist);
365: fprintf(stderr, "\n");
366: err_flag = TRUE;
367: return ERROR;
368: }
369:
370:
371: /***********************************************************
372: * fatalerr():
373: * Like error, except global flag "fatal" is set.
374: ***********************************************************/
375:
376: #if __STDC__ /* start function the ANSI way... */
377: int fatalerr(char *fmt, ... /)
378: {
379: va_list arglist;
380: va_start(arglist, fmt);
381: #else /* or the old "varargs" way... */
382: int fatalerr(fmt, va_alist)
383: char *fmt;
384: va_dcl
385: {
386: va_list arglist;
387: va_start(arglist);
388: #endif
389:
390: error(fmt, arglist); /* the rest is same, ANSI or varargs */
391: va_end(arglist);
392: fatal = TRUE;
393: return ERROR;
394: }
395:
396:
397: /***********************************************************
398: * matchkey():
399: * Test if given string is a reserved word. Return the token
400: * value of the matching token if so; else return NULL.
401: ***********************************************************/
402:
403: int matchkey(str)
404: char *str;
405: {
406: char str2[MAX_CMD], *cp;
407: int i;
408:
409: strcpy(str2, str);
410: for (cp = str2; *cp; cp++)
411: *cp = tolower(*cp);
412:
413: for (i = 0; i < (int) N_KEYWORDS; i++)
414: if (!strcmp(keywords[i].keyword, str2))
415: return i;
416:
417: return NULL;
418: }
419:
420:
421: #ifdef NEEDSTR
422: /*
423: * Search for first occurence of substring s2 in s1:
424: * (provided for Xenix only; this function is in
425: * most modern standard distribution libraries)
426: */
427:
428: char *strstr(s1, s2)
429: char *s1, *s2;
430: {
431: int i, j, nposs;
432: int len1 = strlen(s1);
433:
434: int len2 = strlen(s2);
435: char *pl;
436:
437:
438: if (len1 < len2)
439: return NULL;
440:
441: nposs = len1 - len2;
442:
443: for (i = 0; i <= nposs; i++)
444: {
445: for (j = 0, p1 = &s1[i]; j < len2; j++)
446: if (*pl++ != s2[j])
447: break;
448: if (j == len2)
449: return &s1[i];
450: }
451: return NULL;
452: }
453: #endif
/* End of File */