1 /*
2 ** $PROJECT:
3 **
4 ** $VER: autodoc.c 2.2 (25.01.95)
5 **
6 ** by
7 **
8 ** Stefan Ruppert , Windthorststra_e 5 , 65439 Flvrsheim , GERMANY
9 **
10 ** (C) Copyright 1995
11 ** All Rights Reserved !
12 **
13 ** $HISTORY:
14 **
15 ** 25.01.95 : 002.002 : changed to patchlevel 33
16 ** 22.01.95 : 000.001 : initial
17 */
18
19 #include "c2man.h"
20 #include "manpage.h"
21 #include "output.h"
22 #include <ctype.h>
23
24 #ifdef DEBUG
25 #define D(x) x
26 #else
27 #define D(x)
28 #endif
29
30 #define MAX_TAG 10
31
32 static const int linelength = 79;
33 static const int tablength = 4;
34 static const int indentlength = 4;
35
36 static int indent = 4;
37 static int list_indent = 0;
38 static int column = 0;
39 static int newline = FALSE;
40 static int breakline = FALSE;
41 static int see_also = FALSE;
42 static int fileend = FALSE;
43 static int acttable = -1;
44 static int tablemaxtag[MAX_TAG];
45
autodoc_format(text)46 void autodoc_format(text)
47 const char *text;
48 {
49 if(see_also)
50 {
51 if(column + ((text) ? strlen(text) + 2 : 1) > linelength)
52 {
53 putchar('\n');
54 newline = TRUE;
55 }
56 }
57
58 if(newline)
59 {
60 int i;
61 column = i = indent + list_indent;
62 for(; i ; i--)
63 putchar(' ');
64 newline = FALSE;
65 }
66 }
67
autodoc_text(text)68 void autodoc_text(text)
69 const char *text;
70 {
71 int br = 1;
72 autodoc_format(text);
73
74 if(!see_also || (br = strcmp(text,",\n")))
75 {
76 if(see_also < 2)
77 {
78 put_string(text);
79 column += strlen(text);
80 }
81 } else if(!br)
82 {
83 column += 2;
84 put_string(", ");
85 }
86 }
87
autodoc_char(c)88 void autodoc_char(c)
89 const int c;
90 {
91 if(c != '\f')
92 {
93 autodoc_format(NULL);
94
95 if(c == '\t')
96 {
97 int i = tablength - (column % tablength);
98 column += i;
99 for(; i ; i--)
100 putchar(' ');
101 } else
102 {
103 if(see_also)
104 {
105 if(c == '(')
106 see_also++;
107 else if(c == ')')
108 see_also--;
109 }
110
111 putchar(c);
112 column++;
113 }
114
115 if((newline = (c == '\n')))
116 column = 0;
117 }
118 }
119
autodoc_comment()120 void autodoc_comment() { }
121
autodoc_header(firstpage,input_files,grouped,name,terse,section)122 void autodoc_header(firstpage, input_files, grouped, name, terse, section)
123 ManualPage *firstpage;
124 int input_files;
125 boolean grouped;
126 const char *name;
127 const char *terse;
128 const char *section;
129 {
130 const char *basename = strrchr(firstpage->sourcefile, '/');
131 int len;
132 int spc;
133
134 fileend = FALSE;
135
136 if(basename && *basename == '/')
137 basename++;
138
139 len = ((basename) ? strlen(basename) + 1 : 0) + strlen(name);
140 spc = linelength - 2 * len;
141
142 see_also = FALSE;
143
144 if(basename)
145 {
146 autodoc_text(basename);
147 autodoc_char('/');
148 }
149 autodoc_text(name);
150
151 if(spc > 0)
152 {
153 while(spc)
154 {
155 autodoc_char(' ');
156 spc--;
157 }
158 if(basename)
159 {
160 autodoc_text(basename);
161 autodoc_char('/');
162 }
163 autodoc_text(name);
164 } else
165 {
166 const char *ptr = name;
167 len = linelength - 1 - len;
168
169 while(len)
170 {
171 if(basename && *basename)
172 {
173 autodoc_char(*basename);
174 basename++;
175 } else
176 {
177 if(ptr == name && basename)
178 autodoc_char('/');
179 else
180 {
181 autodoc_char(*ptr);
182 ptr++;
183 }
184 }
185 len--;
186 }
187 }
188
189 put_string("\n");
190 }
191
autodoc_dash()192 void autodoc_dash() { put_string("-"); }
193
autodoc_section(name)194 void autodoc_section(name)
195 const char *name;
196 {
197 D((fprintf(stderr,"section : %s\n",name)));
198 newline = FALSE;
199 see_also = FALSE;
200 put_string("\n");
201 if(!strcmp(name,"DESCRIPTION"))
202 name = "FUNCTION";
203 else if(!strcmp(name,"PARAMETERS"))
204 name = "INPUTS";
205 else if(!strcmp(name,"RETURNS"))
206 name = "RESULT";
207 else if(!strcmp(name,"SEE ALSO"))
208 see_also = TRUE;
209
210 put_string(" ");
211 autodoc_text(name);
212 indent = 8;
213 list_indent = 0;
214 autodoc_char('\n');
215 }
216
autodoc_sub_section(name)217 void autodoc_sub_section(name)
218 const char *name;
219 {
220 autodoc_text(name);
221 indent = 12;
222 }
223
autodoc_break_line()224 void autodoc_break_line()
225 {
226 breakline = TRUE;
227 }
228
autodoc_blank_line()229 void autodoc_blank_line()
230 {
231 autodoc_char('\n');
232 }
233
autodoc_code_start()234 void autodoc_code_start() { }
autodoc_code_end()235 void autodoc_code_end() { }
236
autodoc_code(text)237 void autodoc_code(text)
238 const char *text;
239 {
240 autodoc_text(text);
241 }
242
autodoc_tag_entry_start()243 void autodoc_tag_entry_start()
244 {
245 if(list_indent > 0)
246 {
247 autodoc_char('\n');
248 list_indent -= indentlength;
249 }
250 }
autodoc_tag_entry_start_extra()251 void autodoc_tag_entry_start_extra()
252 {
253 if(list_indent > 0)
254 {
255 autodoc_char('\n');
256 list_indent -= indentlength;
257 }
258 }
autodoc_tag_entry_end()259 void autodoc_tag_entry_end()
260 {
261 list_indent += indentlength;
262 autodoc_char('\n');
263 }
autodoc_tag_entry_end_extra(text)264 void autodoc_tag_entry_end_extra(text)
265 const char *text;
266 {
267 put_string("\" \"\t(");
268 autodoc_text(text);
269 put_string(")\"\n");
270 list_indent += indentlength;
271 }
272
autodoc_table_start(longestag)273 void autodoc_table_start(longestag)
274 const char *longestag;
275 {
276 if(acttable < MAX_TAG - 1)
277 {
278 acttable++;
279 tablemaxtag[acttable] = strlen(longestag);
280 }
281
282 indent += indentlength;
283 newline = TRUE;
284 }
285
autodoc_table_entry(name,description)286 void autodoc_table_entry(name, description)
287 const char *name;
288 const char *description;
289 {
290 int i = tablemaxtag[acttable] - strlen(name) + 1;
291
292 autodoc_code(name);
293 while(i > 0)
294 {
295 putchar(' ');
296 i--;
297 }
298 putchar('-');
299 putchar(' ');
300
301 if (description)
302 output_comment(description);
303 else
304 autodoc_char('\n');
305 }
306
autodoc_table_end()307 void autodoc_table_end()
308 {
309 if(acttable > -1)
310 acttable--;
311
312 autodoc_char('\n');
313 indent -= indentlength;
314 if(list_indent > 0)
315 list_indent -= indentlength;
316 }
317
autodoc_indent()318 void autodoc_indent()
319 {
320 int i;
321 for(i = indent + list_indent; i ; i--)
322 autodoc_char(' ');
323 }
324
autodoc_list_start()325 void autodoc_list_start()
326 {
327 indent += indentlength;
328 newline = TRUE;
329 }
330
autodoc_list_entry(name)331 void autodoc_list_entry(name)
332 const char *name;
333 {
334 autodoc_code(name);
335 }
336
autodoc_list_separator()337 void autodoc_list_separator() { put_string(" ,"); }
autodoc_list_end()338 void autodoc_list_end() { autodoc_char('\n'); autodoc_table_end(); }
339
autodoc_include(filename)340 void autodoc_include(filename)
341 const char *filename;
342 {
343
344 }
345
autodoc_terse_sep()346 void autodoc_terse_sep()
347 {
348 autodoc_char(' ');
349 autodoc_dash();
350 autodoc_char(' ');
351 }
352
autodoc_name(name)353 void autodoc_name(name)
354 const char *name;
355 {
356 if(name)
357 autodoc_text(name);
358 else
359 autodoc_section("NAME");
360 }
361
autodoc_file_end()362 void autodoc_file_end()
363 {
364 if(!fileend)
365 putchar('\f');
366 fileend = TRUE;
367 newline = FALSE;
368 }
369
370 /* ideally, this should be made aware of embedded autodoc commands */
autodoc_description(text)371 void autodoc_description(text)
372 const char *text;
373 {
374 enum { TEXT, PERIOD, CAPITALISE } state = CAPITALISE;
375 boolean new_line = TRUE;
376
377 /* correct punctuation a bit as it goes out */
378 for (;*text;text++)
379 {
380 int c = *text;
381
382 if (new_line && (c == '-' || c == '*'))
383 {
384 output->break_line();
385 state = CAPITALISE;
386 }
387 else if (c == '.')
388 state = PERIOD;
389 else if (isspace(c) && state == PERIOD)
390 state = CAPITALISE;
391 else if (isalnum(c) || ispunct(c))
392 {
393 if (islower(c) && state == CAPITALISE) c = toupper(c);
394 state = TEXT;
395 }
396
397 output->character(c);
398 new_line = c == '\n';
399 }
400
401 /* do a full stop if there wasn't one */
402 if (state == TEXT) output->character('.');
403 }
404
405 /* ideally, this should be made aware of embedded autodoc commands */
406 void
autodoc_returns(comment)407 autodoc_returns(comment)
408 const char *comment;
409 {
410 enum { TEXT, PERIOD, CAPITALISE } state = CAPITALISE;
411 char lastchar = '\n';
412 boolean tag_list_started = FALSE;
413
414 /* for each line... */
415 while (*comment)
416 {
417 boolean tagged = FALSE;
418
419 {
420 const char *c = comment;
421
422 /* search along until the end of a word */
423 while (*c && *c != ':' && !isspace(*c))
424 c++;
425
426 /* skip all spaces or tabs after the first word */
427 while (*c && *c != '\n')
428 {
429 if (*c == '\t' || *c == ':')
430 {
431 tagged = TRUE;
432 break;
433 }
434 else if (!isspace(*c))
435 break;
436
437 c++;
438 }
439 }
440
441 /* is it tagged?; explicitly reject dot commands */
442 if (tagged)
443 {
444 /* output lingering newline if necessary */
445 if (lastchar != '\n')
446 {
447 if (state == TEXT && !ispunct(lastchar)) output->character('.');
448 output->character(lastchar = '\n');
449 }
450
451 if (!tag_list_started)
452 {
453 output->tag_list_start();
454 tag_list_started = TRUE;
455 }
456
457 /* output the taggy bit */
458 output->tag_entry_start();
459 while (*comment && *comment != ':' && !isspace(*comment))
460 output->character(*comment++);
461 output->tag_entry_end();
462
463 /* skip any extra tabs or spaces */
464 while (*comment == ':' || (isspace(*comment) && *comment != '\n'))
465 comment++;
466
467 state = CAPITALISE;
468 }
469
470 /* terminate the previous line if necessary */
471 if (lastchar != '\n') output->character(lastchar = '\n');
472
473 /* correct punctuation a bit as the line goes out */
474 for (;*comment && *comment != '\n'; comment++)
475 {
476 char c = *comment;
477
478 if (c == '.')
479 state = PERIOD;
480 else if (isspace(c) && state == PERIOD)
481 state = CAPITALISE;
482 else if (isalnum(c))
483 {
484 if (islower(c) && state == CAPITALISE && fixup_comments)
485 c = toupper(c);
486 state = TEXT;
487 }
488
489 output->character(lastchar = c);
490 }
491
492 /* if it ended in punctuation, just output the nl straight away. */
493 if (ispunct(lastchar))
494 {
495 if (lastchar == '.') state = CAPITALISE;
496 output->character(lastchar = '\n');
497 }
498
499 if (*comment) comment++;
500 }
501
502 /* output lingering newline if necessary */
503 if (lastchar != '\n')
504 {
505 if (state == TEXT && !ispunct(lastchar) && fixup_comments)
506 output->character('.');
507 output->character('\n');
508 }
509
510 if (tag_list_started)
511 output->tag_list_end();
512 }
513
514
515 struct Output autodoc_output =
516 {
517 autodoc_comment,
518 autodoc_header,
519 autodoc_dash,
520 autodoc_section,
521 autodoc_sub_section,
522 autodoc_break_line,
523 autodoc_blank_line,
524 autodoc_code_start,
525 autodoc_code_end,
526 autodoc_code,
527 dummy, /* autodoc_tag_list_start */
528 dummy, /* autodoc_tag_list_end */
529 autodoc_tag_entry_start,
530 autodoc_tag_entry_start_extra,
531 autodoc_tag_entry_end,
532 autodoc_tag_entry_end_extra,
533 autodoc_table_start,
534 autodoc_table_entry,
535 autodoc_table_end,
536 autodoc_indent,
537 autodoc_list_start,
538 autodoc_code, /* autodoc_list_entry */
539 autodoc_list_separator,
540 autodoc_list_end,
541 autodoc_include,
542 autodoc_file_end, /* autodoc_file_end */
543 autodoc_text,
544 autodoc_char,
545 NULL, /* autodoc_parse_option */
546 dummy, /* autodoc_print_options */
547 autodoc_name,
548 autodoc_terse_sep,
549 autodoc_text, /* autodoc_reference */
550 autodoc_text, /* autodoc_emphasized */
551 autodoc_description,
552 autodoc_returns
553 };
554
555