1: /************************************************************
2: * Program: RMENU Menu Interpreter
3: * Module: rmenu1.c
4: * Main and Utility Functions
5: * Written by: Leor Zolman, 7/91
6: ************************************************************/
7:
8: #include "cmenu.h"
9: #include "rcmenu.h"
10:
11: #if __STDC__
12: # pragma hdrstop
13: # include <stdarg.h>
14: #else
15: # include <varargs.h>
16: #endif
17:
18: /********************** Global Data *************************/
19:
20: LEVELS LMenus[MAX_NEST];
21: int nestlev; /* current nesting level */
22: int echox, echoy; /* Location of item # echo area */
23: int debug; /* true to display sys commands */
24: char SysShell[80]; /* System command interpreter */
25:
26: /************************************************************
27: * main():
28: * Initialize the program and run
29: * the master menu
30: ************************************************************/
31:
32: main(argc, argv)
33: int argc;
34: char **argv;
35: {
36: char *mname = "menu";
37: int i, j;
38:
39: debug = 0; /* No debugging by default */
40:
41: /* Process command line options: */
42: for (i = 1; i < argc; i++)
43: if (argv[i][0] == '-')
44: {
45: switch (tolower(argv[i][1]))
46: {
47: case 'd': debug = TRUE;
48: break;
49:
50: default: fprintf(stderr, "Unknown option: '%s'\n",
51: argv[i]);
52: exit(0);
53: }
54: for (j = i; j < argc - 1; j++) /* compress */
55: argv[j] = argv[j + 1]; /* arg list */
56: argc--;
57: i--;
58: }
59:
60: init_win(); /* initialize curses */
61:
62: if (argc == 2)
63: mname = argv[1];
64:
65: nestlev = 0;
66: do_menu("", mname);
67: free_menus();
68: close_win();
69: return OK;
70: }
71:
72:
73: /************************************************************
74: * do_menu():
75: * Run a compiled menu file, supporting recursive
76: * calls for nested external menus.
77: * Default command/menu path is supplied as "path".
78: *************************************************************/
79:
80: int do_menu(path, file)
81: char *path, *file;
82: {
83: char pathname[MAX_PATH];
84:
85: strcpy(pathname, path);
86: if (*path)
87: strcat(pathname, "/");
88: strcat (pathname, file);
89: strcat (pathname, ".mnc");
90:
91: if (ld_menu(pathname) == ERROR)
92: return EXITALL;
93:
94: return sub_menu(0, path); /* run main menu in file */
95: }
96:
97:
98: /************************************************************
99: * ld_menu():
100: * Load a compiled menu object file from disk,
101: * into nesting level nestlev, allocating memory
102: * as required.
103: * For each menu in the menu file being loaded,
104: * compute screen placement as per spacing/columns
105: * specifications and the total number of items.
106: ************************************************************/
107:
108: int ld_menu(path)
109: char *path;
110: {
111: LEVELS *Levp = &LMenus[nestlev];
112: MENU *Mp;
113: ITEM *Ip;
114: MENU2 *M2p;
115:
116: FILE *fp;
117: int widest;
118: int i, j, k, l;
119:
120: if ((fp = fopen(path, "rb")) == NULL)
121: return fatal("Can't open %s", path);
122:
123: if (fread((Void *) &Levp->n_menus, sizeof (int), 1, fp)
124: != 1)
125: return fatal("Error reading menu count from %s", path);
126:
127: for (i = 0 ; i < Levp->n_menus; i++)
128: {
129: if (i < Levp -> max_menus)
130: M2p = Levp -> Menus[i];
131: else /* allocate memory for Menu */
132: {
133: M2p = Levp -> Menus[i] = (MENU2 *) malloc(sizeof(MENU2));
134: if (M2p == NULL)
135: return fatal("Out of memory loading %s", path);
136: Levp -> max_menus++;
137: M2p -> most items = O;
138: }
139:
140: Mp = &M2p -> Menu;
141:
142: if (fread((Void *) Mp, sizeof(MENU), 1, fp) != 1)
143: return fatal("Error reading Menu data from %s", path);
144:
145: /* Now determine screen placement strategy. */
146:
147: placement(Mp);
148:
149: M2p -> field_len = min(MAX_TXTWID,
150: (SCREEN_COLS / Mp -> columns) - 5);
151:
152: /* Read in each item, and assign screen coordinate info */
153: /* to each on-the-fly as per spacing/column parameters */
154:
155: for (j = O; j < Mp -> nitems; j++)
156: {
157: if (j < M2p -> most_items)
158: Ip = M2p -> Items[j];
159: else
160: {
161: Ip = M2p -> Items[j] = (ITEM *) malloc(sizeof(ITEM));
162: if (Ip == NULL)
163: return fatal("Out of RAM in %s, menu #%d/item #%d",
164: path, i,j);
165: M2p -> most_items++;
166: }
167: if (fread((Void *) Ip, sizeof(ITEM), 1, fp) != 1)
168: return fatal("Error reading %s", path);
169:
170: Ip -> text[M2p -> field_len - 1] = '\0'; /* truncate */
171:
172: if ((Ip -> acttyp == ACT_LMENU ||
173: Ip -> acttyp == ACT_EMENU) &&
174: strlen(Ip -> text) + 6 < M2p -> field_len)
175: {
176: int limit;
177:
178: limit = min (Mp -> widest + 2,
179: M2p -> field_len - 7);
180: for (k = strlen(Ip -> text);
181: k < limit && k < (MAX_TXTWID - 6); k++)
182: strcat(Ip -> text, " ");
183: strcat(Ip -> text, "(MENU)");
184: }
185:
186: M2p -> coords[j] .ypos =
187: HOME_Y + (j % (MAX_IROWS / Mp -> spacing))
188: * Mp -> spacing;
189:
190: widest = Mp -> widest;
191: M2p -> coords[j].xpos = HOME_X +
192: (
193: (Mp -> columns == 1)
194: ?
195: (
196: (SCREEN_COLS - HOME_X -
197: (widest + ((widest < 66) ? 14 : 6) )) / 2
198: )
199: :
200: (j / (MAX_IROWS / Mp -> spacing) *
201: (SCREEN_COLS / Mp -> columns))
202: );
203:
204:
205: M2p -> coords[j].spaces_needed =
206: min(M2p -> field_len, Mp -> widest)
207: - strlen(Ip -> text);
208: }
209: }
210: fclose(fp);
211: return OK;
212: }
213:
214:
215: /************************************************************
216: * placement():
217: * Calculate values for columns and spacing
218: * for the given Menu:
219: ************************************************************/
220:
221: Void placement(Mp)
222: MENU *Mp;
223: {
224: int columns = Mp -> columns;
225: int spacing = Mp -> spacing;
226: int nitems = Mp -> nitems;
227:
228: /* Step 1: fill in real values if either */
229: /* columns or spacing was not specified: */
230:
231: if (spacing == DEFAULT && columns == DEFAULT)
232: {
233: if (nitems <= (MAX_IROWS / 2))
234: {
235: Mp -> columns = 1;
236: Mp -> spacing = 2;
237: }
238: else if (nitems <= MAX_IROWS)
239: if ((Mp -> widest * 2 + 5) <= SCREEN_COLS)
240: Mp -> columns = Mp -> spacing = 2;
241: else
242: Mp -> columns = Mp -> spacing = 1;
243: else
244: {
245: Mp -> spacing = 1;
246: Mp -> columns = (nitems - 1) / MAX_IROWS + 1;
247: }
248: }
249: else if (spacing == DEFAULT)
250: Mp -> spacing =
251: (nitems <= (MAX_IROWS / 2)) ? 2 : 1;
252: else if (columns == DEFAULT)
253: if (Mp -> spacing == 1)
254: Mp -> columns = (nitems - 1) / MAX_IROWS + 1;
255: else
256: Mp -> columns = (nitems - 1) / (MAX_IROWS / 2) + 1;
257:
258: /* Step 2: Adjust if out of range: */
259:
260: while (MAX_IROWS / Mp -> spacing * Mp -> columns < nitems)
261: if (Mp -> spacing != 1)
262: Mp -> spacing = 1;
263: else
264: Mp -> columns++;
265: return;
266: }
267:
268:
269: /************************************************************
270: * free_menus():
271: * Free up memory allocated for ALL menu items:
272: ************************************************************/
273:
274: Void free_menus()
275: {
276: int i, j, k;
277: MENU2 *m2p;
278:
279: for (i = O; i < MAX_NEST; i++)
280: for (j = O; j < LMenus[i].max_menus; j++)
281: {
282: m2p = LMenus[i].Menus[j];
283: for (k = 0; k < m2p -> most_items; k++)
284: free(m2p -> Items[k]);
285: free(m2p);
286: }
287: }
288:
289:
290: /************************************************************
291: * fatal(): Complain and exit.
292: ************************************************************/
293:
294: #if _STDC_ /* use ANSI variable-#-of-args method */
295:
296: int fatal (char *fmt, ...)
297: {
298: char ftext[80], ffmt[55];
299: va_list arglist;
300:
301: va_start(arglist, fmt);
302:
303: #else /* or old varargs method: */
304:
305: int fatal(fmt, va_alist)
306: char *fmt;
307: va_dcl
308: {
309: char ftext[80], ffmt[55];
310: va_list arglist;
311:
312: va_start(arglist);
313: #endif
314:
315: vsprintf(ffmt, fmt, arglist);
316: sprintf(ftext, "Fatal error in rmenu: %s", ffmt);
317:
318: put_msg(1, ftext);
319:
320: va_end(arglist);
321: return ERROR;
322: }
323:
324:
325: /************************************************************
326: * put_msg(): Display a message on the menu screen
327: * Return the character typed to continue
328: ************************************************************/
329:
330: #if _STDC__
331: int put_msg (int bell, char *fmt, ...)
332: {
333: char ftext[80];
334: va_list arglist;
335: char c;
336:
337: va_start(arglist, fmt);
338:
339: #else
340: int put_msg(bell, fmt, va_alist)
341: int bell;
342: char *fmt;
343: va_dcl
344: {
345: char ftext[80];
346: va_list arglist;
347: char c;
348:
349: va_start(arglist);
350: #endif
351:
352: move(ERR_ROW, 0);
353: hlight_on();
354:
355: if (bell)
356: beep();
357:
358: /* vwprintw(stdscr, fmt, arglist); */
359: vsprintf(ftext, fmt, arglist);
360: addstr(ftext);
361: va_end(arglist);
362: refresh();
363:
364: c = getch();
365:
366: move (ERR_ROW, 0);
367: hlight_end();
368: clrtoeol();
369: refresh();
370: return c;
371: }
/* End of File */