man.c revision 6d36ef34
1/* 2 3Copyright (c) 1987, 1988 X Consortium 4 5Permission is hereby granted, free of charge, to any person obtaining 6a copy of this software and associated documentation files (the 7"Software"), to deal in the Software without restriction, including 8without limitation the rights to use, copy, modify, merge, publish, 9distribute, sublicense, and/or sell copies of the Software, and to 10permit persons to whom the Software is furnished to do so, subject to 11the following conditions: 12 13The above copyright notice and this permission notice shall be included 14in all copies or substantial portions of the Software. 15 16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR 20OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22OTHER DEALINGS IN THE SOFTWARE. 23 24Except as contained in this notice, the name of the X Consortium shall 25not be used in advertising or otherwise to promote the sale, use or 26other dealings in this Software without prior written authorization 27from the X Consortium. 28 29*/ 30 31 32#include "globals.h" 33#include "vendor.h" /* vendor-specific defines and data */ 34 35#include <dirent.h> 36 37#ifdef DEBUG 38static char error_buf[BUFSIZ]; /* The buffer for error messages. */ 39#endif /* DEBUG */ 40 41static void AddToCurrentSection(Manual * local_manual, char *path); 42static void InitManual(Manual * l_manual, char *label); 43static void ReadCurrentSection(Manual * local_manual, char *path); 44static void ReadMandescFile(SectionList ** section_list, char *path); 45static void SortAndRemove(Manual * man, int number); 46static void SortList(SectionList ** list); 47 48#define SECT_ERROR -1 49 50#ifndef Byte 51#define Byte unsigned char 52#endif 53 54#ifndef reg 55#define reg register 56#endif 57 58static void sortstrs(Byte * data[], int size, Byte * otherdata[]); 59static void sortstrs_block(Byte **, Byte **, int, Byte, Byte **, Byte **); 60static void sortstrs_block_oo(Byte **, Byte **, int, Byte, int *, int *, 61 Byte **, Byte **); 62 63/* Function Name: Man 64 * Description: Builds a list of all manual directories and files. 65 * Arguments: none. 66 * Returns: the number of manual sections. 67 */ 68 69int 70Man(void) 71{ 72 SectionList *list = NULL; 73 74 char *ptr, *lang = NULL, manpath[BUFSIZ], buf[BUFSIZ], 75 *path, *current_label; 76 int sect, num_alloced; 77 78/* 79 * Get the environment variable MANPATH, and if it doesn't exist then use 80 * SYSMANPATH and LOCALMANPATH. 81 */ 82 83 /* if MANPATH variable ends in ':'. So, should extend it's value to the 84 * default search path. 85 */ 86 87 *manpath = '\0'; 88 if ((ptr = getenv("MANPATH")) != NULL) 89 strcpy(manpath, ptr); 90 if (ptr == NULL || streq(ptr, "") || ptr[strlen(ptr) - 1] == ':') { 91 lang = getenv("LANG"); 92#ifdef MANCONF 93 if (!ReadManConfig(manpath + strlen(manpath))) 94#endif 95 { 96#ifdef MANCONF 97 if (manpath[strlen(manpath) - 1] != ':') 98 strcat(manpath, ":"); 99#endif 100 strcat(manpath, SYSMANPATH); 101#ifdef LOCALMANPATH 102 strcat(manpath, ":"); 103 strcat(manpath, LOCALMANPATH); 104#endif 105 } 106 } 107 108/* 109 * Get the list of manual directories in the users MANPATH that we should 110 * open to look for manual pages. The ``mandesc'' file is read here. 111 */ 112 113 for (path = manpath; (ptr = strchr(path, ':')) != NULL; path = ++ptr) { 114 *ptr = '\0'; 115 if (lang != NULL) { 116 strcpy(buf, path); 117 strcat(buf, "/"); 118 strncat(buf, lang, sizeof(buf) - strlen(path) + 1); 119 buf[sizeof(buf) - strlen(path) + 1] = '\0'; 120 ReadMandescFile(&list, buf); 121 } 122 ReadMandescFile(&list, path); 123 } 124 if (lang != NULL) { 125 strcpy(buf, path); 126 strcat(buf, "/"); 127 strncat(buf, lang, sizeof(buf) - strlen(path) + 1); 128 buf[sizeof(buf) - strlen(path) + 1] = '\0'; 129 ReadMandescFile(&list, buf); 130 } 131 ReadMandescFile(&list, path); 132 133 SortList(&list); 134 135 sect = 0; 136 num_alloced = SECTALLOC; 137 manual = (Manual *) XtMalloc(sizeof(Manual) * num_alloced); 138 InitManual(manual, list->label); 139 manual[sect].flags = list->flags; 140 current_label = NULL; 141 142 while (list != NULL) { 143 SectionList *old_list; 144 145 if (current_label == NULL || streq(list->label, current_label)) 146 AddToCurrentSection(manual + sect, list->directory); 147 else { 148 if (manual[sect].nentries == 0) { /* empty section, re-use it. */ 149 XtFree(manual[sect].blabel); 150 manual[sect].blabel = list->label; 151 manual[sect].flags = list->flags; 152 } 153 else { 154 if (++sect >= num_alloced) { 155 num_alloced += SECTALLOC; 156 manual = (Manual *) XtRealloc((char *) manual, 157 (sizeof(Manual) * num_alloced)); 158 if (manual == NULL) 159 PrintError 160 ("Could not allocate memory for manual sections."); 161 } 162 InitManual(manual + sect, list->label); 163 manual[sect].flags = list->flags; 164 } 165 AddToCurrentSection(manual + sect, list->directory); 166 } 167 /* Save label to see if it matches next entry. */ 168 current_label = list->label; 169 old_list = list; 170 list = list->next; 171 XtFree((char *) old_list); /* free what you allocate. */ 172 } 173 if (manual[sect].nentries != 0) 174 sect++; /* don't forget that last section. */ 175 176 SortAndRemove(manual, sect); 177 178#ifdef notdef /* dump info. */ 179 DumpManual(sect); 180#endif 181 182/* 183 * realloc manual to be minimum space necessary. 184 */ 185 186 if (sect == 0) 187 PrintError("No manual pages found."); 188 manual = (Manual *) XtRealloc((char *) manual, (sizeof(Manual) * sect)); 189 if (manual == NULL) 190 PrintError("Could not allocate memory for manual sections."); 191 192 return (sect); /* return the number of man sections. */ 193} 194 195/* Function Name: SortList 196 * Description: Sorts the list of sections to search. 197 * Arguments: list - a pointer to the list to sort. 198 * Returns: a sorted list. 199 * 200 * This is the most complicated part of the entire operation. 201 * all sections with the same label must by right next to each other, 202 * but the sections that are in the standard list have to come first. 203 */ 204 205static void 206SortList(SectionList ** list) 207{ 208 SectionList *local; 209 SectionList *head, *last, *inner, *old; 210 211 if (*list == NULL) 212 PrintError("No manual sections to read, exiting."); 213 214/* 215 * First step 216 * 217 * Look for standard list items, and more them to the top of the list. 218 */ 219 220 last = NULL; /* keep Saber happy. */ 221 for (local = *list; local->next != NULL; local = local->next) { 222 if (local->flags) { 223 if (local == *list) /* top element is already standard. */ 224 break; 225 head = local; 226 227 /* Find end of standard block */ 228 for (old = NULL; (local->next != NULL) && (local->flags); 229 old = local, local = local->next); 230 231 if (old != NULL) { 232 last->next = old->next; /* Move the block. */ 233 old->next = *list; 234 *list = head; 235 } 236 237 break; /* First step accomplished. */ 238 } 239 last = local; 240 } 241 242/* 243 * Second step 244 * 245 * Move items with duplicate labels right next to each other. 246 * 247 * Changed to keep the order of the list entries unchanged. 248 */ 249 250 for (local = *list; local->next != NULL; local = local->next) { 251 head = local; 252 old = inner = local->next; 253 while (inner != NULL) { 254 if (streq(inner->label, local->label)) { 255 if (old != inner) { 256 old->next = inner->next; 257 last = inner->next; 258 inner->next = head->next; 259 head->next = inner; 260 head = inner; 261 old = inner = last; 262 continue; 263 } 264 else 265 head = inner; 266 } 267 old = inner; 268 inner = inner->next; 269 } 270 } 271} 272 273/* Function Name: ReadMandescFile 274 * Description: Reads the mandesc file, and adds more sections as 275 * necessary. 276 * Arguments: path - path name if the current search directory. 277 * section_list - pointer to the list of sections. 278 * Returns: TRUE in we should use default sections 279 */ 280 281static void 282ReadMandescFile(SectionList ** section_list, char *path) 283{ 284 char mandesc_file[BUFSIZ]; /* full path to the mandesc file. */ 285 FILE *descfile; 286 char string[BUFSIZ], local_file[BUFSIZ]; 287 Boolean use_defaults = TRUE; 288 char *cp; 289 290 snprintf(mandesc_file, sizeof(mandesc_file), "%s/%s", path, MANDESC); 291 if ((descfile = fopen(mandesc_file, "r")) != NULL) { 292 while (fgets(string, BUFSIZ, descfile) != NULL) { 293 string[strlen(string) - 1] = '\0'; /* Strip off the CR. */ 294 295 if (streq(string, NO_SECTION_DEFAULTS)) { 296 use_defaults = FALSE; 297 continue; 298 } 299 300 if ((cp = strchr(string, '\t')) != NULL) { 301 char *s; 302 303 *cp++ = '\0'; 304 strcpy(local_file, MAN); 305 strcat(local_file, string); 306 if ((s = strchr(cp, '\t')) != NULL) { 307 *s++ = '\0'; 308 if (streq(s, SUFFIX)) 309 AddNewSection(section_list, path, local_file, cp, 310 MSUFFIX); 311 else if (streq(s, FOLD)) 312 AddNewSection(section_list, path, local_file, cp, 313 MFOLD); 314 else if (streq(s, FOLDSUFFIX)) 315 AddNewSection(section_list, path, local_file, cp, 316 MFOLDSUFFIX); 317 else 318 AddNewSection(section_list, path, local_file, cp, 319 MNULL); 320 } 321 else 322 AddNewSection(section_list, path, local_file, cp, MNULL); 323 } 324 else { 325 snprintf(local_file, sizeof(local_file), "%s%c", MAN, 326 string[0]); 327 AddNewSection(section_list, path, local_file, (string + 1), 328 FALSE); 329#ifdef SEARCHOTHER 330 snprintf(local_file, sizeof(local_file), "%s%c", SEARCHOTHER, 331 string[0]); 332 AddNewSection(section_list, path, local_file, (string + 1), 333 FALSE); 334#endif 335 } 336 } 337 338 fclose(descfile); 339 } 340 if (use_defaults) 341 AddStandardSections(section_list, path); 342} 343 344/* Function Name: AddNewSection 345 * Description: Adds the new section onto the current section list. 346 * Arguments: list - pointer to the section list. 347 * path - the path to the current manual section. 348 * file - the file to save. 349 * label - the current section label. 350 * flags = 1 - add a suffix 351 * = 2 - fold to lower case 352 * Returns: none. 353 */ 354 355void 356AddNewSection(SectionList ** list, const char *path, const char *file, 357 const char *label, int flags) 358{ 359 SectionList *local_list, *end; 360 char full_path[BUFSIZ]; 361 362/* Allocate a new list element */ 363 364 local_list = (SectionList *) XtMalloc(sizeof(SectionList)); 365 366 if (*list != NULL) { 367 for (end = *list; end->next != NULL; end = end->next); 368 end->next = local_list; 369 } 370 else 371 *list = local_list; 372 373 local_list->next = NULL; 374 local_list->label = XtNewString(label); 375 snprintf(full_path, sizeof(full_path), "%s/%s", path, file); 376 local_list->directory = XtNewString(full_path); 377 local_list->flags = flags; 378} 379 380/* Function Name: AddToCurrentSection 381 * Description: This function gets the names of the manual page 382 * directories, then closes the directory. 383 * Arguments: local_manual - a pointer to a manual pages structure. 384 * path - the path to this directory. 385 * Returns: none. 386 */ 387 388static void 389AddToCurrentSection(Manual * local_manual, char *path) 390{ 391 char temp_path[BUFSIZ]; 392 393#if defined(__OpenBSD__) || defined(__NetBSD__) 394 snprintf(temp_path, sizeof(temp_path), "%s/%s", path, MACHINE); 395 ReadCurrentSection(local_manual, temp_path); 396#endif 397 ReadCurrentSection(local_manual, path); 398 snprintf(temp_path, sizeof(temp_path), "%s.%s", path, 399 COMPRESSION_EXTENSION); 400 ReadCurrentSection(local_manual, temp_path); 401} 402 403/* Function Name: ReadCurrentSection 404 * Description: Actually does the work of adding entries to the 405 * new section 406 * Arguments: local_manual - a pointer to a manual pages structure. 407 * path - the path to this directory. 408 * compressed - Is this a compressed directory? 409 * Returns: TRUE if any entries are found. 410 */ 411 412static void 413ReadCurrentSection(Manual * local_manual, char *path) 414{ 415 DIR *dir; 416 register struct dirent *dp; 417 418 register int nentries; 419 register int nalloc; 420 char full_name[BUFSIZ], *ptr; 421 422 if ((dir = opendir(path)) == NULL) { 423#ifdef DEBUG 424 snprintf(error_buf, sizeof(error_buf), "Can't open directory %s", path); 425 PopupWarning(NULL, error_buf); 426#endif /* DEBUG */ 427 return; 428 } 429 430/* 431 * Remove the compression extension from the path name. 432 */ 433 434 if ((ptr = strrchr(path, '.')) != NULL) { 435#if !defined(__SCO__) && !defined(ISC) 436 if (streq(ptr + 1, COMPRESSION_EXTENSION)) 437#else 438 if (strpbrk(ptr + 1, COMPRESSION_EXTENSIONS) != NULL) 439#endif 440 *ptr = '\0'; 441#ifdef GZIP_EXTENSION 442 else if (streq(ptr + 1, GZIP_EXTENSION)) 443 *ptr = '\0'; 444#endif 445#ifdef BZIP2_EXTENSION 446 else if (streq(ptr + 1, BZIP2_EXTENSION)) 447 *ptr = '\0'; 448#endif 449#ifdef LZMA_EXTENSION 450 else if (streq(ptr + 1, LZMA_EXTENSION)) 451 *ptr = '\0'; 452#endif 453 } 454 455 nentries = local_manual->nentries; 456 nalloc = local_manual->nalloc; 457 458 while ((dp = readdir(dir)) != NULL) { 459 char *name = dp->d_name; 460 461 if (name[0] == '.') 462 continue; 463 if (strchr(name, '.') == NULL) 464 continue; 465 if (nentries >= nalloc) { 466 nalloc += ENTRYALLOC; 467 local_manual->entries = 468 (char **) XtRealloc((char *) local_manual->entries, 469 nalloc * sizeof(char *)); 470 local_manual->entries_less_paths = 471 (char **) XtRealloc((char *) local_manual->entries_less_paths, 472 nalloc * sizeof(char *)); 473 } 474 475 snprintf(full_name, sizeof(full_name), "%s/%s", path, name); 476/* 477 * Remove the compression extension from the entry name. 478 */ 479 480 if ((ptr = strrchr(full_name, '.')) != NULL) { 481#if !defined(__SCO__) && !defined(ISC) 482 if (streq(ptr + 1, COMPRESSION_EXTENSION)) 483#else 484 if (strpbrk(ptr + 1, COMPRESSION_EXTENSIONS) != NULL) 485#endif 486 *ptr = '\0'; 487#ifdef GZIP_EXTENSION 488 else if (streq(ptr + 1, GZIP_EXTENSION)) 489 *ptr = '\0'; 490#endif 491#ifdef BZIP2_EXTENSION 492 else if (streq(ptr + 1, BZIP2_EXTENSION)) 493 *ptr = '\0'; 494#endif 495#ifdef LZMA_EXTENSION 496 else if (streq(ptr + 1, LZMA_EXTENSION)) 497 *ptr = '\0'; 498#endif 499#ifdef IGNORE_EXTENSION 500 /* skip files with specified extension - they're not real man pages */ 501 else if (streq(ptr + 1, IGNORE_EXTENSION)) { 502 continue; 503 } 504#endif /* IGNORE_EXTENSION */ 505 } 506 local_manual->entries[nentries] = XtNewString(full_name); 507 local_manual->entries_less_paths[nentries] = 508 strrchr(local_manual->entries[nentries], '/'); 509 if (local_manual->entries_less_paths[nentries] == NULL) 510 PrintError("Internal error while cataloging manual pages."); 511 ++nentries; 512 } 513 514 local_manual->nentries = nentries; 515 local_manual->nalloc = nalloc; 516 517 closedir(dir); 518} 519 520/* Function Name: SortAndRemove 521 * Description: This function sorts all the entry names and 522 * then removes all the duplicate entries. 523 * Arguments: man - a pointer to the manual structure. 524 * number - the number of manual sections. 525 * Returns: an improved manual stucure 526 */ 527 528static void 529SortAndRemove(Manual * man, int number) 530{ 531 int i; 532 char *l1, *l2, **s1; 533 534 for (i = 0; i < number; man++, i++) { /* sort each section */ 535 register int i2 = 0; 536 537#ifdef DEBUG 538 printf("sorting section %d - %s\n", i, man->blabel); 539#endif /* DEBUG */ 540 541 s1 = (char **) malloc(man->nentries * sizeof(char *)); 542 543 /* temporarily remove suffixes of entries, preventing them from */ 544 /* being used in alphabetic comparison ie sccs-delta.1 vs sccs.1 */ 545 for (i2 = 0; i2 < man->nentries; i2++) 546 if ((s1[i2] = strrchr(man->entries_less_paths[i2], '.')) != NULL) 547 *s1[i2] = '\0'; 548 549 sortstrs((Byte **) man->entries_less_paths, man->nentries, 550 (Byte **) man->entries); 551 552 /* put back suffixes */ 553 for (i2 = 0; i2 < man->nentries; i2++) 554 if (s1[i2] != NULL) 555 *s1[i2] = '.'; 556 557 free(s1); 558 559#ifdef DEBUG 560 printf("removing from section %d.\n", i); 561#endif /* DEBUG */ 562 563 { 564 register int j, k, nent, nentm1; 565 int j2; 566 567 nent = man->nentries; 568 nentm1 = nent - 1; 569 j = 0; 570 l2 = man->entries_less_paths[j++]; 571 if (l2 == NULL) 572 PrintError 573 ("Internal error while removing duplicate manual pages."); 574 while (j < nentm1) { 575 l1 = l2; 576 l2 = man->entries_less_paths[j++]; 577 if (l2 == NULL) 578 PrintError 579 ("Internal error while removing duplicate manual pages."); 580 if (streq(l1, l2)) { 581 j2 = j - 1; 582 k = j2; 583 while (j < nent) { 584 man->entries_less_paths[k] = man->entries_less_paths[j]; 585 man->entries[k++] = man->entries[j++]; 586 } 587 j = j2; 588 --man->nentries; 589 --nent; 590 --nentm1; 591 } 592 } 593 } 594 } 595} 596 597 /* 598 ******* Replacement for qsort to keep 599 ******* identical entries in order 600 601 A somewhat ugly hack of something that was once simpler... 602 */ 603 /* 604 Sort an array of pointers to strings, keeping it 605 in ascending order by (1) string comparison and 606 (2) original entry order in the pointer array. 607 608 This is a modified radix exchange algorithm. 609 610 In case there's insufficient memory for a temporary copy 611 of the pointer array, the original order of identical strings 612 isn't preserved. 613 */ 614 615static void 616sortstrs(Byte * data[], int size, Byte * otherdata[]) 617{ 618 Byte **sp, **ep; 619 Byte **othersp, **otherep; 620 int *origorder; 621 622 origorder = (int *) calloc(size, sizeof(int)); 623 if (origorder) { 624 reg int i; 625 626 for (i = 0; i < size; ++i) 627 origorder[i] = i; 628 } 629 630 sp = data; 631 ep = &data[size - 1]; 632 othersp = otherdata; 633 otherep = &otherdata[size - 1]; 634 if (origorder) { 635 sortstrs_block_oo(sp, ep, 0, 0x80, origorder, &origorder[size - 1], 636 othersp, otherep); 637 free(origorder); 638 } 639 else 640 sortstrs_block(sp, ep, 0, 0x80, othersp, otherep); 641} 642 643 644 645 /*---------------------------------*/ 646 /* Sort 1 block of data on 1 bit */ 647 /*---------------------------------*/ 648 649static void 650sortstrs_block(Byte ** start, Byte ** end, int offset, Byte mask, 651 Byte ** otherstart, Byte ** otherend) 652{ 653 reg Byte **sp, **ep; 654 reg Byte m; 655 reg int off; 656 reg Byte *t; 657 reg int curstrlen; 658 int maxstrlen; 659 Byte **othersp, **otherep; 660 661 662#define newstring(ptr) \ 663 { \ 664 t = *ptr; \ 665 curstrlen = 0; \ 666 while ( *t++ ) ++ curstrlen; \ 667 if ( curstrlen > maxstrlen ) maxstrlen = curstrlen; \ 668 t = *ptr; \ 669 } 670 671 672 maxstrlen = 0; 673 sp = start; 674 ep = end; 675 off = offset; 676 m = mask; 677 othersp = otherstart; 678 otherep = otherend; 679 680 while (1) { 681 newstring(sp) 682 while (((sp != ep) && ((curstrlen < off) || ((t[off] & m) == 0)))) { 683 ++sp; 684 ++othersp; 685 newstring(sp) 686 } 687 if (sp == ep) 688 break; 689 690 newstring(ep); 691 while (((sp != ep) && (curstrlen >= off) && ((t[off] & m) != 0))) { 692 --ep; 693 --otherep; 694 newstring(ep) 695 } 696 if (sp == ep) 697 break; 698 699 t = *sp; 700 *sp = *ep; 701 *ep = t; 702 703 t = *othersp; 704 *othersp = *otherep; 705 *otherep = t; 706 } 707 708 t = *sp; 709 if ((curstrlen < off) || ((t[off] & m) == 0)) { 710 if (ep != end) { 711 ++ep; 712 ++otherep; 713 } 714 } 715 else { 716 if (sp != start) { 717 --sp; 718 --othersp; 719 } 720 } 721 722 m >>= 1; 723 if (m == 0) { 724 m = 0x80; 725 if (++off >= maxstrlen) 726 return; 727 } 728 729 if (sp != start) 730 sortstrs_block(start, sp, off, m, otherstart, othersp); 731 if (ep != end) 732 sortstrs_block(ep, end, off, m, otherep, otherend); 733} 734 735 736 737 /*-----------------------------------------------------------------*/ 738 /* Sort 1 block of data on 1 bit; check for out-of-order entries */ 739 /*-----------------------------------------------------------------*/ 740 741static void 742sortstrs_block_oo(Byte ** start, Byte ** end, int offset, Byte mask, 743 int *ostart, int *oend, Byte ** otherstart, Byte ** otherend) 744{ 745 reg Byte **sp, **ep; 746 reg int *osp, *oep; 747 reg Byte m; 748 reg int off; 749 reg Byte *t; 750 reg int u; 751 reg int curstrlen; 752 int maxstrlen; 753 Byte **othersp, **otherep; 754 755 756#define newstring(ptr) \ 757 { \ 758 t = *ptr; \ 759 curstrlen = 0; \ 760 while ( *t++ ) ++ curstrlen; \ 761 if ( curstrlen > maxstrlen ) maxstrlen = curstrlen; \ 762 t = *ptr; \ 763 } 764 765 766 maxstrlen = 0; 767 sp = start; 768 ep = end; 769 osp = ostart; 770 oep = oend; 771 off = offset; 772 m = mask; 773 othersp = otherstart; 774 otherep = otherend; 775 776 while (1) { 777 newstring(sp) 778 while (((sp != ep) && ((curstrlen < off) || ((t[off] & m) == 0)))) { 779 ++sp; 780 ++osp; 781 ++othersp; 782 newstring(sp) 783 } 784 if (sp == ep) 785 break; 786 787 newstring(ep); 788 while (((sp != ep) && (curstrlen >= off) && ((t[off] & m) != 0))) { 789 --ep; 790 --oep; 791 --otherep; 792 newstring(ep) 793 } 794 if (sp == ep) 795 break; 796 797 t = *sp; 798 *sp = *ep; 799 *ep = t; 800 801 t = *othersp; 802 *othersp = *otherep; 803 *otherep = t; 804 805 u = *osp; 806 *osp = *oep; 807 *oep = u; 808 } 809 810 t = *sp; 811 if ((curstrlen < off) || ((t[off] & m) == 0)) { 812 if (ep != end) { 813 ++ep; 814 ++oep; 815 ++otherep; 816 } 817 } 818 else { 819 if (sp != start) { 820 --sp; 821 --osp; 822 --othersp; 823 } 824 } 825 826 m >>= 1; 827 if (m == 0) { 828 m = 0x80; 829 if (++off >= maxstrlen) { /* Finished sorting block of strings: *//* Restore duplicates to original order */ 830 reg Byte **cp; 831 reg int *ocp; 832 Byte **othercp; 833 834 if (sp != start) { 835 cp = start; 836 ocp = ostart; 837 othercp = otherstart; 838 while (cp != sp) { 839 if (*ocp > *(ocp + 1)) { 840 t = *(cp + 1); 841 *(cp + 1) = *cp; 842 *cp = t; 843 844 t = *(othercp + 1); 845 *(othercp + 1) = *othercp; 846 *othercp = t; 847 848 u = *(ocp + 1); 849 *(ocp + 1) = *ocp; 850 *ocp = u; 851 852 if (cp != start) { 853 --cp; 854 --ocp; 855 --othercp; 856 continue; 857 } 858 } 859 ++cp; 860 ++ocp; 861 ++othercp; 862 } 863 } 864 if (ep != end) { 865 cp = ep; 866 ocp = oep; 867 othercp = otherep; 868 while (cp != end) { 869 if (*ocp > *(ocp + 1)) { 870 t = *(cp + 1); 871 *(cp + 1) = *cp; 872 *cp = t; 873 874 t = *(othercp + 1); 875 *(othercp + 1) = *othercp; 876 *othercp = t; 877 878 u = *(ocp + 1); 879 *(ocp + 1) = *ocp; 880 *ocp = u; 881 882 if (cp != ep) { 883 --cp; 884 --ocp; 885 --othercp; 886 continue; 887 } 888 } 889 ++cp; 890 ++ocp; 891 ++othercp; 892 } 893 } 894 return; 895 } 896 } 897 898 if (sp != start) 899 sortstrs_block_oo(start, sp, off, m, ostart, osp, otherstart, othersp); 900 if (ep != end) 901 sortstrs_block_oo(ep, end, off, m, oep, oend, otherep, otherend); 902} 903 904 905/* Function Name: InitManual 906 * Description: Initializes this manual section. 907 * Arguments: l_manual - local copy of the manual structure. 908 * label - the button label for this section. 909 * Returns: none. 910 */ 911 912static void 913InitManual(Manual * l_manual, char *label) 914{ 915 bzero(l_manual, sizeof(Manual)); /* clear it. */ 916 l_manual->blabel = label; /* set label. */ 917} 918 919#if defined(DEBUG) 920 921/* Function Name: DumpManual 922 * Description: Debugging function that dumps the entire manual page 923 * structure. 924 * Arguments: number - the number of sections. 925 * Returns: none. 926 */ 927 928void 929DumpManual(int number) 930{ 931 register int i, j; 932 933 for (i = 0; i < number; i++) { 934 printf("label: %s\n", manual[i].blabel); 935 for (j = 0; j < manual[i].nentries; j++) 936 printf("%s\n", manual[i].entries[j]); 937 } 938} 939 940#endif /* DEBUG */ 941 942 943 944#ifdef MANCONF 945 946#if defined(MANCONFIGSTYLE_FreeBSD) 947 948/* Function Name: ReadManConfig 949 * Description: Reads man.conf file used by FreeBSD man 950 * Argument: manpath - char array to return path in. 951 * Returns: TRUE if read was successful. 952 */ 953 954Bool 955ReadManConfig(char manpath[]) 956{ 957 FILE *fp; 958 char line[BUFSIZ]; 959 char *path; 960 Bool firstpath = TRUE; 961 962 if (!(fp = fopen(MANCONF, "r"))) 963 return (FALSE); 964 965 while (fgets(line, sizeof(line), fp)) { 966 path = strtok(line, " \t\n"); 967 if (!path || *path == '#') 968 continue; 969 if (strcmp(path, "MANPATH_MAP") == 0) 970 path = strtok((char *) NULL, " \t\n"); 971 else if (strcmp(path, "MANDATORY_MANPATH") != 0 && 972 strcmp(path, "OPTIONAL_MANPATH") != 0) 973 return (FALSE); 974 path = strtok((char *) NULL, " \t\n"); 975 if (!path || *path == '#') 976 return FALSE; 977 if (firstpath) { 978 strcpy(manpath, path); 979 firstpath = FALSE; 980 } 981 else if (!strstr(manpath, path)) { 982 strcat(manpath, ":"); 983 strcat(manpath, path); 984 } 985 } 986 fclose(fp); 987 return (!firstpath); 988} 989 990 991#elif defined(MANCONFIGSTYLE_Linux) /* not FreeBSD */ 992 993/* Function Name: ReadManConfig 994 * Description: Reads man.conf file used by Linux man 995 * Argument: manpath - char array to return path in. 996 * Returns: TRUE if read was successful. 997 */ 998 999Bool 1000ReadManConfig(char manpath[]) 1001{ 1002 FILE *fp; 1003 char line[BUFSIZ]; 1004 char *path; 1005 Bool firstpath = TRUE; 1006 1007 if (!(fp = fopen(MANCONF, "r"))) 1008 return (FALSE); 1009 1010 while (fgets(line, sizeof(line), fp)) { 1011 path = strtok(line, " \t\n"); 1012 if (!path || *path == '#' || (strcmp(path, "MANPATH") != 0)) 1013 continue; 1014 path = strtok((char *) NULL, " \t\n"); 1015 if (!path || *path == '#') 1016 return FALSE; 1017 if (firstpath) { 1018 strcpy(manpath, path); 1019 firstpath = FALSE; 1020 } 1021 else { 1022 strcat(manpath, ":"); 1023 strcat(manpath, path); 1024 } 1025 } 1026 fclose(fp); 1027 return (!firstpath); 1028} 1029 1030#elif defined(MANCONFIGSTYLE_OpenBSD) /* not FreeBSD or Linux */ 1031 1032/* Function Name: ReadManConfig 1033 * Description: Reads man.conf file used by Open/NetBSD 1034 * Argument: manpath - char array to return path in. 1035 * Returns: TRUE if read was successful. 1036 * 1037 * This version expands the glob pattern that can be found 1038 * in man.conf 1039 */ 1040#include <glob.h> 1041 1042Bool 1043ReadManConfig(char manpath[]) 1044{ 1045 FILE *fp; 1046 char line[BUFSIZ]; 1047 char *path; 1048 Bool firstpath = TRUE; 1049 glob_t gs; 1050 int i; 1051 1052 if (!(fp = fopen(MANCONF, "r"))) 1053 return (FALSE); 1054 1055 while (fgets(line, sizeof(line), fp)) { 1056 path = strtok(line, " \t\n"); 1057 if (!path || *path == '#') 1058 continue; 1059 if (strcmp(path, "_default")) { 1060 /* for now */ 1061 continue; 1062 } 1063 memset(&gs, 0, sizeof(glob_t)); 1064 while ((path = strtok((char *) NULL, " \t\n"))) { 1065 if (glob(path, GLOB_BRACE, NULL, &gs) < 0) { 1066 fclose(fp); 1067 return FALSE; 1068 } 1069 } /* while */ 1070 for (i = 0; i < gs.gl_pathc; i++) { 1071 1072 if (firstpath) { 1073 strcpy(manpath, gs.gl_pathv[i]); 1074 firstpath = FALSE; 1075 } 1076 else { 1077 strcat(manpath, ":"); 1078 strcat(manpath, gs.gl_pathv[i]); 1079 } 1080 } /* for */ 1081 globfree(&gs); 1082 } 1083 fclose(fp); 1084 return (!firstpath); 1085} 1086 1087#elif defined(MANCONFIGSTYLE_BSD) /* not FreeBSD, Linux, or OpenBSD */ 1088 1089/* Function Name: ReadManConfig 1090 * Description: Reads man.conf file used by BSD 4.4 1091 * Argument: manpath - char array to return path in. 1092 * Returns: TRUE if read was successful. 1093 */ 1094 1095Bool 1096ReadManConfig(char manpath[]) 1097{ 1098 FILE *fp; 1099 char line[BUFSIZ]; 1100 char *path; 1101 Bool firstpath = TRUE; 1102 1103 if (!(fp = fopen(MANCONF, "r"))) 1104 return (FALSE); 1105 1106 while (fgets(line, sizeof(line), fp)) { 1107 path = strtok(line, " \t\n"); 1108 if (!path || *path == '#' || strcmp(path, "_default")) 1109 continue; 1110 while ((path = strtok((char *) NULL, " \t\n"))) { 1111 if (firstpath) { 1112 strcpy(manpath, path); 1113 firstpath = FALSE; 1114 } 1115 else { 1116 strcat(manpath, ":"); 1117 strcat(manpath, path); 1118 } 1119 } 1120 } 1121 fclose(fp); 1122 return (!firstpath); 1123} 1124 1125#else /* not BSD */ 1126 1127#error "MANCONF defined (in vendor.h) for unknown operating system." 1128 1129#endif /* MANCONFIGSTYLE == FreeBSD ... BSD */ 1130 1131#endif /* MANCONF */ 1132