style: compare return value of getopt() against -1 rather than EOF
[games.git] / gnu / usr.bin / man / man / man.c
CommitLineData
984263bc
MD
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
1de703da
MD
15 *
16 * $FreeBSD: src/gnu/usr.bin/man/man/man.c,v 1.37.2.10 2003/02/14 15:38:51 ru Exp $
9b0ec895 17 * $DragonFly: src/gnu/usr.bin/man/man/man.c,v 1.9 2008/07/10 18:29:51 swildner Exp $
984263bc
MD
18 */
19
984263bc
MD
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>
b3215932 27#include <libgen.h>
0e387216 28#ifdef __DragonFly__
984263bc
MD
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
51extern uid_t getuid ();
52extern int setuid ();
53#endif
54
55#ifdef STDC_HEADERS
56#include <stdlib.h>
57#else
58extern char *malloc ();
59extern char *getenv ();
60extern void free ();
61extern int system ();
62extern int strcmp ();
63extern int strncmp ();
64extern int exit ();
65extern int fflush ();
66extern int printf ();
67extern int fprintf ();
68extern FILE *fopen ();
69extern int fclose ();
70extern char *sprintf ();
71#endif
72
73extern char **glob_filename ();
74extern int is_newer ();
75extern int is_directory ();
76extern int do_system_command ();
77
78char *prognam;
79static char *pager;
80static char *machine;
81static char *manp;
82static char *manpathlist[MAXDIRS];
83static char *shortsec;
84static char *longsec;
85static char *colon_sep_section_list;
86static char **section_list;
87static char *roff_directive;
88static int apropos;
89static int whatis;
90static int findall;
91static int print_where;
92
0e387216 93#ifdef __DragonFly__
984263bc
MD
94static char *locale, *locale_opts, *locale_nroff, *locale_codeset;
95static char locale_terr[3], locale_lang[3];
96static char *man_locale;
97static int use_man_locale;
98static int use_original;
99struct ltable {
100 char *lcode;
101 char *nroff;
102};
103static struct ltable ltable[] = {
104 {"KOI8-R", "koi8-r"},
105 {"ISO8859-1", "latin1"},
106 {"ISO8859-15", "latin1"},
107 {NULL}
108};
109#endif
110
111static int troff = 0;
112
113int debug;
114
115#ifdef HAS_TROFF
0e387216 116#ifdef __DragonFly__
a186ce37 117static char args[] = "M:P:S:adfhkm:op:tw?";
984263bc 118#else
a186ce37 119static char args[] = "M:P:S:adfhkm:p:tw?";
984263bc
MD
120#endif
121#else
0e387216 122#ifdef __DragonFly__
a186ce37 123static char args[] = "M:P:S:adfhkm:op:w?";
984263bc 124#else
a186ce37 125static char args[] = "M:P:S:adfhkm:p:w?";
984263bc
MD
126#endif
127#endif
128
129#ifdef SETREUID
130uid_t ruid;
131uid_t euid;
132gid_t rgid;
133gid_t egid;
134#endif
135
136int
137main (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");
0e387216 156#ifdef __DragonFly__
984263bc
MD
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
223void
224usage ()
225{
226 static char usage_string[1024] = "%s, version %s\n\n";
227
228#ifdef HAS_TROFF
0e387216 229#ifdef __DragonFly__
984263bc 230 static char s1[] =
a186ce37 231 "usage: %s [-adfhkotw] [section] [-M path] [-P pager] [-S list]\n\
984263bc
MD
232 [-m machine] [-p string] name ...\n\n";
233#else
234 static char s1[] =
a186ce37 235 "usage: %s [-adfhktw] [section] [-M path] [-P pager] [-S list]\n\
984263bc
MD
236 [-m machine] [-p string] name ...\n\n";
237#endif
238#else
0e387216 239#ifdef __DragonFly__
984263bc 240 static char s1[] =
a186ce37 241 "usage: %s [-adfhkow] [section] [-M path] [-P pager] [-S list]\n\
984263bc
MD
242 [-m machine] [-p string] name ...\n\n";
243#else
244 static char s1[] =
a186ce37 245 "usage: %s [-adfhkw] [section] [-M path] [-P pager] [-S list]\n\
984263bc
MD
246 [-m machine] [-p string] name ...\n\n";
247#endif
248#endif
249
250static 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
0e387216 256#ifdef __DragonFly__
984263bc
MD
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);
0e387216 276#ifdef __DragonFly__
984263bc
MD
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
292char **
293add_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 */
322void
323man_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
9b0ec895 334 while ((c = getopt (argc, argv, args)) != -1)
984263bc
MD
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;
0e387216 376#ifdef __DragonFly__
984263bc
MD
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
0e387216 412#ifdef __DragonFly__
984263bc
MD
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 }
0e387216 471#endif /* __DragonFly__ */
984263bc
MD
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 */
526char *
527is_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 */
582void
583do_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 */
604void
605do_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 */
627char *
628convert_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 */
705char **
706glob_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 */
759char **
760make_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
800char *
801get_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 */
828int
829display_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 */
859char *
860ultimate_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
911void
912add_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
934int
935parse_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 {
0e387216 963#ifdef __DragonFly__
984263bc
MD
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 {
0e387216 1042#ifdef __DragonFly__
984263bc
MD
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
1063char *
1064make_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
1153sig_t ohup, oint, oquit, oterm;
1154static char temp[FILENAME_MAX];
1155
1156void cleantmp()
1157{
1158 unlink(temp);
1159 exit(1);
1160}
1161
1162void
1163set_sigs()
1164{
1165 ohup = signal(SIGHUP, cleantmp);
1166 oint = signal(SIGINT, cleantmp);
1167 oquit = signal(SIGQUIT, cleantmp);
1168 oterm = signal(SIGTERM, cleantmp);
1169}
1170
1171void
1172restore_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 */
1184int
1185make_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 */
1346int
1347format_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 {
b96278a2
SS
1374 if (cat_file == NULL)
1375 goto format_and_display;
1376
984263bc
MD
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 */
b3215932 1447format_and_display:
984263bc
MD
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 */
1483int
1484try_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 */
1604int
1605man (name)
1606 char *name;
1607{
1608 register int found;
1609 register int glob;
1610 register char **mp;
1611 register char **sp;
0e387216 1612#ifdef __DragonFly__
984263bc
MD
1613 int l_found;
1614 char buf[FILENAME_MAX];
1615#endif
1616
1617 found = 0;
1618
1619 fflush (stdout);
092dad06
SW
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)
984263bc
MD
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
0e387216 1639#ifdef __DragonFly__
984263bc
MD
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);
0e387216 1671#ifdef __DragonFly__
984263bc
MD
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
0e387216 1691#ifdef __DragonFly__
984263bc
MD
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);
0e387216 1723#ifdef __DragonFly__
984263bc
MD
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
1736char **
1737get_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}