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