man.c revision 8b6d6341
11abf7346Smrg/* $XConsortium: man.c,v 1.30 94/04/17 20:43:56 rws Exp $ */
21abf7346Smrg/* $XdotOrg: $ */
31abf7346Smrg/*
41abf7346Smrg
51abf7346SmrgCopyright (c) 1987, 1988  X Consortium
61abf7346Smrg
71abf7346SmrgPermission is hereby granted, free of charge, to any person obtaining
81abf7346Smrga copy of this software and associated documentation files (the
91abf7346Smrg"Software"), to deal in the Software without restriction, including
101abf7346Smrgwithout limitation the rights to use, copy, modify, merge, publish,
111abf7346Smrgdistribute, sublicense, and/or sell copies of the Software, and to
121abf7346Smrgpermit persons to whom the Software is furnished to do so, subject to
131abf7346Smrgthe following conditions:
141abf7346Smrg
151abf7346SmrgThe above copyright notice and this permission notice shall be included
161abf7346Smrgin all copies or substantial portions of the Software.
171abf7346Smrg
181abf7346SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
191abf7346SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
201abf7346SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
211abf7346SmrgIN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
221abf7346SmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
231abf7346SmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
241abf7346SmrgOTHER DEALINGS IN THE SOFTWARE.
251abf7346Smrg
261abf7346SmrgExcept as contained in this notice, the name of the X Consortium shall
271abf7346Smrgnot be used in advertising or otherwise to promote the sale, use or
281abf7346Smrgother dealings in this Software without prior written authorization
291abf7346Smrgfrom the X Consortium.
301abf7346Smrg
311abf7346Smrg*/
321abf7346Smrg/* $XFree86: xc/programs/xman/man.c,v 1.8 2003/04/09 20:31:31 herrb Exp $ */
331abf7346Smrg
341abf7346Smrg
351abf7346Smrg#include "globals.h"
361abf7346Smrg#include "vendor.h"		/* vendor-specific defines and data */
371abf7346Smrg
381abf7346Smrg#ifndef X_NOT_POSIX
391abf7346Smrg#include <dirent.h>
401abf7346Smrg#else
411abf7346Smrg#ifdef SYSV
421abf7346Smrg#include <dirent.h>
431abf7346Smrg#else
441abf7346Smrg#ifdef USG
451abf7346Smrg#include <dirent.h>
461abf7346Smrg#else
471abf7346Smrg#include <sys/dir.h>
481abf7346Smrg#ifndef dirent
491abf7346Smrg#define dirent direct
501abf7346Smrg#endif
511abf7346Smrg#endif
521abf7346Smrg#endif
531abf7346Smrg#endif
541abf7346Smrg
551abf7346Smrg#ifdef DEBUG
561abf7346Smrgstatic char error_buf[BUFSIZ];		/* The buffer for error messages. */
571abf7346Smrg#endif /* DEBUG */
581abf7346Smrg
591abf7346Smrgstatic void AddToCurrentSection(Manual * local_manual, char * path);
601abf7346Smrgstatic void InitManual(Manual * l_manual, char * label);
611abf7346Smrgstatic void ReadCurrentSection(Manual * local_manual, char * path);
621abf7346Smrgstatic void ReadMandescFile(SectionList ** section_list, char * path);
631abf7346Smrgstatic void SortAndRemove(Manual *man, int number);
641abf7346Smrgstatic void SortList(SectionList ** list);
651abf7346Smrg
661abf7346Smrg#define SECT_ERROR -1
671abf7346Smrg
681abf7346Smrg#ifndef       Byte
691abf7346Smrg#define       Byte    unsigned char
701abf7346Smrg#endif
711abf7346Smrg
721abf7346Smrg#ifndef       reg
731abf7346Smrg#define       reg     register
741abf7346Smrg#endif
751abf7346Smrg
761abf7346Smrgstatic void sortstrs (Byte *data[], int size, Byte *otherdata[]);
771abf7346Smrgstatic void sortstrs_block (Byte **, Byte **, int, Byte, Byte **, Byte **);
781abf7346Smrgstatic void sortstrs_block_oo (Byte **, Byte **, int, Byte, int *, int *, Byte **, Byte **);
791abf7346Smrg
801abf7346Smrg/*	Function Name: Man
811abf7346Smrg *	Description: Builds a list of all manual directories and files.
821abf7346Smrg *	Arguments: none.
831abf7346Smrg *	Returns: the number of manual sections.
841abf7346Smrg */
851abf7346Smrg
861abf7346Smrgint
871abf7346SmrgMan(void)
881abf7346Smrg{
891abf7346Smrg  SectionList *list = NULL;
908b6d6341Smrg  char *ptr, *lang = NULL, manpath[BUFSIZ], buf[BUFSIZ], *path, *current_label;
911abf7346Smrg  int sect, num_alloced;
921abf7346Smrg
931abf7346Smrg/*
941abf7346Smrg * Get the environment variable MANPATH, and if it doesn't exist then use
951abf7346Smrg * SYSMANPATH and LOCALMANPATH.
961abf7346Smrg */
971abf7346Smrg
981abf7346Smrg  /* if MANPATH variable ends in ':'. So, should extend it's value to the
991abf7346Smrg   * default search path.
1001abf7346Smrg   */
1011abf7346Smrg
1021abf7346Smrg  *manpath = '\0';
1031abf7346Smrg  if ((ptr = getenv("MANPATH")) != NULL)
1041abf7346Smrg    strcpy(manpath, ptr);
1051abf7346Smrg  if (ptr == NULL || streq(ptr , "") || ptr[strlen(ptr) - 1] == ':') {
1061abf7346Smrg    lang = getenv("LANG");
1071abf7346Smrg#ifdef MANCONF
1081abf7346Smrg    if (!ReadManConfig(manpath + strlen(manpath)))
1091abf7346Smrg#endif
1101abf7346Smrg    {
1111abf7346Smrg#ifdef MANCONF
1121abf7346Smrg      if (manpath[strlen(manpath) - 1] != ':')
1131abf7346Smrg	strcat(manpath, ":");
1141abf7346Smrg#endif
1151abf7346Smrg      strcat(manpath, SYSMANPATH);
1161abf7346Smrg#ifdef LOCALMANPATH
1171abf7346Smrg      strcat(manpath, ":");
1181abf7346Smrg      strcat(manpath, LOCALMANPATH);
1191abf7346Smrg#endif
1201abf7346Smrg    }
1211abf7346Smrg  }
1221abf7346Smrg
1231abf7346Smrg/*
1241abf7346Smrg * Get the list of manual directories in the users MANPATH that we should
1251abf7346Smrg * open to look for manual pages.  The ``mandesc'' file is read here.
1261abf7346Smrg */
1271abf7346Smrg
1281abf7346Smrg  for ( path = manpath ; (ptr = index(path , ':')) != NULL ; path = ++ptr) {
1291abf7346Smrg    *ptr = '\0';
1308b6d6341Smrg    if (lang != NULL) {
1311abf7346Smrg      strcpy(buf, path);
1321abf7346Smrg      strcat(buf, "/");
1331abf7346Smrg      strncat(buf, lang, sizeof(buf) - strlen(path) + 1);
1341abf7346Smrg      buf[sizeof(buf) - strlen(path) + 1] = '\0';
1351abf7346Smrg      ReadMandescFile(&list, buf);
1361abf7346Smrg    }
1371abf7346Smrg    ReadMandescFile(&list, path);
1381abf7346Smrg  }
1398b6d6341Smrg  if (lang != NULL) {
1401abf7346Smrg    strcpy(buf, path);
1411abf7346Smrg    strcat(buf, "/");
1421abf7346Smrg    strncat(buf, lang, sizeof(buf) - strlen(path) + 1);
1431abf7346Smrg    buf[sizeof(buf) - strlen(path) + 1] = '\0';
1441abf7346Smrg    ReadMandescFile(&list, buf);
1451abf7346Smrg  }
1461abf7346Smrg  ReadMandescFile(&list, path);
1471abf7346Smrg
1481abf7346Smrg  SortList(&list);
1491abf7346Smrg
1501abf7346Smrg  sect = 0;
1511abf7346Smrg  num_alloced = SECTALLOC;
1521abf7346Smrg  manual = (Manual *) XtMalloc( sizeof(Manual) * num_alloced );
1531abf7346Smrg  InitManual( manual, list->label );
1541abf7346Smrg  manual[sect].flags = list->flags;
1551abf7346Smrg  current_label = NULL;
1561abf7346Smrg
1571abf7346Smrg  while ( list != NULL ) {
1581abf7346Smrg    SectionList * old_list;
1591abf7346Smrg
1601abf7346Smrg    if ( current_label == NULL || streq(list->label, current_label) )
1611abf7346Smrg      AddToCurrentSection( manual + sect, list->directory);
1621abf7346Smrg    else {
1631abf7346Smrg      if (manual[sect].nentries == 0) {	/* empty section, re-use it. */
1641abf7346Smrg	XtFree(manual[sect].blabel);
1651abf7346Smrg	manual[sect].blabel = list->label;
1661abf7346Smrg	manual[sect].flags = list->flags;
1671abf7346Smrg      }
1681abf7346Smrg      else {
1691abf7346Smrg	if ( ++sect >= num_alloced ) {
1701abf7346Smrg	  num_alloced += SECTALLOC;
1711abf7346Smrg	  manual = (Manual *) XtRealloc ( (char *) manual,
1721abf7346Smrg				        (sizeof(Manual) * num_alloced));
1731abf7346Smrg	  if (manual == NULL)
1741abf7346Smrg	    PrintError("Could not allocate memory for manual sections.");
1751abf7346Smrg	}
1761abf7346Smrg	InitManual( manual + sect, list->label );
1771abf7346Smrg	manual[sect].flags = list->flags;
1781abf7346Smrg      }
1791abf7346Smrg      AddToCurrentSection( manual + sect, list->directory);
1801abf7346Smrg    }
1811abf7346Smrg    /* Save label to see if it matches next entry. */
1821abf7346Smrg    current_label = list->label;
1831abf7346Smrg    old_list = list;
1841abf7346Smrg    list = list->next;
1851abf7346Smrg    XtFree((char *) old_list);		/* free what you allocate. */
1861abf7346Smrg  }
1871abf7346Smrg  if (manual[sect].nentries != 0)
1881abf7346Smrg    sect++;			/* don't forget that last section. */
1891abf7346Smrg
1901abf7346Smrg  SortAndRemove(manual, sect);
1911abf7346Smrg
1921abf7346Smrg#ifdef notdef			/* dump info. */
1931abf7346Smrg  DumpManual(sect);
1941abf7346Smrg#endif
1951abf7346Smrg
1961abf7346Smrg/*
1971abf7346Smrg * realloc manual to be minimum space necessary.
1981abf7346Smrg */
1991abf7346Smrg
2001abf7346Smrg  if (sect == 0)
2011abf7346Smrg    PrintError("No manual pages found.");
2021abf7346Smrg  manual = (Manual *) XtRealloc( (char *) manual, (sizeof(Manual) * sect));
2031abf7346Smrg  if (manual == NULL)
2041abf7346Smrg    PrintError("Could not allocate memory for manual sections.");
2051abf7346Smrg
2061abf7346Smrg  return(sect);		/* return the number of man sections. */
2071abf7346Smrg}
2081abf7346Smrg
2091abf7346Smrg/*	Function Name: SortList
2101abf7346Smrg *	Description: Sorts the list of sections to search.
2111abf7346Smrg *	Arguments: list - a pointer to the list to sort.
2121abf7346Smrg *	Returns: a sorted list.
2131abf7346Smrg *
2141abf7346Smrg * This is the most complicated part of the entire operation.
2151abf7346Smrg * all sections with the same label must by right next to each other,
2161abf7346Smrg * but the sections that are in the standard list have to come first.
2171abf7346Smrg */
2181abf7346Smrg
2191abf7346Smrgstatic void
2201abf7346SmrgSortList(SectionList ** list)
2211abf7346Smrg{
2221abf7346Smrg  SectionList * local;
2231abf7346Smrg  SectionList *head, *last, *inner, *old;
2241abf7346Smrg
2251abf7346Smrg  if (*list == NULL)
2261abf7346Smrg    PrintError("No manual sections to read, exiting.");
2271abf7346Smrg
2281abf7346Smrg/*
2291abf7346Smrg * First step
2301abf7346Smrg *
2311abf7346Smrg * Look for standard list items, and more them to the top of the list.
2321abf7346Smrg */
2331abf7346Smrg
2341abf7346Smrg  last = NULL;			/* keep Saber happy. */
2351abf7346Smrg  for ( local = *list ; local->next != NULL ; local = local->next) {
2361abf7346Smrg    if ( local->flags ) {
2371abf7346Smrg      if ( local == *list )	/* top element is already standard. */
2381abf7346Smrg	break;
2391abf7346Smrg      head = local;
2401abf7346Smrg
2411abf7346Smrg      /* Find end of standard block */
2428b6d6341Smrg      for (old = NULL ; (local->next != NULL) && (local->flags)
2431abf7346Smrg	   ; old = local, local = local->next);
2441abf7346Smrg
2458b6d6341Smrg      if (old != NULL) {
2461abf7346Smrg          last->next = old->next; /* Move the block. */
2471abf7346Smrg          old->next = *list;
2481abf7346Smrg          *list = head;
2491abf7346Smrg      }
2501abf7346Smrg
2511abf7346Smrg      break;			/* First step accomplished. */
2521abf7346Smrg    }
2531abf7346Smrg    last = local;
2541abf7346Smrg  }
2551abf7346Smrg
2561abf7346Smrg/*
2571abf7346Smrg *  Second step
2581abf7346Smrg *
2591abf7346Smrg *  Move items with duplicate labels right next to each other.
2601abf7346Smrg *
2611abf7346Smrg *  Changed to keep the order of the list entries unchanged.
2621abf7346Smrg */
2631abf7346Smrg
2641abf7346Smrg  for (local = *list; local->next != NULL; local = local->next) {
2651abf7346Smrg    head = local;
2661abf7346Smrg    old = inner = local->next;
2671abf7346Smrg    while (inner != NULL) {
2681abf7346Smrg      if (streq(inner->label, local->label)) {
2691abf7346Smrg	if (old != inner) {
2701abf7346Smrg	  old->next = inner->next;
2711abf7346Smrg	  last = inner->next;
2721abf7346Smrg	  inner->next = head->next;
2731abf7346Smrg	  head->next = inner;
2741abf7346Smrg	  head = inner;
2751abf7346Smrg	  old = inner = last;
2761abf7346Smrg	  continue;
2771abf7346Smrg	}
2781abf7346Smrg	else
2791abf7346Smrg	  head = inner;
2801abf7346Smrg      }
2811abf7346Smrg      old = inner;
2821abf7346Smrg      inner = inner->next;
2831abf7346Smrg    }
2841abf7346Smrg  }
2851abf7346Smrg}
2861abf7346Smrg
2871abf7346Smrg/*	Function Name: ReadMandescFile
2881abf7346Smrg *	Description: Reads the mandesc file, and adds more sections as
2891abf7346Smrg *                   necessary.
2901abf7346Smrg *	Arguments: path - path name if the current search directory.
2911abf7346Smrg *                 section_list - pointer to the list of sections.
2921abf7346Smrg *	Returns: TRUE in we should use default sections
2931abf7346Smrg */
2941abf7346Smrg
2951abf7346Smrgstatic void
2961abf7346SmrgReadMandescFile(SectionList ** section_list, char * path)
2971abf7346Smrg{
2981abf7346Smrg  char mandesc_file[BUFSIZ];	/* full path to the mandesc file. */
2991abf7346Smrg  FILE * descfile;
3001abf7346Smrg  char string[BUFSIZ], local_file[BUFSIZ];
3011abf7346Smrg  Boolean use_defaults = TRUE;
3021abf7346Smrg  char *cp;
3031abf7346Smrg
3041abf7346Smrg  snprintf(mandesc_file, sizeof(mandesc_file), "%s/%s", path, MANDESC);
3051abf7346Smrg  if ( (descfile = fopen(mandesc_file, "r")) != NULL) {
3061abf7346Smrg    while ( fgets(string, BUFSIZ, descfile) != NULL) {
3071abf7346Smrg      string[strlen(string)-1] = '\0';        /* Strip off the CR. */
3081abf7346Smrg
3091abf7346Smrg      if ( streq(string, NO_SECTION_DEFAULTS) ) {
3101abf7346Smrg	use_defaults = FALSE;
3111abf7346Smrg	continue;
3121abf7346Smrg      }
3131abf7346Smrg
3141abf7346Smrg      if ((cp = index(string,'\t')) != NULL) {
3151abf7346Smrg	char *s;
3161abf7346Smrg	*cp++ = '\0';
3171abf7346Smrg	strcpy(local_file, MAN);
3181abf7346Smrg	strcat(local_file, string);
3191abf7346Smrg	if ((s = index(cp,'\t')) != NULL) {
3201abf7346Smrg	  *s++ = '\0';
3211abf7346Smrg	  if (streq(s, SUFFIX))
3221abf7346Smrg	    AddNewSection(section_list, path, local_file, cp, MSUFFIX);
3231abf7346Smrg	  else if (streq(s, FOLD))
3241abf7346Smrg	    AddNewSection(section_list, path, local_file, cp, MFOLD);
3251abf7346Smrg	  else if (streq(s, FOLDSUFFIX))
3261abf7346Smrg	    AddNewSection(section_list, path, local_file, cp, MFOLDSUFFIX);
3271abf7346Smrg	  else
3281abf7346Smrg	    AddNewSection(section_list, path, local_file, cp, MNULL);
3291abf7346Smrg        } else
3301abf7346Smrg	    AddNewSection(section_list, path, local_file, cp, MNULL);
3311abf7346Smrg      } else {
3321abf7346Smrg	snprintf(local_file, sizeof(local_file), "%s%c", MAN, string[0]);
3331abf7346Smrg	AddNewSection(section_list, path, local_file, (string + 1), FALSE );
3341abf7346Smrg#ifdef SEARCHOTHER
3351abf7346Smrg	snprintf(local_file, sizeof(local_file), "%s%c", SEARCHOTHER, string[0]);
3361abf7346Smrg	AddNewSection(section_list, path, local_file, (string + 1), FALSE);
3371abf7346Smrg#endif
3381abf7346Smrg      }
3391abf7346Smrg    }
3401abf7346Smrg
3411abf7346Smrg    fclose(descfile);
3421abf7346Smrg  }
3431abf7346Smrg  if (use_defaults)
3441abf7346Smrg    AddStandardSections(section_list, path);
3451abf7346Smrg}
3461abf7346Smrg
3471abf7346Smrg/*	Function Name: AddNewSection
3481abf7346Smrg *	Description: Adds the new section onto the current section list.
3491abf7346Smrg *	Arguments: list - pointer to the section list.
3501abf7346Smrg *                 path - the path to the current manual section.
3511abf7346Smrg *                 file - the file to save.
3521abf7346Smrg *                 label - the current section label.
3531abf7346Smrg *                 flags = 1 - add a suffix
3541abf7346Smrg *			 = 2 - fold to lower case
3551abf7346Smrg *	Returns: none.
3561abf7346Smrg */
3571abf7346Smrg
3581abf7346Smrgvoid
3591abf7346SmrgAddNewSection(
3601abf7346SmrgSectionList **list,
3611abf7346Smrgchar * path, char * file, char * label,
3621abf7346Smrgint flags)
3631abf7346Smrg{
3641abf7346Smrg  SectionList * local_list, * end;
3651abf7346Smrg  char full_path[BUFSIZ];
3661abf7346Smrg
3671abf7346Smrg/* Allocate a new list element */
3681abf7346Smrg
3691abf7346Smrg  local_list = (SectionList *) XtMalloc(sizeof(SectionList));
3701abf7346Smrg
3711abf7346Smrg  if (*list != NULL) {
3721abf7346Smrg    for ( end = *list ; end->next != NULL ; end = end->next );
3731abf7346Smrg    end->next = local_list;
3741abf7346Smrg  }
3751abf7346Smrg  else
3761abf7346Smrg    *list = local_list;
3771abf7346Smrg
3781abf7346Smrg  local_list->next = NULL;
3791abf7346Smrg  local_list->label = StrAlloc(label);
3801abf7346Smrg  snprintf(full_path, sizeof(full_path), "%s/%s", path, file);
3811abf7346Smrg  local_list->directory = StrAlloc(full_path);
3821abf7346Smrg  local_list->flags = flags;
3831abf7346Smrg}
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
3941abf7346SmrgAddToCurrentSection(Manual * local_manual, char * path)
3951abf7346Smrg{
3961abf7346Smrg  char temp_path[BUFSIZ];
3971abf7346Smrg
3981abf7346Smrg#if defined(__OpenBSD__) || defined(__NetBSD__)
3991abf7346Smrg  snprintf(temp_path, sizeof(temp_path), "%s/%s", path, MACHINE);
4001abf7346Smrg  ReadCurrentSection(local_manual, temp_path);
4011abf7346Smrg#endif
4021abf7346Smrg  ReadCurrentSection(local_manual, path);
4031abf7346Smrg  snprintf(temp_path, sizeof(temp_path), "%s.%s", path, COMPRESSION_EXTENSION);
4041abf7346Smrg  ReadCurrentSection(local_manual, temp_path);
4051abf7346Smrg}
4061abf7346Smrg
4071abf7346Smrg/*	Function Name: ReadCurrentSection
4081abf7346Smrg *	Description: Actually does the work of adding entries to the
4091abf7346Smrg *                   new section
4101abf7346Smrg *	Arguments:  local_manual - a pointer to a manual pages structure.
4111abf7346Smrg *                  path - the path to this directory.
4121abf7346Smrg *                  compressed - Is this a compressed directory?
4131abf7346Smrg *	Returns: TRUE if any entries are found.
4141abf7346Smrg */
4151abf7346Smrg
4161abf7346Smrgstatic void
4171abf7346SmrgReadCurrentSection(Manual * local_manual, char * path)
4181abf7346Smrg{
4191abf7346Smrg  DIR * dir;
4201abf7346Smrg
4211abf7346Smrg  register struct dirent *dp;
4221abf7346Smrg
4231abf7346Smrg  register int nentries;
4241abf7346Smrg  register int nalloc;
4251abf7346Smrg  char full_name[BUFSIZ], *ptr;
4261abf7346Smrg
4271abf7346Smrg  if((dir = opendir(path)) == NULL) {
4281abf7346Smrg#ifdef DEBUG
4291abf7346Smrg    snprintf(error_buf, sizeof(error_buf), "Can't open directory %s", path);
4301abf7346Smrg    PopupWarning(NULL, error_buf);
4311abf7346Smrg#endif /* DEBUG */
4321abf7346Smrg    return;
4331abf7346Smrg  }
4341abf7346Smrg
4351abf7346Smrg/*
4361abf7346Smrg * Remove the compression extension from the path name.
4371abf7346Smrg */
4381abf7346Smrg
4391abf7346Smrg  if ( (ptr = rindex(path, '.')) != NULL) {
4401abf7346Smrg#if !defined(__SCO__) && !defined(ISC)
4411abf7346Smrg    if (streq(ptr + 1, COMPRESSION_EXTENSION))
4421abf7346Smrg#else
4431abf7346Smrg    if (strpbrk(ptr + 1, COMPRESSION_EXTENSIONS) != NULL)
4441abf7346Smrg#endif
4451abf7346Smrg      *ptr = '\0';
4461abf7346Smrg#ifdef GZIP_EXTENSION
4471abf7346Smrg    else if (streq(ptr + 1, GZIP_EXTENSION))
4481abf7346Smrg      *ptr = '\0';
4498b6d6341Smrg#endif
4508b6d6341Smrg#ifdef BZIP2_EXTENSION
4518b6d6341Smrg    else if (streq(ptr + 1, BZIP2_EXTENSION))
4528b6d6341Smrg      *ptr = '\0';
4538b6d6341Smrg#endif
4548b6d6341Smrg#ifdef LZMA_EXTENSION
4558b6d6341Smrg    else if (streq(ptr + 1, LZMA_EXTENSION))
4568b6d6341Smrg      *ptr = '\0';
4571abf7346Smrg#endif
4581abf7346Smrg  }
4591abf7346Smrg
4601abf7346Smrg  nentries = local_manual->nentries;
4611abf7346Smrg  nalloc = local_manual->nalloc;
4621abf7346Smrg
4631abf7346Smrg  while( (dp = readdir(dir)) != NULL ) {
4641abf7346Smrg    char * name = dp->d_name;
4651abf7346Smrg    if (name[0] == '.')
4661abf7346Smrg      continue;
4671abf7346Smrg#ifndef CRAY
4681abf7346Smrg    if (index(name, '.') == NULL)
4691abf7346Smrg      continue;
4701abf7346Smrg#endif
4711abf7346Smrg    if( nentries >= nalloc ) {
4721abf7346Smrg      nalloc += ENTRYALLOC;
4731abf7346Smrg      local_manual->entries =(char **) XtRealloc((char *)local_manual->entries,
4741abf7346Smrg						 nalloc * sizeof(char *));
4751abf7346Smrg      local_manual->entries_less_paths =
4761abf7346Smrg	(char **) XtRealloc((char *)local_manual->entries_less_paths,
4771abf7346Smrg			    nalloc * sizeof(char *));
4781abf7346Smrg    }
4791abf7346Smrg
4801abf7346Smrg    snprintf(full_name, sizeof(full_name), "%s/%s", path, name);
4811abf7346Smrg/*
4821abf7346Smrg * Remove the compression extension from the entry name.
4831abf7346Smrg */
4841abf7346Smrg
4851abf7346Smrg    if ( (ptr = rindex(full_name, '.')) != NULL) {
4861abf7346Smrg#if !defined(__SCO__) && !defined(ISC)
4871abf7346Smrg      if (streq(ptr + 1, COMPRESSION_EXTENSION))
4881abf7346Smrg#else
4891abf7346Smrg      if (strpbrk(ptr + 1, COMPRESSION_EXTENSIONS) != NULL)
4901abf7346Smrg#endif
4911abf7346Smrg	*ptr = '\0';
4921abf7346Smrg#ifdef GZIP_EXTENSION
4931abf7346Smrg      else if (streq(ptr + 1, GZIP_EXTENSION))
4941abf7346Smrg	*ptr = '\0';
4951abf7346Smrg#endif
4968b6d6341Smrg#ifdef BZIP2_EXTENSION
4978b6d6341Smrg      else if (streq(ptr + 1, BZIP2_EXTENSION))
4988b6d6341Smrg	*ptr = '\0';
4998b6d6341Smrg#endif
5008b6d6341Smrg#ifdef LZMA_EXTENSION
5018b6d6341Smrg      else if (streq(ptr + 1, LZMA_EXTENSION))
5028b6d6341Smrg	*ptr = '\0';
5038b6d6341Smrg#endif
5041abf7346Smrg#ifdef IGNORE_EXTENSION
5051abf7346Smrg      /* skip files with specified extension - they're not real man pages */
5061abf7346Smrg      else if (streq(ptr + 1, IGNORE_EXTENSION)) {
5071abf7346Smrg	continue;
5081abf7346Smrg      }
5091abf7346Smrg#endif /* IGNORE_EXTENSION */
5101abf7346Smrg    }
5111abf7346Smrg    local_manual->entries[nentries] = StrAlloc(full_name);
5121abf7346Smrg    local_manual->entries_less_paths[nentries] =
5131abf7346Smrg      rindex(local_manual->entries[nentries], '/');
5141abf7346Smrg    if ( local_manual->entries_less_paths[nentries] == NULL )
5151abf7346Smrg      PrintError("Internal error while cataloging manual pages.");
5161abf7346Smrg    ++ nentries;
5171abf7346Smrg  }
5181abf7346Smrg
5191abf7346Smrg  local_manual->nentries = nentries;
5201abf7346Smrg  local_manual->nalloc = nalloc;
5211abf7346Smrg
5221abf7346Smrg  closedir(dir);
5231abf7346Smrg}
5241abf7346Smrg
5251abf7346Smrg/*	Function Name: SortAndRemove
5261abf7346Smrg *	Description: This function sorts all the entry names and
5271abf7346Smrg *                   then removes all the duplicate entries.
5281abf7346Smrg *	Arguments: man - a pointer to the manual structure.
5291abf7346Smrg *                 number - the number of manual sections.
5301abf7346Smrg *	Returns: an improved manual stucure
5311abf7346Smrg */
5321abf7346Smrg
5331abf7346Smrgstatic void
5341abf7346SmrgSortAndRemove(Manual *man, int number)
5351abf7346Smrg{
5361abf7346Smrg  int i;
5371abf7346Smrg  char *l1, *l2, **s1;
5381abf7346Smrg
5391abf7346Smrg  for ( i = 0; i < number; man++, i++) { /* sort each section */
5401abf7346Smrg    register int i2 = 0;
5411abf7346Smrg
5421abf7346Smrg#ifdef DEBUG
5431abf7346Smrg    printf("sorting section %d - %s\n", i, man->blabel);
5441abf7346Smrg#endif /* DEBUG */
5451abf7346Smrg
5461abf7346Smrg    s1 = (char **)malloc(man->nentries * sizeof(char *));
5471abf7346Smrg
5481abf7346Smrg    /* temporarily remove suffixes of entries, preventing them from */
5491abf7346Smrg    /* being used in alpabetic comparison ie sccs-delta.1 vs sccs.1 */
5501abf7346Smrg    for (i2=0; i2<man->nentries; i2++)
5511abf7346Smrg      if ((s1[i2] = rindex(man->entries_less_paths[i2], '.')) != NULL)
5521abf7346Smrg	*s1[i2] = '\0';
5531abf7346Smrg
5541abf7346Smrg    sortstrs ( (Byte **)man->entries_less_paths, man->nentries, (Byte **)man->entries );
5551abf7346Smrg
5561abf7346Smrg    /* put back suffixes */
5571abf7346Smrg    for (i2=0; i2<man->nentries; i2++)
5581abf7346Smrg      if (s1[i2] != NULL) *s1[i2] = '.';
5591abf7346Smrg
5601abf7346Smrg    free(s1);
5611abf7346Smrg
5621abf7346Smrg#ifdef DEBUG
5631abf7346Smrg    printf("removing from section %d.\n", i);
5641abf7346Smrg#endif /* DEBUG */
5651abf7346Smrg
5661abf7346Smrg    {
5671abf7346Smrg      register int   j, k, nent, nentm1;
5681abf7346Smrg      int     j2;
5691abf7346Smrg      nent   = man -> nentries;
5701abf7346Smrg      nentm1 = nent - 1;
5711abf7346Smrg      j = 0;
5721abf7346Smrg      l2 = man->entries_less_paths[j++];
5731abf7346Smrg      if ( l2 == NULL )
5741abf7346Smrg        PrintError("Internal error while removing duplicate manual pages.");
5751abf7346Smrg      while ( j < nentm1 )
5761abf7346Smrg	{
5771abf7346Smrg	  l1 = l2;
5781abf7346Smrg	  l2 = man->entries_less_paths[j++];
5791abf7346Smrg	  if ( l2 == NULL )
5801abf7346Smrg	    PrintError("Internal error while removing duplicate manual pages."
5811abf7346Smrg		       );
5821abf7346Smrg	  if ( streq(l1,l2) )
5831abf7346Smrg	    {
5841abf7346Smrg	      j2 = j-1;
5851abf7346Smrg	      k  = j2;
5861abf7346Smrg	      while ( j < nent )
5871abf7346Smrg                {
5881abf7346Smrg		  man -> entries_less_paths[k] = man -> entries_less_paths[j];
5891abf7346Smrg                man -> entries[k++] = man -> entries[j++];
5901abf7346Smrg                }
5911abf7346Smrg	      j = j2;
5921abf7346Smrg	      -- man -> nentries;
5931abf7346Smrg	      -- nent;
5941abf7346Smrg	      -- nentm1;
5951abf7346Smrg	    }
5961abf7346Smrg	}
5971abf7346Smrg    }
5981abf7346Smrg  }
5991abf7346Smrg}
6001abf7346Smrg
6011abf7346Smrg /*
6021abf7346Smrg       *******  Replacement for qsort to keep
6031abf7346Smrg       *******  identical entries in order
6041abf7346Smrg
6051abf7346Smrg       A somewhat ugly hack of something that was once simpler...
6061abf7346Smrg */
6071abf7346Smrg /*
6081abf7346Smrg       Sort an array of pointers to strings, keeping it
6091abf7346Smrg       in ascending order by (1) string comparison and
6101abf7346Smrg       (2) original entry order in the pointer array.
6111abf7346Smrg
6121abf7346Smrg       This is a modified radix exchange algorithm.
6131abf7346Smrg
6141abf7346Smrg       In case there's insufficient memory for a temporary copy
6151abf7346Smrg       of the pointer array, the original order of identical strings
6161abf7346Smrg       isn't preserved.
6171abf7346Smrg */
6181abf7346Smrg
6191abf7346Smrgstatic void
6201abf7346Smrgsortstrs (Byte *data[], int size, Byte *otherdata[])
6211abf7346Smrg{
6221abf7346Smrg       Byte   **sp, **ep;
6231abf7346Smrg       Byte   **othersp, **otherep;
6241abf7346Smrg       int     *origorder;
6251abf7346Smrg
6261abf7346Smrg origorder = (int *) calloc (size, sizeof(int));
6271abf7346Smrg if ( origorder )
6281abf7346Smrg    {
6291abf7346Smrg    reg int     i;
6301abf7346Smrg
6311abf7346Smrg    for ( i=0; i < size; ++i )
6321abf7346Smrg       origorder[i] = i;
6331abf7346Smrg    }
6341abf7346Smrg
6351abf7346Smrg sp = data;
6361abf7346Smrg ep = &data[size-1];
6371abf7346Smrg othersp = otherdata;
6381abf7346Smrg otherep = &otherdata[size-1];
6391abf7346Smrg if ( origorder )
6401abf7346Smrg    {
6411abf7346Smrg    sortstrs_block_oo ( sp, ep, 0, 0x80, origorder, &origorder[size-1],
6421abf7346Smrg       othersp, otherep );
6431abf7346Smrg    free (origorder);
6441abf7346Smrg    }
6451abf7346Smrg else
6461abf7346Smrg    sortstrs_block ( sp, ep, 0, 0x80, othersp, otherep );
6471abf7346Smrg}
6481abf7346Smrg
6491abf7346Smrg
6501abf7346Smrg
6511abf7346Smrg /*---------------------------------*/
6521abf7346Smrg /*  Sort 1 block of data on 1 bit  */
6531abf7346Smrg /*---------------------------------*/
6541abf7346Smrg
6551abf7346Smrgstatic void
6561abf7346Smrgsortstrs_block (
6571abf7346Smrg       Byte   **start,
6581abf7346Smrg       Byte   **end,
6591abf7346Smrg       int      offset,
6601abf7346Smrg       Byte     mask,
6611abf7346Smrg       Byte   **otherstart,
6621abf7346Smrg       Byte   **otherend)
6631abf7346Smrg
6641abf7346Smrg{
6651abf7346Smrg reg   Byte   **sp, **ep;
6661abf7346Smrg reg   Byte     m;
6671abf7346Smrg reg   int      off;
6681abf7346Smrg reg   Byte    *t;
6691abf7346Smrg reg   int      curstrlen;
6701abf7346Smrg       int      maxstrlen;
6711abf7346Smrg       Byte   **othersp, **otherep;
6721abf7346Smrg
6731abf7346Smrg
6741abf7346Smrg#define       newstring(ptr) \
6751abf7346Smrg { \
6761abf7346Smrg t = *ptr; \
6771abf7346Smrg curstrlen = 0; \
6781abf7346Smrg while ( *t++ ) ++ curstrlen; \
6791abf7346Smrg if ( curstrlen > maxstrlen ) maxstrlen = curstrlen; \
6801abf7346Smrg t = *ptr; \
6811abf7346Smrg }
6821abf7346Smrg
6831abf7346Smrg
6841abf7346Smrg maxstrlen = 0;
6851abf7346Smrg sp  = start;
6861abf7346Smrg ep  = end;
6871abf7346Smrg off = offset;
6881abf7346Smrg m   = mask;
6891abf7346Smrg othersp = otherstart;
6901abf7346Smrg otherep = otherend;
6911abf7346Smrg
6921abf7346Smrg while (1)
6931abf7346Smrg     {
6941abf7346Smrg     newstring(sp)
6951abf7346Smrg     while (((sp != ep) && ((curstrlen < off) || ((t[off] & m) == 0))))
6961abf7346Smrg       {
6971abf7346Smrg       ++ sp;
6981abf7346Smrg       ++ othersp;
6991abf7346Smrg       newstring(sp)
7001abf7346Smrg       }
7011abf7346Smrg     if ( sp == ep )
7021abf7346Smrg       break;
7031abf7346Smrg
7041abf7346Smrg     newstring(ep);
7051abf7346Smrg     while (((sp != ep) && (curstrlen >= off) && ((t[off] & m) != 0)))
7061abf7346Smrg       {
7071abf7346Smrg       -- ep;
7081abf7346Smrg       -- otherep;
7091abf7346Smrg       newstring(ep)
7101abf7346Smrg       }
7111abf7346Smrg     if ( sp == ep )
7121abf7346Smrg       break;
7131abf7346Smrg
7141abf7346Smrg     t = *sp;
7151abf7346Smrg     *sp = *ep;
7161abf7346Smrg     *ep = t;
7171abf7346Smrg
7181abf7346Smrg     t      = *othersp;
7191abf7346Smrg     *othersp = *otherep;
7201abf7346Smrg     *otherep = t;
7211abf7346Smrg     }
7221abf7346Smrg
7231abf7346Smrg t = *sp;
7241abf7346Smrg if ((curstrlen < off) || ((t[off] & m) == 0))
7251abf7346Smrg    {
7261abf7346Smrg    if ( ep != end )
7271abf7346Smrg       {
7281abf7346Smrg       ++ ep;
7291abf7346Smrg       ++ otherep;
7301abf7346Smrg       }
7311abf7346Smrg    }
7321abf7346Smrg else
7331abf7346Smrg    {
7341abf7346Smrg    if ( sp != start )
7351abf7346Smrg       {
7361abf7346Smrg       -- sp;
7371abf7346Smrg       -- othersp;
7381abf7346Smrg       }
7391abf7346Smrg    }
7401abf7346Smrg
7411abf7346Smrg m >>= 1;
7421abf7346Smrg if ( m == 0 )
7431abf7346Smrg    {
7441abf7346Smrg    m = 0x80;
7451abf7346Smrg    if ( ++off >= maxstrlen )
7461abf7346Smrg       return;
7471abf7346Smrg    }
7481abf7346Smrg
7491abf7346Smrg
7501abf7346Smrg if ( sp != start )
7511abf7346Smrg    sortstrs_block ( start, sp, off, m, otherstart, othersp );
7521abf7346Smrg if ( ep != end )
7531abf7346Smrg    sortstrs_block ( ep, end, off, m, otherep, otherend );
7541abf7346Smrg}
7551abf7346Smrg
7561abf7346Smrg
7571abf7346Smrg
7581abf7346Smrg /*-----------------------------------------------------------------*/
7591abf7346Smrg /*  Sort 1 block of data on 1 bit; check for out-of-order entries  */
7601abf7346Smrg /*-----------------------------------------------------------------*/
7611abf7346Smrg
7621abf7346Smrgstatic void
7631abf7346Smrg sortstrs_block_oo (
7641abf7346Smrg       Byte   **start,
7651abf7346Smrg       Byte   **end,
7661abf7346Smrg       int      offset,
7671abf7346Smrg       Byte     mask,
7681abf7346Smrg       int     *ostart,
7691abf7346Smrg       int     *oend,
7701abf7346Smrg       Byte   **otherstart,
7711abf7346Smrg       Byte   **otherend)
7721abf7346Smrg
7731abf7346Smrg{
7741abf7346Smrg reg   Byte   **sp, **ep;
7751abf7346Smrg reg   int     *osp, *oep;
7761abf7346Smrg reg   Byte     m;
7771abf7346Smrg reg   int      off;
7781abf7346Smrg reg   Byte    *t;
7791abf7346Smrg reg   int      u;
7801abf7346Smrg reg   int      curstrlen;
7811abf7346Smrg       int      maxstrlen;
7821abf7346Smrg       Byte   **othersp, **otherep;
7831abf7346Smrg
7841abf7346Smrg
7851abf7346Smrg#define       newstring(ptr) \
7861abf7346Smrg { \
7871abf7346Smrg t = *ptr; \
7881abf7346Smrg curstrlen = 0; \
7891abf7346Smrg while ( *t++ ) ++ curstrlen; \
7901abf7346Smrg if ( curstrlen > maxstrlen ) maxstrlen = curstrlen; \
7911abf7346Smrg t = *ptr; \
7921abf7346Smrg }
7931abf7346Smrg
7941abf7346Smrg
7951abf7346Smrg maxstrlen = 0;
7961abf7346Smrg sp  = start;
7971abf7346Smrg ep  = end;
7981abf7346Smrg osp = ostart;
7991abf7346Smrg oep = oend;
8001abf7346Smrg off = offset;
8011abf7346Smrg m   = mask;
8021abf7346Smrg othersp = otherstart;
8031abf7346Smrg otherep = otherend;
8041abf7346Smrg
8051abf7346Smrg while (1)
8061abf7346Smrg     {
8071abf7346Smrg     newstring(sp)
8081abf7346Smrg     while (((sp != ep) && ((curstrlen < off) || ((t[off] & m) == 0))))
8091abf7346Smrg       {
8101abf7346Smrg       ++ sp;
8111abf7346Smrg       ++ osp;
8121abf7346Smrg       ++ othersp;
8131abf7346Smrg       newstring(sp)
8141abf7346Smrg       }
8151abf7346Smrg     if ( sp == ep )
8161abf7346Smrg       break;
8171abf7346Smrg
8181abf7346Smrg     newstring(ep);
8191abf7346Smrg     while (((sp != ep) && (curstrlen >= off) && ((t[off] & m) != 0)))
8201abf7346Smrg       {
8211abf7346Smrg       -- ep;
8221abf7346Smrg       -- oep;
8231abf7346Smrg       -- otherep;
8241abf7346Smrg       newstring(ep)
8251abf7346Smrg       }
8261abf7346Smrg     if ( sp == ep )
8271abf7346Smrg       break;
8281abf7346Smrg
8291abf7346Smrg     t   = *sp;
8301abf7346Smrg     *sp = *ep;
8311abf7346Smrg     *ep = t;
8321abf7346Smrg
8331abf7346Smrg     t      = *othersp;
8341abf7346Smrg     *othersp = *otherep;
8351abf7346Smrg     *otherep = t;
8361abf7346Smrg
8371abf7346Smrg     u    = *osp;
8381abf7346Smrg     *osp = *oep;
8391abf7346Smrg     *oep = u;
8401abf7346Smrg     }
8411abf7346Smrg
8421abf7346Smrg t = *sp;
8431abf7346Smrg if ((curstrlen < off) || ((t[off] & m) == 0))
8441abf7346Smrg    {
8451abf7346Smrg    if ( ep != end )
8461abf7346Smrg       {
8471abf7346Smrg       ++ ep;
8481abf7346Smrg       ++ oep;
8491abf7346Smrg       ++ otherep;
8501abf7346Smrg       }
8511abf7346Smrg    }
8521abf7346Smrg else
8531abf7346Smrg    {
8541abf7346Smrg    if ( sp != start )
8551abf7346Smrg       {
8561abf7346Smrg       -- sp;
8571abf7346Smrg       -- osp;
8581abf7346Smrg       -- othersp;
8591abf7346Smrg       }
8601abf7346Smrg    }
8611abf7346Smrg
8621abf7346Smrg m >>= 1;
8631abf7346Smrg if ( m == 0 )
8641abf7346Smrg    {
8651abf7346Smrg    m = 0x80;
8661abf7346Smrg    if ( ++off >= maxstrlen )  /*  Finished sorting block of strings:    */
8671abf7346Smrg       {                               /*  Restore duplicates to
8681abf7346Smrgriginal order  */
8691abf7346Smrg       reg Byte **cp;
8701abf7346Smrg       reg int *ocp;
8711abf7346Smrg         Byte **othercp;
8721abf7346Smrg
8731abf7346Smrg
8741abf7346Smrg       if ( sp != start )
8751abf7346Smrg        {
8761abf7346Smrg        cp  = start;
8771abf7346Smrg        ocp = ostart;
8781abf7346Smrg        othercp = otherstart;
8791abf7346Smrg        while ( cp != sp )
8801abf7346Smrg           {
8811abf7346Smrg           if ( *ocp > *(ocp+1) )
8821abf7346Smrg               {
8831abf7346Smrg               t       = *(cp+1);
8841abf7346Smrg               *(cp+1) = *cp;
8851abf7346Smrg               *cp     = t;
8861abf7346Smrg
8871abf7346Smrg               t               = *(othercp+1);
8881abf7346Smrg               *(othercp+1)    = *othercp;
8891abf7346Smrg               *othercp        = t;
8901abf7346Smrg
8911abf7346Smrg               u        = *(ocp+1);
8921abf7346Smrg               *(ocp+1) = *ocp;
8931abf7346Smrg               *ocp     = u;
8941abf7346Smrg
8951abf7346Smrg               if ( cp != start )
8961abf7346Smrg                  {
8971abf7346Smrg                  -- cp;
8981abf7346Smrg                  -- ocp;
8991abf7346Smrg                  -- othercp;
9001abf7346Smrg                  continue;
9011abf7346Smrg                  }
9021abf7346Smrg               }
9031abf7346Smrg           ++ cp;
9041abf7346Smrg           ++ ocp;
9051abf7346Smrg           ++ othercp;
9061abf7346Smrg           }
9071abf7346Smrg        }
9081abf7346Smrg       if ( ep != end )
9091abf7346Smrg        {
9101abf7346Smrg        cp  = ep;
9111abf7346Smrg        ocp = oep;
9121abf7346Smrg        othercp = otherep;
9131abf7346Smrg        while ( cp != end )
9141abf7346Smrg           {
9151abf7346Smrg           if ( *ocp > *(ocp+1) )
9161abf7346Smrg               {
9171abf7346Smrg               t       = *(cp+1);
9181abf7346Smrg               *(cp+1) = *cp;
9191abf7346Smrg               *cp     = t;
9201abf7346Smrg
9211abf7346Smrg               t               = *(othercp+1);
9221abf7346Smrg               *(othercp+1)    = *othercp;
9231abf7346Smrg               *othercp        = t;
9241abf7346Smrg
9251abf7346Smrg               u        = *(ocp+1);
9261abf7346Smrg               *(ocp+1) = *ocp;
9271abf7346Smrg               *ocp     = u;
9281abf7346Smrg
9291abf7346Smrg               if ( cp != ep )
9301abf7346Smrg                  {
9311abf7346Smrg                  -- cp;
9321abf7346Smrg                  -- ocp;
9331abf7346Smrg                  -- othercp;
9341abf7346Smrg                  continue;
9351abf7346Smrg                  }
9361abf7346Smrg               }
9371abf7346Smrg           ++ cp;
9381abf7346Smrg           ++ ocp;
9391abf7346Smrg           ++ othercp;
9401abf7346Smrg           }
9411abf7346Smrg        }
9421abf7346Smrg       return;
9431abf7346Smrg       }
9441abf7346Smrg    }
9451abf7346Smrg
9461abf7346Smrg
9471abf7346Smrg if ( sp != start )
9481abf7346Smrg    sortstrs_block_oo ( start, sp, off, m, ostart, osp, otherstart, othersp );
9491abf7346Smrg if ( ep != end )
9501abf7346Smrg    sortstrs_block_oo ( ep, end, off, m, oep, oend, otherep, otherend );
9511abf7346Smrg}
9521abf7346Smrg
9531abf7346Smrg
9541abf7346Smrg/*	Function Name: InitManual
9551abf7346Smrg *	Description: Initializes this manual section.
9561abf7346Smrg *	Arguments: l_manual - local copy of the manual structure.
9571abf7346Smrg *                 label - the button label for this section.
9581abf7346Smrg *	Returns: none.
9591abf7346Smrg */
9601abf7346Smrg
9611abf7346Smrgstatic void
9621abf7346SmrgInitManual(Manual * l_manual, char * label)
9631abf7346Smrg{
9641abf7346Smrg  bzero( l_manual, sizeof(Manual) );	        /* clear it. */
9651abf7346Smrg  l_manual->blabel = label;	                /* set label. */
9661abf7346Smrg}
9671abf7346Smrg
9681abf7346Smrg#if defined(DEBUG)
9691abf7346Smrg
9701abf7346Smrg/*	Function Name: DumpManual
9711abf7346Smrg *	Description: Debugging function that dumps the entire manual page
9721abf7346Smrg *                   structure.
9731abf7346Smrg *	Arguments: number - the number of sections.
9741abf7346Smrg *	Returns: none.
9751abf7346Smrg */
9761abf7346Smrg
9771abf7346Smrgvoid
9781abf7346SmrgDumpManual(int number)
9791abf7346Smrg{
9801abf7346Smrg  register int i,j;
9811abf7346Smrg
9821abf7346Smrg  for ( i = 0; i < number; i++) {
9831abf7346Smrg    printf("label: %s\n", manual[i].blabel);
9841abf7346Smrg    for (j = 0; j < manual[i].nentries; j++)
9851abf7346Smrg      printf("%s\n", manual[i].entries[j]);
9861abf7346Smrg  }
9871abf7346Smrg}
9881abf7346Smrg
9891abf7346Smrg#endif /* DEBUG */
9901abf7346Smrg
9911abf7346Smrg
9921abf7346Smrg
9931abf7346Smrg#ifdef MANCONF
9941abf7346Smrg
9951abf7346Smrg#if defined(MANCONFIGSTYLE_FreeBSD)
9961abf7346Smrg
9971abf7346Smrg/*    Function Name: ReadManConfig
9981abf7346Smrg *    Description: Reads man.conf file used by FreeBSD man
9991abf7346Smrg *      Argument: manpath - char array to return path in.
10001abf7346Smrg *    Returns: TRUE if read was successful.
10011abf7346Smrg */
10021abf7346Smrg
10031abf7346SmrgBool
10041abf7346SmrgReadManConfig(char manpath[])
10051abf7346Smrg{
10061abf7346Smrg  FILE        *fp;
10071abf7346Smrg  char        line[BUFSIZ];
10081abf7346Smrg  char        *path;
10091abf7346Smrg  Bool  firstpath = TRUE;
10101abf7346Smrg
10111abf7346Smrg  if (!(fp = fopen(MANCONF, "r")))
10121abf7346Smrg    return(FALSE);
10131abf7346Smrg
10141abf7346Smrg  while (fgets(line, sizeof(line), fp)) {
10151abf7346Smrg    path = strtok(line, " \t\n");
10161abf7346Smrg    if (!path || *path == '#')
10171abf7346Smrg      continue;
10181abf7346Smrg    if (strcmp(path, "MANPATH_MAP") == 0)
10191abf7346Smrg      path = strtok((char *)NULL, " \t\n");
10201abf7346Smrg    else if (strcmp(path, "MANDATORY_MANPATH") != 0 &&
10211abf7346Smrg	     strcmp(path, "OPTIONAL_MANPATH") != 0)
10221abf7346Smrg      return(FALSE);
10231abf7346Smrg    path = strtok((char *)NULL, " \t\n");
10241abf7346Smrg    if (!path || *path == '#')
10251abf7346Smrg      return FALSE;
10261abf7346Smrg    if (firstpath) {
10271abf7346Smrg      strcpy(manpath, path);
10281abf7346Smrg      firstpath = FALSE;
10291abf7346Smrg    }
10301abf7346Smrg    else if (!strstr(manpath,path)) {
10311abf7346Smrg      strcat(manpath, ":");
10321abf7346Smrg      strcat(manpath, path);
10331abf7346Smrg    }
10341abf7346Smrg  }
10351abf7346Smrg  fclose(fp);
10361abf7346Smrg  return(!firstpath);
10371abf7346Smrg}
10381abf7346Smrg
10391abf7346Smrg
10401abf7346Smrg#elif defined(MANCONFIGSTYLE_Linux) /* not FreeBSD */
10411abf7346Smrg
10421abf7346Smrg/*    Function Name: ReadManConfig
10431abf7346Smrg *    Description: Reads man.conf file used by Linux man
10441abf7346Smrg *      Argument: manpath - char array to return path in.
10451abf7346Smrg *    Returns: TRUE if read was successful.
10461abf7346Smrg */
10471abf7346Smrg
10481abf7346Smrg
10491abf7346SmrgBool
10501abf7346SmrgReadManConfig(char manpath[])
10511abf7346Smrg{
10521abf7346Smrg  FILE        *fp;
10531abf7346Smrg  char        line[BUFSIZ];
10541abf7346Smrg  char        *path;
10551abf7346Smrg  Bool  firstpath = TRUE;
10561abf7346Smrg
10571abf7346Smrg  if (!(fp = fopen(MANCONF, "r")))
10581abf7346Smrg    return(FALSE);
10591abf7346Smrg
10601abf7346Smrg  while (fgets(line, sizeof(line), fp)) {
10611abf7346Smrg    path = strtok(line, " \t\n");
10621abf7346Smrg    if (!path || *path == '#' || (strcmp(path, "MANPATH") != 0))
10631abf7346Smrg      continue;
10641abf7346Smrg    path = strtok((char *)NULL, " \t\n");
10651abf7346Smrg    if (!path || *path == '#')
10661abf7346Smrg      return FALSE;
10671abf7346Smrg    if (firstpath) {
10681abf7346Smrg      strcpy(manpath, path);
10691abf7346Smrg      firstpath = FALSE;
10701abf7346Smrg    }
10711abf7346Smrg    else {
10721abf7346Smrg      strcat(manpath, ":");
10731abf7346Smrg      strcat(manpath, path);
10741abf7346Smrg    }
10751abf7346Smrg  }
10761abf7346Smrg  fclose(fp);
10771abf7346Smrg  return(!firstpath);
10781abf7346Smrg}
10791abf7346Smrg
10801abf7346Smrg#elif defined(MANCONFIGSTYLE_OpenBSD) /* not FreeBSD or Linux */
10811abf7346Smrg
10821abf7346Smrg/*    Function Name: ReadManConfig
10831abf7346Smrg *    Description: Reads man.conf file used by Open/NetBSD
10841abf7346Smrg *      Argument: manpath - char array to return path in.
10851abf7346Smrg *    Returns: TRUE if read was successful.
10861abf7346Smrg *
10871abf7346Smrg *     This version expands the glob pattern that can be found
10881abf7346Smrg *     in man.conf
10891abf7346Smrg */
10901abf7346Smrg#include <glob.h>
10911abf7346Smrg
10921abf7346SmrgBool
10931abf7346SmrgReadManConfig(char manpath[])
10941abf7346Smrg{
10951abf7346Smrg    FILE        *fp;
10961abf7346Smrg    char        line[BUFSIZ];
10971abf7346Smrg    char        *path;
10981abf7346Smrg    Bool        firstpath = TRUE;
10991abf7346Smrg    glob_t      gs;
11001abf7346Smrg    int         i;
11011abf7346Smrg
11021abf7346Smrg    if (!(fp = fopen(MANCONF, "r")))
11031abf7346Smrg	return(FALSE);
11041abf7346Smrg
11051abf7346Smrg    while (fgets(line, sizeof(line), fp)) {
11061abf7346Smrg	path = strtok(line, " \t\n");
11071abf7346Smrg	if (!path || *path == '#')
11081abf7346Smrg	    continue;
11091abf7346Smrg	if (strcmp(path, "_default")) {
11101abf7346Smrg	    /* for now */
11111abf7346Smrg	    continue;
11121abf7346Smrg	}
11131abf7346Smrg	memset(&gs, 0, sizeof(glob_t));
11141abf7346Smrg	while ((path = strtok((char *)NULL, " \t\n"))) {
11151abf7346Smrg	    if (glob(path, GLOB_BRACE, NULL, &gs) < 0) {
11161abf7346Smrg		fclose(fp);
11171abf7346Smrg		return FALSE;
11181abf7346Smrg	    }
11191abf7346Smrg	} /* while */
11201abf7346Smrg	for (i = 0; i < gs.gl_pathc; i++) {
11211abf7346Smrg
11221abf7346Smrg	    if (firstpath) {
11231abf7346Smrg		strcpy(manpath, gs.gl_pathv[i]);
11241abf7346Smrg		firstpath = FALSE;
11251abf7346Smrg	    }
11261abf7346Smrg	    else {
11271abf7346Smrg		strcat(manpath, ":");
11281abf7346Smrg		strcat(manpath, gs.gl_pathv[i]);
11291abf7346Smrg	    }
11301abf7346Smrg	} /* for */
11311abf7346Smrg	globfree(&gs);
11321abf7346Smrg    }
11331abf7346Smrg    fclose(fp);
11341abf7346Smrg    return(!firstpath);
11351abf7346Smrg}
11361abf7346Smrg
11371abf7346Smrg#elif defined(MANCONFIGSTYLE_BSD) /* not FreeBSD, Linux, or OpenBSD */
11381abf7346Smrg
11391abf7346Smrg/*    Function Name: ReadManConfig
11401abf7346Smrg *    Description: Reads man.conf file used by BSD 4.4
11411abf7346Smrg *      Argument: manpath - char array to return path in.
11421abf7346Smrg *    Returns: TRUE if read was successful.
11431abf7346Smrg */
11441abf7346Smrg
11451abf7346SmrgBool
11461abf7346SmrgReadManConfig(manpath)
11471abf7346Smrg
11481abf7346Smrgchar  manpath[];
11491abf7346Smrg
11501abf7346Smrg{
11511abf7346Smrg  FILE        *fp;
11521abf7346Smrg  char        line[BUFSIZ];
11531abf7346Smrg  char        *path;
11541abf7346Smrg  Bool  firstpath = TRUE;
11551abf7346Smrg
11561abf7346Smrg  if (!(fp = fopen(MANCONF, "r")))
11571abf7346Smrg    return(FALSE);
11581abf7346Smrg
11591abf7346Smrg  while (fgets(line, sizeof(line), fp)) {
11601abf7346Smrg    path = strtok(line, " \t\n");
11611abf7346Smrg    if (!path || *path == '#' || strcmp(path, "_default"))
11621abf7346Smrg      continue;
11631abf7346Smrg    while ((path = strtok((char *)NULL, " \t\n"))) {
11641abf7346Smrg      if (firstpath) {
11651abf7346Smrg        strcpy(manpath, path);
11661abf7346Smrg        firstpath = FALSE;
11671abf7346Smrg      }
11681abf7346Smrg      else {
11691abf7346Smrg        strcat(manpath, ":");
11701abf7346Smrg        strcat(manpath, path);
11711abf7346Smrg      }
11721abf7346Smrg    }
11731abf7346Smrg  }
11741abf7346Smrg  fclose(fp);
11751abf7346Smrg  return(!firstpath);
11761abf7346Smrg}
11771abf7346Smrg
11781abf7346Smrg#else /* not BSD */
11791abf7346Smrg
11801abf7346Smrg#error "MANCONF defined (in vendor.h) for unknown operating system."
11811abf7346Smrg
11821abf7346Smrg#endif /* MANCONFIGSTYLE == FreeBSD ... BSD */
11831abf7346Smrg
11841abf7346Smrg#endif /* MANCONF */
1185