xenocara/app/xman/man.c

1137 lines
31 KiB
C
Raw Normal View History

2006-11-25 13:07:29 -07:00
/*
Copyright (c) 1987, 1988 X Consortium
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of the X Consortium shall
not be used in advertising or otherwise to promote the sale, use or
other dealings in this Software without prior written authorization
from the X Consortium.
*/
#include "globals.h"
2013-09-28 10:22:59 -06:00
#include "vendor.h" /* vendor-specific defines and data */
2006-11-25 13:07:29 -07:00
#include <dirent.h>
#ifdef DEBUG
2013-09-28 10:22:59 -06:00
static char error_buf[BUFSIZ]; /* The buffer for error messages. */
2006-11-25 13:07:29 -07:00
#endif /* DEBUG */
2013-09-28 10:22:59 -06:00
static void AddToCurrentSection(Manual * local_manual, char *path);
static void InitManual(Manual * l_manual, char *label);
static void ReadCurrentSection(Manual * local_manual, char *path);
static void ReadMandescFile(SectionList ** section_list, char *path);
static void SortAndRemove(Manual * man, int number);
2006-11-25 13:07:29 -07:00
static void SortList(SectionList ** list);
#define SECT_ERROR -1
#ifndef Byte
#define Byte unsigned char
#endif
2013-09-28 10:22:59 -06:00
2006-11-25 13:07:29 -07:00
#ifndef reg
#define reg register
#endif
2013-09-28 10:22:59 -06:00
static void sortstrs(Byte * data[], int size, Byte * otherdata[]);
static void sortstrs_block(Byte **, Byte **, int, Byte, Byte **, Byte **);
static void sortstrs_block_oo(Byte **, Byte **, int, Byte, int *, int *,
Byte **, Byte **);
2006-11-25 13:07:29 -07:00
/* Function Name: Man
* Description: Builds a list of all manual directories and files.
2013-09-28 10:22:59 -06:00
* Arguments: none.
2006-11-25 13:07:29 -07:00
* Returns: the number of manual sections.
*/
int
Man(void)
{
2013-09-28 10:22:59 -06:00
SectionList *list = NULL;
2006-11-25 13:07:29 -07:00
2013-09-28 10:22:59 -06:00
char *ptr, *lang = NULL, manpath[BUFSIZ], buf[BUFSIZ],
*path, *current_label;
int sect, num_alloced;
/*
2006-11-25 13:07:29 -07:00
* Get the environment variable MANPATH, and if it doesn't exist then use
* SYSMANPATH and LOCALMANPATH.
*/
2013-09-28 10:22:59 -06:00
/* if MANPATH variable ends in ':'. So, should extend it's value to the
* default search path.
*/
2006-11-25 13:07:29 -07:00
2013-09-28 10:22:59 -06:00
*manpath = '\0';
if ((ptr = getenv("MANPATH")) != NULL)
strcpy(manpath, ptr);
if (ptr == NULL || streq(ptr, "") || ptr[strlen(ptr) - 1] == ':') {
lang = getenv("LANG");
2006-11-25 13:07:29 -07:00
#ifdef MANCONF
2013-09-28 10:22:59 -06:00
if (!ReadManConfig(manpath + strlen(manpath)))
2006-11-25 13:07:29 -07:00
#endif
2013-09-28 10:22:59 -06:00
{
2006-11-25 13:07:29 -07:00
#ifdef MANCONF
2013-09-28 10:22:59 -06:00
if (manpath[strlen(manpath) - 1] != ':')
strcat(manpath, ":");
2006-11-25 13:07:29 -07:00
#endif
2013-09-28 10:22:59 -06:00
strcat(manpath, SYSMANPATH);
2006-11-25 13:07:29 -07:00
#ifdef LOCALMANPATH
2013-09-28 10:22:59 -06:00
strcat(manpath, ":");
strcat(manpath, LOCALMANPATH);
2006-11-25 13:07:29 -07:00
#endif
2013-09-28 10:22:59 -06:00
}
2006-11-25 13:07:29 -07:00
}
/*
* 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.
*/
2013-09-28 10:22:59 -06:00
for (path = manpath; (ptr = strchr(path, ':')) != NULL; path = ++ptr) {
*ptr = '\0';
if (lang != NULL) {
strcpy(buf, path);
strcat(buf, "/");
strncat(buf, lang, sizeof(buf) - strlen(path) + 1);
buf[sizeof(buf) - strlen(path) + 1] = '\0';
ReadMandescFile(&list, buf);
}
ReadMandescFile(&list, path);
}
2009-10-24 09:00:51 -06:00
if (lang != NULL) {
2013-09-28 10:22:59 -06:00
strcpy(buf, path);
strcat(buf, "/");
strncat(buf, lang, sizeof(buf) - strlen(path) + 1);
buf[sizeof(buf) - strlen(path) + 1] = '\0';
ReadMandescFile(&list, buf);
2006-11-25 13:07:29 -07:00
}
ReadMandescFile(&list, path);
2013-09-28 10:22:59 -06:00
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 *) XtRealloc((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. */
2006-11-25 13:07:29 -07:00
}
2013-09-28 10:22:59 -06:00
if (manual[sect].nentries != 0)
sect++; /* don't forget that last section. */
SortAndRemove(manual, sect);
#ifdef notdef /* dump info. */
DumpManual(sect);
2006-11-25 13:07:29 -07:00
#endif
2013-09-28 10:22:59 -06:00
2006-11-25 13:07:29 -07:00
/*
* realloc manual to be minimum space necessary.
*/
2013-09-28 10:22:59 -06:00
if (sect == 0)
PrintError("No manual pages found.");
manual = (Manual *) XtRealloc((char *) manual, (sizeof(Manual) * sect));
if (manual == NULL)
PrintError("Could not allocate memory for manual sections.");
2006-11-25 13:07:29 -07:00
2013-09-28 10:22:59 -06:00
return (sect); /* return the number of man sections. */
}
2006-11-25 13:07:29 -07:00
/* 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(SectionList ** list)
{
2013-09-28 10:22:59 -06:00
SectionList *local;
SectionList *head, *last, *inner, *old;
if (*list == NULL)
PrintError("No manual sections to read, exiting.");
/*
* First step
*
2006-11-25 13:07:29 -07:00
* Look for standard list items, and more them to the top of the list.
*/
2013-09-28 10:22:59 -06:00
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;
2006-11-25 13:07:29 -07:00
2013-09-28 10:22:59 -06:00
/* Find end of standard block */
for (old = NULL; (local->next != NULL) && (local->flags);
old = local, local = local->next);
2006-11-25 13:07:29 -07:00
2013-09-28 10:22:59 -06:00
if (old != NULL) {
last->next = old->next; /* Move the block. */
old->next = *list;
*list = head;
}
2006-11-25 13:07:29 -07:00
2013-09-28 10:22:59 -06:00
break; /* First step accomplished. */
}
last = local;
2006-11-25 13:07:29 -07:00
}
/*
* Second step
*
* Move items with duplicate labels right next to each other.
*
* Changed to keep the order of the list entries unchanged.
*/
2013-09-28 10:22:59 -06:00
for (local = *list; local->next != NULL; local = local->next) {
head = local;
old = inner = local->next;
while (inner != NULL) {
if (streq(inner->label, local->label)) {
if (old != inner) {
old->next = inner->next;
last = inner->next;
inner->next = head->next;
head->next = inner;
head = inner;
old = inner = last;
continue;
}
else
head = inner;
}
old = inner;
inner = inner->next;
}
2006-11-25 13:07:29 -07:00
}
2013-09-28 10:22:59 -06:00
}
2006-11-25 13:07:29 -07:00
/* Function Name: ReadMandescFile
2013-09-28 10:22:59 -06:00
* Description: Reads the mandesc file, and adds more sections as
2006-11-25 13:07:29 -07:00
* necessary.
* 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
*/
2013-09-28 10:22:59 -06:00
2006-11-25 13:07:29 -07:00
static void
2013-09-28 10:22:59 -06:00
ReadMandescFile(SectionList ** section_list, char *path)
2006-11-25 13:07:29 -07:00
{
2013-09-28 10:22:59 -06:00
char mandesc_file[BUFSIZ]; /* full path to the mandesc file. */
FILE *descfile;
char string[BUFSIZ], local_file[BUFSIZ];
Boolean use_defaults = TRUE;
char *cp;
snprintf(mandesc_file, sizeof(mandesc_file), "%s/%s", path, MANDESC);
if ((descfile = fopen(mandesc_file, "r")) != NULL) {
while (fgets(string, BUFSIZ, descfile) != NULL) {
2015-05-10 04:21:18 -06:00
size_t len = strlen(string);
if (len == 0)
continue;
if (string[len - 1] == '\n')
string[len - 1] = '\0'; /* Strip off the CR. */
2013-09-28 10:22:59 -06:00
if (streq(string, NO_SECTION_DEFAULTS)) {
use_defaults = FALSE;
continue;
}
if ((cp = strchr(string, '\t')) != NULL) {
char *s;
*cp++ = '\0';
strcpy(local_file, MAN);
strcat(local_file, string);
if ((s = strchr(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 {
snprintf(local_file, sizeof(local_file), "%s%c", MAN,
string[0]);
AddNewSection(section_list, path, local_file, (string + 1),
FALSE);
2006-11-25 13:07:29 -07:00
#ifdef SEARCHOTHER
2013-09-28 10:22:59 -06:00
snprintf(local_file, sizeof(local_file), "%s%c", SEARCHOTHER,
string[0]);
AddNewSection(section_list, path, local_file, (string + 1),
FALSE);
2006-11-25 13:07:29 -07:00
#endif
2013-09-28 10:22:59 -06:00
}
}
2006-11-25 13:07:29 -07:00
2013-09-28 10:22:59 -06:00
fclose(descfile);
}
if (use_defaults)
AddStandardSections(section_list, path);
2006-11-25 13:07:29 -07:00
}
/* 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
2013-09-28 10:22:59 -06:00
AddNewSection(SectionList ** list, const char *path, const char *file,
const char *label, int flags)
2006-11-25 13:07:29 -07:00
{
2013-09-28 10:22:59 -06:00
SectionList *local_list, *end;
char full_path[BUFSIZ];
2006-11-25 13:07:29 -07:00
/* Allocate a new list element */
2013-09-28 10:22:59 -06:00
local_list = (SectionList *) XtMalloc(sizeof(SectionList));
2006-11-25 13:07:29 -07:00
2013-09-28 10:22:59 -06:00
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 = XtNewString(label);
snprintf(full_path, sizeof(full_path), "%s/%s", path, file);
local_list->directory = XtNewString(full_path);
local_list->flags = flags;
}
2006-11-25 13:07:29 -07:00
/* 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
2013-09-28 10:22:59 -06:00
AddToCurrentSection(Manual * local_manual, char *path)
2006-11-25 13:07:29 -07:00
{
2013-09-28 10:22:59 -06:00
char temp_path[BUFSIZ];
2006-11-25 13:07:29 -07:00
#if defined(__OpenBSD__) || defined(__NetBSD__)
2013-09-28 10:22:59 -06:00
snprintf(temp_path, sizeof(temp_path), "%s/%s", path, MACHINE);
ReadCurrentSection(local_manual, temp_path);
2006-11-25 13:07:29 -07:00
#endif
2013-09-28 10:22:59 -06:00
ReadCurrentSection(local_manual, path);
snprintf(temp_path, sizeof(temp_path), "%s.%s", path,
COMPRESSION_EXTENSION);
ReadCurrentSection(local_manual, temp_path);
2006-11-25 13:07:29 -07:00
}
/* Function Name: ReadCurrentSection
2013-09-28 10:22:59 -06:00
* Description: Actually does the work of adding entries to the
2006-11-25 13:07:29 -07:00
* 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
2013-09-28 10:22:59 -06:00
ReadCurrentSection(Manual * local_manual, char *path)
2006-11-25 13:07:29 -07:00
{
2013-09-28 10:22:59 -06:00
DIR *dir;
register struct dirent *dp;
2006-11-25 13:07:29 -07:00
2013-09-28 10:22:59 -06:00
register int nentries;
register int nalloc;
char full_name[BUFSIZ], *ptr;
2006-11-25 13:07:29 -07:00
2013-09-28 10:22:59 -06:00
if ((dir = opendir(path)) == NULL) {
2006-11-25 13:07:29 -07:00
#ifdef DEBUG
2013-09-28 10:22:59 -06:00
snprintf(error_buf, sizeof(error_buf), "Can't open directory %s", path);
PopupWarning(NULL, error_buf);
2006-11-25 13:07:29 -07:00
#endif /* DEBUG */
2013-09-28 10:22:59 -06:00
return;
}
2006-11-25 13:07:29 -07:00
/*
* Remove the compression extension from the path name.
*/
2013-09-28 10:22:59 -06:00
if ((ptr = strrchr(path, '.')) != NULL) {
2006-11-25 13:07:29 -07:00
#if !defined(__SCO__) && !defined(ISC)
2013-09-28 10:22:59 -06:00
if (streq(ptr + 1, COMPRESSION_EXTENSION))
2006-11-25 13:07:29 -07:00
#else
2013-09-28 10:22:59 -06:00
if (strpbrk(ptr + 1, COMPRESSION_EXTENSIONS) != NULL)
2006-11-25 13:07:29 -07:00
#endif
2013-09-28 10:22:59 -06:00
*ptr = '\0';
2006-11-25 13:07:29 -07:00
#ifdef GZIP_EXTENSION
2013-09-28 10:22:59 -06:00
else if (streq(ptr + 1, GZIP_EXTENSION))
*ptr = '\0';
2009-10-24 09:00:51 -06:00
#endif
#ifdef BZIP2_EXTENSION
2013-09-28 10:22:59 -06:00
else if (streq(ptr + 1, BZIP2_EXTENSION))
*ptr = '\0';
2009-10-24 09:00:51 -06:00
#endif
#ifdef LZMA_EXTENSION
2013-09-28 10:22:59 -06:00
else if (streq(ptr + 1, LZMA_EXTENSION))
*ptr = '\0';
2006-11-25 13:07:29 -07:00
#endif
}
2013-09-28 10:22:59 -06:00
nentries = local_manual->nentries;
nalloc = local_manual->nalloc;
while ((dp = readdir(dir)) != NULL) {
char *name = dp->d_name;
if (name[0] == '.')
continue;
if (strchr(name, '.') == NULL)
continue;
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 *));
}
snprintf(full_name, sizeof(full_name), "%s/%s", path, name);
2006-11-25 13:07:29 -07:00
/*
* Remove the compression extension from the entry name.
*/
2013-09-28 10:22:59 -06:00
if ((ptr = strrchr(full_name, '.')) != NULL) {
2006-11-25 13:07:29 -07:00
#if !defined(__SCO__) && !defined(ISC)
2013-09-28 10:22:59 -06:00
if (streq(ptr + 1, COMPRESSION_EXTENSION))
2006-11-25 13:07:29 -07:00
#else
2013-09-28 10:22:59 -06:00
if (strpbrk(ptr + 1, COMPRESSION_EXTENSIONS) != NULL)
2006-11-25 13:07:29 -07:00
#endif
2013-09-28 10:22:59 -06:00
*ptr = '\0';
2006-11-25 13:07:29 -07:00
#ifdef GZIP_EXTENSION
2013-09-28 10:22:59 -06:00
else if (streq(ptr + 1, GZIP_EXTENSION))
*ptr = '\0';
2006-11-25 13:07:29 -07:00
#endif
2009-10-24 09:00:51 -06:00
#ifdef BZIP2_EXTENSION
2013-09-28 10:22:59 -06:00
else if (streq(ptr + 1, BZIP2_EXTENSION))
*ptr = '\0';
2009-10-24 09:00:51 -06:00
#endif
#ifdef LZMA_EXTENSION
2013-09-28 10:22:59 -06:00
else if (streq(ptr + 1, LZMA_EXTENSION))
*ptr = '\0';
2009-10-24 09:00:51 -06:00
#endif
2006-11-25 13:07:29 -07:00
#ifdef IGNORE_EXTENSION
2013-09-28 10:22:59 -06:00
/* skip files with specified extension - they're not real man pages */
else if (streq(ptr + 1, IGNORE_EXTENSION)) {
continue;
}
2006-11-25 13:07:29 -07:00
#endif /* IGNORE_EXTENSION */
2013-09-28 10:22:59 -06:00
}
local_manual->entries[nentries] = XtNewString(full_name);
local_manual->entries_less_paths[nentries] =
strrchr(local_manual->entries[nentries], '/');
if (local_manual->entries_less_paths[nentries] == NULL)
PrintError("Internal error while cataloging manual pages.");
++nentries;
2006-11-25 13:07:29 -07:00
}
2013-09-28 10:22:59 -06:00
local_manual->nentries = nentries;
local_manual->nalloc = nalloc;
closedir(dir);
2006-11-25 13:07:29 -07:00
}
/* 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
2013-09-28 10:22:59 -06:00
SortAndRemove(Manual * man, int number)
2006-11-25 13:07:29 -07:00
{
2013-09-28 10:22:59 -06:00
int i;
char *l1, *l2, **s1;
for (i = 0; i < number; man++, i++) { /* sort each section */
register int i2 = 0;
2006-11-25 13:07:29 -07:00
#ifdef DEBUG
2013-09-28 10:22:59 -06:00
printf("sorting section %d - %s\n", i, man->blabel);
2006-11-25 13:07:29 -07:00
#endif /* DEBUG */
2013-09-28 10:22:59 -06:00
s1 = (char **) malloc(man->nentries * sizeof(char *));
/* temporarily remove suffixes of entries, preventing them from */
/* being used in alphabetic comparison ie sccs-delta.1 vs sccs.1 */
for (i2 = 0; i2 < man->nentries; i2++)
if ((s1[i2] = strrchr(man->entries_less_paths[i2], '.')) != NULL)
*s1[i2] = '\0';
2006-11-25 13:07:29 -07:00
2013-09-28 10:22:59 -06:00
sortstrs((Byte **) man->entries_less_paths, man->nentries,
(Byte **) man->entries);
2006-11-25 13:07:29 -07:00
2013-09-28 10:22:59 -06:00
/* put back suffixes */
for (i2 = 0; i2 < man->nentries; i2++)
if (s1[i2] != NULL)
*s1[i2] = '.';
free(s1);
2006-11-25 13:07:29 -07:00
#ifdef DEBUG
2013-09-28 10:22:59 -06:00
printf("removing from section %d.\n", i);
2006-11-25 13:07:29 -07:00
#endif /* DEBUG */
2013-09-28 10:22:59 -06:00
{
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;
2006-11-25 13:07:29 -07:00
}
2013-09-28 10:22:59 -06:00
}
}
2006-11-25 13:07:29 -07:00
}
}
/*
2013-09-28 10:22:59 -06:00
******* Replacement for qsort to keep
******* identical entries in order
A somewhat ugly hack of something that was once simpler...
*/
2006-11-25 13:07:29 -07:00
/*
2013-09-28 10:22:59 -06:00
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.
*/
static void
sortstrs(Byte * data[], int size, Byte * otherdata[])
2006-11-25 13:07:29 -07:00
{
2013-09-28 10:22:59 -06:00
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;
2006-11-25 13:07:29 -07:00
}
2013-09-28 10:22:59 -06:00
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);
2006-11-25 13:07:29 -07:00
}
2013-09-28 10:22:59 -06:00
else
sortstrs_block(sp, ep, 0, 0x80, othersp, otherep);
2006-11-25 13:07:29 -07:00
}
2013-09-28 10:22:59 -06:00
2006-11-25 13:07:29 -07:00
/*---------------------------------*/
/* Sort 1 block of data on 1 bit */
/*---------------------------------*/
2013-09-28 10:22:59 -06:00
2006-11-25 13:07:29 -07:00
static void
2013-09-28 10:22:59 -06:00
sortstrs_block(Byte ** start, Byte ** end, int offset, Byte mask,
Byte ** otherstart, Byte ** otherend)
2006-11-25 13:07:29 -07:00
{
2013-09-28 10:22:59 -06:00
reg Byte **sp, **ep;
reg Byte m;
reg int off;
reg Byte *t;
reg int curstrlen;
int maxstrlen;
Byte **othersp, **otherep;
#define newstring(ptr) \
2006-11-25 13:07:29 -07:00
{ \
t = *ptr; \
curstrlen = 0; \
while ( *t++ ) ++ curstrlen; \
if ( curstrlen > maxstrlen ) maxstrlen = curstrlen; \
t = *ptr; \
}
2013-09-28 10:22:59 -06:00
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;
2006-11-25 13:07:29 -07:00
}
2013-09-28 10:22:59 -06:00
t = *sp;
if ((curstrlen < off) || ((t[off] & m) == 0)) {
if (ep != end) {
++ep;
++otherep;
}
2006-11-25 13:07:29 -07:00
}
2013-09-28 10:22:59 -06:00
else {
if (sp != start) {
--sp;
--othersp;
}
2006-11-25 13:07:29 -07:00
}
2013-09-28 10:22:59 -06:00
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);
2006-11-25 13:07:29 -07:00
}
2013-09-28 10:22:59 -06:00
2006-11-25 13:07:29 -07:00
/*-----------------------------------------------------------------*/
/* Sort 1 block of data on 1 bit; check for out-of-order entries */
/*-----------------------------------------------------------------*/
2013-09-28 10:22:59 -06:00
2006-11-25 13:07:29 -07:00
static void
2013-09-28 10:22:59 -06:00
sortstrs_block_oo(Byte ** start, Byte ** end, int offset, Byte mask,
int *ostart, int *oend, Byte ** otherstart, Byte ** otherend)
2006-11-25 13:07:29 -07:00
{
2013-09-28 10:22:59 -06:00
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;
2006-11-25 13:07:29 -07:00
#define newstring(ptr) \
{ \
t = *ptr; \
curstrlen = 0; \
while ( *t++ ) ++ curstrlen; \
if ( curstrlen > maxstrlen ) maxstrlen = curstrlen; \
t = *ptr; \
}
2013-09-28 10:22:59 -06:00
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;
2006-11-25 13:07:29 -07:00
}
2013-09-28 10:22:59 -06:00
t = *sp;
if ((curstrlen < off) || ((t[off] & m) == 0)) {
if (ep != end) {
++ep;
++oep;
++otherep;
}
2006-11-25 13:07:29 -07:00
}
2013-09-28 10:22:59 -06:00
else {
if (sp != start) {
--sp;
--osp;
--othersp;
2006-11-25 13:07:29 -07:00
}
2013-09-28 10:22:59 -06:00
}
m >>= 1;
if (m == 0) {
m = 0x80;
if (++off >= maxstrlen) { /* Finished sorting block of strings: *//* Restore duplicates to original 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;
2006-11-25 13:07:29 -07:00
}
}
2013-09-28 10:22:59 -06:00
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);
2006-11-25 13:07:29 -07:00
}
/* 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
2013-09-28 10:22:59 -06:00
InitManual(Manual * l_manual, char *label)
2006-11-25 13:07:29 -07:00
{
2013-09-28 10:22:59 -06:00
bzero(l_manual, sizeof(Manual)); /* clear it. */
l_manual->blabel = label; /* set label. */
2006-11-25 13:07:29 -07:00
}
2013-09-28 10:22:59 -06:00
2006-11-25 13:07:29 -07:00
#if defined(DEBUG)
/* Function Name: DumpManual
* Description: Debugging function that dumps the entire manual page
* structure.
* Arguments: number - the number of sections.
* Returns: none.
*/
void
DumpManual(int number)
{
2013-09-28 10:22:59 -06:00
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]);
}
2006-11-25 13:07:29 -07:00
}
#endif /* DEBUG */
#ifdef MANCONF
#if defined(MANCONFIGSTYLE_FreeBSD)
/* Function Name: ReadManConfig
* Description: Reads man.conf file used by FreeBSD man
* Argument: manpath - char array to return path in.
* Returns: TRUE if read was successful.
*/
Bool
ReadManConfig(char manpath[])
{
2013-09-28 10:22:59 -06:00
FILE *fp;
char line[BUFSIZ];
char *path;
Bool firstpath = TRUE;
if (!(fp = fopen(MANCONF, "r")))
return (FALSE);
while (fgets(line, sizeof(line), fp)) {
path = strtok(line, " \t\n");
if (!path || *path == '#')
continue;
if (strcmp(path, "MANPATH_MAP") == 0)
path = strtok((char *) NULL, " \t\n");
else if (strcmp(path, "MANDATORY_MANPATH") != 0 &&
strcmp(path, "OPTIONAL_MANPATH") != 0)
return (FALSE);
path = strtok((char *) NULL, " \t\n");
if (!path || *path == '#')
return FALSE;
if (firstpath) {
strcpy(manpath, path);
firstpath = FALSE;
}
else if (!strstr(manpath, path)) {
strcat(manpath, ":");
strcat(manpath, path);
}
2006-11-25 13:07:29 -07:00
}
2013-09-28 10:22:59 -06:00
fclose(fp);
return (!firstpath);
2006-11-25 13:07:29 -07:00
}
2013-09-28 10:22:59 -06:00
#elif defined(MANCONFIGSTYLE_Linux) /* not FreeBSD */
2006-11-25 13:07:29 -07:00
/* Function Name: ReadManConfig
* Description: Reads man.conf file used by Linux man
* Argument: manpath - char array to return path in.
* Returns: TRUE if read was successful.
*/
Bool
ReadManConfig(char manpath[])
{
2013-09-28 10:22:59 -06:00
FILE *fp;
char line[BUFSIZ];
char *path;
Bool firstpath = TRUE;
if (!(fp = fopen(MANCONF, "r")))
return (FALSE);
while (fgets(line, sizeof(line), fp)) {
path = strtok(line, " \t\n");
if (!path || *path == '#' || (strcmp(path, "MANPATH") != 0))
continue;
path = strtok((char *) NULL, " \t\n");
if (!path || *path == '#')
return FALSE;
if (firstpath) {
strcpy(manpath, path);
firstpath = FALSE;
}
else {
strcat(manpath, ":");
strcat(manpath, path);
}
2006-11-25 13:07:29 -07:00
}
2013-09-28 10:22:59 -06:00
fclose(fp);
return (!firstpath);
2006-11-25 13:07:29 -07:00
}
2013-09-28 10:22:59 -06:00
#elif defined(MANCONFIGSTYLE_OpenBSD) /* not FreeBSD or Linux */
2006-11-25 13:07:29 -07:00
/* Function Name: ReadManConfig
* Description: Reads man.conf file used by Open/NetBSD
* Argument: manpath - char array to return path in.
* Returns: TRUE if read was successful.
*
2013-09-28 10:22:59 -06:00
* This version expands the glob pattern that can be found
2006-11-25 13:07:29 -07:00
* in man.conf
*/
#include <glob.h>
Bool
ReadManConfig(char manpath[])
{
2013-09-28 10:22:59 -06:00
FILE *fp;
char line[BUFSIZ];
char *path;
Bool firstpath = TRUE;
glob_t gs;
int i;
2006-11-25 13:07:29 -07:00
if (!(fp = fopen(MANCONF, "r")))
2013-09-28 10:22:59 -06:00
return (FALSE);
2006-11-25 13:07:29 -07:00
while (fgets(line, sizeof(line), fp)) {
2013-09-28 10:22:59 -06:00
path = strtok(line, " \t\n");
if (!path || *path == '#')
continue;
if (strcmp(path, "_default")) {
/* for now */
continue;
}
memset(&gs, 0, sizeof(glob_t));
while ((path = strtok((char *) NULL, " \t\n"))) {
if (glob(path, GLOB_BRACE, NULL, &gs) < 0) {
fclose(fp);
return FALSE;
}
} /* while */
for (i = 0; i < gs.gl_pathc; i++) {
if (firstpath) {
strcpy(manpath, gs.gl_pathv[i]);
firstpath = FALSE;
}
else {
strcat(manpath, ":");
strcat(manpath, gs.gl_pathv[i]);
}
} /* for */
globfree(&gs);
2006-11-25 13:07:29 -07:00
}
fclose(fp);
2013-09-28 10:22:59 -06:00
return (!firstpath);
2006-11-25 13:07:29 -07:00
}
2013-09-28 10:22:59 -06:00
#elif defined(MANCONFIGSTYLE_BSD) /* not FreeBSD, Linux, or OpenBSD */
2006-11-25 13:07:29 -07:00
/* Function Name: ReadManConfig
* Description: Reads man.conf file used by BSD 4.4
* Argument: manpath - char array to return path in.
* Returns: TRUE if read was successful.
*/
Bool
2013-09-28 10:22:59 -06:00
ReadManConfig(char manpath[])
{
FILE *fp;
char line[BUFSIZ];
char *path;
Bool firstpath = TRUE;
2006-11-25 13:07:29 -07:00
2013-09-28 10:22:59 -06:00
if (!(fp = fopen(MANCONF, "r")))
return (FALSE);
2006-11-25 13:07:29 -07:00
2013-09-28 10:22:59 -06:00
while (fgets(line, sizeof(line), fp)) {
path = strtok(line, " \t\n");
if (!path || *path == '#' || strcmp(path, "_default"))
continue;
while ((path = strtok((char *) NULL, " \t\n"))) {
if (firstpath) {
strcpy(manpath, path);
firstpath = FALSE;
}
else {
strcat(manpath, ":");
strcat(manpath, path);
}
}
2006-11-25 13:07:29 -07:00
}
2013-09-28 10:22:59 -06:00
fclose(fp);
return (!firstpath);
2006-11-25 13:07:29 -07:00
}
#else /* not BSD */
#error "MANCONF defined (in vendor.h) for unknown operating system."
#endif /* MANCONFIGSTYLE == FreeBSD ... BSD */
#endif /* MANCONF */