Listing 2

  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 = 0;
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 = 0; 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 = 0; i < MAX_NEST; i++)
280:         for (j = 0; 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 */