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