home *** CD-ROM | disk | FTP | other *** search
- /*
- * xman - X Window System manual page display program.
- *
- * $XConsortium: man.c,v 1.29 91/07/30 22:03:20 rws Exp $
- *
- * Copyright 1987, 1988 Massachusetts Institute of Technology
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose and without fee is hereby granted, provided
- * that the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of M.I.T. not be used in advertising or
- * publicity pertaining to distribution of the software without specific,
- * written prior permission. M.I.T. makes no representations about the
- * suitability of this software for any purpose. It is provided "as is"
- * without express or implied warranty.
- *
- * Author: Chris D. Peterson, MIT Project Athena
- * Created: August 10, 1987
- */
-
- #include "globals.h"
- #include "vendor.h" /* vendor-specific defines and data */
-
- #ifndef X_NOT_POSIX
- #include <dirent.h>
- #else
- #ifdef SYSV
- #include <dirent.h>
- #else
- #ifdef USG
- #include <dirent.h>
- #else
- #include <sys/dir.h>
- #ifndef dirent
- #define dirent direct
- #endif
- #endif
- #endif
- #endif
-
- #ifdef DEBUG
- static char error_buf[BUFSIZ]; /* The buffer for error messages. */
- #endif /* DEBUG */
-
- static void SortList(), ReadMandescFile(), SortAndRemove(), InitManual();
- static void AddToCurrentSection();
- static void ReadCurrentSection();
-
- #define SECT_ERROR -1
-
- /* Function Name: Man
- * Description: Builds a list of all manual directories and files.
- * Arguments: none.
- * Returns: the number of manual sections.
- */
-
- int
- Man()
- {
- SectionList *list = NULL;
- char *ptr, manpath[BUFSIZ], *path, *current_label;
- int sect, num_alloced;
-
- /*
- * Get the environment variable MANPATH, and if it doesn't exist then use
- * SYSMANPATH and LOCALMANPATH.
- */
-
- ptr = getenv("MANPATH");
- if (ptr == NULL || streq(ptr , "") ) {
- strcpy(manpath, SYSMANPATH);
- #ifdef LOCALMANPATH
- strcat(manpath, ":");
- strcat(manpath, LOCALMANPATH);
- #endif
- } else {
- strcpy(manpath, ptr);
- }
-
- /*
- * Get the list of manual directories in the users MANPATH that we should
- * open to look for manual pages. The ``mandesc'' file is read here.
- */
-
- for ( path = manpath ; (ptr = index(path , ':')) != NULL ; path = ++ptr) {
- *ptr = '\0';
- ReadMandescFile(&list, path);
- }
- ReadMandescFile(&list, path);
-
- SortList(&list);
-
- sect = 0;
- num_alloced = SECTALLOC;
- manual = (Manual *) XtMalloc( sizeof(Manual) * num_alloced );
- InitManual( manual, list->label );
- manual[sect].flags = list->flags;
- current_label = NULL;
-
- while ( list != NULL ) {
- SectionList * old_list;
-
- if ( current_label == NULL || streq(list->label, current_label) )
- AddToCurrentSection( manual + sect, list->directory);
- else {
- if (manual[sect].nentries == 0) { /* empty section, re-use it. */
- XtFree(manual[sect].blabel);
- manual[sect].blabel = list->label;
- manual[sect].flags = list->flags;
- }
- else {
- if ( ++sect >= num_alloced ) {
- num_alloced += SECTALLOC;
- manual = (Manual *) realloc ( (char *) manual,
- (sizeof(Manual) * num_alloced));
- if (manual == NULL)
- PrintError("Could not allocate memory for manual sections.");
- }
- InitManual( manual + sect, list->label );
- manual[sect].flags = list->flags;
- }
- AddToCurrentSection( manual + sect, list->directory);
- }
- /* Save label to see if it matches next entry. */
- current_label = list->label;
- old_list = list;
- list = list->next;
- XtFree((char *) old_list); /* free what you allocate. */
- }
- if (manual[sect].nentries != 0)
- sect++; /* don't forget that last section. */
-
- SortAndRemove(manual, sect);
-
- #ifdef notdef /* dump info. */
- DumpManual(sect);
- #endif
-
- /*
- * realloc manual to be minimum space necessary.
- */
-
- manual = (Manual *) realloc( (char *) manual, (sizeof(Manual) * sect));
- if (manual == NULL)
- PrintError("Could not allocate memory for manual sections.");
-
- return(sect); /* return the number of man sections. */
- }
-
- /* Function Name: SortList
- * Description: Sorts the list of sections to search.
- * Arguments: list - a pointer to the list to sort.
- * Returns: a sorted list.
- *
- * This is the most complicated part of the entire operation.
- * all sections with the same label must by right next to each other,
- * but the sections that are in the standard list have to come first.
- */
-
- static void
- SortList(list)
- SectionList ** list;
- {
- SectionList * local;
- SectionList *head, *last, *inner, *old;
-
- if (*list == NULL)
- PrintError("No manual sections to read, exiting.");
-
- /*
- * First step
- *
- * Look for standard list items, and more them to the top of the list.
- */
-
- last = NULL; /* keep Saber happy. */
- for ( local = *list ; local->next != NULL ; local = local->next) {
- if ( local->flags ) {
- if ( local == *list ) /* top element is already standard. */
- break;
- head = local;
-
- /* Find end of standard block */
- for ( ; (local->next != NULL) && (local->flags)
- ; old = local, local = local->next);
-
- last->next = old->next; /* Move the block. */
- old->next = *list;
- *list = head;
-
- break; /* First step accomplished. */
- }
- last = local;
- }
-
- /*
- * Second step
- *
- * Move items with duplicate labels right next to each other.
- */
-
- local = *list;
- for ( local = *list ; local->next != NULL ; local = local->next) {
- inner = local->next;
- while ( inner != NULL) {
- if ( streq(inner->label, local->label) && (inner != local->next)) {
- last->next = inner->next; /* Move it to directly follow local. */
- inner->next = local->next;
- local->next = inner;
- inner = last; /* just so that we keep marching down the
- tree (this keeps us from looping). */
- }
- last = inner;
- inner = inner->next;
- }
- }
- }
-
- /* Function Name: ReadMandescFile
- * Description: Reads the mandesc file, and adds more sections as
- * nescessary.
- * Arguments: path - path name if the current search directory.
- * section_list - pointer to the list of sections.
- * Returns: TRUE in we should use default sections
- */
-
- static void
- ReadMandescFile( section_list, path )
- SectionList ** section_list;
- char * path;
- {
- char mandesc_file[BUFSIZ]; /* full path to the mandesc file. */
- FILE * descfile;
- char string[BUFSIZ], local_file[BUFSIZ];
- Boolean use_defaults = TRUE;
- char *cp;
-
- sprintf(mandesc_file, "%s/%s", path, MANDESC);
- if ( (descfile = fopen(mandesc_file, "r")) != NULL) {
- while ( fgets(string, BUFSIZ, descfile) != NULL) {
- string[strlen(string)-1] = '\0'; /* Strip off the CR. */
-
- if ( streq(string, NO_SECTION_DEFAULTS) ) {
- use_defaults = FALSE;
- continue;
- }
-
- if ((cp = index(string,'\t')) != NULL) {
- char *s;
- *cp++ = '\0';
- strcpy(local_file, MAN);
- strcat(local_file, string);
- if ((s = index(cp,'\t')) != NULL) {
- *s++ = '\0';
- if (streq(s, SUFFIX))
- AddNewSection(section_list, path, local_file, cp, MSUFFIX);
- else if (streq(s, FOLD))
- AddNewSection(section_list, path, local_file, cp, MFOLD);
- else if (streq(s, FOLDSUFFIX))
- AddNewSection(section_list, path, local_file, cp, MFOLDSUFFIX);
- else
- AddNewSection(section_list, path, local_file, cp, MNULL);
- } else
- AddNewSection(section_list, path, local_file, cp, MNULL);
- } else {
- sprintf(local_file, "%s%c", MAN, string[0]);
- AddNewSection(section_list, path, local_file, (string + 1), FALSE );
- }
- }
-
- fclose(descfile);
- }
- if (use_defaults)
- AddStandardSections(section_list, path);
- }
-
- /* Function Name: AddNewSection
- * Description: Adds the new section onto the current section list.
- * Arguments: list - pointer to the section list.
- * path - the path to the current manual section.
- * file - the file to save.
- * label - the current section label.
- * flags = 1 - add a suffix
- * = 2 - fold to lower case
- * Returns: none.
- */
-
- void
- AddNewSection(list, path, file, label, flags)
- SectionList **list;
- char * path, * label, * file;
- int flags;
- {
- SectionList * local_list, * end;
- char full_path[BUFSIZ];
-
- /* Allocate a new list element */
-
- local_list = (SectionList *) XtMalloc(sizeof(SectionList));
-
- if (*list != NULL) {
- for ( end = *list ; end->next != NULL ; end = end->next );
- end->next = local_list;
- }
- else
- *list = local_list;
-
- local_list->next = NULL;
- local_list->label = StrAlloc(label);
- sprintf(full_path, "%s/%s", path, file);
- local_list->directory = StrAlloc(full_path);
- local_list->flags = flags;
- }
-
- /* Function Name: AddToCurrentSection
- * Description: This function gets the names of the manual page
- * directories, then closes the directory.
- * Arguments: local_manual - a pointer to a manual pages structure.
- * path - the path to this directory.
- * Returns: none.
- */
-
- static void
- AddToCurrentSection(local_manual, path)
- Manual * local_manual;
- char * path;
- {
- char temp_path[BUFSIZ];
-
- ReadCurrentSection(local_manual, path);
- sprintf(temp_path, "%s.%s", path, COMPRESSION_EXTENSION);
- ReadCurrentSection(local_manual, temp_path);
- }
-
- /* Function Name: ReadCurrentSection
- * Description: Actually does the work of adding entries to the
- * new section
- * Arguments: local_manual - a pointer to a manual pages structure.
- * path - the path to this directory.
- * compressed - Is this a compressed directory?
- * Returns: TRUE if any entries are found.
- */
-
- static void
- ReadCurrentSection(local_manual, path)
- Manual * local_manual;
- char * path;
- {
- DIR * dir;
-
- register struct dirent *dp;
-
- register int nentries;
- register int nalloc;
- char full_name[BUFSIZ], *ptr;
-
- if((dir = opendir(path)) == NULL) {
- #ifdef DEBUG
- sprintf(error_buf,"Can't open directory %s", path);
- PopupWarning(NULL, error_buf);
- #endif /* DEBUG */
- return;
- }
-
- /*
- * Remove the compression extension from the path name.
- */
-
- if ( (ptr = rindex(path, '.')) != NULL)
- if (streq(ptr + 1, COMPRESSION_EXTENSION))
- *ptr = '\0';
-
- nentries = local_manual->nentries;
- nalloc = local_manual->nalloc;
-
- while( (dp = readdir(dir)) != NULL ) {
- char * name = dp->d_name;
- if (name[0] == '.')
- continue;
- #ifndef CRAY
- if (index(name, '.') == NULL)
- continue;
- #endif
- if( nentries >= nalloc ) {
- nalloc += ENTRYALLOC;
- local_manual->entries =(char **) XtRealloc((char *)local_manual->entries,
- nalloc * sizeof(char *));
- local_manual->entries_less_paths =
- (char **) XtRealloc((char *)local_manual->entries_less_paths,
- nalloc * sizeof(char *));
- }
-
- sprintf(full_name, "%s/%s", path, name);
- /*
- * Remove the compression extension from the entry name.
- */
-
- if ( (ptr = rindex(full_name, '.')) != NULL)
- if (streq(ptr + 1, COMPRESSION_EXTENSION))
- *ptr = '\0';
- local_manual->entries[nentries] = StrAlloc(full_name);
- local_manual->entries_less_paths[nentries] =
- rindex(local_manual->entries[nentries], '/');
- if ( local_manual->entries_less_paths[nentries] == NULL )
- PrintError("Internal error while cataloging manual pages.");
- ++ nentries;
- }
-
- local_manual->nentries = nentries;
- local_manual->nalloc = nalloc;
-
- closedir(dir);
- }
-
- /* Function Name: SortAndRemove
- * Description: This function sorts all the entry names and
- * then removes all the duplicate entries.
- * Arguments: man - a pointer to the manual structure.
- * number - the number of manual sections.
- * Returns: an improved manual stucure
- */
-
- static void
- SortAndRemove(man, number)
- Manual *man;
- int number;
- {
- int i,j;
- char *l1, *l2, **s1;
-
- for ( i = 0; i < number; man++, i++) { /* sort each section */
- register int j = 0;
-
- #ifdef DEBUG
- printf("sorting section %d - %s\n", i, man->blabel);
- #endif /* DEBUG */
-
- s1 = (char **)malloc(man->nentries * sizeof(char *));
-
- /* temporarily remove suffixes of entries, preventing them from */
- /* being used in alpabetic comparison ie sccs-delta.1 vs sccs.1 */
- for (j=0; j<man->nentries; j++)
- if ((s1[j] = rindex(man->entries_less_paths[j], '.')) != NULL)
- *s1[j] = '\0';
-
- sortstrs ( man->entries_less_paths, man->nentries, man->entries );
-
- /* put back suffixes */
- for (j=0; j<man->nentries; j++)
- if (s1[j] != NULL) *s1[j] = '.';
-
- free(s1);
-
- #ifdef DEBUG
- printf("removing from section %d.\n", i);
- #endif /* DEBUG */
-
- {
- register int j, k, nent, nentm1;
- int j2;
- nent = man -> nentries;
- nentm1 = nent - 1;
- j = 0;
- l2 = man->entries_less_paths[j++];
- if ( l2 == NULL )
- PrintError("Internal error while removing duplicate manual pages.");
- while ( j < nentm1 )
- {
- l1 = l2;
- l2 = man->entries_less_paths[j++];
- if ( l2 == NULL )
- PrintError("Internal error while removing duplicate manual pages."
- );
- if ( streq(l1,l2) )
- {
- j2 = j-1;
- k = j2;
- while ( j < nent )
- {
- man -> entries_less_paths[k] = man -> entries_less_paths[j];
- man -> entries[k++] = man -> entries[j++];
- }
- j = j2;
- -- man -> nentries;
- -- nent;
- -- nentm1;
- }
- }
- }
- }
- }
-
- /*
- ******* Replacement for qsort to keep
- ******* identical entries in order
-
- A somewhat ugly hack of something that was once simpler...
- */
- /*
- Sort an array of pointers to strings, keeping it
- in ascending order by (1) string comparison and
- (2) original entry order in the pointer array.
-
- This is a modified radix exchange algorithm.
-
- In case there's insufficient memory for a temporary copy
- of the pointer array, the original order of identical strings
- isn't preserved.
- */
-
- #ifndef Byte
- #define Byte unsigned char
- #endif
-
- #ifndef reg
- #define reg register
- #endif
-
-
-
- sortstrs ( data, size, otherdata ) /* Sort an array of string ptrs */
-
- Byte *data[];
- int size;
- Byte *otherdata[];
-
- {
- Byte **sp, **ep;
- Byte **othersp, **otherep;
- int *origorder;
-
- origorder = (int *) calloc (size, sizeof(int));
- if ( origorder )
- {
- reg int i;
-
- for ( i=0; i < size; ++i )
- origorder[i] = i;
- }
-
- sp = data;
- ep = &data[size-1];
- othersp = otherdata;
- otherep = &otherdata[size-1];
- if ( origorder )
- {
- sortstrs_block_oo ( sp, ep, 0, 0x80, origorder, &origorder[size-1],
- othersp, otherep );
- free (origorder);
- }
- else
- sortstrs_block ( sp, ep, 0, 0x80, othersp, otherep );
- }
-
-
-
- /*---------------------------------*/
- /* Sort 1 block of data on 1 bit */
- /*---------------------------------*/
-
- sortstrs_block ( start, end, offset, mask, otherstart, otherend )
-
- Byte **start;
- Byte **end;
- int offset;
- Byte mask;
- Byte **otherstart;
- Byte **otherend;
-
- {
- reg Byte **sp, **ep;
- reg Byte m;
- reg int off;
- reg Byte *t;
- reg int curstrlen;
- int maxstrlen;
- Byte **othersp, **otherep;
-
-
- #define newstring(ptr) \
- { \
- t = *ptr; \
- curstrlen = 0; \
- while ( *t++ ) ++ curstrlen; \
- if ( curstrlen > maxstrlen ) maxstrlen = curstrlen; \
- t = *ptr; \
- }
-
-
- maxstrlen = 0;
- sp = start;
- ep = end;
- off = offset;
- m = mask;
- othersp = otherstart;
- otherep = otherend;
-
- while (1)
- {
- newstring(sp)
- while (((sp != ep) && ((curstrlen < off) || ((t[off] & m) == 0))))
- {
- ++ sp;
- ++ othersp;
- newstring(sp)
- }
- if ( sp == ep )
- break;
-
- newstring(ep);
- while (((sp != ep) && (curstrlen >= off) && ((t[off] & m) != 0)))
- {
- -- ep;
- -- otherep;
- newstring(ep)
- }
- if ( sp == ep )
- break;
-
- t = *sp;
- *sp = *ep;
- *ep = t;
-
- t = *othersp;
- *othersp = *otherep;
- *otherep = t;
- }
-
- t = *sp;
- if ((curstrlen < off) || ((t[off] & m) == 0))
- {
- if ( ep != end )
- {
- ++ ep;
- ++ otherep;
- }
- }
- else
- {
- if ( sp != start )
- {
- -- sp;
- -- othersp;
- }
- }
-
- m >>= 1;
- if ( m == 0 )
- {
- m = 0x80;
- if ( ++off >= maxstrlen )
- return;
- }
-
-
- if ( sp != start )
- sortstrs_block ( start, sp, off, m, otherstart, othersp );
- if ( ep != end )
- sortstrs_block ( ep, end, off, m, otherep, otherend );
- }
-
-
-
- /*-----------------------------------------------------------------*/
- /* Sort 1 block of data on 1 bit; check for out-of-order entries */
- /*-----------------------------------------------------------------*/
-
- sortstrs_block_oo ( start, end, offset, mask, ostart, oend,
- otherstart, otherend )
-
- Byte **start;
- Byte **end;
- int offset;
- Byte mask;
- int *ostart;
- int *oend;
- Byte **otherstart;
- Byte **otherend;
-
- {
- reg Byte **sp, **ep;
- reg int *osp, *oep;
- reg Byte m;
- reg int off;
- reg Byte *t;
- reg int u;
- reg int curstrlen;
- int maxstrlen;
- Byte **othersp, **otherep;
-
-
- #define newstring(ptr) \
- { \
- t = *ptr; \
- curstrlen = 0; \
- while ( *t++ ) ++ curstrlen; \
- if ( curstrlen > maxstrlen ) maxstrlen = curstrlen; \
- t = *ptr; \
- }
-
-
- maxstrlen = 0;
- sp = start;
- ep = end;
- osp = ostart;
- oep = oend;
- off = offset;
- m = mask;
- othersp = otherstart;
- otherep = otherend;
-
- while (1)
- {
- newstring(sp)
- while (((sp != ep) && ((curstrlen < off) || ((t[off] & m) == 0))))
- {
- ++ sp;
- ++ osp;
- ++ othersp;
- newstring(sp)
- }
- if ( sp == ep )
- break;
-
- newstring(ep);
- while (((sp != ep) && (curstrlen >= off) && ((t[off] & m) != 0)))
- {
- -- ep;
- -- oep;
- -- otherep;
- newstring(ep)
- }
- if ( sp == ep )
- break;
-
- t = *sp;
- *sp = *ep;
- *ep = t;
-
- t = *othersp;
- *othersp = *otherep;
- *otherep = t;
-
- u = *osp;
- *osp = *oep;
- *oep = u;
- }
-
- t = *sp;
- if ((curstrlen < off) || ((t[off] & m) == 0))
- {
- if ( ep != end )
- {
- ++ ep;
- ++ oep;
- ++ otherep;
- }
- }
- else
- {
- if ( sp != start )
- {
- -- sp;
- -- osp;
- -- othersp;
- }
- }
-
- m >>= 1;
- if ( m == 0 )
- {
- m = 0x80;
- if ( ++off >= maxstrlen ) /* Finished sorting block of strings: */
- { /* Restore duplicates to
- riginal order */
- reg Byte **cp;
- reg int *ocp;
- Byte **othercp;
-
-
- if ( sp != start )
- {
- cp = start;
- ocp = ostart;
- othercp = otherstart;
- while ( cp != sp )
- {
- if ( *ocp > *(ocp+1) )
- {
- t = *(cp+1);
- *(cp+1) = *cp;
- *cp = t;
-
- t = *(othercp+1);
- *(othercp+1) = *othercp;
- *othercp = t;
-
- u = *(ocp+1);
- *(ocp+1) = *ocp;
- *ocp = u;
-
- if ( cp != start )
- {
- -- cp;
- -- ocp;
- -- othercp;
- continue;
- }
- }
- ++ cp;
- ++ ocp;
- ++ othercp;
- }
- }
- if ( ep != end )
- {
- cp = ep;
- ocp = oep;
- othercp = otherep;
- while ( cp != end )
- {
- if ( *ocp > *(ocp+1) )
- {
- t = *(cp+1);
- *(cp+1) = *cp;
- *cp = t;
-
- t = *(othercp+1);
- *(othercp+1) = *othercp;
- *othercp = t;
-
- u = *(ocp+1);
- *(ocp+1) = *ocp;
- *ocp = u;
-
- if ( cp != ep )
- {
- -- cp;
- -- ocp;
- -- othercp;
- continue;
- }
- }
- ++ cp;
- ++ ocp;
- ++ othercp;
- }
- }
- return;
- }
- }
-
-
- if ( sp != start )
- sortstrs_block_oo ( start, sp, off, m, ostart, osp, otherstart, othersp );
- if ( ep != end )
- sortstrs_block_oo ( ep, end, off, m, oep, oend, otherep, otherend );
- }
-
-
- /* Function Name: InitManual
- * Description: Initializes this manual section.
- * Arguments: l_manual - local copy of the manual structure.
- * label - the button label for this section.
- * Returns: none.
- */
-
- static void
- InitManual(l_manual, label)
- Manual * l_manual;
- char * label;
- {
- bzero( l_manual, sizeof(Manual) ); /* clear it. */
- l_manual->blabel = label; /* set label. */
- }
-
- #if defined(DEBUG)
-
- /* Function Name: DumpManual
- * Description: Debugging function that dumps the entire manual page
- * structure.
- * Arguments: number - the number of sections.
- * Returns: none.
- */
-
- DumpManual(number)
- {
- register int i,j;
-
- for ( i = 0; i < number; i++) {
- printf("label: %s\n", manual[i].blabel);
- for (j = 0; j < manual[i].nentries; j++)
- printf("%s\n", manual[i].entries[j]);
- }
- }
-
- #endif /* DEBUG */
-