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