3f4696c6bcde84140a5b6095b53a102f4afe3498
[games.git] / gnu / usr.bin / man / man / man.c
1 /*
2  * man.c
3  *
4  * Copyright (c) 1990, 1991, John W. Eaton.
5  *
6  * You may distribute under the terms of the GNU General Public
7  * License as specified in the file COPYING that comes with the man
8  * distribution.
9  *
10  * John W. Eaton
11  * jwe@che.utexas.edu
12  * Department of Chemical Engineering
13  * The University of Texas at Austin
14  * Austin, Texas  78712
15  *
16  * $FreeBSD: src/gnu/usr.bin/man/man/man.c,v 1.37.2.10 2003/02/14 15:38:51 ru Exp $
17  * $DragonFly: src/gnu/usr.bin/man/man/man.c,v 1.8 2008/04/04 19:25:46 swildner Exp $
18  */
19
20 #define MAN_MAIN
21
22 #include <sys/file.h>
23 #include <sys/stat.h>
24 #include <sys/param.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #include <libgen.h>
28 #ifdef __DragonFly__
29 #include <locale.h>
30 #include <langinfo.h>
31 #endif
32 #include <stdio.h>
33 #include <string.h>
34 #include <signal.h>
35 #if HAVE_LIBZ > 0
36 #include <zlib.h>
37 #endif
38 #include "config.h"
39 #include "gripes.h"
40 #include "version.h"
41
42 #ifdef POSIX
43 #include <unistd.h>
44 #else
45 #ifndef R_OK
46 #define R_OK 4
47 #endif
48 #endif
49
50 #ifdef SECURE_MAN_UID
51 extern uid_t getuid ();
52 extern int setuid ();
53 #endif
54
55 #ifdef STDC_HEADERS
56 #include <stdlib.h>
57 #else
58 extern char *malloc ();
59 extern char *getenv ();
60 extern void free ();
61 extern int system ();
62 extern int strcmp ();
63 extern int strncmp ();
64 extern int exit ();
65 extern int fflush ();
66 extern int printf ();
67 extern int fprintf ();
68 extern FILE *fopen ();
69 extern int fclose ();
70 extern char *sprintf ();
71 #endif
72
73 extern char **glob_filename ();
74 extern int is_newer ();
75 extern int is_directory ();
76 extern int do_system_command ();
77
78 char *prognam;
79 static char *pager;
80 static char *machine;
81 static char *manp;
82 static char *manpathlist[MAXDIRS];
83 static char *shortsec;
84 static char *longsec;
85 static char *colon_sep_section_list;
86 static char **section_list;
87 static char *roff_directive;
88 static int apropos;
89 static int whatis;
90 static int findall;
91 static int print_where;
92
93 #ifdef __DragonFly__
94 static char *locale, *locale_opts, *locale_nroff, *locale_codeset;
95 static char locale_terr[3], locale_lang[3];
96 static char *man_locale;
97 static int use_man_locale;
98 static int use_original;
99 struct ltable {
100         char *lcode;
101         char *nroff;
102 };
103 static struct ltable ltable[] = {
104         {"KOI8-R", "koi8-r"},
105         {"ISO8859-1", "latin1"},
106         {"ISO8859-15", "latin1"},
107         {NULL}
108 };
109 #endif
110
111 static int troff = 0;
112
113 int debug;
114
115 #ifdef HAS_TROFF
116 #ifdef __DragonFly__
117 static char args[] = "M:P:S:adfhkm:op:tw?";
118 #else
119 static char args[] = "M:P:S:adfhkm:p:tw?";
120 #endif
121 #else
122 #ifdef __DragonFly__
123 static char args[] = "M:P:S:adfhkm:op:w?";
124 #else
125 static char args[] = "M:P:S:adfhkm:p:w?";
126 #endif
127 #endif
128
129 #ifdef SETREUID
130 uid_t ruid;
131 uid_t euid;
132 gid_t rgid;
133 gid_t egid;
134 #endif
135
136 int
137 main (argc, argv)
138      int argc;
139      char **argv;
140 {
141   int status = 0;
142   char *nextarg;
143   char *tmp;
144   extern char *mkprogname ();
145   char *is_section ();
146   char **get_section_list ();
147   void man_getopt ();
148   void do_apropos ();
149   void do_whatis ();
150   int man ();
151
152   prognam = mkprogname (argv[0]);
153   longsec = NULL;
154
155   unsetenv("IFS");
156 #ifdef __DragonFly__
157   (void) setlocale(LC_ALL, "");
158 #endif
159   man_getopt (argc, argv);
160
161   if (optind == argc)
162     gripe_no_name ((char *)NULL);
163
164   section_list = get_section_list ();
165
166   if (optind == argc - 1)
167     {
168       tmp = is_section (argv[optind], manp);
169
170       if (tmp != NULL)
171         gripe_no_name (tmp);
172     }
173
174 #ifdef SETREUID
175   ruid = getuid();
176   rgid = getgid();
177   euid = geteuid();
178   egid = getegid();
179   setreuid(-1, ruid);
180   setregid(-1, rgid);
181 #endif
182
183   while (optind < argc)
184     {
185       nextarg = argv[optind++];
186
187       /*
188        * See if this argument is a valid section name.  If not,
189        * is_section returns NULL.
190        */
191       tmp = is_section (nextarg, manp);
192
193       if (tmp != NULL)
194         {
195           shortsec = tmp;
196
197           if (debug)
198             fprintf (stderr, "\nsection: %s\n", shortsec);
199
200           continue;
201         }
202
203       if (apropos) {
204         do_apropos (nextarg);
205         status = (status ? 0 : 1); /* reverts status, see below */
206       }
207       else if (whatis) {
208         do_whatis (nextarg);
209         status = (status ? 0 : 1); /* reverts status, see below */
210       }
211       else
212         {
213           status = man (nextarg);
214
215           if (status == 0)
216             gripe_not_found (nextarg, longsec);
217         }
218     }
219   return (status==0);         /* status==1 --> exit(0),
220                                  status==0 --> exit(1) */
221 }
222
223 void
224 usage ()
225 {
226   static char usage_string[1024] = "%s, version %s\n\n";
227
228 #ifdef HAS_TROFF
229 #ifdef __DragonFly__
230   static char s1[] =
231     "usage: %s [-adfhkotw] [section] [-M path] [-P pager] [-S list]\n\
232            [-m machine] [-p string] name ...\n\n";
233 #else
234   static char s1[] =
235     "usage: %s [-adfhktw] [section] [-M path] [-P pager] [-S list]\n\
236            [-m machine] [-p string] name ...\n\n";
237 #endif
238 #else
239 #ifdef __DragonFly__
240   static char s1[] =
241     "usage: %s [-adfhkow] [section] [-M path] [-P pager] [-S list]\n\
242            [-m machine] [-p string] name ...\n\n";
243 #else
244   static char s1[] =
245     "usage: %s [-adfhkw] [section] [-M path] [-P pager] [-S list]\n\
246            [-m machine] [-p string] name ...\n\n";
247 #endif
248 #endif
249
250 static char s2[] = "  a : find all matching entries\n\
251   d : print gobs of debugging information\n\
252   f : same as whatis(1)\n\
253   h : print this help message\n\
254   k : same as apropos(1)\n";
255
256 #ifdef __DragonFly__
257   static char s3[] = "  o : use original, non-localized manpages\n";
258 #endif
259
260 #ifdef HAS_TROFF
261   static char s4[] = "  t : use troff to format pages for printing\n";
262 #endif
263
264   static char s5[] = "  w : print location of man page(s) that would be displayed\n\n\
265   M path    : set search path for manual pages to `path'\n\
266   P pager   : use program `pager' to display pages\n\
267   S list    : colon separated section list\n\
268   m machine : search for alternate architecture man pages\n";
269
270   static char s6[] = "  p string : string tells which preprocessors to run\n\
271                e - [n]eqn(1)   p - pic(1)    t - tbl(1)\n\
272                g - grap(1)     r - refer(1)  v - vgrind(1)\n";
273
274   strcat (usage_string, s1);
275   strcat (usage_string, s2);
276 #ifdef __DragonFly__
277   strcat (usage_string, s3);
278 #endif
279
280 #ifdef HAS_TROFF
281   strcat (usage_string, s4);
282 #endif
283
284   strcat (usage_string, s5);
285
286   strcat (usage_string, s6);
287
288   fprintf (stderr, usage_string, prognam, version, prognam);
289   exit(1);
290 }
291
292 char **
293 add_dir_to_mpath_list (mp, p)
294      char **mp;
295      char *p;
296 {
297   int status;
298
299   status = is_directory (p);
300
301   if (status < 0 && debug)
302     {
303       fprintf (stderr, "Warning: couldn't stat file %s!\n", p);
304     }
305   else if (status == 0 && debug)
306     {
307       fprintf (stderr, "Warning: %s isn't a directory!\n", p);
308     }
309   else if (status == 1)
310     {
311       if (debug)
312         fprintf (stderr, "adding %s to manpathlist\n", p);
313
314       *mp++ = strdup (p);
315     }
316   return mp;
317 }
318
319 /*
320  * Get options from the command line and user environment.
321  */
322 void
323 man_getopt (argc, argv)
324      register int argc;
325      register char **argv;
326 {
327   register int c;
328   register char *p;
329   register char *end;
330   register char **mp;
331   extern void downcase ();
332   extern char *manpath ();
333
334   while ((c = getopt (argc, argv, args)) != EOF)
335     {
336       switch (c)
337         {
338         case 'M':
339           manp = strdup (optarg);
340           break;
341         case 'P':
342           pager = strdup (optarg);
343           if (setenv("PAGER", pager, 1) != 0)
344                   (void)fprintf(stderr, "setenv PAGER=%s\n", pager);
345           break;
346         case 'S':
347           colon_sep_section_list = strdup (optarg);
348           break;
349         case 'a':
350           findall++;
351           break;
352         case 'd':
353           debug++;
354           break;
355         case 'f':
356           if (troff)
357             gripe_incompatible ("-f and -t");
358           if (apropos)
359             gripe_incompatible ("-f and -k");
360           if (print_where)
361             gripe_incompatible ("-f and -w");
362           whatis++;
363           break;
364         case 'k':
365           if (troff)
366             gripe_incompatible ("-k and -t");
367           if (whatis)
368             gripe_incompatible ("-k and -f");
369           if (print_where)
370             gripe_incompatible ("-k and -w");
371           apropos++;
372           break;
373         case 'm':
374           machine = optarg;
375           break;
376 #ifdef __DragonFly__
377         case 'o':
378           use_original++;
379           break;
380 #endif
381         case 'p':
382           roff_directive = strdup (optarg);
383           break;
384 #ifdef HAS_TROFF
385         case 't':
386           if (apropos)
387             gripe_incompatible ("-t and -k");
388           if (whatis)
389             gripe_incompatible ("-t and -f");
390           if (print_where)
391             gripe_incompatible ("-t and -w");
392           troff++;
393           break;
394 #endif
395         case 'w':
396           if (apropos)
397             gripe_incompatible ("-w and -k");
398           if (whatis)
399             gripe_incompatible ("-w and -f");
400           if (troff)
401             gripe_incompatible ("-w and -t");
402           print_where++;
403           break;
404         case 'h':
405         case '?':
406         default:
407           usage();
408           break;
409         }
410     }
411
412 #ifdef __DragonFly__
413   /* "" intentionally used to catch error */
414   if ((locale = setlocale(LC_CTYPE, "")) != NULL)
415         locale_codeset = nl_langinfo(CODESET);
416   if (!use_original && locale != NULL && *locale_codeset != '\0' &&
417       strcmp(locale_codeset, "US-ASCII") != 0
418      ) {
419         char *tmp, *short_locale;
420         struct ltable *pltable;
421
422         *locale_lang = '\0';
423         *locale_terr = '\0';
424
425         if ((short_locale = strdup(locale)) == NULL) {
426                 perror ("ctype locale strdup");
427                 exit (1);
428         }
429         if ((tmp = strchr(short_locale, '.')) != NULL)
430                 *tmp = '\0';
431
432         if (strlen(short_locale) == 2)
433                 strcpy(locale_lang, short_locale);
434         else if ((tmp = strchr(short_locale, '_')) == NULL ||
435                  tmp != short_locale + 2 ||
436                  strlen(tmp + 1) != 2
437                 ) {
438                 errno = EINVAL;
439                 perror ("ctype locale format");
440                 locale = NULL;
441         } else {
442                 strncpy(locale_terr, short_locale + 3, 2);
443                 locale_terr[2] = '\0';
444                 strncpy(locale_lang, short_locale, 2);
445                 locale_lang[2] = '\0';
446         }
447
448         free(short_locale);
449
450         if (locale != NULL) {
451                 for (pltable = ltable; pltable->lcode != NULL; pltable++) {
452                         if (strcmp(pltable->lcode, locale_codeset) == 0) {
453                                 locale_nroff = pltable->nroff;
454                                 break;
455                         }
456                 }
457                 asprintf(&man_locale, "%s.%s", locale_lang, locale_codeset);
458         }
459   } else {
460         if (locale == NULL) {
461                 errno = EINVAL;
462                 perror ("ctype locale");
463         } else {
464                 locale = NULL;
465                 if (*locale_codeset == '\0') {
466                         errno = EINVAL;
467                         perror ("ctype codeset");
468                 }
469         }
470   }
471 #endif /* __DragonFly__ */
472
473   if (pager == NULL || *pager == '\0')
474     if ((pager = getenv ("PAGER")) == NULL || *pager == '\0')
475       pager = strdup (PAGER);
476
477   if (debug)
478     fprintf (stderr, "\nusing %s as pager\n", pager);
479
480   if (machine == NULL && (machine = getenv ("MACHINE")) == NULL)
481     machine = MACHINE;
482
483   if (debug)
484     fprintf (stderr, "\nusing %s architecture\n", machine);
485
486   if (manp == NULL)
487     {
488       if ((manp = manpath (0)) == NULL)
489         gripe_manpath ();
490
491       if (debug)
492         fprintf (stderr,
493                  "\nsearch path for pages determined by manpath is\n%s\n\n",
494                  manp);
495     }
496
497   /*
498    * Expand the manpath into a list for easier handling.
499    */
500   mp = manpathlist;
501   for (p = manp; ; p = end+1)
502     {
503       if (mp == manpathlist + MAXDIRS - 1) {
504         fprintf (stderr, "Warning: too many directories in manpath, truncated!\n");
505         break;
506       }
507       if ((end = strchr (p, ':')) != NULL)
508         *end = '\0';
509
510       mp = add_dir_to_mpath_list (mp, p);
511       if (end == NULL)
512         break;
513
514       *end = ':';
515     }
516   *mp = NULL;
517 }
518
519 /*
520  * Check to see if the argument is a valid section number.  If the
521  * first character of name is a numeral, or the name matches one of
522  * the sections listed in section_list, we'll assume that it's a section.
523  * The list of sections in config.h simply allows us to specify oddly
524  * named directories like .../man3f.  Yuk.
525  */
526 char *
527 is_section (name, path)
528      char *name;
529      char *path;
530 {
531   register char **vs;
532   char *temp, *end, *loc;
533   char **plist;
534   int x;
535
536   for (vs = section_list; *vs != NULL; vs++)
537     if ((strcmp (*vs, name) == 0)
538         || (isdigit ((unsigned char)name[0]) && strlen(name) == 1))
539       return (longsec = strdup (name));
540
541   plist = manpathlist;
542   if (isdigit ((unsigned char)name[0]))
543     {
544       while (*plist != NULL)
545         {
546           asprintf(&temp, "%s/man%c/*", *plist, name[0]);
547           plist++;
548
549           x = 0;
550           vs = glob_filename (temp);
551           if ((int)vs == -1)
552             {
553               free (temp);
554               return NULL;
555             }
556           for ( ; *vs != NULL; vs++)
557             {
558               end = strrchr (*vs, '/');
559               if ((loc = strstr (end, name)) != NULL && loc - end > 2
560                   && *(loc-1) == '.'
561                   && (*(loc+strlen(name)) == '\0' || *(loc+strlen(name)) == '.'))
562                 {
563                   x = 1;
564                   break;
565                 }
566             }
567           free (temp);
568           if (x == 1)
569             {
570               asprintf(&temp, "%c", name[0]);
571               longsec = strdup (name);
572               return (temp);
573             }
574         }
575     }
576   return NULL;
577 }
578
579 /*
580  * Handle the apropos option.  Cheat by using another program.
581  */
582 void
583 do_apropos (name)
584      register char *name;
585 {
586   register int len;
587   register char *command;
588
589   len = strlen (APROPOS) + strlen (name) + 4;
590
591   if ((command = (char *) malloc(len)) == NULL)
592     gripe_alloc (len, "command");
593
594   sprintf (command, "%s \"%s\"", APROPOS, name);
595
596   (void) do_system_command (command);
597
598   free (command);
599 }
600
601 /*
602  * Handle the whatis option.  Cheat by using another program.
603  */
604 void
605 do_whatis (name)
606      register char *name;
607 {
608   register int len;
609   register char *command;
610
611   len = strlen (WHATIS) + strlen (name) + 4;
612
613   if ((command = (char *) malloc(len)) == NULL)
614     gripe_alloc (len, "command");
615
616   sprintf (command, "%s \"%s\"", WHATIS, name);
617
618   (void) do_system_command (command);
619
620   free (command);
621 }
622
623 /*
624  * Change a name of the form ...man/man1/name.1 to ...man/cat1/name.1
625  * or a name of the form ...man/cat1/name.1 to ...man/man1/name.1
626  */
627 char *
628 convert_name (name, to_cat)
629      register char *name;
630      register int to_cat;
631 {
632   register char *to_name;
633   register char *t1;
634   register char *t2 = NULL;
635
636 #ifdef DO_COMPRESS
637   if (to_cat)
638     {
639       int olen = strlen(name);
640       int cextlen = strlen(COMPRESS_EXT);
641       int len = olen + cextlen;
642
643       to_name = malloc (len+1);
644       if (to_name == NULL)
645         gripe_alloc (len+1, "to_name");
646       strcpy (to_name, name);
647       olen -= cextlen;
648       /* Avoid tacking it on twice */
649       if (olen >= 1 && strcmp(name + olen, COMPRESS_EXT) != 0)
650         strcat (to_name, COMPRESS_EXT);
651     }
652   else
653     to_name = strdup (name);
654 #else
655   to_name = strdup (name);
656 #endif
657
658   t1 = strrchr (to_name, '/');
659   if (t1 != NULL)
660     {
661       *t1 = '\0';
662       t2 = strrchr (to_name, '/');
663       *t1 = '/';
664
665       /* Skip architecture part (if present). */
666       if (t2 != NULL && (t1 - t2 < 5 || *(t2 + 1) != 'm' || *(t2 + 3) != 'n'))
667         {
668           t1 = t2;
669           *t1 = '\0';
670           t2 = strrchr (to_name, '/');
671           *t1 = '/';
672         }
673     }
674
675   if (t2 == NULL)
676     gripe_converting_name (name, to_cat);
677
678   if (to_cat)
679     {
680       *(++t2) = 'c';
681       *(t2+2) = 't';
682     }
683   else
684     {
685       *(++t2) = 'm';
686       *(t2+2) = 'n';
687     }
688
689   if (debug)
690     fprintf (stderr, "to_name in convert_name () is: %s\n", to_name);
691
692   return to_name;
693 }
694
695 /*
696  * Try to find the man page corresponding to the given name.  The
697  * reason we do this with globbing is because some systems have man
698  * page directories named man3 which contain files with names like
699  * XtPopup.3Xt.  Rather than requiring that this program know about
700  * all those possible names, we simply try to match things like
701  * .../man[sect]/name[sect]*.  This is *much* easier.
702  *
703  * Note that globbing is only done when the section is unspecified.
704  */
705 char **
706 glob_for_file (path, section, longsec, name, cat)
707      char *path;
708      char *section;
709      char *longsec;
710      char *name;
711      int cat;
712 {
713   char pathname[FILENAME_MAX];
714   char **gf;
715
716   if (longsec == NULL)
717     longsec = section;
718
719   if (cat)
720     snprintf (pathname, sizeof(pathname), "%s/cat%s/%s.%s*", path, section,
721        name, longsec);
722   else
723     snprintf (pathname, sizeof(pathname), "%s/man%s/%s.%s*", path, section,
724        name, longsec);
725
726   if (debug)
727     fprintf (stderr, "globbing %s\n", pathname);
728
729   gf = glob_filename (pathname);
730
731   if ((gf == (char **) -1 || *gf == NULL) && isdigit ((unsigned char)*section)
732       && strlen (longsec) == 1)
733     {
734       if (cat)
735         snprintf (pathname, sizeof(pathname), "%s/cat%s/%s.%c*", path, section, name, *section);
736       else
737         snprintf (pathname, sizeof(pathname), "%s/man%s/%s.%c*", path, section, name, *section);
738
739       gf = glob_filename (pathname);
740     }
741   if ((gf == (char **) -1 || *gf == NULL) && isdigit ((unsigned char)*section)
742       && strlen (longsec) == 1)
743     {
744       if (cat)
745         snprintf (pathname, sizeof(pathname), "%s/cat%s/%s.0*", path, section, name);
746       else
747         snprintf (pathname, sizeof(pathname), "%s/man%s/%s.0*", path, section, name);
748       if (debug)
749         fprintf (stderr, "globbing %s\n", pathname);
750       gf = glob_filename (pathname);
751     }
752   return gf;
753 }
754
755 /*
756  * Return an un-globbed name in the same form as if we were doing
757  * globbing.
758  */
759 char **
760 make_name (path, section, longsec, name, cat)
761      char *path;
762      char *section;
763      char *longsec;
764      char *name;
765      int cat;
766 {
767   register int i = 0;
768   static char *names[3];
769   char buf[FILENAME_MAX];
770
771   if (cat)
772     snprintf (buf, sizeof(buf), "%s/cat%s/%s.%s", path, section, name, longsec);
773   else
774     snprintf (buf, sizeof(buf), "%s/man%s/%s.%s", path, section, name, longsec);
775
776   if (access (buf, R_OK) == 0)
777     names[i++] = strdup (buf);
778
779   /*
780    * If we're given a section that looks like `3f', we may want to try
781    * file names like .../man3/foo.3f as well.  This seems a bit
782    * kludgey to me, but what the hey...
783    */
784   if (section[1] != '\0')
785     {
786       if (cat)
787         snprintf (buf, sizeof(buf), "%s/cat%c/%s.%s", path, section[0], name, section);
788       else
789         snprintf (buf, sizeof(buf), "%s/man%c/%s.%s", path, section[0], name, section);
790
791       if (access (buf, R_OK) == 0)
792         names[i++] = strdup (buf);
793     }
794
795   names[i] = NULL;
796
797   return &names[0];
798 }
799
800 char *
801 get_expander (file)
802      char *file;
803 {
804   char *end = file + (strlen (file) - 1);
805
806   while (end > file && end[-1] != '.')
807     --end;
808   if (end == file)
809     return NULL;
810 #ifdef FCAT
811   if (*end == 'F')
812     return FCAT;
813 #endif  /* FCAT */
814 #ifdef YCAT
815   if (*end == 'Y')
816     return YCAT;
817 #endif  /* YCAT */
818 #ifdef ZCAT
819   if (*end == 'Z' || !strcmp(end, "gz"))
820     return ZCAT;
821 #endif  /* ZCAT */
822   return NULL;
823 }
824
825 /*
826  * Simply display the preformatted page.
827  */
828 int
829 display_cat_file (file)
830      register char *file;
831 {
832   register int found;
833   char command[FILENAME_MAX];
834
835   found = 0;
836
837   if (access (file, R_OK) == 0)
838     {
839       char *expander = get_expander (file);
840
841       if (expander != NULL)
842         snprintf (command, sizeof(command), "%s %s | %s", expander, file, pager);
843       else
844         snprintf (command, sizeof(command), "%s %s", pager, file);
845
846       found = do_system_command (command);
847     }
848   return found;
849 }
850
851 /*
852  * Try to find the ultimate source file.  If the first line of the
853  * current file is not of the form
854  *
855  *      .so man3/printf.3s
856  *
857  * the input file name is returned.
858  */
859 char *
860 ultimate_source (name, path)
861      char *name;
862      char *path;
863 {
864   static  char buf[BUFSIZ];
865   static  char ult[FILENAME_MAX];
866
867   FILE *fp;
868   char *beg;
869   char *end;
870
871   strncpy (ult, name, sizeof(ult)-1);
872   ult[sizeof(ult)-1] = '\0';
873   strncpy (buf, name, sizeof(buf)-1);
874   ult[sizeof(buf)-1] = '\0';
875
876  next:
877
878   if ((fp = fopen (ult, "r")) == NULL)
879     return ult;
880
881   end = fgets (buf, BUFSIZ, fp);
882   fclose(fp);
883
884   if (!end || strlen (buf) < 5)
885     return ult;
886
887   beg = buf;
888   if (*beg++ == '.' && *beg++ == 's' && *beg++ == 'o')
889     {
890       while ((*beg == ' ' || *beg == '\t') && *beg != '\0')
891         beg++;
892
893       end = beg;
894       while (*end != ' ' && *end != '\t' && *end != '\n' && *end != '\0')
895         end++;
896
897       *end = '\0';
898
899       snprintf(ult, sizeof(ult), "%s/%s", path, beg);
900       snprintf(buf, sizeof(buf), "%s", ult);
901
902       goto next;
903     }
904
905   if (debug)
906     fprintf (stderr, "found ultimate source file %s\n", ult);
907
908   return ult;
909 }
910
911 void
912 add_directive (first, d, file, buf, bufsize)
913      int *first;
914      char *d;
915      char *file;
916      char *buf;
917      int bufsize;
918 {
919   if (strcmp (d, "") != 0)
920     {
921       if (*first)
922         {
923           *first = 0;
924           snprintf(buf, bufsize, "%s %s", d, file);
925         }
926       else
927         {
928           strncat (buf, " | ", bufsize-strlen(buf)-1);
929           strncat (buf, d, bufsize-strlen(buf)-1);
930         }
931     }
932 }
933
934 int
935 parse_roff_directive (cp, file, buf, bufsize)
936   char *cp;
937   char *file;
938   char *buf;
939   int bufsize;
940 {
941   char c;
942   char *exp;
943   int first = 1;
944   int preproc_found = 0;
945   int use_col = 0;
946
947   if ((exp = get_expander(file)) != NULL)
948         add_directive (&first, exp, file, buf, bufsize);
949
950   while ((c = *cp++) != '\0')
951     {
952       switch (c)
953         {
954         case 'e':
955
956           if (debug)
957             fprintf (stderr, "found eqn(1) directive\n");
958
959           preproc_found++;
960           if (troff)
961             add_directive (&first, EQN, file, buf, bufsize);
962           else {
963 #ifdef __DragonFly__
964             char lbuf[FILENAME_MAX];
965
966             snprintf(lbuf, sizeof(lbuf), "%s -T%s", NEQN,
967                      locale_opts == NULL ? "ascii" : locale_opts);
968             add_directive (&first, lbuf, file, buf, bufsize);
969 #else
970             add_directive (&first, NEQN, file, buf, bufsize);
971 #endif
972           }
973
974           break;
975
976         case 'g':
977
978           if (debug)
979             fprintf (stderr, "found grap(1) directive\n");
980
981           preproc_found++;
982           add_directive (&first, GRAP, file, buf, bufsize);
983
984           break;
985
986         case 'p':
987
988           if (debug)
989             fprintf (stderr, "found pic(1) directive\n");
990
991           preproc_found++;
992           add_directive (&first, PIC, file, buf, bufsize);
993
994           break;
995
996         case 't':
997
998           if (debug)
999             fprintf (stderr, "found tbl(1) directive\n");
1000
1001           preproc_found++;
1002           use_col++;
1003           add_directive (&first, TBL, file, buf, bufsize);
1004           break;
1005
1006         case 'v':
1007
1008           if (debug)
1009             fprintf (stderr, "found vgrind(1) directive\n");
1010
1011           add_directive (&first, VGRIND, file, buf, bufsize);
1012           break;
1013
1014         case 'r':
1015
1016           if (debug)
1017             fprintf (stderr, "found refer(1) directive\n");
1018
1019           add_directive (&first, REFER, file, buf, bufsize);
1020           break;
1021
1022         case ' ':
1023         case '\t':
1024         case '\n':
1025
1026           goto done;
1027
1028         default:
1029
1030           return -1;
1031         }
1032     }
1033
1034  done:
1035
1036 #ifdef HAS_TROFF
1037   if (troff)
1038     add_directive (&first, TROFF, file, buf, bufsize);
1039   else
1040 #endif
1041     {
1042 #ifdef __DragonFly__
1043       char lbuf[FILENAME_MAX];
1044
1045       snprintf(lbuf, sizeof(lbuf), "%s -T%s%s%s", NROFF,
1046                locale_opts == NULL ? "ascii" : locale_opts,
1047                use_man_locale ? " -dlocale=" : "",
1048                use_man_locale ? man_locale : "");
1049             add_directive (&first, lbuf, file, buf, bufsize);
1050 #else
1051       add_directive (&first, NROFF " -Tascii", file, buf, bufsize);
1052 #endif
1053     }
1054   if (use_col && !troff)
1055       add_directive (&first, COL, file, buf, bufsize);
1056
1057   if (preproc_found)
1058     return 0;
1059   else
1060     return 1;
1061 }
1062
1063 char *
1064 make_roff_command (file)
1065      char *file;
1066 {
1067 #if HAVE_LIBZ > 0
1068   gzFile fp;
1069 #else
1070   FILE *fp;
1071 #endif
1072   char line [BUFSIZ];
1073   static char buf [BUFSIZ];
1074   int status;
1075   char *cp;
1076
1077   if (roff_directive != NULL)
1078     {
1079       if (debug)
1080         fprintf (stderr, "parsing directive from command line\n");
1081
1082       status = parse_roff_directive (roff_directive, file, buf, sizeof(buf));
1083
1084       if (status == 0)
1085         return buf;
1086
1087       if (status == -1)
1088         gripe_roff_command_from_command_line (file);
1089     }
1090
1091 #if HAVE_LIBZ > 0
1092   if ((fp = gzopen (file, "r")) != NULL)
1093 #else
1094   if ((fp = fopen (file, "r")) != NULL)
1095 #endif
1096     {
1097       cp = line;
1098 #if HAVE_LIBZ > 0
1099       gzgets (fp, line, BUFSIZ);
1100       gzclose(fp);
1101 #else
1102       fgets (line, BUFSIZ, fp);
1103       fclose(fp);
1104 #endif
1105       if (*cp++ == '\'' && *cp++ == '\\' && *cp++ == '"' && *cp++ == ' ')
1106         {
1107           if (debug)
1108             fprintf (stderr, "parsing directive from file\n");
1109
1110           status = parse_roff_directive (cp, file, buf, sizeof(buf));
1111
1112           if (status == 0)
1113             return buf;
1114
1115           if (status == -1)
1116             gripe_roff_command_from_file (file);
1117         }
1118     }
1119   else
1120     {
1121       /*
1122        * Is there really any point in continuing to look for
1123        * preprocessor options if we can't even read the man page source?
1124        */
1125       gripe_reading_man_file (file);
1126       return NULL;
1127     }
1128
1129   if ((cp = getenv ("MANROFFSEQ")) != NULL)
1130     {
1131       if (debug)
1132         fprintf (stderr, "parsing directive from environment\n");
1133
1134       status = parse_roff_directive (cp, file, buf, sizeof(buf));
1135
1136       if (status == 0)
1137         return buf;
1138
1139       if (status == -1)
1140         gripe_roff_command_from_env ();
1141     }
1142
1143   if (debug)
1144     fprintf (stderr, "using default preprocessor sequence\n");
1145
1146   status = parse_roff_directive ("t", file, buf, sizeof(buf));
1147   if (status >= 0)
1148     return buf;
1149   else          /* can't happen */
1150     return NULL;
1151 }
1152
1153 sig_t ohup, oint, oquit, oterm;
1154 static char temp[FILENAME_MAX];
1155
1156 void cleantmp()
1157 {
1158         unlink(temp);
1159         exit(1);
1160 }
1161
1162 void
1163 set_sigs()
1164 {
1165   ohup = signal(SIGHUP, cleantmp);
1166   oint = signal(SIGINT, cleantmp);
1167   oquit = signal(SIGQUIT, cleantmp);
1168   oterm = signal(SIGTERM, cleantmp);
1169 }
1170
1171 void
1172 restore_sigs()
1173 {
1174   signal(SIGHUP, ohup);
1175   signal(SIGINT, oint);
1176   signal(SIGQUIT, oquit);
1177   signal(SIGTERM, oterm);
1178 }
1179
1180 /*
1181  * Try to format the man page and create a new formatted file.  Return
1182  * 1 for success and 0 for failure.
1183  */
1184 int
1185 make_cat_file (path, man_file, cat_file, manid)
1186      register char *path;
1187      register char *man_file;
1188      register char *cat_file;
1189 {
1190   int s, f;
1191   FILE *fp, *pp;
1192   char *roff_command;
1193   char command[FILENAME_MAX];
1194
1195   roff_command = make_roff_command (man_file);
1196   if (roff_command == NULL)
1197       return 0;
1198
1199   snprintf(temp, sizeof(temp), "%s.tmpXXXXXX", cat_file);
1200   if ((f = mkstemp(temp)) >= 0 && (fp = fdopen(f, "w")) != NULL)
1201     {
1202       set_sigs();
1203
1204       if (fchmod (f, CATMODE) < 0) {
1205         perror("fchmod");
1206         unlink(temp);
1207         restore_sigs();
1208         fclose(fp);
1209         return 0;
1210       } else if (debug)
1211         fprintf (stderr, "mode of %s is now %o\n", temp, CATMODE);
1212
1213 #ifdef DO_COMPRESS
1214       snprintf (command, sizeof(command), "(cd %s ; %s | %s)", path,
1215                 roff_command, COMPRESSOR);
1216 #else
1217       snprintf (command, sizeof(command), "(cd %s ; %s)", path,
1218                 roff_command);
1219 #endif
1220       fprintf (stderr, "Formatting page, please wait...");
1221       fflush(stderr);
1222
1223       if (debug)
1224         fprintf (stderr, "\ntrying command: %s\n", command);
1225       else {
1226
1227 #ifdef SETREUID
1228         if (manid) {
1229           setreuid(-1, ruid);
1230           setregid(-1, rgid);
1231         }
1232 #endif
1233         if ((pp = popen(command, "r")) == NULL) {
1234           s = errno;
1235           fprintf(stderr, "Failed.\n");
1236           errno = s;
1237           perror("popen");
1238 #ifdef SETREUID
1239           if (manid) {
1240             setreuid(-1, euid);
1241             setregid(-1, egid);
1242           }
1243 #endif
1244           unlink(temp);
1245           restore_sigs();
1246           fclose(fp);
1247           return 0;
1248         }
1249 #ifdef SETREUID
1250         if (manid) {
1251           setreuid(-1, euid);
1252           setregid(-1, egid);
1253         }
1254 #endif
1255
1256         f = 0;
1257         while ((s = getc(pp)) != EOF) {
1258           putc(s, fp); f++;
1259         }
1260
1261         if (!f || ((s = pclose(pp)) == -1)) {
1262           s = errno;
1263           fprintf(stderr, "Failed.\n");
1264           errno = s;
1265           perror("pclose");
1266           unlink(temp);
1267           restore_sigs();
1268           fclose(fp);
1269           return 0;
1270         }
1271
1272         if (s != 0) {
1273           fprintf(stderr, "Failed.\n");
1274           gripe_system_command(s);
1275           unlink(temp);
1276           restore_sigs();
1277           fclose(fp);
1278           return 0;
1279         }
1280       }
1281
1282       if (debug)
1283         unlink(temp);
1284       else if (rename(temp, cat_file) == -1) {
1285         s = errno;
1286         fprintf(stderr,
1287                  "\nHmm!  Can't seem to rename %s to %s, check permissions on man dir!\n",
1288                  temp, cat_file);
1289         errno = s;
1290         perror("rename");
1291         unlink(temp);
1292         restore_sigs();
1293         fclose(fp);
1294         return 0;
1295       }
1296       restore_sigs();
1297
1298       if (fclose(fp)) {
1299         s = errno;
1300         if (!debug)
1301           unlink(cat_file);
1302         fprintf(stderr, "Failed.\n");
1303         errno = s;
1304         perror("fclose");
1305         return 0;
1306       }
1307
1308       if (debug) {
1309         fprintf(stderr, "No output, debug mode.\n");
1310         return 0;
1311       }
1312
1313       fprintf(stderr, "Done.\n");
1314
1315       return 1;
1316     }
1317   else
1318     {
1319       if (f >= 0) {
1320         s = errno;
1321         unlink(temp);
1322         errno = s;
1323       }
1324       if (debug) {
1325         s = errno;
1326         fprintf (stderr, "Couldn't open %s for writing.\n", temp);
1327         errno = s;
1328       }
1329       if (f >= 0) {
1330         perror("fdopen");
1331         close(f);
1332       }
1333
1334       return 0;
1335     }
1336 }
1337
1338 /*
1339  * Try to format the man page source and save it, then display it.  If
1340  * that's not possible, try to format the man page source and display
1341  * it directly.
1342  *
1343  * Note that we've already been handed the name of the ultimate source
1344  * file at this point.
1345  */
1346 int
1347 format_and_display (path, man_file, cat_file)
1348      register char *path;
1349      register char *man_file;
1350      register char *cat_file;
1351 {
1352   int status;
1353   register int found;
1354   char *roff_command;
1355   char command[FILENAME_MAX];
1356
1357   found = 0;
1358
1359   if (access (man_file, R_OK) != 0)
1360     return 0;
1361
1362   if (troff)
1363     {
1364       roff_command = make_roff_command (man_file);
1365       if (roff_command == NULL)
1366         return 0;
1367       else
1368         snprintf (command, sizeof(command), "(cd %s ; %s)", path, roff_command);
1369
1370       found = do_system_command (command);
1371     }
1372   else
1373     {
1374       if (cat_file == NULL)
1375         goto format_and_display;
1376
1377       status = is_newer (man_file, cat_file);
1378       if (debug)
1379         fprintf (stderr, "status from is_newer() = %d\n", status);
1380
1381       if (status == 1 || status == -2)
1382         {
1383           /*
1384            * Cat file is out of date.  Try to format and save it.
1385            */
1386           if (print_where)
1387             {
1388               printf ("%s\n", man_file);
1389               found++;
1390             }
1391           else
1392             {
1393
1394 #ifdef SETREUID
1395               setreuid(-1, euid);
1396               setregid(-1, egid);
1397               found = make_cat_file (path, man_file, cat_file, 1);
1398 #else
1399               found = make_cat_file (path, man_file, cat_file, 0);
1400 #endif
1401 #ifdef SETREUID
1402               setreuid(-1, ruid);
1403               setregid(-1, rgid);
1404
1405               if (!found)
1406                 {
1407                   /* Try again as real user - see note below.
1408                      By running with
1409                        effective group (user) ID == real group (user) ID
1410                      except for the call above, I believe the problems
1411                      of reading private man pages is avoided.  */
1412                   found = make_cat_file (path, man_file, cat_file, 0);
1413                 }
1414 #endif
1415 #ifdef SECURE_MAN_UID
1416               if (!found)
1417                 {
1418                   /*
1419                    * Try again as real user.  Note that for private
1420                    * man pages, we won't even get this far unless the
1421                    * effective user can read the real user's man page
1422                    * source.  Also, if we are trying to find all the
1423                    * man pages, this will probably make it impossible
1424                    * to make cat files in the system directories if
1425                    * the real user's man directories are searched
1426                    * first, because there's no way to undo this (is
1427                    * there?).  Yikes, am I missing something obvious?
1428                    */
1429                   setuid (getuid ());
1430
1431                   found = make_cat_file (path, man_file, cat_file, 0);
1432                 }
1433 #endif
1434               if (found)
1435                 {
1436                   /*
1437                    * Creating the cat file worked.  Now just display it.
1438                    */
1439                   (void) display_cat_file (cat_file);
1440                 }
1441               else
1442                 {
1443                   /*
1444                    * Couldn't create cat file.  Just format it and
1445                    * display it through the pager.
1446                    */
1447 format_and_display:
1448                   roff_command = make_roff_command (man_file);
1449                   if (roff_command == NULL)
1450                     return 0;
1451                   else
1452                     snprintf (command, sizeof(command), "(cd %s ; %s | %s)", path,
1453                              roff_command, pager);
1454
1455                   found = do_system_command (command);
1456                 }
1457             }
1458         }
1459       else if (access (cat_file, R_OK) == 0)
1460         {
1461           /*
1462            * Formatting not necessary.  Cat file is newer than source
1463            * file, or source file is not present but cat file is.
1464            */
1465           if (print_where)
1466             {
1467               printf ("%s (source: %s)\n", cat_file, man_file);
1468               found++;
1469             }
1470           else
1471             {
1472               found = display_cat_file (cat_file);
1473             }
1474         }
1475     }
1476   return found;
1477 }
1478
1479 /*
1480  * See if the preformatted man page or the source exists in the given
1481  * section.
1482  */
1483 int
1484 try_section (path, section, longsec, name, glob)
1485      char *path;
1486      char *section;
1487      char *longsec;
1488      char *name;
1489      int glob;
1490 {
1491   register int found = 0;
1492   register int to_cat;
1493   register int cat;
1494   register char **names;
1495   register char **np;
1496   static int arch_search;
1497   char buf[FILENAME_MAX];
1498
1499   if (!arch_search)
1500     {
1501       snprintf(buf, sizeof(buf), "%s/man%s/%s", path, section, machine);
1502       if (is_directory (buf) == 1)
1503         {
1504           snprintf(buf, sizeof(buf), "%s/%s", machine, name);
1505           arch_search++;
1506           found = try_section (path, section, longsec, buf, glob);
1507           arch_search--;
1508           if (found && !findall)   /* only do this architecture... */
1509             return found;
1510         }
1511     }
1512
1513   if (debug)
1514     {
1515       if (glob)
1516         fprintf (stderr, "trying section %s with globbing\n", section);
1517       else
1518         fprintf (stderr, "trying section %s without globbing\n", section);
1519     }
1520
1521 #ifndef NROFF_MISSING
1522   /*
1523    * Look for man page source files.
1524    */
1525   cat = 0;
1526   if (glob)
1527     names = glob_for_file (path, section, longsec, name, cat);
1528   else
1529     names = make_name (path, section, longsec, name, cat);
1530
1531   if (names == (char **) -1 || *names == NULL)
1532     /*
1533      * No files match.  See if there's a preformatted page around that
1534      * we can display.
1535      */
1536 #endif /* NROFF_MISSING */
1537     {
1538       if (!troff)
1539         {
1540           cat = 1;
1541           if (glob)
1542             names = glob_for_file (path, section, longsec, name, cat);
1543           else
1544             names = make_name (path, section, longsec, name, cat);
1545
1546           if (names != (char **) -1 && *names != NULL)
1547             {
1548               for (np = names; *np != NULL; np++)
1549                 {
1550                   if (print_where)
1551                     {
1552                       printf ("%s\n", *np);
1553                       found++;
1554                     }
1555                   else
1556                     {
1557                       found += display_cat_file (*np);
1558                     }
1559                 }
1560             }
1561         }
1562     }
1563 #ifndef NROFF_MISSING
1564   else
1565     {
1566       for (np = names; *np != NULL; np++)
1567         {
1568           register char *cat_file = NULL;
1569           register char *man_file;
1570
1571           man_file = ultimate_source (*np, path);
1572
1573           if (!troff)
1574             {
1575               to_cat = 1;
1576
1577               cat_file = convert_name (man_file, to_cat);
1578
1579               if (debug)
1580                 fprintf (stderr, "will try to write %s if needed\n", cat_file);
1581             }
1582
1583           found += format_and_display (path, man_file, cat_file);
1584         }
1585     }
1586 #endif /* NROFF_MISSING */
1587   return found;
1588 }
1589
1590 /*
1591  * Search for manual pages.
1592  *
1593  * If preformatted manual pages are supported, look for the formatted
1594  * file first, then the man page source file.  If they both exist and
1595  * the man page source file is newer, or only the source file exists,
1596  * try to reformat it and write the results in the cat directory.  If
1597  * it is not possible to write the cat file, simply format and display
1598  * the man file.
1599  *
1600  * If preformatted pages are not supported, or the troff option is
1601  * being used, only look for the man page source file.
1602  *
1603  */
1604 int
1605 man (name)
1606      char *name;
1607 {
1608   register int found;
1609   register int glob;
1610   register char **mp;
1611   register char **sp;
1612 #ifdef __DragonFly__
1613   int l_found;
1614   char buf[FILENAME_MAX];
1615 #endif
1616
1617   found = 0;
1618
1619   fflush (stdout);
1620   if (strchr(name, '/'))  /* Treat name as file name if it's a path */
1621     {
1622       struct stat st;
1623
1624       if (debug)
1625         fprintf(stderr, "Trying as file name\n");
1626
1627       if (stat(name, &st) == 0)
1628         found += format_and_display(dirname(name), name, NULL);
1629     }
1630   else if (shortsec != NULL)
1631     {
1632       for (mp = manpathlist; *mp != NULL; mp++)
1633         {
1634           if (debug)
1635             fprintf (stderr, "\nsearching in %s\n", *mp);
1636
1637           glob = 1;
1638
1639 #ifdef __DragonFly__
1640           l_found = 0;
1641           if (locale != NULL) {
1642             locale_opts = locale_nroff;
1643             use_man_locale = 1;
1644             if (*locale_lang != '\0' && *locale_terr != '\0') {
1645               snprintf(buf, sizeof(buf), "%s/%s_%s.%s", *mp,
1646                        locale_lang, locale_terr, locale_codeset);
1647               if (is_directory (buf) == 1)
1648                 l_found = try_section (buf, shortsec, longsec, name, glob);
1649             }
1650             if (!l_found) {
1651               if (*locale_lang != '\0') {
1652                 snprintf(buf, sizeof(buf), "%s/%s.%s", *mp,
1653                          locale_lang, locale_codeset);
1654                 if (is_directory (buf) == 1)
1655                   l_found = try_section (buf, shortsec, longsec, name, glob);
1656               }
1657               use_man_locale = 0;
1658               if (!l_found && strcmp(locale_lang, "en") != 0) {
1659                 snprintf(buf, sizeof(buf), "%s/en.%s", *mp,
1660                          locale_codeset);
1661                 if (is_directory (buf) == 1)
1662                   l_found = try_section (buf, shortsec, longsec, name, glob);
1663               }
1664             }
1665             locale_opts = NULL;
1666             use_man_locale = 0;
1667           }
1668           if (!l_found) {
1669 #endif
1670           found += try_section (*mp, shortsec, longsec, name, glob);
1671 #ifdef __DragonFly__
1672           } else
1673             found += l_found;
1674 #endif
1675
1676           if (found && !findall)   /* i.e. only do this section... */
1677             return found;
1678         }
1679     }
1680   else
1681     {
1682       for (sp = section_list; *sp != NULL; sp++)
1683         {
1684           for (mp = manpathlist; *mp != NULL; mp++)
1685             {
1686               if (debug)
1687                 fprintf (stderr, "\nsearching in %s\n", *mp);
1688
1689               glob = 1;
1690
1691 #ifdef __DragonFly__
1692               l_found = 0;
1693               if (locale != NULL) {
1694                 locale_opts = locale_nroff;
1695                 use_man_locale = 1;
1696                 if (*locale_lang != '\0' && *locale_terr != '\0') {
1697                   snprintf(buf, sizeof(buf), "%s/%s_%s.%s", *mp,
1698                            locale_lang, locale_terr, locale_codeset);
1699                   if (is_directory (buf) == 1)
1700                     l_found = try_section (buf, *sp, longsec, name, glob);
1701                 }
1702                 if (!l_found) {
1703                   if (*locale_lang != '\0') {
1704                     snprintf(buf, sizeof(buf), "%s/%s.%s", *mp,
1705                              locale_lang, locale_codeset);
1706                     if (is_directory (buf) == 1)
1707                       l_found = try_section (buf, *sp, longsec, name, glob);
1708                   }
1709                   use_man_locale = 0;
1710                   if (!l_found && strcmp(locale_lang, "en") != 0) {
1711                     snprintf(buf, sizeof(buf), "%s/en.%s", *mp,
1712                              locale_codeset);
1713                     if (is_directory (buf) == 1)
1714                       l_found = try_section (buf, *sp, longsec, name, glob);
1715                   }
1716                 }
1717                 locale_opts = NULL;
1718                 use_man_locale = 0;
1719               }
1720               if (!l_found) {
1721 #endif
1722               found += try_section (*mp, *sp, longsec, name, glob);
1723 #ifdef __DragonFly__
1724               } else
1725                 found += l_found;
1726 #endif
1727
1728               if (found && !findall)   /* i.e. only do this section... */
1729                 return found;
1730             }
1731         }
1732     }
1733   return found;
1734 }
1735
1736 char **
1737 get_section_list ()
1738 {
1739   int i;
1740   char *p;
1741   char *end;
1742 #define TMP_SECTION_LIST_SIZE 100
1743   static char *tmp_section_list[TMP_SECTION_LIST_SIZE];
1744
1745   if (colon_sep_section_list == NULL)
1746     {
1747       if ((p = getenv ("MANSECT")) == NULL)
1748         {
1749           return std_sections;
1750         }
1751       else
1752         {
1753           colon_sep_section_list = strdup (p);
1754         }
1755     }
1756
1757   i = 0;
1758   for (p = colon_sep_section_list; i < TMP_SECTION_LIST_SIZE ; p = end+1) 
1759     {
1760       if ((end = strchr (p, ':')) != NULL)
1761         *end = '\0';
1762
1763       tmp_section_list[i++] = strdup (p);
1764
1765       if (end == NULL)
1766         break;
1767     }
1768
1769   tmp_section_list [i] = NULL;
1770   return tmp_section_list;
1771 }