home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Mint / mintman4.zoo / mintman / catman.c < prev    next >
C/C++ Source or Header  |  1992-12-15  |  27KB  |  857 lines

  1. /******************************************************************/
  2. /* catman.c - a simple-minded catman program for MiNT and TOS     */
  3. /* Copyright (c) 1992 by HPP Biersma (schuller@dutiag.tudelft.nl) */
  4. /* This program comes under the GNU public license -              */
  5. /*                            see the file "copying" for details. */
  6. /******************************************************************/
  7. /* bugs: - not UN*X compatible, either in source-code or behavior */
  8. /*       - string operations are not safe, ie not limits checked  */
  9. /******************************************************************/
  10. /* version: 0.2 (second released version), December 15, 1992      */
  11. /* written for: - GCC version 2.3.1, patchlevel 1                 */
  12. /*              - mintlib patchlevel 25                           */
  13. /* compile with: gcc -o catman.ttp catman.c -mbaserel -mpcrel -O2 */
  14. /******************************************************************/
  15.  
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <unistd.h>
  20. #include <stat.h>
  21. #include <dirent.h> /* used for opendir(), readdir(), closedir() */
  22. #include <mintbind.h>
  23.  
  24. /* Comment out the following definitions if you want subprograms  */
  25. /* (nroff, less and cat) to get UN*X (not GEMDOS-like) filenames. */
  26. #define SUBPROGRAMS_GROK_GEMDOS_NAMES /* the longest #define yet? */
  27.  
  28. /* Maximum length of path + file name */
  29. #define NAME_LENGTH 256 /* Note: stacksize must be > (10 * NAME_LENGTH) */
  30.  
  31. /* Local type definitions */
  32. typedef struct direntry_st
  33. {
  34.   char   name[NAME_LENGTH];
  35.   time_t timestamp;
  36.   struct direntry_st *next, *previous;
  37. } direntry_type, *direntry_ptr;
  38.  
  39. typedef struct whatis_st
  40. {
  41.   char   line[NAME_LENGTH];
  42.   struct whatis_st *next, *previous;
  43. } whatis_type, *whatis_ptr;
  44.  
  45.  
  46. /* prototypes for local (static) functions */
  47. static void format_file(const char *mandir, const char *manfile, 
  48.                         const char *catfile_name, const int only_print);
  49. static int format_manpages(const char *mandir, const int sections[9], 
  50.                            const int only_print);
  51. static int update_manfiles(const char *catdir, const char *mandir,
  52.                            const int only_print);
  53. static direntry_ptr make_direntry(const char *name, const time_t timestamp);
  54. static void destroy_direntry(direntry_ptr destroy);
  55. static void destroy_free_lists(void);
  56. static void make_whatis(const char *mandir);
  57. static void add_to_whatis(whatis_ptr *database, const char *filename, 
  58.                           const char section_code, const char *explanation, 
  59.                           const int catfile);
  60. static void write_whatis_database(const char *mandir, whatis_ptr *database);
  61. static whatis_ptr make_whatis_entry(const char *contents);
  62. static void destroy_whatis_entry(whatis_ptr destroy);                          
  63. static int get_name_from_catfile(const char *catdir, const char *filename,
  64.                                  char *result);
  65. static int get_name_from_manfile(const char *mandir, const char *filename,
  66.                                  char *result);
  67. static FILE *open_so_file(const char *mandir, const char *so_line);
  68. static int check_directory_name(const char *dirname);
  69. static void build_catdir_name(const char *dirname, const char section_code,
  70.                               char *catdir_name);
  71. static void build_mandir_name(const char *dirname, const char section_code,
  72.                               char *mandir_name);
  73.  
  74. /* Extern and local variables */
  75. static char man_path[NAME_LENGTH] = "/usr/man";
  76. static char macro_package[NAME_LENGTH] = "an";
  77. static direntry_ptr direntry_free_list = NULL;
  78. static whatis_ptr whatis_free_list = NULL;
  79.  
  80. void main(int argc, char *argv[])
  81. {
  82.   char *ptr, *arg_ptr, *manptr, mandir[NAME_LENGTH];
  83.   int  only_nroff = 0, only_print = 0, only_whatis = 0, sections_set = 0;
  84.   int  sections[9], counter;
  85.  
  86.   /* Set the search path for the man pages*/
  87.   if ((ptr = getenv("MANPATH")) != NULL)
  88.     strncpy(man_path, ptr, NAME_LENGTH - 1);
  89.  
  90.   for (counter = 1; counter <= 8; counter++)
  91.     sections[counter] = 0;
  92.   argv += 1;
  93.   ptr = argv[0];
  94.   while (argc > 1)
  95.   {
  96.     if (ptr[0] == '-')
  97.     {
  98.       /* handle options */
  99.       switch(ptr[1])
  100.       {
  101.         case 'n':
  102.         case 'p':
  103.         case 'w':
  104.           arg_ptr = ptr;
  105.           while (*++arg_ptr != 0x00)
  106.           {
  107.             switch(*arg_ptr)
  108.             {
  109.               case 'n':
  110.                 only_nroff = 1;
  111.                 break;
  112.               case 'p':
  113.                 only_print = 1;
  114.                 break;
  115.               case 'w':
  116.                 only_whatis = 1;
  117.                 break;
  118.               default:
  119.                 fprintf(stderr, "catman: no option %s supported\n", ptr);
  120.                 fprintf(stderr, "usage: catman [-npw] [-M path] [-T macro-package] [sections]\n");
  121.                 exit(1);
  122.             }
  123.           } /* End of while (-npw option) */
  124.           break;
  125.         case 'M':
  126.           if (ptr[2] != 0x00)
  127.             strncpy(man_path, &(ptr[2]), NAME_LENGTH - 1);
  128.           else if (argc > 2)
  129.           {
  130.             argv += 1;
  131.             strncpy(man_path, argv[0], NAME_LENGTH - 1);
  132.             argc -= 1;
  133.           }
  134.           else
  135.           {
  136.             fprintf(stderr, "catman: -M option needs an argument\n");
  137.             exit(1);
  138.           }
  139.           break;
  140.         case 'T':
  141.           if (ptr[2] != 0x00)
  142.             strncpy(macro_package, &(ptr[2]), NAME_LENGTH - 1);
  143.           else if (argc > 2)
  144.           {
  145.             argv += 1;
  146.             strncpy(macro_package, argv[0], NAME_LENGTH - 1);
  147.             argc -= 1;
  148.           }
  149.           else
  150.           {
  151.             fprintf(stderr, "catman: -T option needs an argument\n");
  152.             exit(1);
  153.           }
  154.           break;
  155.         default:
  156.           fprintf(stderr, "catman: no option %s supported\n", ptr);
  157.           fprintf(stderr, "usage: catman [-npw] [-M path] [-T macro-package] [sections]\n");
  158.           exit(1);
  159.       }
  160.     } /* end of if: argument is option */
  161.     else
  162.     {
  163.       /* Not an option: must be section code (1..8) */
  164.       do
  165.       {
  166.         if ((*ptr < '1') || (*ptr > '8'))
  167.         {
  168.           fprintf(stderr, "catman: section argument must be in 1..8\n");
  169.           exit(1);
  170.         }
  171.         sections_set = 1;
  172.         sections[*ptr - ('1' - 1)] = 1;
  173.         ptr += 1;
  174.       } while (*ptr != 0x00);
  175.     } /* end of else (not an option) */
  176.     argc -= 1;
  177.     argv += 1;
  178.     ptr = argv[0];
  179.   } /* end of while (command line arguments left) */
  180.  
  181.   if (sections_set == 0)
  182.     for (counter = 1; counter <= 8; counter++)
  183.       sections[counter] = 1;
  184.  
  185.   /* walk along manual path and format pages, build whatis database */
  186.   ptr = man_path;
  187.   while (*ptr != 0x00)
  188.   {
  189.     int did_format;
  190.     
  191.     /* Copy one directory from the manual search path into mandir */
  192.     manptr = mandir;
  193.     while ((*ptr != 0x00) && (*ptr != ';') && (*ptr != ','))
  194.       *manptr++ = *ptr++;
  195.     *manptr = 0x00;
  196.     if (*ptr != 0x00)
  197.       ptr += 1;
  198.  
  199.     if (check_directory_name(mandir) == 0)
  200.     {
  201.       fprintf(stderr, "catman: directory %s on search path not found\n",
  202.               mandir);
  203.       continue; /* go on to next part of manual search path */
  204.     }
  205.       
  206.     if (only_whatis == 0)
  207.       did_format = format_manpages(mandir, sections, only_print);
  208.     else
  209.       did_format = 0;
  210.     if ((only_nroff == 0) && 
  211.         ((only_whatis == 1) || (did_format == 1)))
  212.     {
  213.       if (only_print == 0)
  214.         make_whatis(mandir);
  215.       else
  216.         fprintf(stdout, "makewhatis %s\n", mandir);
  217.     }
  218.   } /* end of while (walk along manual search path) */
  219.   destroy_free_lists();
  220.   exit(0);
  221. } /* End of main() */
  222.  
  223.  
  224. /* Format all manpages that need updating from specific sections in */
  225. /* a manual directory. Print instead of doing if only_print is set. */
  226. static int format_manpages(const char *dir, const int sections[9], 
  227.                            const int only_print)
  228. {
  229.   int counter, changes_made;
  230.   
  231.   changes_made = 0;
  232.   for (counter = 1; counter <= 8; counter++)
  233.   {
  234.     if (sections[counter] == 1)
  235.     {
  236.       int  catdir_exists, mandir_exists;
  237.       char catdir_name[NAME_LENGTH], mandir_name[NAME_LENGTH];
  238.       
  239.       build_catdir_name(dir, counter + ('1' - 1), catdir_name);
  240.       catdir_exists = check_directory_name(catdir_name);
  241.       build_mandir_name(dir, counter + ('1' - 1), mandir_name);
  242.       mandir_exists = check_directory_name(mandir_name);
  243.       
  244.       if ((catdir_exists == 1) && (mandir_exists == 1))
  245.         changes_made |= update_manfiles(catdir_name, mandir_name, only_print);
  246.     } /* End of if (section must be searched and formatted) */
  247.   } /* End of for (all sections) */
  248.   return(changes_made);
  249. } /* End of format_manpages() */
  250.  
  251.  
  252. /* Update the files in the catdir directory from the files in the */
  253. /* mandir directory. Print instead of doing if only_print is set. */
  254. static int update_manfiles(const char *catdir, const char *mandir,
  255.                            const int only_print)
  256. {
  257.   DIR *dir;
  258.   struct dirent *this_entry;
  259.   direntry_ptr  direntry_list;
  260.   int changes_made;
  261.  
  262.   direntry_list = NULL;
  263.   changes_made = 0;
  264.   if ((dir = opendir(catdir)) == NULL)
  265.   {
  266.     /* Note that the existence of the directory has been checked before */
  267.     fprintf(stderr, "catman: could not open directory %s\n", catdir);
  268.     exit(1);
  269.   }
  270.   readdir(dir); /* skip over `.' */
  271.   readdir(dir); /* skip over `..' */ 
  272.   while ((this_entry = readdir(dir)) != NULL)
  273.   {
  274.     struct stat this_stat;
  275.     direntry_ptr new;
  276.     char full_name[NAME_LENGTH];
  277.     
  278.     strcpy(full_name, catdir);
  279.     strcat(full_name, "/");
  280.     strcat(full_name, this_entry->d_name);
  281.     stat(full_name, &this_stat);
  282.     new = make_direntry(this_entry->d_name, this_stat.st_mtime);
  283.     if (direntry_list == NULL)
  284.       direntry_list = new;
  285.     else
  286.     {
  287.       new->next = direntry_list;
  288.       direntry_list->previous = new;
  289.       direntry_list = new;
  290.     }
  291.   } /* End of while (not out of files in catdir) */
  292.   closedir(dir);
  293.   
  294.   if ((dir = opendir(mandir)) == NULL)
  295.   {
  296.     /* Note that the existence of the directory has been checked before */
  297.     fprintf(stderr, "catman: could not open directory %s\n", mandir);
  298.     exit(1);
  299.   }
  300.   readdir(dir); /* skip over `.' */
  301.   readdir(dir); /* skip over `..' */
  302.   while ((this_entry = readdir(dir)) != NULL)
  303.   {
  304.     struct stat this_stat;
  305.     char full_man_name[NAME_LENGTH], full_cat_name[NAME_LENGTH];
  306.     direntry_ptr current;
  307.     int done;
  308.     
  309.     strncpy(full_man_name, mandir, NAME_LENGTH - 1);
  310.     strcat(full_man_name, "/");
  311.     strcat(full_man_name, this_entry->d_name);
  312.     strncpy(full_cat_name, catdir, NAME_LENGTH - 1);
  313.     strcat(full_cat_name, "/");
  314.     strcat(full_cat_name, this_entry->d_name);
  315.     current = direntry_list;
  316.     done = 0;
  317.     while ((current != NULL) && (done == 0))
  318.     {
  319.       if (strncmp(current->name, this_entry->d_name, NAME_LENGTH - 1) == 0)
  320.       {
  321.         stat(full_man_name, &this_stat);
  322.         if (this_stat.st_mtime >= current->timestamp)
  323.         {
  324.           format_file(mandir, this_entry->d_name, full_cat_name, only_print);
  325.           changes_made = 1;
  326.         }
  327.         
  328.         if (current == direntry_list)
  329.         {
  330.           direntry_list = direntry_list->next;
  331.           if (direntry_list != NULL)
  332.             direntry_list->previous = NULL;
  333.         }
  334.         else
  335.         {
  336.           if (current->next != NULL)
  337.             current->next->previous = current->previous;
  338.           current->previous->next = current->next;
  339.         }
  340.         destroy_direntry(current);
  341.         done = 1;
  342.       } /* End of if (current name found) */
  343.       else
  344.         current = current->next;
  345.     } /* End of while (not end of direntry_list) */
  346.     
  347.     if (done == 0)
  348.     {
  349.       /* Formatted file does not exist in cat directory */
  350.       format_file(mandir, this_entry->d_name, full_cat_name, only_print);
  351.       changes_made = 1;
  352.     }
  353.   } /* End of while (not end of mandir) */
  354.   closedir(dir);
  355.   
  356.   /* Destroy the list of directory entries */
  357.   while (direntry_list != NULL)
  358.   {
  359.     direntry_ptr ptr;
  360.     
  361.     ptr = direntry_list;
  362.     direntry_list = direntry_list->next;
  363.     destroy_direntry(ptr);
  364.   }
  365.   return(changes_made);
  366. } /* End of update_manfiles() */
  367.  
  368.  
  369. static direntry_ptr make_direntry(const char *name, const time_t timestamp)
  370. {
  371.   direntry_ptr ptr;
  372.   
  373.   if (direntry_free_list != NULL)
  374.   {
  375.     ptr = direntry_free_list;
  376.     direntry_free_list = direntry_free_list->next;
  377.   }
  378.   else if ((ptr = malloc(sizeof(direntry_type))) == NULL)
  379.   {
  380.     fprintf(stderr, "catman: malloc() failed in make_direntry()\n");
  381.     exit(1);
  382.   }
  383.   
  384.   ptr->next = ptr->previous = NULL;
  385.   strncpy(ptr->name, name, NAME_LENGTH - 1);
  386.   ptr->timestamp = timestamp;
  387.   return(ptr);
  388. } /* End of make_direntry() */
  389.  
  390.  
  391. /* Destroy a direntry (put in free-list) */
  392. static void destroy_direntry(direntry_ptr destroy)
  393. {
  394.   destroy->next = direntry_free_list;
  395.   direntry_free_list = destroy;
  396. } /* End of destroy_direntry() */
  397.  
  398.  
  399. /* Destroy all the free-lists the program uses */
  400. static void destroy_free_lists(void)
  401. {
  402.   while (direntry_free_list != NULL)
  403.   {
  404.     direntry_ptr ptr;
  405.     
  406.     ptr = direntry_free_list;
  407.     direntry_free_list = direntry_free_list->next;
  408.     free(ptr);
  409.   }
  410.   
  411.   while (whatis_free_list != NULL)
  412.   {
  413.     whatis_ptr ptr;
  414.     
  415.     ptr = whatis_free_list;
  416.     whatis_free_list = whatis_free_list->next;
  417.     free(ptr);
  418.   }
  419. } /* End of destroy_free_lists() */
  420.  
  421.  
  422. /* Build the whatis database in a main manual directory */
  423. static void make_whatis(const char *mandir_name)
  424. {
  425.   DIR *man_dir, *this_dir;
  426.   struct dirent *this_entry;
  427.   whatis_ptr    database;
  428.  
  429.   database = NULL;
  430.   if ((man_dir = opendir(mandir_name)) == NULL)
  431.   {
  432.     /* Note that the existence of the directory has been checked before */
  433.     fprintf(stderr, "catman: could not open directory %s\n", mandir_name);
  434.     exit(1);
  435.   }
  436.   readdir(man_dir); /* skip over `.' */
  437.   readdir(man_dir); /* skip over `..' */
  438.   while ((this_entry = readdir(man_dir)) != 0)
  439.   {
  440.     char section_code, full_name[NAME_LENGTH];
  441.     int  catdir;
  442.    
  443.     if ((this_entry->d_name[0] == 'c') && (this_entry->d_name[1] == 'a') &&
  444.         (this_entry->d_name[2] == 't') && (this_entry->d_name[4] == 0x00) &&
  445.         (this_entry->d_name[3] >= '1') && (this_entry->d_name[3] <= '8'))
  446.       catdir = 1;
  447.     else if ((this_entry->d_name[0] == 'm') && (this_entry->d_name[1] == 'a') &&
  448.              (this_entry->d_name[2] == 'n') && (this_entry->d_name[4] == 0x00) &&
  449.              (this_entry->d_name[3] >= '1') && (this_entry->d_name[3] <= '8'))
  450.       catdir = 0;
  451.     else
  452.       continue; /* name doesn't match cat? or man?: go on to next entry */
  453.     
  454.     strcpy(full_name, mandir_name);
  455.     strcat(full_name, "/");
  456.     strcat(full_name, this_entry->d_name);    
  457.     if (check_directory_name(full_name) != 1)
  458.       continue; /* not a directory: go on to next entry in while */
  459.       
  460.     section_code = this_entry->d_name[3];
  461.     if ((this_dir = opendir(full_name)) == NULL)
  462.     {
  463.       /* Note that the existence of the directory has been checked before */
  464.       fprintf(stderr, "catman: could not open directory %s\n", full_name);
  465.       exit(1);
  466.     }
  467.     readdir(this_dir); /* skip over `.' */
  468.     readdir(this_dir); /* skip over `.' */
  469.     while ((this_entry = readdir(this_dir)) != NULL)
  470.     {
  471.       char result[NAME_LENGTH];
  472.       int  ok;
  473.       
  474.       if (catdir == 0)
  475.         ok = get_name_from_manfile(full_name, this_entry->d_name, result);
  476.       else
  477.         ok = get_name_from_catfile(full_name, this_entry->d_name, result);
  478.       if (ok == 1)
  479.         add_to_whatis(&database, this_entry->d_name, section_code, result, 
  480.                       catdir);
  481.     } /* End of while (not out of entries in cat/man dir) */
  482.     closedir(this_dir);
  483.   } /* End of while (not out of entries in manual directory) */
  484.   closedir(man_dir);
  485.   write_whatis_database(mandir_name, &database);
  486. } /* End of make_whatis() */
  487.  
  488.  
  489. /* Add a line to the whatis database. Lines from the unformatted manpage */
  490. /* are preferred (catfile == 0). Lines are sorted alphabetically.        */
  491. static void add_to_whatis(whatis_ptr *database, const char *filename, 
  492.                           const char section_code, const char *explanation, 
  493.                           const int catfile)
  494. {
  495.   char   buffer[NAME_LENGTH], name[NAME_LENGTH], *ptr;
  496.   size_t size;
  497.   whatis_ptr current, previous;
  498.  
  499.   /* Find the name of the manpage */
  500.   strcpy(name, filename);
  501.   ptr = name;
  502.   while (*ptr != 0x00)
  503.   {
  504.     if (*ptr == '.')
  505.       *ptr = 0x00;
  506.     else
  507.       ptr += 1;
  508.   }
  509.   *ptr++ = ' ';
  510.   *ptr++ = '(';
  511.   *ptr++ = section_code;
  512.   *ptr++ = ')';
  513.   while ((ptr - name) < 16)
  514.     *ptr++ = ' ';
  515.   *ptr++ = 0x00;
  516.   size = strlen(name);
  517.   strcpy(buffer, name);
  518.   strcat(buffer, " ");
  519.   strcat(buffer, explanation);
  520.   
  521.   /* Search for the correct place in the whatis database */
  522.   if (*database == NULL)
  523.   {
  524.     *database = make_whatis_entry(buffer);
  525.     return;
  526.   }
  527.   
  528.   if (strncmp(name, (*database)->line, size) < 0)
  529.   {
  530.     /* new entry fits in before current start of list */
  531.     current = make_whatis_entry(buffer);
  532.     current->next = *database;
  533.     (*database)->previous = current;
  534.     *database = current;
  535.     return;
  536.   }
  537.   
  538.   current = *database;
  539.   previous = NULL;
  540.   while (current != NULL)
  541.   {
  542.     int result;
  543.     
  544.     result = strncmp(name, current->line, size);
  545.     if (result == 0)
  546.     {
  547.       if (catfile == 1)
  548.         return; /* previous entry is from manfile and wins */
  549.       else
  550.       {
  551.         /* new entry overwrites old one from catfile */
  552.         strcpy(current->line, buffer);
  553.         return;
  554.       }
  555.     } /* end of if (result == 0: names are equal) */
  556.     else if (result < 0)
  557.     {
  558.       /* Note that this cannot happen on the first item in the list */
  559.       whatis_ptr new;
  560.       
  561.       new = make_whatis_entry(buffer);
  562.       new->next = current;
  563.       new->previous = previous;
  564.       current->previous = new;
  565.       previous->next = new;
  566.       return;
  567.     } /* end of else if (result < 0: name fits before current) */
  568.     else
  569.     {
  570.       previous = current;
  571.       current = current->next;
  572.     } /* end of else (result > 0: name first after current) */
  573.   } /* End of while (current != NULL) */
  574.   current = make_whatis_entry(buffer);
  575.   previous->next = current;
  576.   current->previous = previous;
  577. } /* End of add_to_whatis() */
  578.  
  579.  
  580. static void write_whatis_database(const char *mandir, whatis_ptr *database)
  581. {
  582.   FILE *whatis;
  583.   char name[NAME_LENGTH];
  584.   
  585.   strcpy(name, mandir);
  586.   strcat(name, "/whatis");
  587.   if ((whatis = fopen(name, "w")) == NULL)
  588.   {
  589.     fprintf(stderr, "catman: could not open file %s\n", name);
  590.     exit(1);
  591.   }
  592.   
  593.   while (*database != NULL)
  594.   {
  595.     whatis_ptr ptr;
  596.     
  597.     ptr = *database;
  598.     *database = (*database)->next;
  599.     fputs(ptr->line, whatis);
  600.     destroy_whatis_entry(ptr);
  601.   }
  602.   fclose(whatis);
  603. } /* End of write_whatis_database() */
  604.  
  605.  
  606. /* Make a new whatis record */
  607. static whatis_ptr make_whatis_entry(const char *contents)
  608. {
  609.   whatis_ptr result;
  610.   
  611.   if (whatis_free_list != NULL)
  612.   {
  613.     result = whatis_free_list;
  614.     whatis_free_list = whatis_free_list->next;
  615.   }
  616.   else if ((result = malloc(sizeof(whatis_type))) == NULL)
  617.   {
  618.     fprintf(stderr, "catman: malloc() failed in make_whatis_entry()\n");
  619.     exit(1);
  620.   }
  621.   strcpy(result->line, contents);
  622.   result->next = result->previous = NULL;
  623.   return(result);
  624. } /* End of make_whatis_entry() */
  625.  
  626.  
  627. /* Destroy a whatis record (add to free-list) */
  628. static void destroy_whatis_entry(whatis_ptr destroy)
  629. {
  630.   destroy->next = whatis_free_list;
  631.   whatis_free_list = destroy;
  632. } /* End of destroy_whatis_entry() */
  633.  
  634.  
  635. /* Extract the man page name from a man file in a cat? directory */
  636. static int get_name_from_catfile(const char *catdir, const char *filename, 
  637.                                  char *result)
  638. {
  639.   FILE *catfile;
  640.   int lines_read;
  641.   char full_name[NAME_LENGTH], buffer[NAME_LENGTH], *ptr;
  642.  
  643.   strcpy(full_name, catdir);
  644.   strcat(full_name, "/");
  645.   strcat(full_name, filename);
  646.   if ((catfile = fopen(full_name, "r")) == NULL)
  647.   {
  648.     /* Note that the existence of the file has been checked before */
  649.     fprintf(stderr, "catman: could not open file %s\n", full_name);
  650.     return(0); /* failure */
  651.   }
  652.  
  653.   lines_read = 0;
  654.   while (!feof(catfile) && (lines_read <= 15))
  655.   {
  656.     fgets(buffer, NAME_LENGTH - 1, catfile);
  657.     lines_read += 1;
  658.     if ((strstr(buffer, "NAME") != NULL) && !feof(catfile))
  659.     {
  660.       fgets(buffer, NAME_LENGTH - 1, catfile);
  661.       /* Set ptr to the start of the explanation (minus char) */
  662.       ptr = buffer;
  663.       while ((*ptr != 0x00) && (*ptr != '-'))
  664.         ptr += 1;
  665.       strcpy(result, ptr);
  666.       fclose(catfile);
  667.       return(1);
  668.     }
  669.   }
  670.   fclose(catfile);
  671.   return(0); /* failure */
  672. } /* End of get_name_from_catfile() */
  673.  
  674.  
  675. /* Extract the man page name from a man file in a man? directory */
  676. static int get_name_from_manfile(const char *mandir, const char *filename, 
  677.                                  char *result)
  678. {
  679.   FILE *manfile;
  680.   char full_name[NAME_LENGTH], buffer[NAME_LENGTH], *ptr;
  681.   int  first_line, no_redirections;
  682.  
  683.   strcpy(full_name, mandir);
  684.   strcat(full_name, "/");
  685.   strcat(full_name, filename);
  686.   if ((manfile = fopen(full_name, "r")) == NULL)
  687.   {
  688.     /* Note that the existence of the file has been checked before */
  689.     fprintf(stderr, "catman: could not open file %s\n", full_name);
  690.     return(0); /* failure */
  691.   }
  692.  
  693.   first_line = 1;
  694.   no_redirections = 0;
  695.   while (!feof(manfile))
  696.   {
  697.     fgets(buffer, NAME_LENGTH - 1, manfile);
  698.     if (first_line == 1)
  699.     {
  700.       if ((buffer[0] == '.') && (buffer[1] == 's') && (buffer[2] == 'o'))
  701.       {
  702.         fclose(manfile);
  703.         if (++no_redirections > 5)
  704.         {
  705.           fprintf(stderr, "catman: too many redirections from file %s\n",
  706.                   full_name);
  707.           return(0); /* failure */
  708.         }
  709.         if ((manfile = open_so_file(mandir, buffer)) == NULL)
  710.         {
  711.           fprintf(stderr, "catman: redirection from file %s failed\n",
  712.                   full_name);
  713.           return(0); /* failure */
  714.         }
  715.       } /* End of if (line start with .so) */
  716.       else
  717.         first_line = 0;
  718.     } /* End of if (first line) */
  719.     if ((strncmp(buffer, ".SH NAME", 7) == 0) && !feof(manfile))
  720.     {
  721.       fgets(buffer, NAME_LENGTH - 1, manfile);
  722.       /* Set ptr to the start of the explanation (minus char) */
  723.       ptr = buffer;
  724.       while ((*ptr != 0x00) && (*ptr != '-'))
  725.         ptr += 1;
  726.       strcpy(result, ptr);
  727.       fclose(manfile);
  728.       return(1); /* success */
  729.     }
  730.   } /* End of while (not end of file and not found) */
  731.   fclose(manfile);
  732.   return(0); /* failure */
  733. } /* End of get_name_from_manfile() */
  734.  
  735.  
  736. /* Find and open a file from a .so redirection in a manfile */
  737. static FILE *open_so_file(const char *mandir, const char *so_line)
  738. {
  739.   char name[NAME_LENGTH], full_name[NAME_LENGTH], *ptr1, *ptr2;
  740.   
  741.   strcpy(name, &(so_line[3])); /* Right after the .so */
  742.   /* ptr1 gets set to the start of the filename */
  743.   ptr1 = name; 
  744.   while ((*ptr1 == ' ') || (*ptr1 == '\t'))
  745.     ptr1 += 1;
  746.   
  747.   ptr2 = ptr1;
  748.   while ((*ptr2 != 0x00) && (*ptr2 != ' ') && (*ptr2 != '\t') &&
  749.          (*ptr2 != '\n') && (*ptr2 != '\r'))
  750.     ptr2 += 1;
  751.   *ptr2 = 0x00;
  752.     
  753.   strcpy(full_name, mandir);
  754.   strcat(full_name, "/");
  755.   strcat(full_name, ptr1);
  756.   return(fopen(full_name, "r"));
  757. } /* End of open_so_file() */
  758.  
  759.  
  760. /* Format (nroff) a file and write the result to another file */
  761. static void format_file(const char *mandir, const char *manfile,
  762.                         const char *catfile, const int only_print)
  763. {
  764.   char command_line[NAME_LENGTH], cwd[NAME_LENGTH];
  765. #ifdef SUBPROGRAMS_GROK_GEMDOS_NAMES  
  766.   char dosname[NAME_LENGTH];
  767. #endif
  768.  
  769.   getcwd(cwd, NAME_LENGTH);
  770.   if (chdir(mandir) != 0)
  771.   {
  772.     /* Note that the existence of the directory has been checked before */
  773.     fprintf(stderr, "catman: change directory to %s failed\n", mandir);
  774.     exit(1);
  775.   }
  776.   strcpy(command_line, "nroff -m");
  777.   strcat(command_line, macro_package);
  778.   strcat(command_line, " ");
  779. #ifdef SUBPROGRAMS_GROK_GEMDOS_NAMES  
  780.   _unx2dos(manfile, dosname); /* send nroff a proper GEMDOS name */
  781.   strcat(command_line, dosname);
  782. #else
  783.   strcat(command_line, manfile);
  784. #endif
  785.   strcat(command_line, " >");
  786. #ifdef SUBPROGRAMS_GROK_GEMDOS_NAMES  
  787.   _unx2dos(catfile, dosname); /* redirect to a proper GEMDOS name */
  788.   strcat(command_line, dosname);
  789. #else
  790.   strcat(command_line, catfile);
  791. #endif
  792.   if (only_print == 0)
  793.   {
  794.     fprintf(stderr, "Formatting file %s. Wait...", manfile);
  795.     if (system(command_line) == 0) /* successful execution */
  796.     {
  797.       fprintf(stderr, "Done\n");
  798.       return;
  799.     }
  800.     else
  801.     {
  802.       fprintf(stderr, "Aborted (sorry)\n");
  803.       exit(1);
  804.     }
  805.   }
  806.   else
  807.   {
  808.     fprintf(stdout, command_line);
  809.     fprintf(stdout, "\n");
  810.   }
  811.   
  812.   if (chdir(cwd) != 0)
  813.   {
  814.     fprintf(stderr, "catman: cannot change back to directory %s\n", cwd);
  815.     exit(1);
  816.   }
  817. } /* End of format_file() */
  818.  
  819.  
  820. /* Check if a dirname is a valid directory */
  821. static int check_directory_name(const char *dirname)
  822. {
  823.   struct stat dir_stat;
  824.  
  825.   if (stat(dirname, &dir_stat) == -1)
  826.     return(0);
  827.   else if (dir_stat.st_mode & S_IFDIR == 0)
  828.   {
  829.     fprintf(stderr, "catman: %s is not a directory\n", dirname);
  830.     return(0);
  831.   }
  832.   else
  833.     return(1);
  834. } /* End of check_directory_name() */
  835.  
  836. static void build_catdir_name(const char *dirname, const char section_code,
  837.                               char *catdir_name)
  838. {
  839.   static char extension[] = "/cat0";
  840.   
  841.   strcpy(catdir_name, dirname);
  842.   extension[4] = section_code;
  843.   strcat(catdir_name, extension);
  844. } /* End of build_catdir_name() */  
  845.  
  846.                            
  847. /* Build the name of man dir #section_code within the man dir */
  848. static void build_mandir_name(const char *dirname, const char section_code,
  849.                               char *mandir_name)
  850. {
  851.   static char extension[] = "/man0";
  852.   
  853.   strcpy(mandir_name, dirname);
  854.   extension[4] = section_code;
  855.   strcat(mandir_name, extension);
  856. } /* End of build_mandir_name() */
  857.