11abf7346Smrg/*
21abf7346Smrg
31abf7346SmrgCopyright (c) 1987, 1988  X Consortium
41abf7346Smrg
51abf7346SmrgPermission is hereby granted, free of charge, to any person obtaining
61abf7346Smrga copy of this software and associated documentation files (the
71abf7346Smrg"Software"), to deal in the Software without restriction, including
81abf7346Smrgwithout limitation the rights to use, copy, modify, merge, publish,
91abf7346Smrgdistribute, sublicense, and/or sell copies of the Software, and to
101abf7346Smrgpermit persons to whom the Software is furnished to do so, subject to
111abf7346Smrgthe following conditions:
121abf7346Smrg
131abf7346SmrgThe above copyright notice and this permission notice shall be included
141abf7346Smrgin all copies or substantial portions of the Software.
151abf7346Smrg
161abf7346SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
171abf7346SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
181abf7346SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
191abf7346SmrgIN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
201abf7346SmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
211abf7346SmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
221abf7346SmrgOTHER DEALINGS IN THE SOFTWARE.
231abf7346Smrg
241abf7346SmrgExcept as contained in this notice, the name of the X Consortium shall
251abf7346Smrgnot be used in advertising or otherwise to promote the sale, use or
261abf7346Smrgother dealings in this Software without prior written authorization
271abf7346Smrgfrom the X Consortium.
281abf7346Smrg
291abf7346Smrg*/
301abf7346Smrg
311abf7346Smrg
321abf7346Smrg#include "globals.h"
336d36ef34Smrg#include "vendor.h"             /* vendor-specific defines and data */
341abf7346Smrg
351abf7346Smrg#include <dirent.h>
361abf7346Smrg
371abf7346Smrg#ifdef DEBUG
386d36ef34Smrgstatic char error_buf[BUFSIZ];  /* The buffer for error messages. */
391abf7346Smrg#endif /* DEBUG */
401abf7346Smrg
416d36ef34Smrgstatic void AddToCurrentSection(Manual * local_manual, char *path);
426d36ef34Smrgstatic void InitManual(Manual * l_manual, char *label);
436d36ef34Smrgstatic void ReadCurrentSection(Manual * local_manual, char *path);
446d36ef34Smrgstatic void ReadMandescFile(SectionList ** section_list, char *path);
456d36ef34Smrgstatic void SortAndRemove(Manual * man, int number);
461abf7346Smrgstatic void SortList(SectionList ** list);
471abf7346Smrg
481abf7346Smrg#define SECT_ERROR -1
491abf7346Smrg
501abf7346Smrg#ifndef       Byte
511abf7346Smrg#define       Byte    unsigned char
521abf7346Smrg#endif
536d36ef34Smrg
541abf7346Smrg#ifndef       reg
551abf7346Smrg#define       reg     register
561abf7346Smrg#endif
576d36ef34Smrg
586d36ef34Smrgstatic void sortstrs(Byte * data[], int size, Byte * otherdata[]);
596d36ef34Smrgstatic void sortstrs_block(Byte **, Byte **, int, Byte, Byte **, Byte **);
606d36ef34Smrgstatic void sortstrs_block_oo(Byte **, Byte **, int, Byte, int *, int *,
616d36ef34Smrg                              Byte **, Byte **);
626d36ef34Smrg
631abf7346Smrg/*	Function Name: Man
641abf7346Smrg *	Description: Builds a list of all manual directories and files.
656d36ef34Smrg *	Arguments: none.
661abf7346Smrg *	Returns: the number of manual sections.
671abf7346Smrg */
681abf7346Smrg
691abf7346Smrgint
701abf7346SmrgMan(void)
711abf7346Smrg{
726d36ef34Smrg    SectionList *list = NULL;
731abf7346Smrg
746d36ef34Smrg    char *ptr, *lang = NULL, manpath[BUFSIZ], buf[BUFSIZ],
756d36ef34Smrg        *path, *current_label;
766d36ef34Smrg    int sect, num_alloced;
776d36ef34Smrg
786d36ef34Smrg/*
791abf7346Smrg * Get the environment variable MANPATH, and if it doesn't exist then use
801abf7346Smrg * SYSMANPATH and LOCALMANPATH.
811abf7346Smrg */
821abf7346Smrg
836d36ef34Smrg    /* if MANPATH variable ends in ':'. So, should extend it's value to the
846d36ef34Smrg     * default search path.
856d36ef34Smrg     */
861abf7346Smrg
876d36ef34Smrg    *manpath = '\0';
886d36ef34Smrg    if ((ptr = getenv("MANPATH")) != NULL)
896d36ef34Smrg        strcpy(manpath, ptr);
906d36ef34Smrg    if (ptr == NULL || streq(ptr, "") || ptr[strlen(ptr) - 1] == ':') {
916d36ef34Smrg        lang = getenv("LANG");
921abf7346Smrg#ifdef MANCONF
936d36ef34Smrg        if (!ReadManConfig(manpath + strlen(manpath)))
941abf7346Smrg#endif
956d36ef34Smrg        {
961abf7346Smrg#ifdef MANCONF
976d36ef34Smrg            if (manpath[strlen(manpath) - 1] != ':')
986d36ef34Smrg                strcat(manpath, ":");
991abf7346Smrg#endif
1006d36ef34Smrg            strcat(manpath, SYSMANPATH);
1011abf7346Smrg#ifdef LOCALMANPATH
1026d36ef34Smrg            strcat(manpath, ":");
1036d36ef34Smrg            strcat(manpath, LOCALMANPATH);
1041abf7346Smrg#endif
1056d36ef34Smrg        }
1061abf7346Smrg    }
1071abf7346Smrg
1081abf7346Smrg/*
1091abf7346Smrg * Get the list of manual directories in the users MANPATH that we should
1101abf7346Smrg * open to look for manual pages.  The ``mandesc'' file is read here.
1111abf7346Smrg */
1121abf7346Smrg
1136d36ef34Smrg    for (path = manpath; (ptr = strchr(path, ':')) != NULL; path = ++ptr) {
1146d36ef34Smrg        *ptr = '\0';
1156d36ef34Smrg        if (lang != NULL) {
1166d36ef34Smrg            strcpy(buf, path);
1176d36ef34Smrg            strcat(buf, "/");
1186d36ef34Smrg            strncat(buf, lang, sizeof(buf) - strlen(path) + 1);
1196d36ef34Smrg            buf[sizeof(buf) - strlen(path) + 1] = '\0';
1206d36ef34Smrg            ReadMandescFile(&list, buf);
1216d36ef34Smrg        }
1226d36ef34Smrg        ReadMandescFile(&list, path);
1236d36ef34Smrg    }
1248b6d6341Smrg    if (lang != NULL) {
1256d36ef34Smrg        strcpy(buf, path);
1266d36ef34Smrg        strcat(buf, "/");
1276d36ef34Smrg        strncat(buf, lang, sizeof(buf) - strlen(path) + 1);
1286d36ef34Smrg        buf[sizeof(buf) - strlen(path) + 1] = '\0';
1296d36ef34Smrg        ReadMandescFile(&list, buf);
1301abf7346Smrg    }
1311abf7346Smrg    ReadMandescFile(&list, path);
1326d36ef34Smrg
1336d36ef34Smrg    SortList(&list);
1346d36ef34Smrg
1356d36ef34Smrg    sect = 0;
1366d36ef34Smrg    num_alloced = SECTALLOC;
1376d36ef34Smrg    manual = (Manual *) XtMalloc(sizeof(Manual) * num_alloced);
1386d36ef34Smrg    InitManual(manual, list->label);
1396d36ef34Smrg    manual[sect].flags = list->flags;
1406d36ef34Smrg    current_label = NULL;
1416d36ef34Smrg
1426d36ef34Smrg    while (list != NULL) {
1436d36ef34Smrg        SectionList *old_list;
1446d36ef34Smrg
1456d36ef34Smrg        if (current_label == NULL || streq(list->label, current_label))
1466d36ef34Smrg            AddToCurrentSection(manual + sect, list->directory);
1476d36ef34Smrg        else {
1486d36ef34Smrg            if (manual[sect].nentries == 0) {   /* empty section, re-use it. */
1496d36ef34Smrg                XtFree(manual[sect].blabel);
1506d36ef34Smrg                manual[sect].blabel = list->label;
1516d36ef34Smrg                manual[sect].flags = list->flags;
1526d36ef34Smrg            }
1536d36ef34Smrg            else {
1546d36ef34Smrg                if (++sect >= num_alloced) {
1556d36ef34Smrg                    num_alloced += SECTALLOC;
1566d36ef34Smrg                    manual = (Manual *) XtRealloc((char *) manual,
1576d36ef34Smrg                                              (sizeof(Manual) * num_alloced));
1586d36ef34Smrg                    if (manual == NULL)
1596d36ef34Smrg                        PrintError
1606d36ef34Smrg                            ("Could not allocate memory for manual sections.");
1616d36ef34Smrg                }
1626d36ef34Smrg                InitManual(manual + sect, list->label);
1636d36ef34Smrg                manual[sect].flags = list->flags;
1646d36ef34Smrg            }
1656d36ef34Smrg            AddToCurrentSection(manual + sect, list->directory);
1666d36ef34Smrg        }
1676d36ef34Smrg        /* Save label to see if it matches next entry. */
1686d36ef34Smrg        current_label = list->label;
1696d36ef34Smrg        old_list = list;
1706d36ef34Smrg        list = list->next;
1716d36ef34Smrg        XtFree((char *) old_list);      /* free what you allocate. */
1721abf7346Smrg    }
1736d36ef34Smrg    if (manual[sect].nentries != 0)
1746d36ef34Smrg        sect++;                 /* don't forget that last section. */
1756d36ef34Smrg
1766d36ef34Smrg    SortAndRemove(manual, sect);
1776d36ef34Smrg
1786d36ef34Smrg#ifdef notdef                   /* dump info. */
1796d36ef34Smrg    DumpManual(sect);
1801abf7346Smrg#endif
1816d36ef34Smrg
1821abf7346Smrg/*
1831abf7346Smrg * realloc manual to be minimum space necessary.
1841abf7346Smrg */
1851abf7346Smrg
1866d36ef34Smrg    if (sect == 0)
1876d36ef34Smrg        PrintError("No manual pages found.");
1886d36ef34Smrg    manual = (Manual *) XtRealloc((char *) manual, (sizeof(Manual) * sect));
1896d36ef34Smrg    if (manual == NULL)
1906d36ef34Smrg        PrintError("Could not allocate memory for manual sections.");
1911abf7346Smrg
1926d36ef34Smrg    return (sect);              /* return the number of man sections. */
1936d36ef34Smrg}
1941abf7346Smrg
1951abf7346Smrg/*	Function Name: SortList
1961abf7346Smrg *	Description: Sorts the list of sections to search.
1971abf7346Smrg *	Arguments: list - a pointer to the list to sort.
1981abf7346Smrg *	Returns: a sorted list.
1991abf7346Smrg *
2001abf7346Smrg * This is the most complicated part of the entire operation.
2011abf7346Smrg * all sections with the same label must by right next to each other,
2021abf7346Smrg * but the sections that are in the standard list have to come first.
2031abf7346Smrg */
2041abf7346Smrg
2051abf7346Smrgstatic void
2061abf7346SmrgSortList(SectionList ** list)
2071abf7346Smrg{
2086d36ef34Smrg    SectionList *local;
2096d36ef34Smrg    SectionList *head, *last, *inner, *old;
2106d36ef34Smrg
2116d36ef34Smrg    if (*list == NULL)
2126d36ef34Smrg        PrintError("No manual sections to read, exiting.");
2136d36ef34Smrg
2146d36ef34Smrg/*
2156d36ef34Smrg * First step
2166d36ef34Smrg *
2171abf7346Smrg * Look for standard list items, and more them to the top of the list.
2181abf7346Smrg */
2191abf7346Smrg
2206d36ef34Smrg    last = NULL;                /* keep Saber happy. */
2216d36ef34Smrg    for (local = *list; local->next != NULL; local = local->next) {
2226d36ef34Smrg        if (local->flags) {
2236d36ef34Smrg            if (local == *list) /* top element is already standard. */
2246d36ef34Smrg                break;
2256d36ef34Smrg            head = local;
2261abf7346Smrg
2276d36ef34Smrg            /* Find end of standard block */
2286d36ef34Smrg            for (old = NULL; (local->next != NULL) && (local->flags);
2296d36ef34Smrg                 old = local, local = local->next);
2301abf7346Smrg
2316d36ef34Smrg            if (old != NULL) {
2326d36ef34Smrg                last->next = old->next; /* Move the block. */
2336d36ef34Smrg                old->next = *list;
2346d36ef34Smrg                *list = head;
2356d36ef34Smrg            }
2361abf7346Smrg
2376d36ef34Smrg            break;              /* First step accomplished. */
2386d36ef34Smrg        }
2396d36ef34Smrg        last = local;
2401abf7346Smrg    }
2411abf7346Smrg
2421abf7346Smrg/*
2431abf7346Smrg *  Second step
2441abf7346Smrg *
2451abf7346Smrg *  Move items with duplicate labels right next to each other.
2461abf7346Smrg *
2471abf7346Smrg *  Changed to keep the order of the list entries unchanged.
2481abf7346Smrg */
2491abf7346Smrg
2506d36ef34Smrg    for (local = *list; local->next != NULL; local = local->next) {
2516d36ef34Smrg        head = local;
2526d36ef34Smrg        old = inner = local->next;
2536d36ef34Smrg        while (inner != NULL) {
2546d36ef34Smrg            if (streq(inner->label, local->label)) {
2556d36ef34Smrg                if (old != inner) {
2566d36ef34Smrg                    old->next = inner->next;
2576d36ef34Smrg                    last = inner->next;
2586d36ef34Smrg                    inner->next = head->next;
2596d36ef34Smrg                    head->next = inner;
2606d36ef34Smrg                    head = inner;
2616d36ef34Smrg                    old = inner = last;
2626d36ef34Smrg                    continue;
2636d36ef34Smrg                }
2646d36ef34Smrg                else
2656d36ef34Smrg                    head = inner;
2666d36ef34Smrg            }
2676d36ef34Smrg            old = inner;
2686d36ef34Smrg            inner = inner->next;
2696d36ef34Smrg        }
2701abf7346Smrg    }
2716d36ef34Smrg}
2721abf7346Smrg
2731abf7346Smrg/*	Function Name: ReadMandescFile
2746d36ef34Smrg *	Description: Reads the mandesc file, and adds more sections as
2751abf7346Smrg *                   necessary.
2761abf7346Smrg *	Arguments: path - path name if the current search directory.
2771abf7346Smrg *                 section_list - pointer to the list of sections.
2781abf7346Smrg *	Returns: TRUE in we should use default sections
2791abf7346Smrg */
2806d36ef34Smrg
2811abf7346Smrgstatic void
2826d36ef34SmrgReadMandescFile(SectionList ** section_list, char *path)
2831abf7346Smrg{
2846d36ef34Smrg    char mandesc_file[BUFSIZ];  /* full path to the mandesc file. */
2856d36ef34Smrg    FILE *descfile;
2866d36ef34Smrg    char string[BUFSIZ], local_file[BUFSIZ];
2876d36ef34Smrg    Boolean use_defaults = TRUE;
2886d36ef34Smrg    char *cp;
2896d36ef34Smrg
2906d36ef34Smrg    snprintf(mandesc_file, sizeof(mandesc_file), "%s/%s", path, MANDESC);
2916d36ef34Smrg    if ((descfile = fopen(mandesc_file, "r")) != NULL) {
2926d36ef34Smrg        while (fgets(string, BUFSIZ, descfile) != NULL) {
293da4a0041Smrg            size_t len = strlen(string);
294da4a0041Smrg
295da4a0041Smrg            if (len == 0)
296da4a0041Smrg                continue;
297da4a0041Smrg            if (string[len - 1] == '\n')
298da4a0041Smrg                string[len - 1] = '\0';  /* Strip off the CR. */
2996d36ef34Smrg
3006d36ef34Smrg            if (streq(string, NO_SECTION_DEFAULTS)) {
3016d36ef34Smrg                use_defaults = FALSE;
3026d36ef34Smrg                continue;
3036d36ef34Smrg            }
3046d36ef34Smrg
3056d36ef34Smrg            if ((cp = strchr(string, '\t')) != NULL) {
3066d36ef34Smrg                char *s;
3076d36ef34Smrg
3086d36ef34Smrg                *cp++ = '\0';
3096d36ef34Smrg                strcpy(local_file, MAN);
3106d36ef34Smrg                strcat(local_file, string);
3116d36ef34Smrg                if ((s = strchr(cp, '\t')) != NULL) {
3126d36ef34Smrg                    *s++ = '\0';
3136d36ef34Smrg                    if (streq(s, SUFFIX))
3146d36ef34Smrg                        AddNewSection(section_list, path, local_file, cp,
3156d36ef34Smrg                                      MSUFFIX);
3166d36ef34Smrg                    else if (streq(s, FOLD))
3176d36ef34Smrg                        AddNewSection(section_list, path, local_file, cp,
3186d36ef34Smrg                                      MFOLD);
3196d36ef34Smrg                    else if (streq(s, FOLDSUFFIX))
3206d36ef34Smrg                        AddNewSection(section_list, path, local_file, cp,
3216d36ef34Smrg                                      MFOLDSUFFIX);
3226d36ef34Smrg                    else
3236d36ef34Smrg                        AddNewSection(section_list, path, local_file, cp,
3246d36ef34Smrg                                      MNULL);
3256d36ef34Smrg                }
3266d36ef34Smrg                else
3276d36ef34Smrg                    AddNewSection(section_list, path, local_file, cp, MNULL);
3286d36ef34Smrg            }
3296d36ef34Smrg            else {
3306d36ef34Smrg                snprintf(local_file, sizeof(local_file), "%s%c", MAN,
3316d36ef34Smrg                         string[0]);
3326d36ef34Smrg                AddNewSection(section_list, path, local_file, (string + 1),
3336d36ef34Smrg                              FALSE);
3341abf7346Smrg#ifdef SEARCHOTHER
3356d36ef34Smrg                snprintf(local_file, sizeof(local_file), "%s%c", SEARCHOTHER,
3366d36ef34Smrg                         string[0]);
3376d36ef34Smrg                AddNewSection(section_list, path, local_file, (string + 1),
3386d36ef34Smrg                              FALSE);
3391abf7346Smrg#endif
3406d36ef34Smrg            }
3416d36ef34Smrg        }
3421abf7346Smrg
3436d36ef34Smrg        fclose(descfile);
3446d36ef34Smrg    }
3456d36ef34Smrg    if (use_defaults)
3466d36ef34Smrg        AddStandardSections(section_list, path);
3471abf7346Smrg}
3481abf7346Smrg
3491abf7346Smrg/*	Function Name: AddNewSection
3501abf7346Smrg *	Description: Adds the new section onto the current section list.
3511abf7346Smrg *	Arguments: list - pointer to the section list.
3521abf7346Smrg *                 path - the path to the current manual section.
3531abf7346Smrg *                 file - the file to save.
3541abf7346Smrg *                 label - the current section label.
3551abf7346Smrg *                 flags = 1 - add a suffix
3561abf7346Smrg *			 = 2 - fold to lower case
3571abf7346Smrg *	Returns: none.
3581abf7346Smrg */
3591abf7346Smrg
3601abf7346Smrgvoid
3616d36ef34SmrgAddNewSection(SectionList ** list, const char *path, const char *file,
3626d36ef34Smrg              const char *label, int flags)
3631abf7346Smrg{
3646d36ef34Smrg    SectionList *local_list, *end;
3656d36ef34Smrg    char full_path[BUFSIZ];
3661abf7346Smrg
3671abf7346Smrg/* Allocate a new list element */
3681abf7346Smrg
3696d36ef34Smrg    local_list = (SectionList *) XtMalloc(sizeof(SectionList));
3701abf7346Smrg
3716d36ef34Smrg    if (*list != NULL) {
3726d36ef34Smrg        for (end = *list; end->next != NULL; end = end->next);
3736d36ef34Smrg        end->next = local_list;
3746d36ef34Smrg    }
3756d36ef34Smrg    else
3766d36ef34Smrg        *list = local_list;
3776d36ef34Smrg
3786d36ef34Smrg    local_list->next = NULL;
3796d36ef34Smrg    local_list->label = XtNewString(label);
3806d36ef34Smrg    snprintf(full_path, sizeof(full_path), "%s/%s", path, file);
3816d36ef34Smrg    local_list->directory = XtNewString(full_path);
3826d36ef34Smrg    local_list->flags = flags;
3836d36ef34Smrg}
3841abf7346Smrg
3851abf7346Smrg/*	Function Name: AddToCurrentSection
3861abf7346Smrg *	Description: This function gets the names of the manual page
3871abf7346Smrg *                   directories, then closes the directory.
3881abf7346Smrg *	Arguments:  local_manual - a pointer to a manual pages structure.
3891abf7346Smrg *                  path - the path to this directory.
3901abf7346Smrg *	Returns: none.
3911abf7346Smrg */
3921abf7346Smrg
3931abf7346Smrgstatic void
3946d36ef34SmrgAddToCurrentSection(Manual * local_manual, char *path)
3951abf7346Smrg{
3966d36ef34Smrg    char temp_path[BUFSIZ];
3971abf7346Smrg
3981abf7346Smrg#if defined(__OpenBSD__) || defined(__NetBSD__)
3996d36ef34Smrg    snprintf(temp_path, sizeof(temp_path), "%s/%s", path, MACHINE);
4006d36ef34Smrg    ReadCurrentSection(local_manual, temp_path);
4011abf7346Smrg#endif
4026d36ef34Smrg    ReadCurrentSection(local_manual, path);
4036d36ef34Smrg    snprintf(temp_path, sizeof(temp_path), "%s.%s", path,
4046d36ef34Smrg             COMPRESSION_EXTENSION);
4056d36ef34Smrg    ReadCurrentSection(local_manual, temp_path);
4061abf7346Smrg}
4071abf7346Smrg
4081abf7346Smrg/*	Function Name: ReadCurrentSection
4096d36ef34Smrg *	Description: Actually does the work of adding entries to the
4101abf7346Smrg *                   new section
4111abf7346Smrg *	Arguments:  local_manual - a pointer to a manual pages structure.
4121abf7346Smrg *                  path - the path to this directory.
4131abf7346Smrg *                  compressed - Is this a compressed directory?
4141abf7346Smrg *	Returns: TRUE if any entries are found.
4151abf7346Smrg */
4161abf7346Smrg
4171abf7346Smrgstatic void
4186d36ef34SmrgReadCurrentSection(Manual * local_manual, char *path)
4191abf7346Smrg{
4206d36ef34Smrg    DIR *dir;
4216d36ef34Smrg    register struct dirent *dp;
4221abf7346Smrg
4236d36ef34Smrg    register int nentries;
4246d36ef34Smrg    register int nalloc;
4256d36ef34Smrg    char full_name[BUFSIZ], *ptr;
4261abf7346Smrg
4276d36ef34Smrg    if ((dir = opendir(path)) == NULL) {
4281abf7346Smrg#ifdef DEBUG
4296d36ef34Smrg        snprintf(error_buf, sizeof(error_buf), "Can't open directory %s", path);
4306d36ef34Smrg        PopupWarning(NULL, error_buf);
4311abf7346Smrg#endif /* DEBUG */
4326d36ef34Smrg        return;
4336d36ef34Smrg    }
4341abf7346Smrg
4351abf7346Smrg/*
4361abf7346Smrg * Remove the compression extension from the path name.
4371abf7346Smrg */
4381abf7346Smrg
4396d36ef34Smrg    if ((ptr = strrchr(path, '.')) != NULL) {
4406d36ef34Smrg        if (streq(ptr + 1, COMPRESSION_EXTENSION))
4416d36ef34Smrg            *ptr = '\0';
4421abf7346Smrg#ifdef GZIP_EXTENSION
4436d36ef34Smrg        else if (streq(ptr + 1, GZIP_EXTENSION))
4446d36ef34Smrg            *ptr = '\0';
4458b6d6341Smrg#endif
4468b6d6341Smrg#ifdef BZIP2_EXTENSION
4476d36ef34Smrg        else if (streq(ptr + 1, BZIP2_EXTENSION))
4486d36ef34Smrg            *ptr = '\0';
4498b6d6341Smrg#endif
4508b6d6341Smrg#ifdef LZMA_EXTENSION
4516d36ef34Smrg        else if (streq(ptr + 1, LZMA_EXTENSION))
4526d36ef34Smrg            *ptr = '\0';
4531abf7346Smrg#endif
4541abf7346Smrg    }
4551abf7346Smrg
4566d36ef34Smrg    nentries = local_manual->nentries;
4576d36ef34Smrg    nalloc = local_manual->nalloc;
4586d36ef34Smrg
4596d36ef34Smrg    while ((dp = readdir(dir)) != NULL) {
4606d36ef34Smrg        char *name = dp->d_name;
4616d36ef34Smrg
4626d36ef34Smrg        if (name[0] == '.')
4636d36ef34Smrg            continue;
4646d36ef34Smrg        if (strchr(name, '.') == NULL)
4656d36ef34Smrg            continue;
4666d36ef34Smrg        if (nentries >= nalloc) {
4676d36ef34Smrg            nalloc += ENTRYALLOC;
4686d36ef34Smrg            local_manual->entries =
4696d36ef34Smrg                (char **) XtRealloc((char *) local_manual->entries,
4706d36ef34Smrg                                    nalloc * sizeof(char *));
4716d36ef34Smrg            local_manual->entries_less_paths =
4726d36ef34Smrg                (char **) XtRealloc((char *) local_manual->entries_less_paths,
4736d36ef34Smrg                                    nalloc * sizeof(char *));
4746d36ef34Smrg        }
4756d36ef34Smrg
4766d36ef34Smrg        snprintf(full_name, sizeof(full_name), "%s/%s", path, name);
4771abf7346Smrg/*
4781abf7346Smrg * Remove the compression extension from the entry name.
4791abf7346Smrg */
4801abf7346Smrg
4816d36ef34Smrg        if ((ptr = strrchr(full_name, '.')) != NULL) {
4826d36ef34Smrg            if (streq(ptr + 1, COMPRESSION_EXTENSION))
4836d36ef34Smrg                *ptr = '\0';
4841abf7346Smrg#ifdef GZIP_EXTENSION
4856d36ef34Smrg            else if (streq(ptr + 1, GZIP_EXTENSION))
4866d36ef34Smrg                *ptr = '\0';
4871abf7346Smrg#endif
4888b6d6341Smrg#ifdef BZIP2_EXTENSION
4896d36ef34Smrg            else if (streq(ptr + 1, BZIP2_EXTENSION))
4906d36ef34Smrg                *ptr = '\0';
4918b6d6341Smrg#endif
4928b6d6341Smrg#ifdef LZMA_EXTENSION
4936d36ef34Smrg            else if (streq(ptr + 1, LZMA_EXTENSION))
4946d36ef34Smrg                *ptr = '\0';
4958b6d6341Smrg#endif
4961abf7346Smrg#ifdef IGNORE_EXTENSION
4976d36ef34Smrg            /* skip files with specified extension - they're not real man pages */
4986d36ef34Smrg            else if (streq(ptr + 1, IGNORE_EXTENSION)) {
4996d36ef34Smrg                continue;
5006d36ef34Smrg            }
5011abf7346Smrg#endif /* IGNORE_EXTENSION */
5026d36ef34Smrg        }
5036d36ef34Smrg        local_manual->entries[nentries] = XtNewString(full_name);
5046d36ef34Smrg        local_manual->entries_less_paths[nentries] =
5056d36ef34Smrg            strrchr(local_manual->entries[nentries], '/');
5066d36ef34Smrg        if (local_manual->entries_less_paths[nentries] == NULL)
5076d36ef34Smrg            PrintError("Internal error while cataloging manual pages.");
5086d36ef34Smrg        ++nentries;
5091abf7346Smrg    }
5106d36ef34Smrg
5116d36ef34Smrg    local_manual->nentries = nentries;
5126d36ef34Smrg    local_manual->nalloc = nalloc;
5136d36ef34Smrg
5146d36ef34Smrg    closedir(dir);
5151abf7346Smrg}
5161abf7346Smrg
5171abf7346Smrg/*	Function Name: SortAndRemove
5181abf7346Smrg *	Description: This function sorts all the entry names and
5191abf7346Smrg *                   then removes all the duplicate entries.
5201abf7346Smrg *	Arguments: man - a pointer to the manual structure.
5211abf7346Smrg *                 number - the number of manual sections.
5221abf7346Smrg *	Returns: an improved manual stucure
5231abf7346Smrg */
5241abf7346Smrg
5251abf7346Smrgstatic void
5266d36ef34SmrgSortAndRemove(Manual * man, int number)
5271abf7346Smrg{
5286d36ef34Smrg    int i;
5296d36ef34Smrg    char *l1, *l2, **s1;
5306d36ef34Smrg
5316d36ef34Smrg    for (i = 0; i < number; man++, i++) {       /* sort each section */
5326d36ef34Smrg        register int i2 = 0;
5336d36ef34Smrg
5341abf7346Smrg#ifdef DEBUG
5356d36ef34Smrg        printf("sorting section %d - %s\n", i, man->blabel);
5361abf7346Smrg#endif /* DEBUG */
5371abf7346Smrg
5386d36ef34Smrg        s1 = (char **) malloc(man->nentries * sizeof(char *));
5396d36ef34Smrg
5406d36ef34Smrg        /* temporarily remove suffixes of entries, preventing them from */
5416d36ef34Smrg        /* being used in alphabetic comparison ie sccs-delta.1 vs sccs.1 */
5426d36ef34Smrg        for (i2 = 0; i2 < man->nentries; i2++)
5436d36ef34Smrg            if ((s1[i2] = strrchr(man->entries_less_paths[i2], '.')) != NULL)
5446d36ef34Smrg                *s1[i2] = '\0';
5451abf7346Smrg
5466d36ef34Smrg        sortstrs((Byte **) man->entries_less_paths, man->nentries,
5476d36ef34Smrg                 (Byte **) man->entries);
5481abf7346Smrg
5496d36ef34Smrg        /* put back suffixes */
5506d36ef34Smrg        for (i2 = 0; i2 < man->nentries; i2++)
5516d36ef34Smrg            if (s1[i2] != NULL)
5526d36ef34Smrg                *s1[i2] = '.';
5536d36ef34Smrg
5546d36ef34Smrg        free(s1);
5551abf7346Smrg
5561abf7346Smrg#ifdef DEBUG
5576d36ef34Smrg        printf("removing from section %d.\n", i);
5581abf7346Smrg#endif /* DEBUG */
5596d36ef34Smrg
5606d36ef34Smrg        {
5616d36ef34Smrg            register int j, k, nent, nentm1;
5626d36ef34Smrg            int j2;
5636d36ef34Smrg
5646d36ef34Smrg            nent = man->nentries;
5656d36ef34Smrg            nentm1 = nent - 1;
5666d36ef34Smrg            j = 0;
5676d36ef34Smrg            l2 = man->entries_less_paths[j++];
5686d36ef34Smrg            if (l2 == NULL)
5696d36ef34Smrg                PrintError
5706d36ef34Smrg                    ("Internal error while removing duplicate manual pages.");
5716d36ef34Smrg            while (j < nentm1) {
5726d36ef34Smrg                l1 = l2;
5736d36ef34Smrg                l2 = man->entries_less_paths[j++];
5746d36ef34Smrg                if (l2 == NULL)
5756d36ef34Smrg                    PrintError
5766d36ef34Smrg                        ("Internal error while removing duplicate manual pages.");
5776d36ef34Smrg                if (streq(l1, l2)) {
5786d36ef34Smrg                    j2 = j - 1;
5796d36ef34Smrg                    k = j2;
5806d36ef34Smrg                    while (j < nent) {
5816d36ef34Smrg                        man->entries_less_paths[k] = man->entries_less_paths[j];
5826d36ef34Smrg                        man->entries[k++] = man->entries[j++];
5836d36ef34Smrg                    }
5846d36ef34Smrg                    j = j2;
5856d36ef34Smrg                    --man->nentries;
5866d36ef34Smrg                    --nent;
5876d36ef34Smrg                    --nentm1;
5881abf7346Smrg                }
5896d36ef34Smrg            }
5906d36ef34Smrg        }
5911abf7346Smrg    }
5921abf7346Smrg}
5931abf7346Smrg
5941abf7346Smrg /*
5956d36ef34Smrg  *******  Replacement for qsort to keep
5966d36ef34Smrg  *******  identical entries in order
5976d36ef34Smrg
5986d36ef34Smrg  A somewhat ugly hack of something that was once simpler...
5996d36ef34Smrg  */
6001abf7346Smrg /*
6016d36ef34Smrg    Sort an array of pointers to strings, keeping it
6026d36ef34Smrg    in ascending order by (1) string comparison and
6036d36ef34Smrg    (2) original entry order in the pointer array.
6046d36ef34Smrg
6056d36ef34Smrg    This is a modified radix exchange algorithm.
6066d36ef34Smrg
6076d36ef34Smrg    In case there's insufficient memory for a temporary copy
6086d36ef34Smrg    of the pointer array, the original order of identical strings
6096d36ef34Smrg    isn't preserved.
6106d36ef34Smrg  */
6116d36ef34Smrg
6126d36ef34Smrgstatic void
6136d36ef34Smrgsortstrs(Byte * data[], int size, Byte * otherdata[])
6141abf7346Smrg{
6156d36ef34Smrg    Byte **sp, **ep;
6166d36ef34Smrg    Byte **othersp, **otherep;
6176d36ef34Smrg    int *origorder;
6186d36ef34Smrg
6196d36ef34Smrg    origorder = (int *) calloc(size, sizeof(int));
6206d36ef34Smrg    if (origorder) {
6216d36ef34Smrg        reg int i;
6226d36ef34Smrg
6236d36ef34Smrg        for (i = 0; i < size; ++i)
6246d36ef34Smrg            origorder[i] = i;
6251abf7346Smrg    }
6266d36ef34Smrg
6276d36ef34Smrg    sp = data;
6286d36ef34Smrg    ep = &data[size - 1];
6296d36ef34Smrg    othersp = otherdata;
6306d36ef34Smrg    otherep = &otherdata[size - 1];
6316d36ef34Smrg    if (origorder) {
6326d36ef34Smrg        sortstrs_block_oo(sp, ep, 0, 0x80, origorder, &origorder[size - 1],
6336d36ef34Smrg                          othersp, otherep);
6346d36ef34Smrg        free(origorder);
6351abf7346Smrg    }
6366d36ef34Smrg    else
6376d36ef34Smrg        sortstrs_block(sp, ep, 0, 0x80, othersp, otherep);
6381abf7346Smrg}
6391abf7346Smrg
6406d36ef34Smrg
6416d36ef34Smrg
6421abf7346Smrg /*---------------------------------*/
6431abf7346Smrg /*  Sort 1 block of data on 1 bit  */
6441abf7346Smrg /*---------------------------------*/
6456d36ef34Smrg
6461abf7346Smrgstatic void
6476d36ef34Smrgsortstrs_block(Byte ** start, Byte ** end, int offset, Byte mask,
6486d36ef34Smrg               Byte ** otherstart, Byte ** otherend)
6491abf7346Smrg{
6506d36ef34Smrg    reg Byte **sp, **ep;
6516d36ef34Smrg    reg Byte m;
6526d36ef34Smrg    reg int off;
6536d36ef34Smrg    reg Byte *t;
6546d36ef34Smrg    reg int curstrlen;
6556d36ef34Smrg    int maxstrlen;
6566d36ef34Smrg    Byte **othersp, **otherep;
6576d36ef34Smrg
6586d36ef34Smrg
6596d36ef34Smrg#define       newstring(ptr)                    \
6601abf7346Smrg { \
6611abf7346Smrg t = *ptr; \
6621abf7346Smrg curstrlen = 0; \
6631abf7346Smrg while ( *t++ ) ++ curstrlen; \
6641abf7346Smrg if ( curstrlen > maxstrlen ) maxstrlen = curstrlen; \
6651abf7346Smrg t = *ptr; \
6661abf7346Smrg }
6676d36ef34Smrg
6686d36ef34Smrg
6696d36ef34Smrg    maxstrlen = 0;
6706d36ef34Smrg    sp = start;
6716d36ef34Smrg    ep = end;
6726d36ef34Smrg    off = offset;
6736d36ef34Smrg    m = mask;
6746d36ef34Smrg    othersp = otherstart;
6756d36ef34Smrg    otherep = otherend;
6766d36ef34Smrg
6776d36ef34Smrg    while (1) {
6786d36ef34Smrg        newstring(sp)
6796d36ef34Smrg            while (((sp != ep) && ((curstrlen < off) || ((t[off] & m) == 0)))) {
6806d36ef34Smrg            ++sp;
6816d36ef34Smrg            ++othersp;
6826d36ef34Smrg            newstring(sp)
6836d36ef34Smrg        }
6846d36ef34Smrg        if (sp == ep)
6856d36ef34Smrg            break;
6866d36ef34Smrg
6876d36ef34Smrg        newstring(ep);
6886d36ef34Smrg        while (((sp != ep) && (curstrlen >= off) && ((t[off] & m) != 0))) {
6896d36ef34Smrg            --ep;
6906d36ef34Smrg            --otherep;
6916d36ef34Smrg            newstring(ep)
6926d36ef34Smrg        }
6936d36ef34Smrg        if (sp == ep)
6946d36ef34Smrg            break;
6956d36ef34Smrg
6966d36ef34Smrg        t = *sp;
6976d36ef34Smrg        *sp = *ep;
6986d36ef34Smrg        *ep = t;
6996d36ef34Smrg
7006d36ef34Smrg        t = *othersp;
7016d36ef34Smrg        *othersp = *otherep;
7026d36ef34Smrg        *otherep = t;
7031abf7346Smrg    }
7046d36ef34Smrg
7056d36ef34Smrg    t = *sp;
7066d36ef34Smrg    if ((curstrlen < off) || ((t[off] & m) == 0)) {
7076d36ef34Smrg        if (ep != end) {
7086d36ef34Smrg            ++ep;
7096d36ef34Smrg            ++otherep;
7106d36ef34Smrg        }
7111abf7346Smrg    }
7126d36ef34Smrg    else {
7136d36ef34Smrg        if (sp != start) {
7146d36ef34Smrg            --sp;
7156d36ef34Smrg            --othersp;
7166d36ef34Smrg        }
7171abf7346Smrg    }
7186d36ef34Smrg
7196d36ef34Smrg    m >>= 1;
7206d36ef34Smrg    if (m == 0) {
7216d36ef34Smrg        m = 0x80;
7226d36ef34Smrg        if (++off >= maxstrlen)
7236d36ef34Smrg            return;
7246d36ef34Smrg    }
7256d36ef34Smrg
7266d36ef34Smrg    if (sp != start)
7276d36ef34Smrg        sortstrs_block(start, sp, off, m, otherstart, othersp);
7286d36ef34Smrg    if (ep != end)
7296d36ef34Smrg        sortstrs_block(ep, end, off, m, otherep, otherend);
7301abf7346Smrg}
7311abf7346Smrg
7326d36ef34Smrg
7336d36ef34Smrg
7341abf7346Smrg /*-----------------------------------------------------------------*/
7351abf7346Smrg /*  Sort 1 block of data on 1 bit; check for out-of-order entries  */
7361abf7346Smrg /*-----------------------------------------------------------------*/
7376d36ef34Smrg
7381abf7346Smrgstatic void
7396d36ef34Smrgsortstrs_block_oo(Byte ** start, Byte ** end, int offset, Byte mask,
7406d36ef34Smrg                  int *ostart, int *oend, Byte ** otherstart, Byte ** otherend)
7411abf7346Smrg{
7426d36ef34Smrg    reg Byte **sp, **ep;
7436d36ef34Smrg    reg int *osp, *oep;
7446d36ef34Smrg    reg Byte m;
7456d36ef34Smrg    reg int off;
7466d36ef34Smrg    reg Byte *t;
7476d36ef34Smrg    reg int u;
7486d36ef34Smrg    reg int curstrlen;
7496d36ef34Smrg    int maxstrlen;
7506d36ef34Smrg    Byte **othersp, **otherep;
7516d36ef34Smrg
7526d36ef34Smrg
7531abf7346Smrg#define       newstring(ptr) \
7541abf7346Smrg { \
7551abf7346Smrg t = *ptr; \
7561abf7346Smrg curstrlen = 0; \
7571abf7346Smrg while ( *t++ ) ++ curstrlen; \
7581abf7346Smrg if ( curstrlen > maxstrlen ) maxstrlen = curstrlen; \
7591abf7346Smrg t = *ptr; \
7601abf7346Smrg }
7616d36ef34Smrg
7626d36ef34Smrg
7636d36ef34Smrg    maxstrlen = 0;
7646d36ef34Smrg    sp = start;
7656d36ef34Smrg    ep = end;
7666d36ef34Smrg    osp = ostart;
7676d36ef34Smrg    oep = oend;
7686d36ef34Smrg    off = offset;
7696d36ef34Smrg    m = mask;
7706d36ef34Smrg    othersp = otherstart;
7716d36ef34Smrg    otherep = otherend;
7726d36ef34Smrg
7736d36ef34Smrg    while (1) {
7746d36ef34Smrg        newstring(sp)
7756d36ef34Smrg            while (((sp != ep) && ((curstrlen < off) || ((t[off] & m) == 0)))) {
7766d36ef34Smrg            ++sp;
7776d36ef34Smrg            ++osp;
7786d36ef34Smrg            ++othersp;
7796d36ef34Smrg            newstring(sp)
7806d36ef34Smrg        }
7816d36ef34Smrg        if (sp == ep)
7826d36ef34Smrg            break;
7836d36ef34Smrg
7846d36ef34Smrg        newstring(ep);
7856d36ef34Smrg        while (((sp != ep) && (curstrlen >= off) && ((t[off] & m) != 0))) {
7866d36ef34Smrg            --ep;
7876d36ef34Smrg            --oep;
7886d36ef34Smrg            --otherep;
7896d36ef34Smrg            newstring(ep)
7906d36ef34Smrg        }
7916d36ef34Smrg        if (sp == ep)
7926d36ef34Smrg            break;
7936d36ef34Smrg
7946d36ef34Smrg        t = *sp;
7956d36ef34Smrg        *sp = *ep;
7966d36ef34Smrg        *ep = t;
7976d36ef34Smrg
7986d36ef34Smrg        t = *othersp;
7996d36ef34Smrg        *othersp = *otherep;
8006d36ef34Smrg        *otherep = t;
8016d36ef34Smrg
8026d36ef34Smrg        u = *osp;
8036d36ef34Smrg        *osp = *oep;
8046d36ef34Smrg        *oep = u;
8051abf7346Smrg    }
8066d36ef34Smrg
8076d36ef34Smrg    t = *sp;
8086d36ef34Smrg    if ((curstrlen < off) || ((t[off] & m) == 0)) {
8096d36ef34Smrg        if (ep != end) {
8106d36ef34Smrg            ++ep;
8116d36ef34Smrg            ++oep;
8126d36ef34Smrg            ++otherep;
8136d36ef34Smrg        }
8141abf7346Smrg    }
8156d36ef34Smrg    else {
8166d36ef34Smrg        if (sp != start) {
8176d36ef34Smrg            --sp;
8186d36ef34Smrg            --osp;
8196d36ef34Smrg            --othersp;
8201abf7346Smrg        }
8216d36ef34Smrg    }
8226d36ef34Smrg
8236d36ef34Smrg    m >>= 1;
8246d36ef34Smrg    if (m == 0) {
8256d36ef34Smrg        m = 0x80;
8266d36ef34Smrg        if (++off >= maxstrlen) {       /*  Finished sorting block of strings:    *//*  Restore duplicates to original order  */
8276d36ef34Smrg            reg Byte **cp;
8286d36ef34Smrg            reg int *ocp;
8296d36ef34Smrg            Byte **othercp;
8306d36ef34Smrg
8316d36ef34Smrg            if (sp != start) {
8326d36ef34Smrg                cp = start;
8336d36ef34Smrg                ocp = ostart;
8346d36ef34Smrg                othercp = otherstart;
8356d36ef34Smrg                while (cp != sp) {
8366d36ef34Smrg                    if (*ocp > *(ocp + 1)) {
8376d36ef34Smrg                        t = *(cp + 1);
8386d36ef34Smrg                        *(cp + 1) = *cp;
8396d36ef34Smrg                        *cp = t;
8406d36ef34Smrg
8416d36ef34Smrg                        t = *(othercp + 1);
8426d36ef34Smrg                        *(othercp + 1) = *othercp;
8436d36ef34Smrg                        *othercp = t;
8446d36ef34Smrg
8456d36ef34Smrg                        u = *(ocp + 1);
8466d36ef34Smrg                        *(ocp + 1) = *ocp;
8476d36ef34Smrg                        *ocp = u;
8486d36ef34Smrg
8496d36ef34Smrg                        if (cp != start) {
8506d36ef34Smrg                            --cp;
8516d36ef34Smrg                            --ocp;
8526d36ef34Smrg                            --othercp;
8536d36ef34Smrg                            continue;
8546d36ef34Smrg                        }
8556d36ef34Smrg                    }
8566d36ef34Smrg                    ++cp;
8576d36ef34Smrg                    ++ocp;
8586d36ef34Smrg                    ++othercp;
8596d36ef34Smrg                }
8606d36ef34Smrg            }
8616d36ef34Smrg            if (ep != end) {
8626d36ef34Smrg                cp = ep;
8636d36ef34Smrg                ocp = oep;
8646d36ef34Smrg                othercp = otherep;
8656d36ef34Smrg                while (cp != end) {
8666d36ef34Smrg                    if (*ocp > *(ocp + 1)) {
8676d36ef34Smrg                        t = *(cp + 1);
8686d36ef34Smrg                        *(cp + 1) = *cp;
8696d36ef34Smrg                        *cp = t;
8706d36ef34Smrg
8716d36ef34Smrg                        t = *(othercp + 1);
8726d36ef34Smrg                        *(othercp + 1) = *othercp;
8736d36ef34Smrg                        *othercp = t;
8746d36ef34Smrg
8756d36ef34Smrg                        u = *(ocp + 1);
8766d36ef34Smrg                        *(ocp + 1) = *ocp;
8776d36ef34Smrg                        *ocp = u;
8786d36ef34Smrg
8796d36ef34Smrg                        if (cp != ep) {
8806d36ef34Smrg                            --cp;
8816d36ef34Smrg                            --ocp;
8826d36ef34Smrg                            --othercp;
8836d36ef34Smrg                            continue;
8846d36ef34Smrg                        }
8856d36ef34Smrg                    }
8866d36ef34Smrg                    ++cp;
8876d36ef34Smrg                    ++ocp;
8886d36ef34Smrg                    ++othercp;
8896d36ef34Smrg                }
8906d36ef34Smrg            }
8916d36ef34Smrg            return;
8921abf7346Smrg        }
8931abf7346Smrg    }
8946d36ef34Smrg
8956d36ef34Smrg    if (sp != start)
8966d36ef34Smrg        sortstrs_block_oo(start, sp, off, m, ostart, osp, otherstart, othersp);
8976d36ef34Smrg    if (ep != end)
8986d36ef34Smrg        sortstrs_block_oo(ep, end, off, m, oep, oend, otherep, otherend);
8991abf7346Smrg}
9001abf7346Smrg
9011abf7346Smrg
9021abf7346Smrg/*	Function Name: InitManual
9031abf7346Smrg *	Description: Initializes this manual section.
9041abf7346Smrg *	Arguments: l_manual - local copy of the manual structure.
9051abf7346Smrg *                 label - the button label for this section.
9061abf7346Smrg *	Returns: none.
9071abf7346Smrg */
9081abf7346Smrg
9091abf7346Smrgstatic void
9106d36ef34SmrgInitManual(Manual * l_manual, char *label)
9111abf7346Smrg{
9126d36ef34Smrg    bzero(l_manual, sizeof(Manual));    /* clear it. */
9136d36ef34Smrg    l_manual->blabel = label;   /* set label. */
9141abf7346Smrg}
9156d36ef34Smrg
9161abf7346Smrg#if defined(DEBUG)
9171abf7346Smrg
9181abf7346Smrg/*	Function Name: DumpManual
9191abf7346Smrg *	Description: Debugging function that dumps the entire manual page
9201abf7346Smrg *                   structure.
9211abf7346Smrg *	Arguments: number - the number of sections.
9221abf7346Smrg *	Returns: none.
9231abf7346Smrg */
9241abf7346Smrg
9251abf7346Smrgvoid
9261abf7346SmrgDumpManual(int number)
9271abf7346Smrg{
9286d36ef34Smrg    register int i, j;
9296d36ef34Smrg
9306d36ef34Smrg    for (i = 0; i < number; i++) {
9316d36ef34Smrg        printf("label: %s\n", manual[i].blabel);
9326d36ef34Smrg        for (j = 0; j < manual[i].nentries; j++)
9336d36ef34Smrg            printf("%s\n", manual[i].entries[j]);
9346d36ef34Smrg    }
9351abf7346Smrg}
9361abf7346Smrg
9371abf7346Smrg#endif /* DEBUG */
9381abf7346Smrg
9391abf7346Smrg
9401abf7346Smrg
9411abf7346Smrg#ifdef MANCONF
9421abf7346Smrg
9431abf7346Smrg#if defined(MANCONFIGSTYLE_FreeBSD)
9441abf7346Smrg
9451abf7346Smrg/*    Function Name: ReadManConfig
9461abf7346Smrg *    Description: Reads man.conf file used by FreeBSD man
9471abf7346Smrg *      Argument: manpath - char array to return path in.
9481abf7346Smrg *    Returns: TRUE if read was successful.
9491abf7346Smrg */
9501abf7346Smrg
9511abf7346SmrgBool
9521abf7346SmrgReadManConfig(char manpath[])
9531abf7346Smrg{
9546d36ef34Smrg    FILE *fp;
9556d36ef34Smrg    char line[BUFSIZ];
9566d36ef34Smrg    char *path;
9576d36ef34Smrg    Bool firstpath = TRUE;
9586d36ef34Smrg
9596d36ef34Smrg    if (!(fp = fopen(MANCONF, "r")))
9606d36ef34Smrg        return (FALSE);
9616d36ef34Smrg
9626d36ef34Smrg    while (fgets(line, sizeof(line), fp)) {
9636d36ef34Smrg        path = strtok(line, " \t\n");
9646d36ef34Smrg        if (!path || *path == '#')
9656d36ef34Smrg            continue;
9666d36ef34Smrg        if (strcmp(path, "MANPATH_MAP") == 0)
9676d36ef34Smrg            path = strtok((char *) NULL, " \t\n");
9686d36ef34Smrg        else if (strcmp(path, "MANDATORY_MANPATH") != 0 &&
9696d36ef34Smrg                 strcmp(path, "OPTIONAL_MANPATH") != 0)
9706d36ef34Smrg            return (FALSE);
9716d36ef34Smrg        path = strtok((char *) NULL, " \t\n");
9726d36ef34Smrg        if (!path || *path == '#')
9736d36ef34Smrg            return FALSE;
9746d36ef34Smrg        if (firstpath) {
9756d36ef34Smrg            strcpy(manpath, path);
9766d36ef34Smrg            firstpath = FALSE;
9776d36ef34Smrg        }
9786d36ef34Smrg        else if (!strstr(manpath, path)) {
9796d36ef34Smrg            strcat(manpath, ":");
9806d36ef34Smrg            strcat(manpath, path);
9816d36ef34Smrg        }
9821abf7346Smrg    }
9836d36ef34Smrg    fclose(fp);
9846d36ef34Smrg    return (!firstpath);
9851abf7346Smrg}
9861abf7346Smrg
9871abf7346Smrg
9886d36ef34Smrg#elif defined(MANCONFIGSTYLE_Linux)     /* not FreeBSD */
9891abf7346Smrg
9901abf7346Smrg/*    Function Name: ReadManConfig
9911abf7346Smrg *    Description: Reads man.conf file used by Linux man
9921abf7346Smrg *      Argument: manpath - char array to return path in.
9931abf7346Smrg *    Returns: TRUE if read was successful.
9941abf7346Smrg */
9951abf7346Smrg
9961abf7346SmrgBool
9971abf7346SmrgReadManConfig(char manpath[])
9981abf7346Smrg{
9996d36ef34Smrg    FILE *fp;
10006d36ef34Smrg    char line[BUFSIZ];
10016d36ef34Smrg    char *path;
10026d36ef34Smrg    Bool firstpath = TRUE;
10036d36ef34Smrg
10046d36ef34Smrg    if (!(fp = fopen(MANCONF, "r")))
10056d36ef34Smrg        return (FALSE);
10066d36ef34Smrg
10076d36ef34Smrg    while (fgets(line, sizeof(line), fp)) {
10086d36ef34Smrg        path = strtok(line, " \t\n");
10096d36ef34Smrg        if (!path || *path == '#' || (strcmp(path, "MANPATH") != 0))
10106d36ef34Smrg            continue;
10116d36ef34Smrg        path = strtok((char *) NULL, " \t\n");
10126d36ef34Smrg        if (!path || *path == '#')
10136d36ef34Smrg            return FALSE;
10146d36ef34Smrg        if (firstpath) {
10156d36ef34Smrg            strcpy(manpath, path);
10166d36ef34Smrg            firstpath = FALSE;
10176d36ef34Smrg        }
10186d36ef34Smrg        else {
10196d36ef34Smrg            strcat(manpath, ":");
10206d36ef34Smrg            strcat(manpath, path);
10216d36ef34Smrg        }
10221abf7346Smrg    }
10236d36ef34Smrg    fclose(fp);
10246d36ef34Smrg    return (!firstpath);
10251abf7346Smrg}
10261abf7346Smrg
10276d36ef34Smrg#elif defined(MANCONFIGSTYLE_OpenBSD)   /* not FreeBSD or Linux */
10281abf7346Smrg
10291abf7346Smrg/*    Function Name: ReadManConfig
10301abf7346Smrg *    Description: Reads man.conf file used by Open/NetBSD
10311abf7346Smrg *      Argument: manpath - char array to return path in.
10321abf7346Smrg *    Returns: TRUE if read was successful.
10331abf7346Smrg *
10346d36ef34Smrg *     This version expands the glob pattern that can be found
10351abf7346Smrg *     in man.conf
10361abf7346Smrg */
10371abf7346Smrg#include <glob.h>
10381abf7346Smrg
10391abf7346SmrgBool
10401abf7346SmrgReadManConfig(char manpath[])
10411abf7346Smrg{
10426d36ef34Smrg    FILE *fp;
10436d36ef34Smrg    char line[BUFSIZ];
10446d36ef34Smrg    char *path;
10456d36ef34Smrg    Bool firstpath = TRUE;
10466d36ef34Smrg    glob_t gs;
10476d36ef34Smrg    int i;
10486d36ef34Smrg
10491abf7346Smrg    if (!(fp = fopen(MANCONF, "r")))
10506d36ef34Smrg        return (FALSE);
10516d36ef34Smrg
10521abf7346Smrg    while (fgets(line, sizeof(line), fp)) {
10536d36ef34Smrg        path = strtok(line, " \t\n");
10546d36ef34Smrg        if (!path || *path == '#')
10556d36ef34Smrg            continue;
10566d36ef34Smrg        if (strcmp(path, "_default")) {
10576d36ef34Smrg            /* for now */
10586d36ef34Smrg            continue;
10596d36ef34Smrg        }
10606d36ef34Smrg        memset(&gs, 0, sizeof(glob_t));
10616d36ef34Smrg        while ((path = strtok((char *) NULL, " \t\n"))) {
10626d36ef34Smrg            if (glob(path, GLOB_BRACE, NULL, &gs) < 0) {
10636d36ef34Smrg                fclose(fp);
10646d36ef34Smrg                return FALSE;
10656d36ef34Smrg            }
10666d36ef34Smrg        }                       /* while */
10676d36ef34Smrg        for (i = 0; i < gs.gl_pathc; i++) {
10686d36ef34Smrg
10696d36ef34Smrg            if (firstpath) {
10706d36ef34Smrg                strcpy(manpath, gs.gl_pathv[i]);
10716d36ef34Smrg                firstpath = FALSE;
10726d36ef34Smrg            }
10736d36ef34Smrg            else {
10746d36ef34Smrg                strcat(manpath, ":");
10756d36ef34Smrg                strcat(manpath, gs.gl_pathv[i]);
10766d36ef34Smrg            }
10776d36ef34Smrg        }                       /* for */
10786d36ef34Smrg        globfree(&gs);
10791abf7346Smrg    }
10801abf7346Smrg    fclose(fp);
10816d36ef34Smrg    return (!firstpath);
10821abf7346Smrg}
10831abf7346Smrg
10846d36ef34Smrg#elif defined(MANCONFIGSTYLE_BSD)       /* not FreeBSD, Linux, or OpenBSD */
10851abf7346Smrg
10861abf7346Smrg/*    Function Name: ReadManConfig
10871abf7346Smrg *    Description: Reads man.conf file used by BSD 4.4
10881abf7346Smrg *      Argument: manpath - char array to return path in.
10891abf7346Smrg *    Returns: TRUE if read was successful.
10901abf7346Smrg */
10911abf7346Smrg
10921abf7346SmrgBool
10936d36ef34SmrgReadManConfig(char manpath[])
10946d36ef34Smrg{
10956d36ef34Smrg    FILE *fp;
10966d36ef34Smrg    char line[BUFSIZ];
10976d36ef34Smrg    char *path;
10986d36ef34Smrg    Bool firstpath = TRUE;
10991abf7346Smrg
11006d36ef34Smrg    if (!(fp = fopen(MANCONF, "r")))
11016d36ef34Smrg        return (FALSE);
11021abf7346Smrg
11036d36ef34Smrg    while (fgets(line, sizeof(line), fp)) {
11046d36ef34Smrg        path = strtok(line, " \t\n");
11056d36ef34Smrg        if (!path || *path == '#' || strcmp(path, "_default"))
11066d36ef34Smrg            continue;
11076d36ef34Smrg        while ((path = strtok((char *) NULL, " \t\n"))) {
11086d36ef34Smrg            if (firstpath) {
11096d36ef34Smrg                strcpy(manpath, path);
11106d36ef34Smrg                firstpath = FALSE;
11116d36ef34Smrg            }
11126d36ef34Smrg            else {
11136d36ef34Smrg                strcat(manpath, ":");
11146d36ef34Smrg                strcat(manpath, path);
11156d36ef34Smrg            }
11166d36ef34Smrg        }
11171abf7346Smrg    }
11186d36ef34Smrg    fclose(fp);
11196d36ef34Smrg    return (!firstpath);
11201abf7346Smrg}
11211abf7346Smrg
11221abf7346Smrg#else /* not BSD */
11231abf7346Smrg
11241abf7346Smrg#error "MANCONF defined (in vendor.h) for unknown operating system."
11251abf7346Smrg
11261abf7346Smrg#endif /* MANCONFIGSTYLE == FreeBSD ... BSD */
11271abf7346Smrg
11281abf7346Smrg#endif /* MANCONF */
1129