home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / texinfo-3.7-src.tgz / tar.out / fsf / texinfo / info / makedoc.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  12KB  |  482 lines

  1. /* makedoc.c -- Make DOC.C and FUNS.H from input files. */
  2.  
  3. /* This file is part of GNU Info, a program for reading online documentation
  4.    stored in Info format.
  5.  
  6.    Copyright (C) 1993 Free Software Foundation, Inc.
  7.  
  8.    This program is free software; you can redistribute it and/or modify
  9.    it under the terms of the GNU General Public License as published by
  10.    the Free Software Foundation; either version 2, or (at your option)
  11.    any later version.
  12.  
  13.    This program is distributed in the hope that it will be useful,
  14.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.    GNU General Public License for more details.
  17.  
  18.    You should have received a copy of the GNU General Public License
  19.    along with this program; if not, write to the Free Software
  20.    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21.  
  22.    Written by Brian Fox (bfox@ai.mit.edu). */
  23.  
  24. /* This program grovels the contents of the source files passed as arguments
  25.    and writes out a file of function pointers and documentation strings, and
  26.    a header file which describes the contents.  This only does the functions
  27.    declared with DECLARE_INFO_COMMAND. */
  28.  
  29. #include <stdio.h>
  30. #include <ctype.h>
  31. #include <sys/types.h>
  32. #if defined (HAVE_SYS_FILE_H)
  33. #include <sys/file.h>
  34. #endif /* HAVE_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 = strdup (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.   long file_size;
  267.   EMACS_TAG_BLOCK *block;
  268.  
  269.   if (stat (filename, &finfo) == -1)
  270.     fatal_file_error (filename);
  271.  
  272.   descriptor = open (filename, O_RDONLY, 0666);
  273.  
  274.   if (descriptor == -1)
  275.     fatal_file_error (filename);
  276.  
  277.   file_size = (long) finfo.st_size;
  278.   buffer = (char *)xmalloc (1 + file_size);
  279.   read (descriptor, buffer, file_size);
  280.   close (descriptor);
  281.  
  282.   offset = 0;
  283.   decl_str = DECLARATION_STRING;
  284.   decl_len = strlen (decl_str);
  285.  
  286.   block = make_emacs_tag_block (filename);
  287.  
  288.   while (1)
  289.     {
  290.       long point = 0;
  291.       long line_start = 0;
  292.       int line_number = 0;
  293.  
  294.       char *func, *doc;
  295. #if defined (NAMED_FUNCTIONS)
  296.       char *func_name;
  297. #endif /* NAMED_FUNCTIONS */
  298.  
  299.       for (; offset < (file_size - decl_len); offset++)
  300.     {
  301.       if (buffer[offset] == '\n')
  302.         {
  303.           line_number++;
  304.           line_start = offset + 1;
  305.         }
  306.  
  307.       if (strncmp (buffer + offset, decl_str, decl_len) == 0)
  308.         {
  309.           offset += decl_len;
  310.           point = offset;
  311.           break;
  312.         }
  313.     }
  314.  
  315.       if (!point)
  316.     break;
  317.  
  318.       /* Skip forward until we find the open paren. */
  319.       while (point < file_size)
  320.     {
  321.       if (buffer[point] == '\n')
  322.         {
  323.           line_number++;
  324.           line_start = point + 1;
  325.         }
  326.       else if (buffer[point] == '(')
  327.         break;
  328.  
  329.       point++;
  330.     }
  331.  
  332.       while (point++ < file_size)
  333.     {
  334.       if (!whitespace_or_newline (buffer[point]))
  335.         break;
  336.       else if (buffer[point] == '\n')
  337.         {
  338.           line_number++;
  339.           line_start = point + 1;
  340.         }
  341.     }
  342.  
  343.       if (point >= file_size)
  344.     break;
  345.  
  346.       /* Now looking at name of function.  Get it. */
  347.       for (offset = point; buffer[offset] != ','; offset++);
  348.       func = (char *)xmalloc (1 + (offset - point));
  349.       strncpy (func, buffer + point, offset - point);
  350.       func[offset - point] = '\0';
  351.  
  352.       /* Remember this tag in the current block. */
  353.       {
  354.     char *tag_name;
  355.  
  356.     tag_name = (char *)xmalloc (1 + (offset - line_start));
  357.     strncpy (tag_name, buffer + line_start, offset - line_start);
  358.     tag_name[offset - line_start] = '\0';
  359.     add_tag_to_block (block, tag_name, line_number, point);
  360.       }
  361.  
  362. #if defined (NAMED_FUNCTIONS)
  363.       /* Generate the user-visible function name from the function's name. */
  364.       {
  365.     register int i;
  366.     char *name_start;
  367.  
  368.     name_start = func;
  369.  
  370.     if (strncmp (name_start, "info_", 5) == 0)
  371.       name_start += 5;
  372.  
  373.     func_name = strdup (name_start);
  374.  
  375.     /* Fix up "ea" commands. */
  376.     if (strncmp (func_name, "ea_", 3) == 0)
  377.       {
  378.         char *temp_func_name;
  379.  
  380.         temp_func_name = (char *)xmalloc (10 + strlen (func_name));
  381.         strcpy (temp_func_name, "echo_area_");
  382.         strcat (temp_func_name, func_name + 3);
  383.         free (func_name);
  384.         func_name = temp_func_name;
  385.       }
  386.  
  387.     for (i = 0; func_name[i]; i++)
  388.       if (func_name[i] == '_')
  389.         func_name[i] = '-';
  390.       }
  391. #endif /* NAMED_FUNCTIONS */
  392.  
  393.       /* Find doc string. */
  394.       point = offset + 1;
  395.  
  396.       while (point < file_size)
  397.     {
  398.       if (buffer[point] == '\n')
  399.         {
  400.           line_number++;
  401.           line_start = point + 1;
  402.         }
  403.  
  404.       if (buffer[point] == '"')
  405.         break;
  406.       else
  407.         point++;
  408.     }
  409.  
  410.       offset = point + 1;
  411.  
  412.       while (offset < file_size)
  413.     {
  414.       if (buffer[offset] == '\n')
  415.         {
  416.           line_number++;
  417.           line_start = offset + 1;
  418.         }
  419.  
  420.       if (buffer[offset] == '\\')
  421.         offset += 2;
  422.       else if (buffer[offset] == '"')
  423.         break;
  424.       else
  425.         offset++;
  426.     }
  427.  
  428.       offset++;
  429.       if (offset >= file_size)
  430.     break;
  431.  
  432.       doc = (char *)xmalloc (1 + (offset - point));
  433.       strncpy (doc, buffer + point, offset - point);
  434.       doc[offset - point] = '\0';
  435.  
  436. #if defined (NAMED_FUNCTIONS)
  437.       fprintf (doc_stream, "   { %s, \"%s\", %s },\n", func, func_name, doc);
  438.       free (func_name);
  439. #else /* !NAMED_FUNCTIONS */
  440.       fprintf (doc_stream, "   { %s, %s },\n", func, doc);
  441. #endif /* !NAMED_FUNCTIONS */
  442.  
  443.       fprintf (funs_stream, "extern void %s ();\n", func);
  444.       free (func);
  445.       free (doc);
  446.     }
  447.   free (buffer);
  448.  
  449.   /* If we created any tags, remember this file on our global list.  Otherwise,
  450.      free the memory already allocated to it. */
  451.   if (block->entries)
  452.     add_pointer_to_array (block, emacs_tags_index, emacs_tags,
  453.               emacs_tags_slots, 10, EMACS_TAG_BLOCK *);
  454.   else
  455.     {
  456.       free (block->filename);
  457.       free (block);
  458.     }
  459. }
  460.  
  461. static void
  462. fatal_file_error (filename)
  463.      char *filename;
  464. {
  465.   fprintf (stderr, "Couldn't manipulate the file %s.\n", filename);
  466.   exit (2);
  467. }
  468.  
  469. static FILE *
  470. must_fopen (filename, mode)
  471.      char *filename, *mode;
  472. {
  473.   FILE *stream;
  474.  
  475.   stream = fopen (filename, mode);
  476.   if (!stream)
  477.     fatal_file_error (filename);
  478.  
  479.   return (stream);
  480. }
  481.  
  482.