man.c revision da4a0041
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 size_t len = strlen(string); 294 295 if (len == 0) 296 continue; 297 if (string[len - 1] == '\n') 298 string[len - 1] = '\0'; /* Strip off the CR. */ 299 300 if (streq(string, NO_SECTION_DEFAULTS)) { 301 use_defaults = FALSE; 302 continue; 303 } 304 305 if ((cp = strchr(string, '\t')) != NULL) { 306 char *s; 307 308 *cp++ = '\0'; 309 strcpy(local_file, MAN); 310 strcat(local_file, string); 311 if ((s = strchr(cp, '\t')) != NULL) { 312 *s++ = '\0'; 313 if (streq(s, SUFFIX)) 314 AddNewSection(section_list, path, local_file, cp, 315 MSUFFIX); 316 else if (streq(s, FOLD)) 317 AddNewSection(section_list, path, local_file, cp, 318 MFOLD); 319 else if (streq(s, FOLDSUFFIX)) 320 AddNewSection(section_list, path, local_file, cp, 321 MFOLDSUFFIX); 322 else 323 AddNewSection(section_list, path, local_file, cp, 324 MNULL); 325 } 326 else 327 AddNewSection(section_list, path, local_file, cp, MNULL); 328 } 329 else { 330 snprintf(local_file, sizeof(local_file), "%s%c", MAN, 331 string[0]); 332 AddNewSection(section_list, path, local_file, (string + 1), 333 FALSE); 334#ifdef SEARCHOTHER 335 snprintf(local_file, sizeof(local_file), "%s%c", SEARCHOTHER, 336 string[0]); 337 AddNewSection(section_list, path, local_file, (string + 1), 338 FALSE); 339#endif 340 } 341 } 342 343 fclose(descfile); 344 } 345 if (use_defaults) 346 AddStandardSections(section_list, path); 347} 348 349/* Function Name: AddNewSection 350 * Description: Adds the new section onto the current section list. 351 * Arguments: list - pointer to the section list. 352 * path - the path to the current manual section. 353 * file - the file to save. 354 * label - the current section label. 355 * flags = 1 - add a suffix 356 * = 2 - fold to lower case 357 * Returns: none. 358 */ 359 360void 361AddNewSection(SectionList ** list, const char *path, const char *file, 362 const char *label, int flags) 363{ 364 SectionList *local_list, *end; 365 char full_path[BUFSIZ]; 366 367/* Allocate a new list element */ 368 369 local_list = (SectionList *) XtMalloc(sizeof(SectionList)); 370 371 if (*list != NULL) { 372 for (end = *list; end->next != NULL; end = end->next); 373 end->next = local_list; 374 } 375 else 376 *list = local_list; 377 378 local_list->next = NULL; 379 local_list->label = XtNewString(label); 380 snprintf(full_path, sizeof(full_path), "%s/%s", path, file); 381 local_list->directory = XtNewString(full_path); 382 local_list->flags = flags; 383} 384 385/* Function Name: AddToCurrentSection 386 * Description: This function gets the names of the manual page 387 * directories, then closes the directory. 388 * Arguments: local_manual - a pointer to a manual pages structure. 389 * path - the path to this directory. 390 * Returns: none. 391 */ 392 393static void 394AddToCurrentSection(Manual * local_manual, char *path) 395{ 396 char temp_path[BUFSIZ]; 397 398#if defined(__OpenBSD__) || defined(__NetBSD__) 399 snprintf(temp_path, sizeof(temp_path), "%s/%s", path, MACHINE); 400 ReadCurrentSection(local_manual, temp_path); 401#endif 402 ReadCurrentSection(local_manual, path); 403 snprintf(temp_path, sizeof(temp_path), "%s.%s", path, 404 COMPRESSION_EXTENSION); 405 ReadCurrentSection(local_manual, temp_path); 406} 407 408/* Function Name: ReadCurrentSection 409 * Description: Actually does the work of adding entries to the 410 * new section 411 * Arguments: local_manual - a pointer to a manual pages structure. 412 * path - the path to this directory. 413 * compressed - Is this a compressed directory? 414 * Returns: TRUE if any entries are found. 415 */ 416 417static void 418ReadCurrentSection(Manual * local_manual, char *path) 419{ 420 DIR *dir; 421 register struct dirent *dp; 422 423 register int nentries; 424 register int nalloc; 425 char full_name[BUFSIZ], *ptr; 426 427 if ((dir = opendir(path)) == NULL) { 428#ifdef DEBUG 429 snprintf(error_buf, sizeof(error_buf), "Can't open directory %s", path); 430 PopupWarning(NULL, error_buf); 431#endif /* DEBUG */ 432 return; 433 } 434 435/* 436 * Remove the compression extension from the path name. 437 */ 438 439 if ((ptr = strrchr(path, '.')) != NULL) { 440#if !defined(__SCO__) && !defined(ISC) 441 if (streq(ptr + 1, COMPRESSION_EXTENSION)) 442#else 443 if (strpbrk(ptr + 1, COMPRESSION_EXTENSIONS) != NULL) 444#endif 445 *ptr = '\0'; 446#ifdef GZIP_EXTENSION 447 else if (streq(ptr + 1, GZIP_EXTENSION)) 448 *ptr = '\0'; 449#endif 450#ifdef BZIP2_EXTENSION 451 else if (streq(ptr + 1, BZIP2_EXTENSION)) 452 *ptr = '\0'; 453#endif 454#ifdef LZMA_EXTENSION 455 else if (streq(ptr + 1, LZMA_EXTENSION)) 456 *ptr = '\0'; 457#endif 458 } 459 460 nentries = local_manual->nentries; 461 nalloc = local_manual->nalloc; 462 463 while ((dp = readdir(dir)) != NULL) { 464 char *name = dp->d_name; 465 466 if (name[0] == '.') 467 continue; 468 if (strchr(name, '.') == NULL) 469 continue; 470 if (nentries >= nalloc) { 471 nalloc += ENTRYALLOC; 472 local_manual->entries = 473 (char **) XtRealloc((char *) local_manual->entries, 474 nalloc * sizeof(char *)); 475 local_manual->entries_less_paths = 476 (char **) XtRealloc((char *) local_manual->entries_less_paths, 477 nalloc * sizeof(char *)); 478 } 479 480 snprintf(full_name, sizeof(full_name), "%s/%s", path, name); 481/* 482 * Remove the compression extension from the entry name. 483 */ 484 485 if ((ptr = strrchr(full_name, '.')) != NULL) { 486#if !defined(__SCO__) && !defined(ISC) 487 if (streq(ptr + 1, COMPRESSION_EXTENSION)) 488#else 489 if (strpbrk(ptr + 1, COMPRESSION_EXTENSIONS) != NULL) 490#endif 491 *ptr = '\0'; 492#ifdef GZIP_EXTENSION 493 else if (streq(ptr + 1, GZIP_EXTENSION)) 494 *ptr = '\0'; 495#endif 496#ifdef BZIP2_EXTENSION 497 else if (streq(ptr + 1, BZIP2_EXTENSION)) 498 *ptr = '\0'; 499#endif 500#ifdef LZMA_EXTENSION 501 else if (streq(ptr + 1, LZMA_EXTENSION)) 502 *ptr = '\0'; 503#endif 504#ifdef IGNORE_EXTENSION 505 /* skip files with specified extension - they're not real man pages */ 506 else if (streq(ptr + 1, IGNORE_EXTENSION)) { 507 continue; 508 } 509#endif /* IGNORE_EXTENSION */ 510 } 511 local_manual->entries[nentries] = XtNewString(full_name); 512 local_manual->entries_less_paths[nentries] = 513 strrchr(local_manual->entries[nentries], '/'); 514 if (local_manual->entries_less_paths[nentries] == NULL) 515 PrintError("Internal error while cataloging manual pages."); 516 ++nentries; 517 } 518 519 local_manual->nentries = nentries; 520 local_manual->nalloc = nalloc; 521 522 closedir(dir); 523} 524 525/* Function Name: SortAndRemove 526 * Description: This function sorts all the entry names and 527 * then removes all the duplicate entries. 528 * Arguments: man - a pointer to the manual structure. 529 * number - the number of manual sections. 530 * Returns: an improved manual stucure 531 */ 532 533static void 534SortAndRemove(Manual * man, int number) 535{ 536 int i; 537 char *l1, *l2, **s1; 538 539 for (i = 0; i < number; man++, i++) { /* sort each section */ 540 register int i2 = 0; 541 542#ifdef DEBUG 543 printf("sorting section %d - %s\n", i, man->blabel); 544#endif /* DEBUG */ 545 546 s1 = (char **) malloc(man->nentries * sizeof(char *)); 547 548 /* temporarily remove suffixes of entries, preventing them from */ 549 /* being used in alphabetic comparison ie sccs-delta.1 vs sccs.1 */ 550 for (i2 = 0; i2 < man->nentries; i2++) 551 if ((s1[i2] = strrchr(man->entries_less_paths[i2], '.')) != NULL) 552 *s1[i2] = '\0'; 553 554 sortstrs((Byte **) man->entries_less_paths, man->nentries, 555 (Byte **) man->entries); 556 557 /* put back suffixes */ 558 for (i2 = 0; i2 < man->nentries; i2++) 559 if (s1[i2] != NULL) 560 *s1[i2] = '.'; 561 562 free(s1); 563 564#ifdef DEBUG 565 printf("removing from section %d.\n", i); 566#endif /* DEBUG */ 567 568 { 569 register int j, k, nent, nentm1; 570 int j2; 571 572 nent = man->nentries; 573 nentm1 = nent - 1; 574 j = 0; 575 l2 = man->entries_less_paths[j++]; 576 if (l2 == NULL) 577 PrintError 578 ("Internal error while removing duplicate manual pages."); 579 while (j < nentm1) { 580 l1 = l2; 581 l2 = man->entries_less_paths[j++]; 582 if (l2 == NULL) 583 PrintError 584 ("Internal error while removing duplicate manual pages."); 585 if (streq(l1, l2)) { 586 j2 = j - 1; 587 k = j2; 588 while (j < nent) { 589 man->entries_less_paths[k] = man->entries_less_paths[j]; 590 man->entries[k++] = man->entries[j++]; 591 } 592 j = j2; 593 --man->nentries; 594 --nent; 595 --nentm1; 596 } 597 } 598 } 599 } 600} 601 602 /* 603 ******* Replacement for qsort to keep 604 ******* identical entries in order 605 606 A somewhat ugly hack of something that was once simpler... 607 */ 608 /* 609 Sort an array of pointers to strings, keeping it 610 in ascending order by (1) string comparison and 611 (2) original entry order in the pointer array. 612 613 This is a modified radix exchange algorithm. 614 615 In case there's insufficient memory for a temporary copy 616 of the pointer array, the original order of identical strings 617 isn't preserved. 618 */ 619 620static void 621sortstrs(Byte * data[], int size, Byte * otherdata[]) 622{ 623 Byte **sp, **ep; 624 Byte **othersp, **otherep; 625 int *origorder; 626 627 origorder = (int *) calloc(size, sizeof(int)); 628 if (origorder) { 629 reg int i; 630 631 for (i = 0; i < size; ++i) 632 origorder[i] = i; 633 } 634 635 sp = data; 636 ep = &data[size - 1]; 637 othersp = otherdata; 638 otherep = &otherdata[size - 1]; 639 if (origorder) { 640 sortstrs_block_oo(sp, ep, 0, 0x80, origorder, &origorder[size - 1], 641 othersp, otherep); 642 free(origorder); 643 } 644 else 645 sortstrs_block(sp, ep, 0, 0x80, othersp, otherep); 646} 647 648 649 650 /*---------------------------------*/ 651 /* Sort 1 block of data on 1 bit */ 652 /*---------------------------------*/ 653 654static void 655sortstrs_block(Byte ** start, Byte ** end, int offset, Byte mask, 656 Byte ** otherstart, Byte ** otherend) 657{ 658 reg Byte **sp, **ep; 659 reg Byte m; 660 reg int off; 661 reg Byte *t; 662 reg int curstrlen; 663 int maxstrlen; 664 Byte **othersp, **otherep; 665 666 667#define newstring(ptr) \ 668 { \ 669 t = *ptr; \ 670 curstrlen = 0; \ 671 while ( *t++ ) ++ curstrlen; \ 672 if ( curstrlen > maxstrlen ) maxstrlen = curstrlen; \ 673 t = *ptr; \ 674 } 675 676 677 maxstrlen = 0; 678 sp = start; 679 ep = end; 680 off = offset; 681 m = mask; 682 othersp = otherstart; 683 otherep = otherend; 684 685 while (1) { 686 newstring(sp) 687 while (((sp != ep) && ((curstrlen < off) || ((t[off] & m) == 0)))) { 688 ++sp; 689 ++othersp; 690 newstring(sp) 691 } 692 if (sp == ep) 693 break; 694 695 newstring(ep); 696 while (((sp != ep) && (curstrlen >= off) && ((t[off] & m) != 0))) { 697 --ep; 698 --otherep; 699 newstring(ep) 700 } 701 if (sp == ep) 702 break; 703 704 t = *sp; 705 *sp = *ep; 706 *ep = t; 707 708 t = *othersp; 709 *othersp = *otherep; 710 *otherep = t; 711 } 712 713 t = *sp; 714 if ((curstrlen < off) || ((t[off] & m) == 0)) { 715 if (ep != end) { 716 ++ep; 717 ++otherep; 718 } 719 } 720 else { 721 if (sp != start) { 722 --sp; 723 --othersp; 724 } 725 } 726 727 m >>= 1; 728 if (m == 0) { 729 m = 0x80; 730 if (++off >= maxstrlen) 731 return; 732 } 733 734 if (sp != start) 735 sortstrs_block(start, sp, off, m, otherstart, othersp); 736 if (ep != end) 737 sortstrs_block(ep, end, off, m, otherep, otherend); 738} 739 740 741 742 /*-----------------------------------------------------------------*/ 743 /* Sort 1 block of data on 1 bit; check for out-of-order entries */ 744 /*-----------------------------------------------------------------*/ 745 746static void 747sortstrs_block_oo(Byte ** start, Byte ** end, int offset, Byte mask, 748 int *ostart, int *oend, Byte ** otherstart, Byte ** otherend) 749{ 750 reg Byte **sp, **ep; 751 reg int *osp, *oep; 752 reg Byte m; 753 reg int off; 754 reg Byte *t; 755 reg int u; 756 reg int curstrlen; 757 int maxstrlen; 758 Byte **othersp, **otherep; 759 760 761#define newstring(ptr) \ 762 { \ 763 t = *ptr; \ 764 curstrlen = 0; \ 765 while ( *t++ ) ++ curstrlen; \ 766 if ( curstrlen > maxstrlen ) maxstrlen = curstrlen; \ 767 t = *ptr; \ 768 } 769 770 771 maxstrlen = 0; 772 sp = start; 773 ep = end; 774 osp = ostart; 775 oep = oend; 776 off = offset; 777 m = mask; 778 othersp = otherstart; 779 otherep = otherend; 780 781 while (1) { 782 newstring(sp) 783 while (((sp != ep) && ((curstrlen < off) || ((t[off] & m) == 0)))) { 784 ++sp; 785 ++osp; 786 ++othersp; 787 newstring(sp) 788 } 789 if (sp == ep) 790 break; 791 792 newstring(ep); 793 while (((sp != ep) && (curstrlen >= off) && ((t[off] & m) != 0))) { 794 --ep; 795 --oep; 796 --otherep; 797 newstring(ep) 798 } 799 if (sp == ep) 800 break; 801 802 t = *sp; 803 *sp = *ep; 804 *ep = t; 805 806 t = *othersp; 807 *othersp = *otherep; 808 *otherep = t; 809 810 u = *osp; 811 *osp = *oep; 812 *oep = u; 813 } 814 815 t = *sp; 816 if ((curstrlen < off) || ((t[off] & m) == 0)) { 817 if (ep != end) { 818 ++ep; 819 ++oep; 820 ++otherep; 821 } 822 } 823 else { 824 if (sp != start) { 825 --sp; 826 --osp; 827 --othersp; 828 } 829 } 830 831 m >>= 1; 832 if (m == 0) { 833 m = 0x80; 834 if (++off >= maxstrlen) { /* Finished sorting block of strings: *//* Restore duplicates to original order */ 835 reg Byte **cp; 836 reg int *ocp; 837 Byte **othercp; 838 839 if (sp != start) { 840 cp = start; 841 ocp = ostart; 842 othercp = otherstart; 843 while (cp != sp) { 844 if (*ocp > *(ocp + 1)) { 845 t = *(cp + 1); 846 *(cp + 1) = *cp; 847 *cp = t; 848 849 t = *(othercp + 1); 850 *(othercp + 1) = *othercp; 851 *othercp = t; 852 853 u = *(ocp + 1); 854 *(ocp + 1) = *ocp; 855 *ocp = u; 856 857 if (cp != start) { 858 --cp; 859 --ocp; 860 --othercp; 861 continue; 862 } 863 } 864 ++cp; 865 ++ocp; 866 ++othercp; 867 } 868 } 869 if (ep != end) { 870 cp = ep; 871 ocp = oep; 872 othercp = otherep; 873 while (cp != end) { 874 if (*ocp > *(ocp + 1)) { 875 t = *(cp + 1); 876 *(cp + 1) = *cp; 877 *cp = t; 878 879 t = *(othercp + 1); 880 *(othercp + 1) = *othercp; 881 *othercp = t; 882 883 u = *(ocp + 1); 884 *(ocp + 1) = *ocp; 885 *ocp = u; 886 887 if (cp != ep) { 888 --cp; 889 --ocp; 890 --othercp; 891 continue; 892 } 893 } 894 ++cp; 895 ++ocp; 896 ++othercp; 897 } 898 } 899 return; 900 } 901 } 902 903 if (sp != start) 904 sortstrs_block_oo(start, sp, off, m, ostart, osp, otherstart, othersp); 905 if (ep != end) 906 sortstrs_block_oo(ep, end, off, m, oep, oend, otherep, otherend); 907} 908 909 910/* Function Name: InitManual 911 * Description: Initializes this manual section. 912 * Arguments: l_manual - local copy of the manual structure. 913 * label - the button label for this section. 914 * Returns: none. 915 */ 916 917static void 918InitManual(Manual * l_manual, char *label) 919{ 920 bzero(l_manual, sizeof(Manual)); /* clear it. */ 921 l_manual->blabel = label; /* set label. */ 922} 923 924#if defined(DEBUG) 925 926/* Function Name: DumpManual 927 * Description: Debugging function that dumps the entire manual page 928 * structure. 929 * Arguments: number - the number of sections. 930 * Returns: none. 931 */ 932 933void 934DumpManual(int number) 935{ 936 register int i, j; 937 938 for (i = 0; i < number; i++) { 939 printf("label: %s\n", manual[i].blabel); 940 for (j = 0; j < manual[i].nentries; j++) 941 printf("%s\n", manual[i].entries[j]); 942 } 943} 944 945#endif /* DEBUG */ 946 947 948 949#ifdef MANCONF 950 951#if defined(MANCONFIGSTYLE_FreeBSD) 952 953/* Function Name: ReadManConfig 954 * Description: Reads man.conf file used by FreeBSD man 955 * Argument: manpath - char array to return path in. 956 * Returns: TRUE if read was successful. 957 */ 958 959Bool 960ReadManConfig(char manpath[]) 961{ 962 FILE *fp; 963 char line[BUFSIZ]; 964 char *path; 965 Bool firstpath = TRUE; 966 967 if (!(fp = fopen(MANCONF, "r"))) 968 return (FALSE); 969 970 while (fgets(line, sizeof(line), fp)) { 971 path = strtok(line, " \t\n"); 972 if (!path || *path == '#') 973 continue; 974 if (strcmp(path, "MANPATH_MAP") == 0) 975 path = strtok((char *) NULL, " \t\n"); 976 else if (strcmp(path, "MANDATORY_MANPATH") != 0 && 977 strcmp(path, "OPTIONAL_MANPATH") != 0) 978 return (FALSE); 979 path = strtok((char *) NULL, " \t\n"); 980 if (!path || *path == '#') 981 return FALSE; 982 if (firstpath) { 983 strcpy(manpath, path); 984 firstpath = FALSE; 985 } 986 else if (!strstr(manpath, path)) { 987 strcat(manpath, ":"); 988 strcat(manpath, path); 989 } 990 } 991 fclose(fp); 992 return (!firstpath); 993} 994 995 996#elif defined(MANCONFIGSTYLE_Linux) /* not FreeBSD */ 997 998/* Function Name: ReadManConfig 999 * Description: Reads man.conf file used by Linux man 1000 * Argument: manpath - char array to return path in. 1001 * Returns: TRUE if read was successful. 1002 */ 1003 1004Bool 1005ReadManConfig(char manpath[]) 1006{ 1007 FILE *fp; 1008 char line[BUFSIZ]; 1009 char *path; 1010 Bool firstpath = TRUE; 1011 1012 if (!(fp = fopen(MANCONF, "r"))) 1013 return (FALSE); 1014 1015 while (fgets(line, sizeof(line), fp)) { 1016 path = strtok(line, " \t\n"); 1017 if (!path || *path == '#' || (strcmp(path, "MANPATH") != 0)) 1018 continue; 1019 path = strtok((char *) NULL, " \t\n"); 1020 if (!path || *path == '#') 1021 return FALSE; 1022 if (firstpath) { 1023 strcpy(manpath, path); 1024 firstpath = FALSE; 1025 } 1026 else { 1027 strcat(manpath, ":"); 1028 strcat(manpath, path); 1029 } 1030 } 1031 fclose(fp); 1032 return (!firstpath); 1033} 1034 1035#elif defined(MANCONFIGSTYLE_OpenBSD) /* not FreeBSD or Linux */ 1036 1037/* Function Name: ReadManConfig 1038 * Description: Reads man.conf file used by Open/NetBSD 1039 * Argument: manpath - char array to return path in. 1040 * Returns: TRUE if read was successful. 1041 * 1042 * This version expands the glob pattern that can be found 1043 * in man.conf 1044 */ 1045#include <glob.h> 1046 1047Bool 1048ReadManConfig(char manpath[]) 1049{ 1050 FILE *fp; 1051 char line[BUFSIZ]; 1052 char *path; 1053 Bool firstpath = TRUE; 1054 glob_t gs; 1055 int i; 1056 1057 if (!(fp = fopen(MANCONF, "r"))) 1058 return (FALSE); 1059 1060 while (fgets(line, sizeof(line), fp)) { 1061 path = strtok(line, " \t\n"); 1062 if (!path || *path == '#') 1063 continue; 1064 if (strcmp(path, "_default")) { 1065 /* for now */ 1066 continue; 1067 } 1068 memset(&gs, 0, sizeof(glob_t)); 1069 while ((path = strtok((char *) NULL, " \t\n"))) { 1070 if (glob(path, GLOB_BRACE, NULL, &gs) < 0) { 1071 fclose(fp); 1072 return FALSE; 1073 } 1074 } /* while */ 1075 for (i = 0; i < gs.gl_pathc; i++) { 1076 1077 if (firstpath) { 1078 strcpy(manpath, gs.gl_pathv[i]); 1079 firstpath = FALSE; 1080 } 1081 else { 1082 strcat(manpath, ":"); 1083 strcat(manpath, gs.gl_pathv[i]); 1084 } 1085 } /* for */ 1086 globfree(&gs); 1087 } 1088 fclose(fp); 1089 return (!firstpath); 1090} 1091 1092#elif defined(MANCONFIGSTYLE_BSD) /* not FreeBSD, Linux, or OpenBSD */ 1093 1094/* Function Name: ReadManConfig 1095 * Description: Reads man.conf file used by BSD 4.4 1096 * Argument: manpath - char array to return path in. 1097 * Returns: TRUE if read was successful. 1098 */ 1099 1100Bool 1101ReadManConfig(char manpath[]) 1102{ 1103 FILE *fp; 1104 char line[BUFSIZ]; 1105 char *path; 1106 Bool firstpath = TRUE; 1107 1108 if (!(fp = fopen(MANCONF, "r"))) 1109 return (FALSE); 1110 1111 while (fgets(line, sizeof(line), fp)) { 1112 path = strtok(line, " \t\n"); 1113 if (!path || *path == '#' || strcmp(path, "_default")) 1114 continue; 1115 while ((path = strtok((char *) NULL, " \t\n"))) { 1116 if (firstpath) { 1117 strcpy(manpath, path); 1118 firstpath = FALSE; 1119 } 1120 else { 1121 strcat(manpath, ":"); 1122 strcat(manpath, path); 1123 } 1124 } 1125 } 1126 fclose(fp); 1127 return (!firstpath); 1128} 1129 1130#else /* not BSD */ 1131 1132#error "MANCONF defined (in vendor.h) for unknown operating system." 1133 1134#endif /* MANCONFIGSTYLE == FreeBSD ... BSD */ 1135 1136#endif /* MANCONF */ 1137