171
|
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 |
1315
|
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
171
|
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 |
1242
|
29 #ifdef HAVE_CONFIG_H |
|
30 #include <config.h> |
|
31 #endif |
|
32 |
171
|
33 #include <stdio.h> |
|
34 #include <ctype.h> |
|
35 #include <sys/types.h> |
|
36 #include <sys/file.h> |
|
37 #include <sys/stat.h> |
|
38 #include "general.h" |
|
39 |
|
40 #if !defined (O_RDONLY) |
|
41 #if defined (HAVE_SYS_FCNTL_H) |
|
42 #include <sys/fcntl.h> |
|
43 #else /* !HAVE_SYS_FCNTL_H */ |
|
44 #include <fcntl.h> |
|
45 #endif /* !HAVE_SYS_FCNTL_H */ |
|
46 #endif /* !O_RDONLY */ |
|
47 |
|
48 extern void *xmalloc (), *xrealloc (); |
|
49 static void fatal_file_error (); |
|
50 |
|
51 /* Name of the header file which receives the declarations of functions. */ |
|
52 static char *funs_filename = "funs.h"; |
|
53 |
|
54 /* Name of the documentation to function pointer file. */ |
|
55 static char *doc_filename = "doc.c"; |
|
56 |
|
57 static char *doc_header[] = { |
|
58 "/* doc.c -- Generated structure containing function names and doc strings.", |
|
59 "", |
|
60 " This file was automatically made from various source files with the", |
|
61 " command \"%s\". DO NOT EDIT THIS FILE, only \"%s.c\".", |
|
62 (char *)NULL |
|
63 }; |
|
64 |
|
65 static char *doc_header_1[] = { |
|
66 " An entry in the array FUNCTION_DOC_ARRAY is made for each command", |
|
67 " found in the above files; each entry consists of a function pointer,", |
|
68 #if defined (NAMED_FUNCTIONS) |
|
69 " a string which is the user-visible name of the function,", |
|
70 #endif /* NAMED_FUNCTIONS */ |
|
71 " and a string which documents its purpose. */", |
|
72 "", |
|
73 "#include \"doc.h\"", |
|
74 "#include \"funs.h\"", |
|
75 "", |
|
76 "FUNCTION_DOC function_doc_array[] = {", |
|
77 "", |
|
78 (char *)NULL |
|
79 }; |
|
80 |
|
81 /* How to remember the locations of the functions found so that Emacs |
|
82 can use the information in a tag table. */ |
|
83 typedef struct { |
|
84 char *name; /* Name of the tag. */ |
|
85 int line; /* Line number at which it appears. */ |
|
86 long char_offset; /* Character offset at which it appears. */ |
|
87 } EMACS_TAG; |
|
88 |
|
89 typedef struct { |
|
90 char *filename; /* Name of the file containing entries. */ |
|
91 long entrylen; /* Total number of characters in tag block. */ |
|
92 EMACS_TAG **entries; /* Entries found in FILENAME. */ |
|
93 int entries_index; |
|
94 int entries_slots; |
|
95 } EMACS_TAG_BLOCK; |
|
96 |
|
97 EMACS_TAG_BLOCK **emacs_tags = (EMACS_TAG_BLOCK **)NULL; |
|
98 int emacs_tags_index = 0; |
|
99 int emacs_tags_slots = 0; |
|
100 |
|
101 #define DECLARATION_STRING "\nDECLARE_INFO_COMMAND" |
|
102 |
|
103 static void process_one_file (); |
|
104 static void maybe_dump_tags (); |
|
105 static FILE *must_fopen (); |
|
106 |
|
107 int |
|
108 main (argc, argv) |
|
109 int argc; |
|
110 char **argv; |
|
111 { |
|
112 register int i; |
|
113 int tags_only = 0; |
|
114 FILE *funs_stream, *doc_stream; |
|
115 |
|
116 for (i = 1; i < argc; i++) |
|
117 if (strcmp (argv[i], "-tags") == 0) |
|
118 { |
|
119 tags_only++; |
|
120 break; |
|
121 } |
|
122 |
|
123 if (tags_only) |
|
124 { |
|
125 funs_filename = "/dev/null"; |
|
126 doc_filename = "/dev/null"; |
|
127 } |
|
128 |
|
129 funs_stream = must_fopen (funs_filename, "w"); |
|
130 doc_stream = must_fopen (doc_filename, "w"); |
|
131 |
|
132 fprintf (funs_stream, |
|
133 "/* %s -- Generated declarations for Info commands. */\n", |
|
134 funs_filename); |
|
135 |
|
136 for (i = 0; doc_header[i]; i++) |
|
137 { |
|
138 fprintf (doc_stream, doc_header[i], argv[0], argv[0]); |
|
139 fprintf (doc_stream, "\n"); |
|
140 } |
|
141 |
|
142 fprintf (doc_stream, |
|
143 " Source files groveled to make this file include:\n\n"); |
|
144 |
|
145 for (i = 1; i < argc; i++) |
|
146 fprintf (doc_stream, "\t%s\n", argv[i]); |
|
147 |
|
148 fprintf (doc_stream, "\n"); |
|
149 |
|
150 for (i = 0; doc_header_1[i]; i++) |
|
151 fprintf (doc_stream, "%s\n", doc_header_1[i]); |
|
152 |
|
153 |
|
154 for (i = 1; i < argc; i++) |
|
155 { |
|
156 char *curfile; |
|
157 curfile = argv[i]; |
|
158 |
|
159 if (*curfile == '-') |
|
160 continue; |
|
161 |
|
162 fprintf (doc_stream, "/* Commands found in \"%s\". */\n", curfile); |
|
163 fprintf (funs_stream, "\n/* Functions declared in \"%s\". */\n", |
|
164 curfile); |
|
165 |
|
166 process_one_file (curfile, doc_stream, funs_stream); |
|
167 } |
|
168 |
|
169 fprintf (doc_stream, |
|
170 " { (VFunction *)NULL, (char *)NULL, (char *)NULL }\n};\n"); |
|
171 |
|
172 fclose (funs_stream); |
|
173 fclose (doc_stream); |
|
174 |
|
175 if (tags_only) |
|
176 maybe_dump_tags (stdout); |
|
177 exit (0); |
|
178 } |
|
179 |
|
180 /* Dumping out the contents of an Emacs tags table. */ |
|
181 static void |
|
182 maybe_dump_tags (stream) |
|
183 FILE *stream; |
|
184 { |
|
185 register int i; |
|
186 |
|
187 /* Print out the information for each block. */ |
|
188 for (i = 0; i < emacs_tags_index; i++) |
|
189 { |
|
190 register int j; |
|
191 register EMACS_TAG_BLOCK *block; |
|
192 register EMACS_TAG *etag; |
|
193 long block_len; |
|
194 |
|
195 block_len = 0; |
|
196 block = emacs_tags[i]; |
|
197 |
|
198 /* Calculate the length of the dumped block first. */ |
|
199 for (j = 0; j < block->entries_index; j++) |
|
200 { |
|
201 char digits[30]; |
|
202 etag = block->entries[j]; |
|
203 block_len += 3 + strlen (etag->name); |
|
204 sprintf (digits, "%d,%d", etag->line, etag->char_offset); |
|
205 block_len += strlen (digits); |
|
206 } |
|
207 |
|
208 /* Print out the defining line. */ |
|
209 fprintf (stream, "\f\n%s,%d\n", block->filename, block_len); |
|
210 |
|
211 /* Print out the individual tags. */ |
|
212 for (j = 0; j < block->entries_index; j++) |
|
213 { |
|
214 etag = block->entries[j]; |
|
215 |
|
216 fprintf (stream, "%s,\177%d,%d\n", |
|
217 etag->name, etag->line, etag->char_offset); |
|
218 } |
|
219 } |
|
220 } |
|
221 |
|
222 /* Keeping track of names, line numbers and character offsets of functions |
|
223 found in source files. */ |
|
224 static EMACS_TAG_BLOCK * |
|
225 make_emacs_tag_block (filename) |
|
226 char *filename; |
|
227 { |
|
228 EMACS_TAG_BLOCK *block; |
|
229 |
|
230 block = (EMACS_TAG_BLOCK *)xmalloc (sizeof (EMACS_TAG_BLOCK)); |
|
231 block->filename = savestring (filename); |
|
232 block->entrylen = 0; |
|
233 block->entries = (EMACS_TAG **)NULL; |
|
234 block->entries_index = 0; |
|
235 block->entries_slots = 0; |
|
236 return (block); |
|
237 } |
|
238 |
|
239 static void |
|
240 add_tag_to_block (block, name, line, char_offset) |
|
241 EMACS_TAG_BLOCK *block; |
|
242 char *name; |
|
243 int line; |
|
244 long char_offset; |
|
245 { |
|
246 EMACS_TAG *tag; |
|
247 |
|
248 tag = (EMACS_TAG *)xmalloc (sizeof (EMACS_TAG)); |
|
249 tag->name = name; |
|
250 tag->line = line; |
|
251 tag->char_offset = char_offset; |
|
252 add_pointer_to_array (tag, block->entries_index, block->entries, |
|
253 block->entries_slots, 50, EMACS_TAG *); |
|
254 } |
|
255 |
|
256 /* Read the file represented by FILENAME into core, and search it for Info |
|
257 function declarations. Output the declarations in various forms to the |
|
258 DOC_STREAM and FUNS_STREAM. */ |
|
259 static void |
|
260 process_one_file (filename, doc_stream, funs_stream) |
|
261 char *filename; |
|
262 FILE *doc_stream, *funs_stream; |
|
263 { |
|
264 int descriptor, decl_len; |
|
265 char *buffer, *decl_str; |
|
266 struct stat finfo; |
|
267 long offset; |
|
268 EMACS_TAG_BLOCK *block; |
|
269 |
|
270 if (stat (filename, &finfo) == -1) |
|
271 fatal_file_error (filename); |
|
272 |
|
273 descriptor = open (filename, O_RDONLY, 0666); |
|
274 |
|
275 if (descriptor == -1) |
|
276 fatal_file_error (filename); |
|
277 |
|
278 buffer = (char *)xmalloc (1 + finfo.st_size); |
|
279 read (descriptor, buffer, finfo.st_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 < (finfo.st_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 < finfo.st_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++ < finfo.st_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 >= finfo.st_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 = savestring (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 < finfo.st_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 < finfo.st_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 >= finfo.st_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 |