home *** CD-ROM | disk | FTP | other *** search
/ RISC DISC 2 / RISC_DISC_2.iso / pd_share / utilities / cli / gnuinfo / Source / c / makedoc < prev    next >
Encoding:
Text File  |  1994-10-01  |  11.5 KB  |  480 lines

  1. #include "defines.h"
  2. /* makedoc.c -- Make DOC.C and FUNS.H from input files. */
  3.  
  4. /* This file is part of GNU Info, a program for reading online documentation
  5.    stored in Info format.
  6.  
  7.    Copyright (C) 1993 Free Software Foundation, Inc.
  8.  
  9.    This program is free software; you can redistribute it and/or modify
  10.    it under the terms of the GNU General Public License as published by
  11.    the Free Software Foundation; either version 2, or (at your option)
  12.    any later version.
  13.  
  14.    This program is distributed in the hope that it will be useful,
  15.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.    GNU General Public License for more details.
  18.  
  19.    You should have received a copy of the GNU General Public License
  20.    along with this program; if not, write to the Free Software
  21.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22.  
  23.    Written by Brian Fox (bfox@ai.mit.edu). */
  24.  
  25. /* This program grovels the contents of the source files passed as arguments
  26.    and writes out a file of function pointers and documentation strings, and
  27.    a header file which describes the contents.  This only does the functions
  28.    declared with DECLARE_INFO_COMMAND. */
  29.  
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <ctype.h>
  33. #include <sys/types.h>
  34. #include <sys/file.h>
  35. #include <sys/stat.h>
  36. #include "general.h"
  37.  
  38. #if !defined (O_RDONLY)
  39. #if defined (HAVE_SYS_FCNTL_H)
  40. #include <sys/fcntl.h>
  41. #else /* !HAVE_SYS_FCNTL_H */
  42. #include <fcntl.h>
  43. #endif /* !HAVE_SYS_FCNTL_H */
  44. #endif /* !O_RDONLY */
  45.  
  46. extern void *xmalloc (), *xrealloc ();
  47. static void fatal_file_error ();
  48.  
  49. /* Name of the header file which receives the declarations of functions. */
  50. static char *funs_filename = "funs.h";
  51.  
  52. /* Name of the documentation to function pointer file. */
  53. static char *doc_filename = "doc.c";
  54.  
  55. static char *doc_header[] = {
  56.   "/* doc.c -- Generated structure containing function names and doc strings.",
  57.   "",
  58.   "   This file was automatically made from various source files with the",
  59.   "   command \"%s\".  DO NOT EDIT THIS FILE, only \"%s.c\".",
  60.   (char *)NULL
  61. };
  62.  
  63. static char *doc_header_1[] = {
  64.   "   An entry in the array FUNCTION_DOC_ARRAY is made for each command",
  65.   "   found in the above files; each entry consists of a function pointer,",
  66. #if defined (NAMED_FUNCTIONS)
  67.   "   a string which is the user-visible name of the function,",
  68. #endif /* NAMED_FUNCTIONS */
  69.   "   and a string which documents its purpose. */",
  70.   "",
  71.   "#include \"doc.h\"",
  72.   "#include \"funs.h\"",
  73.   "",
  74.   "FUNCTION_DOC function_doc_array[] = {",
  75.   "",
  76.   (char *)NULL
  77. };
  78.  
  79. /* How to remember the locations of the functions found so that Emacs
  80.    can use the information in a tag table. */
  81. typedef struct {
  82.   char *name;            /* Name of the tag. */
  83.   int line;            /* Line number at which it appears. */
  84.   long char_offset;        /* Character offset at which it appears. */
  85. } EMACS_TAG;
  86.  
  87. typedef struct {
  88.   char *filename;        /* Name of the file containing entries. */
  89.   long entrylen;        /* Total number of characters in tag block. */
  90.   EMACS_TAG **entries;        /* Entries found in FILENAME. */
  91.   int entries_index;
  92.   int entries_slots;
  93. } EMACS_TAG_BLOCK;
  94.  
  95. EMACS_TAG_BLOCK **emacs_tags = (EMACS_TAG_BLOCK **)NULL;
  96. int emacs_tags_index = 0;
  97. int emacs_tags_slots = 0;
  98.  
  99. #define DECLARATION_STRING "\nDECLARE_INFO_COMMAND"
  100.  
  101. static void process_one_file ();
  102. static void maybe_dump_tags ();
  103. static FILE *must_fopen ();
  104.  
  105. int
  106. main (argc, argv)
  107.      int argc;
  108.      char **argv;
  109. {
  110.   register int i;
  111.   int tags_only = 0;
  112.   FILE *funs_stream, *doc_stream;
  113.  
  114.   for (i = 1; i < argc; i++)
  115.     if (strcmp (argv[i], "-tags") == 0)
  116.       {
  117.     tags_only++;
  118.     break;
  119.       }
  120.  
  121.   if (tags_only)
  122.     {
  123.       funs_filename = "/dev/null";
  124.       doc_filename = "/dev/null";
  125.     }
  126.   
  127.   funs_stream = must_fopen (funs_filename, "w");
  128.   doc_stream = must_fopen (doc_filename, "w");
  129.  
  130.   fprintf (funs_stream,
  131.        "/* %s -- Generated declarations for Info commands. */\n",
  132.        funs_filename);
  133.  
  134.   for (i = 0; doc_header[i]; i++)
  135.     {
  136.       fprintf (doc_stream, doc_header[i], argv[0], argv[0]);
  137.       fprintf (doc_stream, "\n");
  138.     }
  139.  
  140.   fprintf (doc_stream,
  141.        "   Source files groveled to make this file include:\n\n");
  142.  
  143.   for (i = 1; i < argc; i++)
  144.     fprintf (doc_stream, "\t%s\n", argv[i]);
  145.  
  146.   fprintf (doc_stream, "\n");
  147.  
  148.   for (i = 0; doc_header_1[i]; i++)
  149.     fprintf (doc_stream, "%s\n", doc_header_1[i]);
  150.  
  151.  
  152.   for (i = 1; i < argc; i++)
  153.     {
  154.       char *curfile;
  155.       curfile = argv[i];
  156.  
  157.       if (*curfile == '-')
  158.     continue;
  159.  
  160.       fprintf (doc_stream, "/* Commands found in \"%s\". */\n", curfile);
  161.       fprintf (funs_stream, "\n/* Functions declared in \"%s\". */\n",
  162.            curfile);
  163.  
  164.       process_one_file (curfile, doc_stream, funs_stream);
  165.     }
  166.  
  167.   fprintf (doc_stream,
  168.        "   { (VFunction *)NULL, (char *)NULL, (char *)NULL }\n};\n");
  169.  
  170.   fclose (funs_stream);
  171.   fclose (doc_stream);
  172.  
  173.   if (tags_only)
  174.     maybe_dump_tags (stdout);
  175.   exit (0);
  176. }
  177.  
  178. /* Dumping out the contents of an Emacs tags table. */
  179. static void
  180. maybe_dump_tags (stream)
  181.      FILE *stream;
  182. {
  183.   register int i;
  184.  
  185.   /* Print out the information for each block. */
  186.   for (i = 0; i < emacs_tags_index; i++)
  187.     {
  188.       register int j;
  189.       register EMACS_TAG_BLOCK *block;
  190.       register EMACS_TAG *etag;
  191.       long block_len;
  192.  
  193.       block_len = 0;
  194.       block = emacs_tags[i];
  195.  
  196.       /* Calculate the length of the dumped block first. */
  197.       for (j = 0; j < block->entries_index; j++)
  198.     {
  199.       char digits[30];
  200.       etag = block->entries[j];
  201.       block_len += 3 + strlen (etag->name);
  202.       sprintf (digits, "%d,%d", etag->line, etag->char_offset);
  203.       block_len += strlen (digits);
  204.     }
  205.  
  206.       /* Print out the defining line. */
  207.       fprintf (stream, "\f\n%s,%d\n", block->filename, block_len);
  208.  
  209.       /* Print out the individual tags. */
  210.       for (j = 0; j < block->entries_index; j++)
  211.     {
  212.       etag = block->entries[j];
  213.  
  214.       fprintf (stream, "%s,\177%d,%d\n",
  215.            etag->name, etag->line, etag->char_offset);
  216.     }
  217.     }
  218. }
  219.  
  220. /* Keeping track of names, line numbers and character offsets of functions
  221.    found in source files. */
  222. static EMACS_TAG_BLOCK *
  223. make_emacs_tag_block (filename)
  224.      char *filename;
  225. {
  226.   EMACS_TAG_BLOCK *block;
  227.  
  228.   block = (EMACS_TAG_BLOCK *)xmalloc (sizeof (EMACS_TAG_BLOCK));
  229.   block->filename = savestring (filename);
  230.   block->entrylen = 0;
  231.   block->entries = (EMACS_TAG **)NULL;
  232.   block->entries_index = 0;
  233.   block->entries_slots = 0;
  234.   return (block);
  235. }
  236.  
  237. static void
  238. add_tag_to_block (block, name, line, char_offset)
  239.      EMACS_TAG_BLOCK *block;
  240.      char *name;
  241.      int line;
  242.      long char_offset;
  243. {
  244.   EMACS_TAG *tag;
  245.  
  246.   tag = (EMACS_TAG *)xmalloc (sizeof (EMACS_TAG));
  247.   tag->name = name;
  248.   tag->line = line;
  249.   tag->char_offset = char_offset;
  250.   add_pointer_to_array (tag, block->entries_index, block->entries,
  251.             block->entries_slots, 50, EMACS_TAG *);
  252. }
  253.  
  254. /* Read the file represented by FILENAME into core, and search it for Info
  255.    function declarations.  Output the declarations in various forms to the
  256.    DOC_STREAM and FUNS_STREAM. */
  257. static void
  258. process_one_file (filename, doc_stream, funs_stream)
  259.      char *filename;
  260.      FILE *doc_stream, *funs_stream;
  261. {
  262.   int descriptor, decl_len;
  263.   char *buffer, *decl_str;
  264.   struct stat finfo;
  265.   long offset;
  266.   EMACS_TAG_BLOCK *block;
  267.  
  268.   if (stat (filename, &finfo) == -1)
  269.     fatal_file_error (filename);
  270.  
  271.   descriptor = open (filename, O_RDONLY, 0666);
  272.  
  273.   if (descriptor == -1)
  274.     fatal_file_error (filename);
  275.  
  276.   buffer = (char *)xmalloc (1 + finfo.st_size);
  277.   read (descriptor, buffer, finfo.st_size);
  278.   close (descriptor);
  279.  
  280.   offset = 0;
  281.   decl_str = DECLARATION_STRING;
  282.   decl_len = strlen (decl_str);
  283.  
  284.   block = make_emacs_tag_block (filename);
  285.  
  286.   while (1)
  287.     {
  288.       long point = 0;
  289.       long line_start = 0;
  290.       int line_number = 0;
  291.  
  292.       char *func, *doc;
  293. #if defined (NAMED_FUNCTIONS)
  294.       char *func_name;
  295. #endif /* NAMED_FUNCTIONS */
  296.  
  297.       for (; offset < (finfo.st_size - decl_len); offset++)
  298.     {
  299.       if (buffer[offset] == '\n')
  300.         {
  301.           line_number++;
  302.           line_start = offset + 1;
  303.         }
  304.  
  305.       if (strncmp (buffer + offset, decl_str, decl_len) == 0)
  306.         {
  307.           offset += decl_len;
  308.           point = offset;
  309.           break;
  310.         }
  311.     }
  312.  
  313.       if (!point)
  314.     break;
  315.  
  316.       /* Skip forward until we find the open paren. */
  317.       while (point < finfo.st_size)
  318.     {
  319.       if (buffer[point] == '\n')
  320.         {
  321.           line_number++;
  322.           line_start = point + 1;
  323.         }
  324.       else if (buffer[point] == '(')
  325.         break;
  326.  
  327.       point++;
  328.     }
  329.  
  330.       while (point++ < finfo.st_size)
  331.     {
  332.       if (!whitespace_or_newline (buffer[point]))
  333.         break;
  334.       else if (buffer[point] == '\n')
  335.         {
  336.           line_number++;
  337.           line_start = point + 1;
  338.         }
  339.     }
  340.  
  341.       if (point >= finfo.st_size)
  342.     break;
  343.  
  344.       /* Now looking at name of function.  Get it. */
  345.       for (offset = point; buffer[offset] != ','; offset++);
  346.       func = (char *)xmalloc (1 + (offset - point));
  347.       strncpy (func, buffer + point, offset - point);
  348.       func[offset - point] = '\0';
  349.  
  350.       /* Remember this tag in the current block. */
  351.       {
  352.     char *tag_name;
  353.  
  354.     tag_name = (char *)xmalloc (1 + (offset - line_start));
  355.     strncpy (tag_name, buffer + line_start, offset - line_start);
  356.     tag_name[offset - line_start] = '\0';
  357.     add_tag_to_block (block, tag_name, line_number, point);
  358.       }
  359.  
  360. #if defined (NAMED_FUNCTIONS)
  361.       /* Generate the user-visible function name from the function's name. */
  362.       {
  363.     register int i;
  364.     char *name_start;
  365.  
  366.     name_start = func;
  367.  
  368.     if (strncmp (name_start, "info_", 5) == 0)
  369.       name_start += 5;
  370.  
  371.     func_name = savestring (name_start);
  372.  
  373.     /* Fix up "ea" commands. */
  374.     if (strncmp (func_name, "ea_", 3) == 0)
  375.       {
  376.         char *temp_func_name;
  377.  
  378.         temp_func_name = (char *)xmalloc (10 + strlen (func_name));
  379.         strcpy (temp_func_name, "echo_area_");
  380.         strcat (temp_func_name, func_name + 3);
  381.         free (func_name);
  382.         func_name = temp_func_name;
  383.       }
  384.  
  385.     for (i = 0; func_name[i]; i++)
  386.       if (func_name[i] == '_')
  387.         func_name[i] = '-';
  388.       }
  389. #endif /* NAMED_FUNCTIONS */
  390.  
  391.       /* Find doc string. */
  392.       point = offset + 1;
  393.  
  394.       while (point < finfo.st_size)
  395.     {
  396.       if (buffer[point] == '\n')
  397.         {
  398.           line_number++;
  399.           line_start = point + 1;
  400.         }
  401.  
  402.       if (buffer[point] == '"')
  403.         break;
  404.       else
  405.         point++;
  406.     }
  407.  
  408.       offset = point + 1;
  409.  
  410.       while (offset < finfo.st_size)
  411.     {
  412.       if (buffer[offset] == '\n')
  413.         {
  414.           line_number++;
  415.           line_start = offset + 1;
  416.         }
  417.  
  418.       if (buffer[offset] == '\\')
  419.         offset += 2;
  420.       else if (buffer[offset] == '"')
  421.         break;
  422.       else
  423.         offset++;
  424.     }
  425.  
  426.       offset++;
  427.       if (offset >= finfo.st_size)
  428.     break;
  429.  
  430.       doc = (char *)xmalloc (1 + (offset - point));
  431.       strncpy (doc, buffer + point, offset - point);
  432.       doc[offset - point] = '\0';
  433.  
  434. #if defined (NAMED_FUNCTIONS)
  435.       fprintf (doc_stream, "   { %s, \"%s\", %s },\n", func, func_name, doc);
  436.       free (func_name);
  437. #else /* !NAMED_FUNCTIONS */
  438.       fprintf (doc_stream, "   { %s, %s },\n", func, doc);
  439. #endif /* !NAMED_FUNCTIONS */
  440.  
  441.       fprintf (funs_stream, "extern void %s ();\n", func);
  442.       free (func);
  443.       free (doc);
  444.     }
  445.   free (buffer);
  446.  
  447.   /* If we created any tags, remember this file on our global list.  Otherwise,
  448.      free the memory already allocated to it. */
  449.   if (block->entries)
  450.     add_pointer_to_array (block, emacs_tags_index, emacs_tags,
  451.               emacs_tags_slots, 10, EMACS_TAG_BLOCK *);
  452.   else
  453.     {
  454.       free (block->filename);
  455.       free (block);
  456.     }
  457. }
  458.  
  459. static void
  460. fatal_file_error (filename)
  461.      char *filename;
  462. {
  463.   fprintf (stderr, "Couldn't manipulate the file %s.\n", filename);
  464.   exit (2);
  465. }
  466.  
  467. static FILE *
  468. must_fopen (filename, mode)
  469.      char *filename, *mode;
  470. {
  471.   FILE *stream;
  472.  
  473.   stream = fopen (filename, mode);
  474.   if (!stream)
  475.     fatal_file_error (filename);
  476.  
  477.   return (stream);
  478. }
  479.  
  480.