]> andersk Git - moira.git/blob - clients/moira/menu.c
POSIX uses fcntl.h not sys/fcntl.h
[moira.git] / clients / moira / menu.c
1 /*
2  * Copyright 1987 by the Massachusetts Institute of Technology.
3  * For copying and distribution information, see the file
4  * "mit-copyright.h".
5  *
6  * $Source$
7  * $Author$
8  * $Header$
9  *
10  * Generic menu system module.
11  *
12  * Basically, we define an enormous tree structure which represents the
13  * menu.  Some extra pieces (ml_command, ma_doc) get thrown in so we can
14  * also use the structure for a command-based system.
15  *
16  * By making the menu descriptions so general, we can ease porting to just
17  * about anything.
18  */
19
20 #ifndef lint
21 static char rcsid_menu_c[] = "$Header$";
22
23 #endif lint
24
25 #include <mit-copyright.h>
26 #include <sys/types.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <signal.h>
30 #include <curses.h>
31 #ifdef POSIX
32 #include <unistd.h>
33 #include <termios.h>
34 #endif /* POSIX */
35 #include <ctype.h>
36 #ifndef sun
37 #include <varargs.h>
38 #endif
39 #include <com_err.h>
40 #include <moira.h>
41 #include "menu.h"
42
43 #ifndef __STDC__
44 #define const
45 #endif
46
47 #define MAX(A,B)        ((A) > (B) ? (A) : (B))
48 #define MIN(A,B)        ((A) < (B) ? (A) : (B))
49 #define CTL(ch)         ((ch) & 037)
50
51 #define MIN_INPUT 2             /* Minimum number of lines for input window */
52
53 extern int interrupt;           /* will be set if ^C is received */
54 extern FILE *fdopen();
55 extern int getpid();
56 extern char *calloc();
57 extern char *whoami;
58
59 FILE *log_file = (FILE *) NULL;         /* file stream of log file */
60 int more_flg = 1;
61
62 #ifdef POSIX
63 extern char *malloc();
64 #endif
65
66 /* Structure for holding current displayed menu */
67 struct menu_screen {
68     WINDOW *ms_screen;          /* Window for this menu */
69     WINDOW *ms_title;           /* Title subwindow */
70     WINDOW *ms_menu;            /* Menu subwindow */
71     WINDOW *ms_input;           /* Input subwindow */
72     int ms_input_y;             /* Input subwindow reference coordinate */
73 }          *cur_ms;
74
75 #define NULLMS ((struct menu_screen *) 0)
76
77 Menu *top_menu;                 /* Root for command search */
78 int parsed_argc;                /* used by extern routines to get additional */
79 char **parsed_argv;             /*   comand line input */
80
81 /*
82  * Hook function to cause error messages to be printed through
83  * curses instead of around it.  Takes at most 5 args to the
84  * printf string (crock...)
85  */
86
87 void
88 menu_com_err_hook(who, code, fmt, arg1, arg2, arg3, arg4, arg5)
89     const char *who;
90     long code;
91     const char *fmt;
92     caddr_t arg1, arg2, arg3, arg4, arg5;
93 {
94     char buf[BUFSIZ], *cp;
95
96     (void) strcpy(buf, who);
97     for (cp = buf; *cp; cp++);
98     *cp++ = ':';
99     *cp++ = ' ';
100     if (code) {
101         (void) strcpy(cp, error_message(code));
102         while (*cp)
103             cp++;
104     }
105     sprintf(cp, fmt, arg1, arg2, arg3, arg4, arg5);
106     Put_message(buf);
107 }
108
109 /*
110  * Start_menu takes a menu as an argument.  It initializes curses u.s.w.,
111  * and a quit in any submenu should unwind back to here.  (it might not,
112  * if user functions which run their own menus don't cooperate.)
113  * Start_menu should only be called once, at the start of the program.
114  */
115 Start_menu(m)
116     Menu *m;
117 {
118     struct menu_screen *make_ms();
119 #ifdef __STDC__
120     register void (*old_hook)(const char *, long, const char *, va_list) = set_com_err_hook(menu_com_err_hook);
121 #else
122     register void (*old_hook)() = set_com_err_hook(menu_com_err_hook);
123 #endif
124     
125     if (initscr() == (WINDOW *)ERR) {
126         fputs("Can't initialize curses!\n", stderr);
127         Start_no_menu(m);
128     } else {
129         (void) raw();           /* We parse & print everything ourselves */
130         (void) noecho();
131         cur_ms = make_ms(0);    /* So we always have some current */
132                                 /* menu_screen */ 
133         /* Run the menu */
134         (void) Do_menu(m, -1, (char **) NULL);
135     }
136     (void) set_com_err_hook(old_hook);
137     Cleanup_menu();
138 }
139
140 Cleanup_menu()
141 {
142     if (cur_ms) {
143         (void) wclear(cur_ms->ms_screen);
144         (void) wrefresh(cur_ms->ms_screen);
145     }
146     endwin();
147 }
148     
149
150 /* Like Start_menu, except it doesn't print menus and doesn't use curses */
151 Start_no_menu(m)
152     Menu *m;
153 {
154     cur_ms = NULLMS;
155     COLS = 80;
156     /* Run the menu */
157     (void) Do_menu(m, -1, (char **) NULL);
158 }
159
160 /*
161  * Create a new menu screen template with the specified menu length
162  * and return it.
163  */
164 struct menu_screen *
165 make_ms(length)
166     int length;
167 {
168     struct menu_screen *ms;
169
170     if (MAX_TITLE + length + MIN_INPUT > LINES) {
171         fputs("Menu too big!\n", stderr);
172         exit(2);
173     }
174
175     ms = (struct menu_screen *) malloc(sizeof(struct menu_screen));
176
177     ms->ms_screen = newwin(0, 0, 0, 0);
178     ms->ms_title = subwin(ms->ms_screen, MAX_TITLE, 0, 0, 0);
179     ms->ms_menu = subwin(ms->ms_screen,
180                          length, 0, MAX_TITLE, 0);
181     ms->ms_input = subwin(ms->ms_screen, 0, 0,
182                           ms->ms_input_y = MAX_TITLE + length,
183                           0);
184
185     scrollok(ms->ms_input, TRUE);
186     (void) wmove(ms->ms_input, 0, 0);
187     (void) wclear(ms->ms_screen);
188
189     return (ms);
190 }
191
192 /*
193  * This routine destroys a menu_screen.
194  */
195 destroy_ms(ms)
196     struct menu_screen *ms;
197 {
198     delwin(ms->ms_title);
199     delwin(ms->ms_menu);
200     delwin(ms->ms_input);
201     delwin(ms->ms_screen);
202     free((char *) ms);
203 }
204
205 /*
206  * This guy actually puts up the menu
207  * Note: if margc < 0, no 'r' option will be displayed (i.e., on the
208  * top level menu)
209  */
210 int 
211 Do_menu(m, margc, margv)
212     Menu *m;
213     int margc;
214     char *margv[];
215 {
216     struct menu_screen *my_ms = NULLMS, *old_cur_ms = NULLMS;
217     char argvals[MAX_ARGC][MAX_ARGLEN]; /* This is where args are stored */
218     char buf[MAX_ARGC * MAX_ARGLEN];
219     char *argv[MAX_ARGC];
220     int line;
221     int i;
222     struct menu_line *command, *Find_command();
223     int argc;
224     int quitflag, is_topmenu = (margc < 0);
225     int toggle_logging();
226     
227     /* Entry function gets called with old menu_screen still current */
228     if (m->m_entry != NULLFUNC) {
229         if (m->m_entry(m, margc, margv) == DM_QUIT)
230             return DM_NORMAL;
231         if (parsed_argc > 0) {
232             margc = parsed_argc + 1;
233             margv = --parsed_argv;
234         } else {
235             margc--;
236             margv++;
237         }
238     }
239
240     parsed_argc = 0;
241
242     /* The following get run only in curses mode */
243     if (cur_ms != NULLMS) {
244         /* Get a menu_screen */
245         old_cur_ms = cur_ms;
246         /* 2 is for the 2 obligatory lines; quit and toggle */
247         cur_ms = my_ms = make_ms(m->m_length + 2 + (is_topmenu ? 0 : 1));
248
249         /* Now print the title and the menu */
250         (void) wclear(my_ms->ms_menu);
251         (void) wmove(my_ms->ms_title, 0, MAX(0, (COLS -
252                                                  strlen(m->m_title)) >> 1));
253         (void) wstandout(my_ms->ms_title);
254         (void) waddstr(my_ms->ms_title, m->m_title);
255         (void) wstandend(my_ms->ms_title);
256
257         for (line = 0; line < m->m_length; line++) {
258             int len = strlen(m->m_lines[line].ml_command);
259             if (len > 12) len=12;
260             
261             (void) wmove(my_ms->ms_menu, line, 0);
262             
263             (void) wprintw(my_ms->ms_menu, "%2d. (%s)%*s %s.", line + 1,
264                            m->m_lines[line].ml_command,
265                            12-len, "",
266                            m->m_lines[line].ml_doc);
267         }
268         (void) wmove(my_ms->ms_menu, line++, 0);
269         if (!is_topmenu) {
270             (void) waddstr(my_ms->ms_menu,
271                            " r. (return)       Return to previous menu.");
272             (void) wmove(my_ms->ms_menu, line++, 0);
273         }
274         (void) waddstr(my_ms->ms_menu,
275                            " t. (toggle)       Toggle logging on and off.");
276         (void) wmove(my_ms->ms_menu, line, 0);
277         (void) waddstr(my_ms->ms_menu, " q. (quit)         Quit.");
278     } else {
279         Put_message(m->m_title);
280         for (line = 0; line < m->m_length; line++) {
281             sprintf(buf, "%2d. (%s)%*s %s.", line + 1,
282                     m->m_lines[line].ml_command,
283                     12 - strlen(m->m_lines[line].ml_command), "",
284                     m->m_lines[line].ml_doc);
285             Put_message(buf);
286         }
287         if (!is_topmenu)
288             Put_message(" r. (return)       Return to previous menu.");
289         Put_message(" t. (toggle)       Toggle logging on and off.");
290         Put_message(" q. (quit)         Quit.");
291         Put_message(" ?.                Print this information.");
292     }
293
294     for (;;) {
295         /* This will be set by a return val from func or submenu */
296         quitflag = DM_NORMAL;
297         /* This is here because we may be coming from another menu */
298         if (cur_ms != NULL)
299             touchwin(my_ms->ms_screen);
300         if (margc > 1) {
301             /* Initialize argv */
302             for (argc = 0; argc < MAX_ARGC; argc++)
303               argv[argc] = argvals[argc];
304             argc = margc - 1;
305             for (i = 1; i < margc; i++)
306               strcpy(argvals[i - 1], margv[i]);
307             margc = 0;
308         } else {
309             /* Get a command */
310             if (!Prompt_input("Command: ", buf, sizeof(buf))) {
311                 if (cur_ms == NULLMS &&
312                     feof(stdin))
313                   sprintf(buf, "quit");
314                 else
315                   continue;
316             }
317             /* Parse it into the argument list */
318             /* If there's nothing there, try again */
319             /* Initialize argv */
320             for (argc = 0; argc < MAX_ARGC; argc++)
321               argv[argc] = argvals[argc];
322
323             if ((argc = Parse_words(buf, argv, MAX_ARGLEN)) == 0)
324               continue;
325         }
326         if ((line = atoi(argv[0])) > 0 && line <= m->m_length) {
327             command = &m->m_lines[line - 1];
328         }
329         else if ((!is_topmenu &&
330                   (!strcmp(argv[0], "r") || !strcmp(argv[0], "return")))
331                  || !strcmp(argv[0], "q") || !strcmp(argv[0], "quit")) {
332                  
333             /* here if it's either return or quit */
334             if (cur_ms != NULLMS) {
335                 cur_ms = old_cur_ms;
336                 destroy_ms(my_ms);
337             }
338             if (m->m_exit != NULLFUNC)
339                 m->m_exit(m);
340             return (*argv[0] == 'r' ? DM_NORMAL : DM_QUIT);
341         }
342         else if (argv[0][0] == '?') {
343             for (line = 0; line < m->m_length; line++) {
344                 sprintf(buf, "%2d. (%s)%*s %s.", line + 1,
345                         m->m_lines[line].ml_command,
346                         12 - strlen(m->m_lines[line].ml_command), "",
347                         m->m_lines[line].ml_doc);
348                 Put_message(buf);
349             }
350             if (!is_topmenu)
351                 Put_message(" r. (return)       Return to previous menu.");
352             Put_message(" t. (toggle)       Toggle logging on and off.");
353             Put_message(" q. (quit)         Quit.");
354             continue;
355         }
356         else if (!strcmp(argv[0], "t") || !strcmp(argv[0], "toggle")) {
357             toggle_logging(argc, argv);
358             continue;
359         } 
360         /* finally, try to find it using Find_command */
361         else if ((command = Find_command(m, argvals[0])) ==
362                  (struct menu_line *) 0) {
363             sprintf(buf, "Command not recognized: %s\n", argvals[0]);
364             Put_message(buf);
365             continue;
366         }
367         /* If we got to here, command is a valid menu_line */
368         /* Send the offical command name into the argv */
369         (void) strcpy(argvals[0], command->ml_command);
370         /* Show that we're working on it */
371         Put_message(command->ml_doc);
372         /* Print args that we've already got */
373         for (i = 1; i < argc; i++) {
374             if (command->ml_args[i].ma_prompt == NULL)
375                 break;
376             (void) sprintf(buf, "%s%s", command->ml_args[i].ma_prompt,
377                            argv[i]);
378             Put_message(buf);
379         }
380         /* Get remaining arguments, if any */
381         for (; argc < command->ml_argc; argc++) {
382             if (!Prompt_input(command->ml_args[argc].ma_prompt,
383                               argvals[argc], sizeof(argvals[argc])))
384                 goto punt_command;
385         }
386         parsed_argc = argc - command->ml_argc;
387         parsed_argv = &(argv[command->ml_argc]);
388         if (command->ml_function != NULLFUNC) {
389             /* If it's got a function, call it */
390             quitflag = command->ml_function(argc, argv);
391         }
392         else if (command->ml_submenu != NULLMENU) {
393             /* Else see if it is a submenu */
394             quitflag = Do_menu(command->ml_submenu, argc, argv);
395         }
396         else {
397             /* If it's got neither, something is wrong */
398             Put_message("*INTERNAL ERROR: NO FUNCTION OR MENU FOR LINE*");
399         }
400         if (quitflag == DM_QUIT) {
401             if (cur_ms != NULLMS) {
402                 cur_ms = old_cur_ms;
403                 destroy_ms(my_ms);
404             }
405             if (m->m_exit != NULLFUNC)
406                 m->m_exit(m);
407             parsed_argc = 0;
408             return (DM_QUIT);
409         }
410     punt_command:
411         parsed_argc = 0;
412     }
413 }
414
415 refresh_screen()
416 {
417     if (cur_ms != NULLMS) {
418         touchwin(cur_ms->ms_screen);
419         refresh_ms(cur_ms);
420     }
421 }
422
423
424 /* Prompt the user for input in the input window of cur_ms */
425 int Prompt_input(prompt, buf, buflen)
426     char *prompt;
427     char *buf;
428     int buflen;
429 {
430     int c;
431     char *p;
432     int y, x, oldx, oldy;
433
434     if (cur_ms != NULLMS) {
435         more_flg = 1;
436         getyx(cur_ms->ms_input, y, x);
437         (void) wmove(cur_ms->ms_input, y, 0);
438
439         refresh_screen();
440         (void) waddstr(cur_ms->ms_input, prompt);
441         getyx(cur_ms->ms_input, y, x);
442
443         oldx = x;
444         oldy = y;
445         p = buf;
446         while(1) {
447             (void) wmove(cur_ms->ms_input, y, x);
448                 (void) touchwin(cur_ms->ms_screen);
449             (void) wclrtoeol(cur_ms->ms_input);
450             (void) wrefresh(cur_ms->ms_input);
451             c = getchar() & 0x7f;
452             switch (c) {
453             case CTL('C'):
454                 *p = '\0';
455                 return 0;
456             case CTL('Z'):
457                 (void) kill(getpid(), SIGTSTP);
458                 touchwin(curscr);
459                 break;
460             case CTL('L'):
461                 (void) wclear(cur_ms->ms_input);
462                 (void) waddstr(cur_ms->ms_input, prompt);
463                 (void) touchwin(cur_ms->ms_input);
464                 (void) move(LINES - 1, 0);
465                 (void) wrefresh(curscr);
466                 getyx(cur_ms->ms_input, y, x);
467                 oldy = y;
468                 oldx = x;
469                 p = buf;
470                 break;
471
472             case '\n':
473             case '\r':
474                 goto end_input;
475                 /* these should be obtained by doing ioctl() on tty */
476             case '\b':
477             case '\177':
478                 if (p > buf) {
479                     p--;
480                     x--;
481                     if (x < 0) {
482                         (void) wmove(cur_ms->ms_input, y, 0);
483                         (void) wclrtoeol(cur_ms->ms_input);
484                         y--;
485                         x = cur_ms->ms_input->_maxx-1;
486                     }
487                 }
488                 break;
489             case CTL('U'):
490             case CTL('G'):
491             case CTL('['):
492                 x = oldx;
493                 y = oldy;
494                 p = buf;
495                 break;
496             default:
497                 /* (buflen - 1) leaves room for the \0 */
498                 if (isprint(c) && (p - buf < buflen - 1)) {
499                     (void) waddch(cur_ms->ms_input, c);
500                     *p++ = c;
501                     x++;
502                     if (x >= cur_ms->ms_input->_maxx) {
503                         x = 0;
504                         y++;
505                     }
506                 } else
507                     putchar(CTL('G'));
508                 break;
509             }
510         }
511     end_input:
512         (void) waddch(cur_ms->ms_input, '\n');
513         
514         (void) wclrtoeol(cur_ms->ms_input);
515         refresh_ms(cur_ms);
516         *p = '\0';
517         Start_paging();
518         goto gotit;
519     } else {
520         printf("%s", prompt);
521         if (gets(buf) == NULL)
522             return 0;
523         if (interrupt) {
524             interrupt = 0;
525             return 0;
526         }
527         Start_paging();
528         goto gotit;
529     }
530 gotit:
531     strcpy(buf, strtrim(buf));
532     return 1;
533 }
534
535 /* Prompt the user for input in the input window of cur_ms, but don't echo
536    and allow some control characters */
537 int Password_input(prompt, buf, buflen)
538     char *prompt;
539     char *buf;
540     int buflen;
541 {
542     int c;
543     char *p;
544     int y, x, oldx;
545
546     if (cur_ms != NULLMS) {
547         more_flg = 1;
548         getyx(cur_ms->ms_input, y, x);
549         (void) wmove(cur_ms->ms_input, y, 0);
550
551         touchwin(cur_ms->ms_screen);
552         refresh_ms(cur_ms);
553         (void) waddstr(cur_ms->ms_input, prompt);
554         getyx(cur_ms->ms_input, y, x);
555
556         oldx = x;
557         for (p = buf; p - buf < buflen;) {
558             (void) wmove(cur_ms->ms_input, y, x);
559             (void) wclrtoeol(cur_ms->ms_input);
560             refresh_ms(cur_ms);
561             c = getchar() & 0x7f;
562             switch (c) {
563             case CTL('C'):
564                 return 0;
565             case CTL('Z'):
566                 (void) kill(getpid(), SIGTSTP);
567                 touchwin(curscr);
568                 break;
569             case CTL('L'):
570                 (void) wclear(cur_ms->ms_input);
571                 (void) waddstr(cur_ms->ms_input, prompt);
572                 refresh_ms(cur_ms);
573                 (void) move(LINES - 1, 0);
574                 (void) wrefresh(curscr);
575                 getyx(cur_ms->ms_input, y, x);
576                 break;
577             case '\n':
578             case '\r':
579                 (void) waddch(cur_ms->ms_input, '\n');
580
581                 (void) wclrtoeol(cur_ms->ms_input);
582                 refresh_ms(cur_ms);
583                 *p = '\0';
584                 Start_paging();
585                 return 1;
586             case '\b':
587             case '\177':
588                 if (p > buf) {
589                     p--;
590                     x--;
591                 }
592                 break;
593             case CTL('U'):
594                 x = oldx;
595                 p = buf;
596                 break;
597             default:
598                 *p++ = c;
599                 break;
600             }
601         }
602     }
603     else {
604 #ifdef POSIX
605         struct termios ttybuf, nttybuf;
606 #else
607         struct sgttyb ttybuf, nttybuf;
608 #endif /* POSIX */
609         printf("%s", prompt);
610         /* turn off echoing */
611 #ifdef POSIX
612         tcgetattr(0, &ttybuf);
613         nttybuf = ttybuf;
614         nttybuf.c_lflag &= ~ECHO;
615         tcsetattr(0, TCSANOW, &nttybuf);
616         if (gets(buf) == NULL) {
617             tcsetattr(0, TCSANOW, &ttybuf);
618             putchar('\n');
619             return 0;
620         }
621         putchar('\n');
622         (void) ioctl(0, TCSETA, (char *)&ttybuf);
623 #else
624         (void) ioctl(0, TIOCGETP, (char *)&ttybuf);
625         nttybuf = ttybuf;
626         nttybuf.sg_flags &= ~ECHO;
627         (void)ioctl(0, TIOCSETP, (char *)&nttybuf);
628         if (gets(buf) == NULL) {
629             (void) ioctl(0, TIOCSETP, (char *)&ttybuf);
630             putchar('\n');
631             return 0;
632         }
633         putchar('\n');
634         (void) ioctl(0, TIOCSETP, (char *)&ttybuf);
635 #endif /* POSIX */
636         Start_paging();
637         return 1;
638     }
639     return 0;
640 }
641
642 int lines_left;
643
644 /* Start paging */
645 /* This routine will cause the most recently put message to be the
646    one at the top of the screen when a ---More--- prompt is displayed */
647 Start_paging()
648 {
649     if (cur_ms != NULLMS) {
650         lines_left = LINES - cur_ms->ms_input_y - 1;
651     }
652     else {
653         lines_left = 23;
654     }
655 }
656
657 /* Turn off paging */
658 Stop_paging()
659 {
660     lines_left = -1;
661 }
662
663 /* Print a message in the input window of cur_ms.  */
664 Put_message(msg)
665 char *msg;
666 {
667     char *copy, *line, *s;
668
669     copy = (char *) malloc((u_int)COLS);
670     s = line = msg;
671     if (log_file) {     /* if we're doing logging; we assume that the */
672                         /* file has already been opened. */
673         (void) fprintf(log_file, "%s\n", msg);
674         fflush(log_file);
675     } 
676
677     while(*s++) {
678         if (s - line >= COLS-1) {
679             (void) strncpy(copy, line, COLS-1);
680             line += COLS-1;
681         } else if (*s == '\n') {
682             *s = '\0';
683             (void) strcpy(copy, line);
684             line = ++s;
685         } else
686             continue;
687         Put_line(copy);
688     }
689     Put_line(line);
690     free(copy);
691 }
692
693 /* Will be truncated to COLS characters.  */
694 Put_line(msg)
695 char *msg;
696 {
697     int y, x, i;
698     char *msg1, chr;
699
700     if (!more_flg)
701         return;
702
703     if (lines_left >= 0) {
704         if (--lines_left == 0) {
705             /* Give the user a more prompt */
706             if (cur_ms != NULLMS) {
707                 (void) wstandout(cur_ms->ms_input);
708                 (void) wprintw(cur_ms->ms_input, "---More---");
709                 (void) wstandend(cur_ms->ms_input);
710                 refresh_ms(cur_ms);
711                 chr = getchar() & 0x7f;/* We do care what it is */
712                 if (chr == 'q' || chr == 'Q' || chr == 3 /* ^C */) {
713                     more_flg = 0;
714                     return;
715                 }
716                 getyx(cur_ms->ms_input, y, x);
717                 /* x is a bitbucket; avoid lint problems */
718                 x=x;
719                 (void) wmove(cur_ms->ms_input, y, 0);
720                 (void) wclrtoeol(cur_ms->ms_input);
721             }
722             else {
723                 printf("---More (hit return)---");
724                 getchar();
725             }
726             Start_paging();     /* Reset lines_left */
727         }
728     }
729
730     if (cur_ms != NULLMS) {
731         msg1 = (char *) calloc((u_int)COLS, 1);
732         (void) strncpy(msg1, msg, COLS-1);
733         for (i = strlen(msg1); i < COLS - 1; i++)
734             msg1[i] = ' ';
735         (void) wprintw(cur_ms->ms_input, "%s\n", msg1);
736     }
737     else {
738         puts(msg);
739     }
740 }
741
742 /* Refresh a menu_screen onto the real screen */
743 refresh_ms(ms)
744     struct menu_screen *ms;
745 {
746     (void) wrefresh(ms->ms_title);
747     (void) wrefresh(ms->ms_menu);
748     (void) wrefresh(ms->ms_input);
749 }
750
751 /* Parse buf into a list of words, which will be placed in strings specified by
752    argv.  Space for these strings must have already been allocated.
753    Only the first n characters of each word will be copied */
754 Parse_words(buf, argv, n)
755     char *buf;
756     char *argv[];
757 int n;
758
759 {
760     char *start, *end;          /* For sausage machine */
761     int argc;
762
763     start = buf;
764     for (argc = 0; argc < MAX_ARGC; argc++) {
765         while (isspace(*start))
766             start++;            /* Kill whitespace */
767         if (*start == '\0')
768             break;              /* Nothing left */
769         /* Now find the end of the word */
770         for (end = start; *end != '\0' && !isspace(*end); end++);
771         (void) strncpy(argv[argc], start, MIN(end - start, n)); /* Copy it */
772         argv[argc][MIN(end - start, n - 1)] = '\0';     /* Terminate */
773         start = end;
774     }
775     return (argc);
776 }
777
778 /* This is the internal form of Find_command, which recursively searches
779    for a menu_line with command command in the specified menu */
780 /* It will search to a maximum depth of d */
781 struct menu_line *
782 find_command_from(c, m, d)
783     char *c;
784     struct menu *m;
785     int d;
786 {
787     int line;
788     struct menu_line *maybe;
789
790     if (d < 0)
791         return ((struct menu_line *) 0);        /* Too deep! */
792     for (line = 0; line < m->m_length; line++) {
793         if (!strcmp(c, m->m_lines[line].ml_command)) {
794             return (&m->m_lines[line]);
795         }
796     }
797     for (line = 0; line < m->m_length; line++) {
798         if (m->m_lines[line].ml_submenu != NULLMENU  &&
799             (maybe = find_command_from(c, m->m_lines[line].ml_submenu, d - 1))
800                 != (struct menu_line *) 0) {
801             return (maybe);
802         }
803     }
804     /* If we got to here, nothing works */
805     return ((struct menu_line *) 0);
806 }
807
808 /* Find_command searches down the current menu tree */
809 /* And returns a pointer to a menu_line with the specified command name */
810 /* It returns (struct menu_line *) 0 if none is found */
811 struct menu_line *
812 Find_command(m, command)
813     Menu *m;
814     char *command;
815 {
816     if (m == NULLMENU) {
817         return ((struct menu_line *) 0);
818     }
819     else {
820         return (find_command_from(command, m, MAX_MENU_DEPTH));
821     }
822 }
823
824 /*ARGSUSED*/
825 int
826 toggle_logging(argc, argv)
827     int argc;
828     char *argv[];
829 {
830     int pid;
831     char buf[BUFSIZ];
832     
833     if (log_file == (FILE *) NULL) {
834         pid = getpid();
835         if (!whoami) {
836             Put_message("I've lost my SENSE of DIRECTION!  I have no IDEA who I AM!");
837             Put_message("My God... You've turned him into a DEMOCRAT!!");
838             Put_message("               -- Doonesbury");
839             Put_message("");
840             Put_message("translation:  your log file can be found in \"/usr/tmp/a.out.pid\".");
841             whoami = "a.out";
842             (void) sprintf(buf, "/usr/tmp/%s-log.%d", whoami, pid);
843         }
844         else
845             (void) sprintf(buf, "/usr/tmp/%s-log.%d", whoami, pid);
846
847         /* open the file */
848         log_file = fopen(buf,"a");
849
850         if (log_file == (FILE *) NULL)
851             Put_message("Open of log file failed.  Logging is not on.");
852         else
853             Put_message("Log file successfully opened.");
854     } 
855     else { /* log_file is a valid pointer; turn off logging. */
856         (void) fflush(log_file);
857         (void) fclose(log_file);
858         log_file = (FILE *) NULL;
859         Put_message("Logging off.");
860     }
861     return(DM_NORMAL);
862
This page took 0.102693 seconds and 5 git commands to generate.