source: vendor/emx/current/src/emxdoc/emxdoc.c

Last change on this file was 18, checked in by bird, 23 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 58.0 KB
Line 
1/* emxdoc.c -- Main module of emxdoc
2 Copyright (c) 1993-2001 Eberhard Mattes
3
4This file is part of emxdoc.
5
6emxdoc is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11emxdoc is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with emxdoc; see the file COPYING. If not, write to
18the Free Software Foundation, 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
21
22#include <assert.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <stdarg.h>
26#include <string.h>
27#include <ctype.h>
28#include <unistd.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31#define EXTERN
32#define INIT(X) = X
33#include "emxdoc.h"
34#include "html.h"
35#include "ipf.h"
36#include "latex.h"
37#include "text.h"
38#include "xref.h"
39#include "cond.h"
40
41#define VERSION "0.9d"
42
43struct word_table
44{
45 unsigned hash_size; /* hash size */
46 struct word **hash_table; /* hash table */
47 int count; /* number of elements */
48};
49
50struct local
51{
52 struct word *wp;
53 enum style style;
54};
55
56/* This is the return code of the program. It is initially 0.
57 nonfatal() sets it to 1. */
58static int history = 0;
59
60static int opt_r = FALSE; /* Make output file read-only */
61
62static const char *xref_fname = NULL;
63
64static const char *output_fname = NULL;
65static int output_flag = FALSE;
66
67static const char *hyphenation_fname = NULL;
68
69static uchar *line;
70static size_t line_size = 0;
71static size_t line_len = 0;
72
73/* Temporary output buffer. */
74static uchar output[512];
75
76/* Syntax style. */
77static enum syntax syntax_style;
78
79static size_t elements_size = 0;
80static size_t elements_count = 0;
81
82static int max_width;
83
84static struct local *local_stack = NULL;
85static int local_size = 0;
86static int local_sp;
87
88static int section_numbers[SECTION_LEVELS];
89
90static struct toc *toc_head = NULL;
91static struct toc *toc_ptr = NULL;
92static struct toc **toc_add = &toc_head;
93static int toc_indent = 0;
94
95static uchar compat[128];
96
97static int copy_flag;
98
99static void usage (void) NORETURN2;
100
101
102/* Display an error message and stop. */
103
104void fatal (const char *fmt, ...)
105{
106 va_list arg_ptr;
107
108 va_start (arg_ptr, fmt);
109 vfprintf (stderr, fmt, arg_ptr);
110 putc ('\n', stderr);
111 exit (1);
112}
113
114
115/* Display an error message and set history to 1. Don't stop. */
116
117void nonfatal (const char *fmt, ...)
118{
119 va_list arg_ptr;
120
121 va_start (arg_ptr, fmt);
122 vfprintf (stderr, fmt, arg_ptr);
123 putc ('\n', stderr);
124 history = 1;
125}
126
127
128/* Display a warning message if opt_w is equal to or greater than
129 LEVEL. Don't change history and don't stop. */
130
131void warning (int level, const char *fmt, ...)
132{
133 va_list arg_ptr;
134
135 if (opt_w >= level)
136 {
137 va_start (arg_ptr, fmt);
138 vfprintf (stderr, fmt, arg_ptr);
139 putc ('\n', stderr);
140 }
141}
142
143
144/* Allocate N bytes of memory. Quit on failure. This function is
145 used like malloc(), but we don't have to check the return value. */
146
147void *xmalloc (size_t n)
148{
149 void *p;
150
151 p = malloc (n);
152 if (p == NULL)
153 fatal ("Out of memory");
154 return p;
155}
156
157
158/* Change the allocation of PTR to N bytes. Quit on failure. This
159 function is used like realloc(), but we don't have to check the
160 return value. */
161
162static void *xrealloc (void *ptr, size_t n)
163{
164 void *p;
165
166 p = realloc (ptr, n);
167 if (p == NULL)
168 fatal ("Out of memory");
169 return p;
170}
171
172
173/* Create a duplicate of the string S on the heap. Quit on failure.
174 This function is used like strdup(), but we don't have to check the
175 return value. */
176
177uchar *xstrdup (const uchar *s)
178{
179 char *p;
180
181 p = xmalloc (strlen (s) + 1);
182 strcpy (p, s);
183 return p;
184}
185
186
187static void usage (void)
188{
189 fputs ("emxdoc " VERSION " -- "
190 "Copyright (c) 1993-1999 by Eberhard Mattes\n\n", stderr);
191 fputs ("Usage:\n", stderr);
192 fputs (" emxdoc -H [-o <output>] [-x <xref>] <input>\n", stderr);
193 fputs (" emxdoc -T [-fr] [-o <output>] <input>\n", stderr);
194 fputs (" emxdoc -L [-fr] [-o <output>] <input>\n", stderr);
195 fputs (" emxdoc -I [-acfgr] [-n <start>] [-o <output>] [-x <xref>] <input>\n", stderr);
196 fputs (" emxdoc -K [-o <output>] <input>\n", stderr);
197 fputs (" emxdoc -M [-o <output>] <input>...\n", stderr);
198 fputs ("\nModes:\n\n", stderr);
199 fputs (" -H Generate HTML file\n", stderr);
200 fputs (" -I Generate IPF file\n", stderr);
201 fputs (" -K Generate index file\n", stderr);
202 fputs (" -L Generate LaTeX file\n", stderr);
203 fputs (" -M Merge directory files\n", stderr);
204 fputs (" -T Generate text file\n", stderr);
205 fputs ("\nOptions:\n\n", stderr);
206 fputs (" -a Concatenate instead of call .INF files\n", stderr);
207 fputs (" -b<number> Select line breaking algorithm for -t\n", stderr);
208 fputs (" -c Use color instead of slanted font\n", stderr);
209 fputs (" -e<char> Set escape character\n", stderr);
210 fputs (" -f Enable French spacing\n", stderr);
211 fputs (" -g Gather global directory data\n", stderr);
212 fputs (" -h<file> Use hyphenation table\n", stderr);
213 fputs (" -i<enc> Select input encoding\n", stderr);
214 fputs (" -n<start> Set first ID number\n", stderr);
215 fputs (" -o<output> Set output file name\n", stderr);
216 fputs (" -r Make output file read-only\n", stderr);
217 fputs (" -w<level> Set warning level\n", stderr);
218 fputs (" -x<xref> Use cross reference file\n", stderr);
219 exit (1);
220}
221
222
223static void upcase (uchar *s)
224{
225 while (*s != 0)
226 {
227 *s = (uchar)toupper (*s);
228 ++s;
229 }
230}
231
232
233static void downcase (uchar *s)
234{
235 while (*s != 0)
236 {
237 *s = (uchar)tolower (*s);
238 ++s;
239 }
240}
241
242
243void write_nl (void)
244{
245 if (output_flag)
246 {
247 putc ('\n', output_file);
248 if (ferror (output_file))
249 {
250 perror (output_fname);
251 exit (1);
252 }
253 if (output_x > max_width)
254 nonfatal ("%s:%d: Output line %d too long",
255 input_fname, line_no, output_line_no);
256 output_x = 0;
257 ++output_line_no;
258 }
259}
260
261
262void write_break (void)
263{
264 if (output_x != 0)
265 write_nl ();
266}
267
268
269/* P must not contain \n! */
270
271void write_nstring (const uchar *p, size_t n)
272{
273 if (output_flag)
274 {
275 fwrite (p, n, 1, output_file);
276 output_x += n;
277 }
278}
279
280
281/* P must not contain \n! */
282
283void write_string (const uchar *p)
284{
285 write_nstring (p, strlen (p));
286}
287
288
289/* P must not contain \n! */
290
291void write_line (const uchar *p)
292{
293 write_string (p);
294 write_nl ();
295}
296
297/* Output must not contain \n! */
298
299void write_fmt (const char *fmt, ...)
300{
301 va_list arg_ptr;
302
303 if (output_flag)
304 {
305 va_start (arg_ptr, fmt);
306 output_x += vfprintf (output_file, fmt, arg_ptr);
307 }
308}
309
310
311void write_space (void)
312{
313 if (output_x >= 60)
314 write_nl ();
315 else
316 write_string (" ");
317}
318
319struct word_table *wt_new (unsigned hash_size)
320{
321 unsigned i;
322 struct word_table *wt = xmalloc (sizeof (*wt));
323
324 wt->hash_size = hash_size;
325 wt->count = 0;
326 wt->hash_table = xmalloc (hash_size * sizeof (wt->hash_table[0]));
327 for (i = 0; i < hash_size; ++i)
328 wt->hash_table[i] = NULL;
329 return wt;
330}
331
332unsigned wt_hash (struct word_table *wt, const uchar *str)
333{
334 unsigned h;
335
336 h = 0;
337 while (*str != 0)
338 {
339 h = (h << 2) ^ *str;
340 ++str;
341 }
342 return h % wt->hash_size;
343}
344
345
346struct word *wt_find (struct word_table *wt, const uchar *str, unsigned hash)
347{
348 struct word *wp;
349
350 for (wp = wt->hash_table[hash]; wp != NULL; wp = wp->next)
351 if (strcmp (wp->str, str) == 0)
352 return wp;
353 return NULL;
354}
355
356
357struct word *wt_add (struct word_table *wt, const uchar *str)
358{
359 struct word *wp;
360 unsigned hash;
361
362 hash = wt_hash (wt, str);
363 wp = wt_find (wt, str, hash);
364 if (wp == NULL)
365 {
366 wp = xmalloc (sizeof (*wp));
367 wp->style = STYLE_NORMAL;
368 wp->str = xstrdup (str);
369 wp->ref = 0; wp->idx = 0;
370 wp->database = NULL;
371 wp->special = NULL;
372 wp->subidx = NULL;
373 wp->repl = NULL;
374 wp->flags = 0;
375 wp->next = wt->hash_table[hash];
376 wt->hash_table[hash] = wp;
377 wt->count += 1;
378 }
379 return wp;
380}
381
382int wt_walk (struct word_table *wt, int (*callback)(struct word *))
383{
384 int x = 0;
385 unsigned i;
386 struct word *wp;
387
388 for (i = 0; i < wt->hash_size; ++i)
389 for (wp = wt->hash_table[i]; wp != NULL; wp = wp->next)
390 {
391 x = callback (wp);
392 if (x != 0)
393 return x;
394 }
395 return x;
396}
397
398int wt_count (const struct word_table *wt)
399{
400 return wt->count;
401}
402
403unsigned word_hash (const uchar *str)
404{
405 return wt_hash (word_top, str);
406}
407
408struct word *word_find (const uchar *str, unsigned hash)
409{
410 return wt_find (word_top, str, hash);
411}
412
413struct word *word_add (const uchar *str)
414{
415 return wt_add (word_top, str);
416}
417
418int word_walk (int (*callback)(struct word *))
419{
420 return wt_walk (word_top, callback);
421}
422
423/* We do not really nest local blocks */
424
425static void local_begin (void)
426{
427}
428
429
430static void local_end (void)
431{
432 while (local_sp > 0)
433 {
434 --local_sp;
435 local_stack[local_sp].wp->style = local_stack[local_sp].style;
436 }
437}
438
439
440static void local_add (struct word *wp)
441{
442 if (local_sp >= local_size)
443 {
444 local_size += 256;
445 local_stack = xrealloc (local_stack, local_size * sizeof (*local_stack));
446 }
447 local_stack[local_sp].wp = wp;
448 local_stack[local_sp].style = wp->style;
449 ++local_sp;
450}
451
452
453void format_output (const uchar *p, int may_break)
454{
455 switch (mode)
456 {
457 case 'H':
458 html_output (p, may_break);
459 break;
460 case 'I':
461 ipf_output (p, may_break);
462 break;
463 case 'L':
464 latex_output (p, may_break);
465 break;
466 case 'T':
467 text_output (p, may_break);
468 break;
469 }
470}
471
472
473void start_hilite (int hilite)
474{
475 if (hl_sp >= HL_STACK_SIZE - 1)
476 fatal ("%s:%d: Highlighting stack overflow", input_fname, line_no);
477 ++hl_sp;
478 hl_stack[hl_sp] = hl_stack[hl_sp-1] | hilite;
479 if (out)
480 switch (mode)
481 {
482 case 'H':
483 html_start_hilite ();
484 break;
485 case 'L':
486 latex_start_hilite ();
487 break;
488 }
489}
490
491
492void end_hilite (void)
493{
494 if (hl_sp == 0)
495 fatal ("%s:%d: Highlighting stack underflow", input_fname, line_no);
496 if (out)
497 switch (mode)
498 {
499 case 'H':
500 html_end_hilite ();
501 break;
502 case 'L':
503 latex_end_hilite ();
504 break;
505 }
506 --hl_sp;
507}
508
509
510static void line_add (const uchar *src, size_t len)
511{
512 if (line_len + len + 1 > line_size)
513 {
514 line_size += 4096;
515 line = xrealloc (line, line_size);
516 }
517 memcpy (line + line_len, src, len);
518 line_len += len;
519 line[line_len] = 0;
520}
521
522
523static struct element *add_element (void)
524{
525 if (elements_count >= elements_size)
526 {
527 elements_size += 512;
528 elements = xrealloc (elements, elements_size * sizeof (*elements));
529 }
530 return &elements[elements_count++];
531}
532
533
534static struct element *add_word (const uchar *word, enum el el)
535{
536 struct element *ep;
537
538 ep = add_element ();
539 ep->el = el;
540 ep->wp = word_add (word);
541 ep->n = 0; /* ref */
542 return ep;
543}
544
545
546static void make_elements_internal (const uchar *p)
547{
548 uchar word[512], *d, start, end, *h1;
549 struct element *ep;
550 struct word *wp;
551 struct toc *tp;
552 int n, level, paren;
553 enum {other, other_dot, abbrev, abbrev_dot} state;
554
555 state = other;
556 while (*p != 0)
557 {
558 if (*p == escape)
559 {
560 state = other;
561 parse_tag (&p);
562 switch (tg_tag)
563 {
564 case TAG_STYLE:
565 case TAG_REF:
566 case TAG_HPT:
567 start = *p;
568 if (start == '{')
569 end = '}';
570 else if (start == '[')
571 end = ']';
572 else
573 fatal ("%s:%d: Missing {", input_fname, line_no);
574 ++p; n = 0; level = 0;
575 while (*p != 0 && !(level == 0 && *p == end))
576 {
577 if (n >= sizeof (word) - 1)
578 fatal ("%s%d: Argument too long", input_fname, line_no);
579 word[n++] = *p;
580 if (*p == start)
581 ++level;
582 else if (*p == end)
583 --level;
584 ++p;
585 }
586 if (*p != end)
587 fatal ("%s:%d: Missing %c", input_fname, line_no, end);
588 ++p;
589 word[n] = 0;
590 break;
591 case TAG_BREAK:
592 ep = add_element ();
593 ep->el = EL_BREAK;
594 ep->n = 0;
595 break;
596 case TAG_FULLSTOP:
597 add_word (".", EL_PUNCT);
598 state = other_dot;
599 break;
600 default:
601 fatal ("%s:%d: Unexpected tag", input_fname, line_no);
602 }
603 switch (tg_tag)
604 {
605 case TAG_STYLE:
606 ep = add_element ();
607 ep->el = EL_STYLE;
608 ep->n = tg_style;
609 add_word (word, EL_WORD);
610 ep = add_element ();
611 ep->el = EL_ENDSTYLE;
612 break;
613 case TAG_REF:
614 wp = word_find (word, word_hash (word));
615 if (wp == NULL)
616 fatal ("%s:%d: Undefined label: %s",
617 input_fname, line_no, word);
618 for (tp = toc_head; tp != NULL; tp = tp->next)
619 if (tp->ref == wp->ref)
620 break;
621 if (tp == NULL)
622 fatal ("%s:%d: Undefined label: %s",
623 input_fname, line_no, word);
624 ep = add_word (tp->number, EL_WORD);
625 if (ep->wp->ref == 0)
626 ep->wp->ref = wp->ref;
627 else if (ep->wp->ref != wp->ref)
628 fatal ("%s:%d: Label redefined: %s",
629 input_fname, line_no, tp->number);
630 ep->n = 1;
631 break;
632 case TAG_HPT:
633 wp = use_reference (word);
634 switch (mode)
635 {
636 case 'H':
637 case 'I':
638 if (wp != NULL)
639 {
640 ep = add_word (word, EL_WORD);
641 ep->n = 1;
642 }
643 break;
644 case 'T':
645 case 'L':
646 make_elements_internal (word); /* Recursive! */
647 break;
648 }
649 break;
650 case TAG_BREAK:
651 case TAG_FULLSTOP:
652 break;
653 default:
654 abort ();
655 }
656 }
657
658 n = 0;
659 while (isspace (*p))
660 ++n, ++p;
661 if (n != 0)
662 {
663 if (state == other_dot && n == 1)
664 n = (opt_f ? 1 : 2);
665 else if (state == abbrev_dot && n == 2)
666 n = 1;
667 state = other;
668 ep = add_element ();
669 ep->el = EL_SPACE;
670 ep->n = n;
671 continue;
672 }
673
674 d = word;
675 while (*p == '(' || *p == '*' || *p == '`')
676 *d++ = *p++;
677 if (d != word)
678 {
679 *d = 0;
680 add_word (word, EL_PUNCT);
681 state = other;
682 continue;
683 }
684
685 d = word; paren = 0;
686 while (*p != 0 && *p != escape
687 && !(isspace (*p) || *p == ',' || *p == ';'
688 || *p == '!' || *p == '?' || *p == '\''
689 || (*p == ')' && paren == 0)
690 || (*p == '[' && prototype_flag)
691 || (*p == '&' && prototype_flag)
692 || ((*p == '.' || *p == ':')
693 && (p[1] == 0 || isspace (p[1])))))
694 {
695 if (*p == '(')
696 ++paren;
697 else if (*p == ')')
698 --paren;
699 *d++ = *p++;
700 }
701 if (d != word)
702 {
703 *d = 0;
704 wp = word_find (word, word_hash (word));
705 state = (wp != NULL && (wp->flags & WF_ABBREV)) ? abbrev : other;
706 if (language == LANG_GERMAN
707 && wp == NULL
708 && (h1 = strchr (word, '-')) != NULL)
709 {
710 *h1 = 0;
711 if (word_find (word, word_hash (word)) != NULL)
712 {
713 add_word (word, EL_WORD);
714 add_word ("-", EL_PUNCT);
715 add_word (h1 + 1, EL_WORD);
716 }
717 else
718 {
719 *h1 = '-';
720 add_word (word, EL_WORD);
721 }
722 }
723 else if (wp != NULL && wp->repl != NULL)
724 make_elements_internal (wp->repl);
725 else
726 add_word (word, EL_WORD);
727 }
728
729 d = word;
730 while (*p == '.' || *p == ',' || *p == ';' || *p == '\''
731 || *p == ':' || *p == '!' || *p == '?' || *p == ')'
732 || (*p == '[' && prototype_flag)
733 || (*p == '&' && prototype_flag))
734 *d++ = *p++;
735 if (d != word)
736 {
737 *d = 0;
738 add_word (word, EL_PUNCT);
739 if (d[-1] == '.')
740 state = ((state == abbrev && d == word + 1)
741 ? abbrev_dot : other_dot);
742 else
743 state = other;
744 }
745 }
746}
747
748
749static void make_elements_start (void)
750{
751 elements_count = 0;
752}
753
754
755static void make_elements_end (void)
756{
757 struct element *ep;
758
759 ep = add_element ();
760 ep->el = EL_END;
761}
762
763
764void make_elements (const uchar *p)
765{
766 make_elements_start ();
767 make_elements_internal (p);
768 make_elements_end ();
769}
770
771
772#define ISSYNTAXARG(C) ((C) == '*' || (C) == '#' \
773 || (syntax_style == SYNTAX_DVIDRV && (C) == '+'))
774
775void format_string (const uchar *p, int sty, int may_break)
776{
777 uchar syntax[512], *d;
778 const uchar *s;
779
780 switch (sty)
781 {
782 case STYLE_NORMAL:
783 format_output (p, may_break);
784 break;
785 case STYLE_BOLD:
786 start_hilite (HL_BF);
787 format_output (p, may_break);
788 end_hilite ();
789 break;
790 case STYLE_SLANTED:
791 start_hilite (HL_SL);
792 format_output (p, may_break);
793 end_hilite ();
794 break;
795 case STYLE_UNDERLINE:
796 start_hilite (HL_UL);
797 format_output (p, may_break);
798 end_hilite ();
799 break;
800 case STYLE_TTY:
801 start_hilite (HL_TT);
802 format_output (p, may_break);
803 end_hilite ();
804 break;
805 case STYLE_EMPHASIZE:
806 strcpy (syntax, p);
807 if (mode == 'T')
808 upcase (syntax);
809 start_hilite (HL_EM);
810 format_output (syntax, may_break);
811 end_hilite ();
812 break;
813 case STYLE_PARAM:
814 strcpy (syntax, p);
815 if (mode != 'T' || prototype_flag)
816 downcase (syntax);
817 start_hilite (HL_SL);
818 format_output (syntax, may_break);
819 end_hilite ();
820 break;
821 case STYLE_SYNTAX:
822 s = p;
823 while (*s != 0)
824 {
825 if (isspace (*s) && output_x >= 60)
826 {
827 ++s;
828 write_nl ();
829 }
830 d = syntax;
831 while (*s != 0 && *s != '<' && *s != '|' && *s != '[' && *s != ']'
832 && !(ISSYNTAXARG (s[0]) && s[1] == 0))
833 *d++ = *s++;
834 if (d != syntax)
835 {
836 *d = 0;
837 start_hilite (HL_TT);
838 format_output (syntax, may_break);
839 end_hilite ();
840 }
841
842 if (ISSYNTAXARG (s[0]) && s[1] == 0)
843 {
844 start_hilite (HL_SL);
845 format_output (s, may_break);
846 end_hilite ();
847 ++s;
848 }
849
850 if (*s == '[' || *s == ']' || *s == '|')
851 {
852 syntax[0] = *s++;
853 syntax[1] = 0;
854 start_hilite (HL_BF);
855 format_output (syntax, may_break);
856 end_hilite ();
857 }
858
859 if (*s == '<')
860 {
861 if (mode != 'T')
862 ++s;
863 d = syntax;
864 while (*s != 0 && *s != '>')
865 *d++ = *s++;
866 if (*s == '>')
867 {
868 if (mode == 'T')
869 *d++ = *s;
870 ++s;
871 }
872 *d = 0;
873 start_hilite (HL_SL);
874 format_output (syntax, may_break);
875 end_hilite ();
876 }
877 }
878 break;
879 default:
880 abort ();
881 }
882}
883
884
885void format_spaces (int n, enum style style, int may_break)
886{
887 uchar *p;
888
889 p = alloca (n + 1);
890 memset (p, ' ', n);
891 p[n] = 0;
892 format_string (p, style, may_break);
893}
894
895
896static void start_env (int env, int tindent, int iindent)
897{
898 if (env_sp >= ENV_STACK_SIZE - 1)
899 fatal ("%s:%d: Environment stack overflow", input_fname, line_no);
900 ++env_sp;
901 env_stack[env_sp].env = env;
902 env_stack[env_sp].tmargin = env_stack[env_sp-1].tmargin + tindent;
903 env_stack[env_sp].imargin = env_stack[env_sp-1].imargin + iindent;
904 env_stack[env_sp].start_line = line_no;
905 env_stack[env_sp].counter = 0;
906}
907
908
909static void end_env (int env)
910{
911 const char *name;
912
913 if (env_stack[env_sp].env != env)
914 {
915 switch (env_stack[env_sp].env)
916 {
917 case ENV_DESCRIPTION:
918 name = "description";
919 break;
920 case ENV_ENUMERATE:
921 name = "enumerate";
922 break;
923 case ENV_ITEMIZE:
924 name = "itemize";
925 break;
926 case ENV_LIST:
927 name = "list";
928 break;
929 case ENV_INDENT:
930 name = "indent";
931 break;
932 case ENV_TYPEWRITER:
933 name = "typewriter";
934 break;
935 default:
936 fatal ("%s:%d: No environment to end", input_fname, line_no);
937 break;
938 }
939 fatal ("%s:%d: %cend%s expected", input_fname, line_no, escape, name);
940 }
941 if (out)
942 switch (mode)
943 {
944 case 'H':
945 html_end_env ();
946 break;
947 case 'I':
948 ipf_end_env ();
949 break;
950 case 'L':
951 latex_end_env ();
952 break;
953 }
954 --env_sp;
955}
956
957
958static void check_copy (void)
959{
960 if (out && !copy_flag)
961 warning (2, "%s:%d: Text should be inserted here", input_fname, line_no);
962 copy_flag = FALSE;
963}
964
965
966static void do_end_env (int env)
967{
968 end_env (env);
969 para_flag = TRUE; copy_flag = FALSE;
970 read_line ();
971}
972
973
974static void do_format (const uchar *p)
975{
976 const uchar *q;
977 enum style sty;
978 struct word *wp;
979 int len;
980 uchar word[512];
981 uchar flg;
982
983 if (!out)
984 {
985 flg = 0;
986 if (strncmp (p, "bold", 4) == 0 && isspace (p[4]))
987 {
988 sty = STYLE_BOLD;
989 p += 4;
990 }
991 else if (strncmp (p, "tty", 3) == 0 && isspace (p[3]))
992 {
993 sty = STYLE_TTY;
994 p += 3;
995 }
996 else if (strncmp (p, "slanted", 7) == 0 && isspace (p[7]))
997 {
998 sty = STYLE_SLANTED;
999 p += 7;
1000 }
1001 else if (strncmp (p, "syntax", 6) == 0 && isspace (p[6]))
1002 {
1003 sty = STYLE_SYNTAX;
1004 p += 6;
1005 }
1006 else if (strncmp (p, "param", 5) == 0 && isspace (p[5]))
1007 {
1008 sty = STYLE_PARAM;
1009 p += 5;
1010 }
1011 else if (strncmp (p, "underline", 9) == 0 && isspace (p[9]))
1012 {
1013 sty = STYLE_UNDERLINE;
1014 p += 9;
1015 }
1016 else if (strncmp (p, "emphasize", 9) == 0 && isspace (p[9]))
1017 {
1018 sty = STYLE_EMPHASIZE;
1019 p += 9;
1020 }
1021 else if (strncmp (p, "abbrev", 6) == 0 && isspace (p[6]))
1022 {
1023 sty = STYLE_NORMAL; flg = WF_ABBREV;
1024 p += 6;
1025 }
1026 else
1027 fatal ("%s:%d: Invalid style", input_fname, line_no);
1028 for (;;)
1029 {
1030 while (isspace (*p))
1031 ++p;
1032 if (*p == 0)
1033 break;
1034 len = 0; q = p;
1035 while (*p != 0 && !isspace (*p))
1036 word[len++] = *p++;
1037 word[len] = 0;
1038 if (sty == STYLE_NORMAL && flg == WF_ABBREV)
1039 {
1040 if (len < 2 || word[len-1] != '.')
1041 fatal ("%s:%d: Abbreviation must end with a period",
1042 input_fname, line_no);
1043 word[len-1] = 0;
1044 }
1045 wp = word_add (word);
1046 if (sty != STYLE_NORMAL)
1047 wp->style = sty;
1048 else
1049 wp->flags |= flg;
1050 }
1051 }
1052 read_line ();
1053}
1054
1055
1056static void do_special (const uchar *p)
1057{
1058 const uchar *q;
1059 char m;
1060 struct word *wp;
1061 int len;
1062 uchar word[512], *repl;
1063
1064 if (!out)
1065 {
1066 if (strncmp (p, "text", 4) == 0 && isspace (p[4]))
1067 {
1068 m = 'T'; p += 4;
1069 }
1070 else if (strncmp (p, "ipf", 3) == 0 && isspace (p[3]))
1071 {
1072 m = 'I'; p += 3;
1073 }
1074 else if (strncmp (p, "latex", 5) == 0 && isspace (p[5]))
1075 {
1076 m = 'L'; p += 5;
1077 }
1078 else if (strncmp (p, "html", 4) == 0 && isspace (p[4]))
1079 {
1080 m = 'H'; p += 4;
1081 }
1082 else
1083 fatal ("%s:%d: Invalid special mode", input_fname, line_no);
1084 while (isspace (*p))
1085 ++p;
1086 if (*p == 0)
1087 fatal ("%s:%d: Missing word", input_fname, line_no);
1088 len = 0; q = p;
1089 while (*p != 0 && !isspace (*p))
1090 word[len++] = *p++;
1091 word[len] = 0;
1092 while (isspace (*p))
1093 ++p;
1094 if (*p == 0)
1095 fatal ("%s:%d: Missing replacement", input_fname, line_no);
1096 repl = xstrdup (p);
1097 wp = word_add (word);
1098 if (wp->special == NULL)
1099 {
1100 wp->special = xmalloc (sizeof (struct special));
1101 wp->special->text = NULL;
1102 wp->special->ipf = NULL;
1103 wp->special->latex = NULL;
1104 wp->special->html = NULL;
1105 }
1106 switch (m)
1107 {
1108 case 'H':
1109 wp->special->html = repl; break;
1110 case 'T':
1111 wp->special->text = repl; break;
1112 case 'I':
1113 wp->special->ipf = repl; break;
1114 case 'L':
1115 wp->special->latex = repl; break;
1116 default:
1117 abort ();
1118 }
1119 }
1120 read_line ();
1121}
1122
1123
1124static void do_replace (const uchar *p)
1125{
1126 const uchar *q;
1127 struct word *wp;
1128 int len;
1129 uchar word[512], *repl;
1130
1131 if (!out)
1132 {
1133 len = 0; q = p;
1134 while (*p != 0 && !isspace (*p))
1135 word[len++] = *p++;
1136 word[len] = 0;
1137 while (isspace (*p))
1138 ++p;
1139 if (*p == 0)
1140 fatal ("%s:%d: Missing replacement", input_fname, line_no);
1141 repl = xstrdup (p);
1142 wp = word_add (word);
1143 wp->repl = repl;
1144 }
1145 read_line ();
1146}
1147
1148
1149static void do_set (const uchar *p)
1150{
1151 int len, value;
1152 uchar word[512];
1153
1154 len = 0;
1155 if (!isalpha (*p))
1156 fatal ("%s:%d: Invalid variable name", input_fname, line_no);
1157 word[len++] = *p++;
1158 while (isalnum (*p) || *p == '_')
1159 word[len++] = *p++;
1160 word[len] = 0;
1161 if (!isspace (*p))
1162 fatal ("%s:%d: Invalid variable name ", input_fname, line_no);
1163 while (isspace (*p))
1164 ++p;
1165 if (strcmp (p, "false") == 0)
1166 value = FALSE;
1167 else if (strcmp (p, "true") == 0)
1168 value = TRUE;
1169 else
1170 fatal ("%s:%d: Invalid value ", input_fname, line_no);
1171 cond_set (word, value);
1172 read_line ();
1173}
1174
1175
1176static void do_language (const uchar *p)
1177{
1178 if (!out)
1179 {
1180 if (strcmp (p, "english") == 0)
1181 language = LANG_ENGLISH;
1182 else if (strcmp (p, "german") == 0)
1183 language = LANG_GERMAN;
1184 else
1185 fatal ("%s:%d: Invalid language", input_fname, line_no);
1186 }
1187 read_line ();
1188}
1189
1190
1191static void do_syntax (const uchar *p)
1192{
1193 if (strcmp (p, "emx") == 0)
1194 language = SYNTAX_EMX;
1195 else if (strcmp (p, "dvidrv") == 0)
1196 language = SYNTAX_DVIDRV;
1197 else
1198 fatal ("%s:%d: Invalid syntax style", input_fname, line_no);
1199 read_line ();
1200}
1201
1202
1203static void new_section (int level, unsigned flags)
1204{
1205 struct toc *tp;
1206 int i;
1207 uchar *d;
1208
1209 tp = xmalloc (sizeof (*tp));
1210 tp->next = NULL;
1211 tp->level = level;
1212 tp->ref = ref_no++;
1213 tp->print = FALSE;
1214 tp->global = FALSE;
1215 if (flags & HF_UNNUMBERED)
1216 tp->number = NULL;
1217 else
1218 {
1219 ++section_numbers[level-1];
1220 for (i = level; i < SECTION_LEVELS; ++i)
1221 section_numbers[i] = 0;
1222 d = output;
1223 for (i = 0; i < level; ++i)
1224 {
1225 if (i != 0)
1226 *d++ = '.';
1227 d += sprintf (d, "%d", section_numbers[i]);
1228 }
1229 i = strlen (output);
1230 if (i > toc_indent)
1231 toc_indent = i;
1232 tp->number = xstrdup (output);
1233 }
1234 tp->title = NULL;
1235 tp->flags = flags;
1236 *toc_add = tp;
1237 toc_add = &tp->next;
1238 toc_ptr = tp;
1239}
1240
1241
1242static void do_heading_def (const uchar *p)
1243{
1244 if (tg_level > 0)
1245 {
1246 new_section (tg_level, tg_flags);
1247 toc_ptr->print = TRUE;
1248 toc_ptr->title = xstrdup (p);
1249 }
1250}
1251
1252static void do_heading_out (const uchar *p)
1253{
1254 check_copy ();
1255 if (tg_level > 0)
1256 {
1257 toc_ptr = (toc_ptr == NULL ? toc_head : toc_ptr->next);
1258 assert (toc_ptr != NULL);
1259 assert (strcmp (p, toc_ptr->title) == 0);
1260 if (toc_ptr->number == NULL)
1261 output[0] = 0;
1262 else
1263 {
1264 strcpy (output, toc_ptr->number);
1265 strcat (output, " ");
1266 }
1267 switch (mode)
1268 {
1269 case 'H':
1270 html_heading1 (toc_ptr->ref);
1271 break;
1272 case 'I':
1273 ipf_heading1 (toc_ptr->level, toc_ptr->ref, toc_ptr->global,
1274 tg_flags);
1275 break;
1276 case 'L':
1277 latex_heading1 ();
1278 break;
1279 case 'T':
1280 text_heading1 ();
1281 break;
1282 }
1283 strcat (output, p);
1284 }
1285 else
1286 strcpy (output, p);
1287 switch (mode)
1288 {
1289 case 'H':
1290 html_heading2 (output);
1291 break;
1292 case 'I':
1293 ipf_heading2 (output);
1294 break;
1295 case 'L':
1296 latex_heading2 (p);
1297 break;
1298 case 'T':
1299 text_heading2 (output);
1300 break;
1301 }
1302 para_flag = TRUE;
1303}
1304
1305
1306static void do_toc_out (const uchar *p)
1307{
1308 struct toc *tp;
1309 int i, len;
1310
1311 if (out && para_flag)
1312 switch (mode)
1313 {
1314 case 'T':
1315 write_nl ();
1316 break;
1317 }
1318 para_flag = FALSE;
1319 if (toc_head != NULL)
1320 switch (mode)
1321 {
1322 case 'H':
1323 html_toc_start ();
1324 break;
1325 case 'I':
1326 ipf_toc_start ();
1327 break;
1328 }
1329 for (tp = toc_head; tp != NULL; tp = tp->next)
1330 if (tp->print)
1331 {
1332 if (tp->number == NULL)
1333 len = 0;
1334 else
1335 {
1336 len = strlen (tp->number);
1337 memcpy (output, tp->number, len);
1338 }
1339 i = toc_indent + 2 * tp->level - len;
1340 memset (output + len, ' ', i);
1341 output[len+i] = 0;
1342 switch (mode)
1343 {
1344 case 'H':
1345 html_toc_line (output, tp);
1346 break;
1347 case 'I':
1348 ipf_toc_line (output, tp);
1349 break;
1350 case 'T':
1351 if (!(tp->flags & HF_UNNUMBERED))
1352 text_toc_line (output, tp);
1353 break;
1354 }
1355 }
1356 if (mode == 'I' && toc_head != NULL)
1357 ipf_toc_end ();
1358 copy_flag = TRUE;
1359}
1360
1361
1362static void do_description (void)
1363{
1364 check_copy ();
1365 para_flag = FALSE;
1366 start_env (ENV_DESCRIPTION, 8, IPF_DESCRIPTION_INDENT);
1367 if (out)
1368 switch (mode)
1369 {
1370 case 'H':
1371 html_description ();
1372 break;
1373 case 'I':
1374 ipf_description ();
1375 break;
1376 case 'L':
1377 latex_description ();
1378 break;
1379 }
1380 read_line ();
1381}
1382
1383
1384static void do_enumerate (void)
1385{
1386 check_copy ();
1387 para_flag = FALSE;
1388 start_env (ENV_ENUMERATE, 4, 3);
1389 if (out)
1390 switch (mode)
1391 {
1392 case 'H':
1393 html_enumerate ();
1394 break;
1395 case 'I':
1396 ipf_enumerate ();
1397 break;
1398 case 'L':
1399 latex_enumerate ();
1400 break;
1401 }
1402 read_line ();
1403}
1404
1405
1406static void do_itemize (void)
1407{
1408 check_copy ();
1409 para_flag = FALSE;
1410 start_env (ENV_ITEMIZE, 2, 2);
1411 if (out)
1412 switch (mode)
1413 {
1414 case 'H':
1415 html_itemize ();
1416 break;
1417 case 'I':
1418 ipf_itemize ();
1419 break;
1420 case 'L':
1421 latex_itemize ();
1422 break;
1423 }
1424 read_line ();
1425}
1426
1427
1428static void do_indent (int env)
1429{
1430 check_copy ();
1431 start_env (env, 4, 4);
1432 ipf_env_margin (env_sp);
1433 if (out)
1434 switch (mode)
1435 {
1436 case 'H':
1437 html_indent ();
1438 break;
1439 case 'L':
1440 latex_indent ();
1441 break;
1442 }
1443 read_line ();
1444}
1445
1446
1447static void do_list (void)
1448{
1449 check_copy ();
1450 start_env (ENV_LIST, 4, 4);
1451 if (out)
1452 switch (mode)
1453 {
1454 case 'H':
1455 html_list ();
1456 break;
1457 case 'L':
1458 latex_description ();
1459 break;
1460 }
1461 read_line ();
1462}
1463
1464
1465static void do_verbatim (enum tag tag_end)
1466{
1467 int start_line, tmargin;
1468 const uchar *p;
1469
1470 check_copy ();
1471 para_flag = FALSE;
1472 start_line = line_no;
1473 tmargin = env_stack[env_sp].tmargin;
1474 if (out)
1475 switch (mode)
1476 {
1477 case 'H':
1478 html_verbatim_start (tag_end);
1479 break;
1480 case 'I':
1481 ipf_verbatim_start (tag_end);
1482 break;
1483 case 'L':
1484 latex_verbatim_start (tag_end);
1485 break;
1486 case 'T':
1487 text_verbatim_start (tag_end, &tmargin);
1488 break;
1489 }
1490 for (;;)
1491 {
1492 read_line ();
1493 if (end_of_file)
1494 switch (tag_end)
1495 {
1496 case TAG_ENDEXAMPLE:
1497 fatal ("%s:%d: Missing %cendexample",
1498 input_fname, start_line, escape);
1499 break;
1500 case TAG_ENDHEADERS:
1501 fatal ("%s:%d: Missing %cendheaders",
1502 input_fname, start_line, escape);
1503 break;
1504 case TAG_ENDSAMPLECODE:
1505 fatal ("%s:%d: Missing %cendsamplecode",
1506 input_fname, start_line, escape);
1507 break;
1508 case TAG_ENDVERBATIM:
1509 fatal ("%s:%d: Missing %cendverbatim",
1510 input_fname, start_line, escape);
1511 break;
1512 default:
1513 abort ();
1514 }
1515 p = input;
1516 if (parse_tag (&p) && tg_tag == tag_end)
1517 break;
1518 if (out)
1519 {
1520 switch (mode)
1521 {
1522 case 'H':
1523 html_verbatim_line ();
1524 break;
1525 case 'I':
1526 ipf_verbatim_line ();
1527 break;
1528 case 'L':
1529 case 'T':
1530 text_verbatim_line (tag_end, tmargin, compat);
1531 break;
1532 }
1533 }
1534 }
1535 if (out)
1536 switch (mode)
1537 {
1538 case 'H':
1539 html_verbatim_end (tag_end);
1540 break;
1541 case 'I':
1542 ipf_verbatim_end (tag_end);
1543 break;
1544 case 'L':
1545 latex_verbatim_end (tag_end);
1546 break;
1547 case 'T':
1548 para_flag = TRUE;
1549 break;
1550 }
1551 read_line ();
1552}
1553
1554
1555static void do_table (const uchar *p)
1556{
1557 int start_line, tmargin, wn;
1558 int do_indent;
1559 uchar word[512], *d;
1560 int widths[20];
1561 char *tmp;
1562 long n;
1563
1564 check_copy ();
1565 para_flag = FALSE;
1566 start_line = line_no;
1567 tmargin = env_stack[env_sp].tmargin;
1568 do_indent = FALSE; wn = 0;
1569 while (*p != 0)
1570 {
1571 d = word;
1572 while (*p != 0 && !isspace (*p))
1573 *d++ = *p++;
1574 *d = 0;
1575 if (strcmp (word, "indent") == 0)
1576 do_indent = TRUE;
1577 else if (isdigit (word[0]))
1578 {
1579 errno = 0;
1580 n = strtol (word, &tmp, 10);
1581 if (errno != 0 || *tmp != 0)
1582 fatal ("%s:%d: Invalid %ctable width",
1583 input_fname, line_no, escape);
1584 widths[wn++] = (int)n;
1585 }
1586 else
1587 fatal ("%s:%d: Invalid %ctable attribute",
1588 input_fname, line_no, escape);
1589 while (isspace (*p))
1590 ++p;
1591 }
1592
1593 if (out)
1594 switch (mode)
1595 {
1596 case 'H':
1597 fatal ("%ctable not yet implemented for HTML", escape);
1598 case 'I':
1599 ipf_table_start (do_indent, widths, wn);
1600 break;
1601 case 'L':
1602 fatal ("%ctable not yet implemented for LaTeX", escape);
1603 case 'T':
1604 text_table_start (do_indent, &tmargin);
1605 break;
1606 }
1607 for (;;)
1608 {
1609 read_line ();
1610 if (end_of_file)
1611 fatal ("%s:%d: Missing %cendtable", input_fname, start_line, escape);
1612 p = input;
1613 if (parse_tag (&p))
1614 {
1615 if (tg_tag == TAG_ENDTABLE)
1616 break;
1617 fatal ("%s%d: %cendtable expected", input_fname, line_no, escape);
1618 }
1619 if (out)
1620 {
1621 p = input;
1622 while (isspace (*p))
1623 ++p;
1624 switch (mode)
1625 {
1626 case 'I':
1627 ipf_table_line (p, wn);
1628 break;
1629 case 'T':
1630 text_table_line (p, tmargin);
1631 break;
1632 }
1633 }
1634 }
1635 if (out)
1636 switch (mode)
1637 {
1638 case 'I':
1639 ipf_table_end (do_indent);
1640 break;
1641 case 'T':
1642 para_flag = TRUE;
1643 break;
1644 }
1645 read_line ();
1646}
1647
1648
1649static void do_ipf (void)
1650{
1651 int start_line;
1652 const uchar *p;
1653
1654 start_line = line_no;
1655 for (;;)
1656 {
1657 read_line ();
1658 if (end_of_file)
1659 fatal ("%s:%d: Missing %cendipf", input_fname, start_line, escape);
1660 p = input;
1661 if (parse_tag (&p) && tg_tag == TAG_ENDIPF)
1662 break;
1663 if (out && mode == 'I' && output_flag)
1664 {
1665 fprintf (output_file, "%s\n", input);
1666 output_x = 0; ++output_line_no;
1667 }
1668 }
1669 read_line ();
1670}
1671
1672
1673static void do_text (void)
1674{
1675 int start_line;
1676 const uchar *p;
1677
1678 start_line = line_no;
1679 for (;;)
1680 {
1681 read_line ();
1682 if (end_of_file)
1683 fatal ("%s:%d: Missing %cendtext", input_fname, start_line, escape);
1684 p = input;
1685 if (parse_tag (&p) && tg_tag == TAG_ENDTEXT)
1686 break;
1687 if (out && mode == 'T' && output_flag)
1688 {
1689 fprintf (output_file, "%s\n", input);
1690 output_x = 0; ++output_line_no;
1691 }
1692 }
1693 read_line ();
1694}
1695
1696
1697static void do_latex (void)
1698{
1699 int start_line;
1700 const uchar *p;
1701
1702 start_line = line_no;
1703 for (;;)
1704 {
1705 read_line ();
1706 if (end_of_file)
1707 fatal ("%s:%d: Missing %cendlatex", input_fname, start_line, escape);
1708 p = input;
1709 if (parse_tag (&p) && tg_tag == TAG_ENDLATEX)
1710 break;
1711 if (out && mode == 'L' && output_flag)
1712 {
1713 fprintf (output_file, "%s\n", input);
1714 output_x = 0; ++output_line_no;
1715 }
1716 }
1717 read_line ();
1718}
1719
1720
1721static void do_html (void)
1722{
1723 int start_line;
1724 const uchar *p;
1725
1726 start_line = line_no;
1727 for (;;)
1728 {
1729 read_line ();
1730 if (end_of_file)
1731 fatal ("%s:%d: Missing %cendhtml", input_fname, start_line, escape);
1732 p = input;
1733 if (parse_tag (&p) && tg_tag == TAG_ENDHTML)
1734 break;
1735 if (out && mode == 'H' && output_flag)
1736 {
1737 fprintf (output_file, "%s\n", input);
1738 output_x = 0; ++output_line_no;
1739 }
1740 }
1741 read_line ();
1742}
1743
1744
1745static void do_label (const uchar *p)
1746{
1747 if (!out)
1748 {
1749 if (toc_ptr == NULL)
1750 fatal ("%s:%d: Cannot use %clabel before %ch1",
1751 input_fname, line_no, escape, escape);
1752 define_label (p, toc_ptr->ref, "Label");
1753 }
1754 read_line ();
1755}
1756
1757
1758static void do_index (const uchar *p)
1759{
1760 if (toc_ptr == NULL)
1761 fatal ("%s:%d: Cannot use %cindex before %ch1",
1762 input_fname, line_no, escape, escape);
1763 switch (mode)
1764 {
1765 case 'H':
1766 html_index (toc_ptr, p, tg_level);
1767 break;
1768 case 'I':
1769 ipf_index (p);
1770 break;
1771 case 'L':
1772 latex_index (p, tg_level);
1773 break;
1774 }
1775 read_line ();
1776}
1777
1778
1779static void do_keyword (const uchar *p)
1780{
1781 switch (mode)
1782 {
1783 case 'K':
1784 keywords_keyword (p);
1785 break;
1786 }
1787 read_line ();
1788}
1789
1790
1791static void do_item (const uchar *p)
1792{
1793 switch (env_stack[env_sp].env)
1794 {
1795 case ENV_DESCRIPTION:
1796 para_flag = FALSE;
1797 if (out)
1798 switch (mode)
1799 {
1800 case 'H':
1801 html_description_item (p);
1802 break;
1803 case 'I':
1804 ipf_description_item (p);
1805 break;
1806 case 'L':
1807 latex_description_item (p);
1808 break;
1809 case 'T':
1810 text_description_item (p);
1811 break;
1812 }
1813 break;
1814 case ENV_ENUMERATE:
1815 para_flag = FALSE;
1816 if (*p != 0)
1817 fatal ("%s:%d: %citem of %cenumerate doesn't take an argument",
1818 input_fname, line_no, escape, escape);
1819 if (out)
1820 switch (mode)
1821 {
1822 case 'H':
1823 html_enumerate_item ();
1824 break;
1825 case 'I':
1826 ipf_enumerate_item ();
1827 break;
1828 case 'L':
1829 latex_enumerate_item ();
1830 break;
1831 case 'T':
1832 text_enumerate_item ();
1833 break;
1834 }
1835 break;
1836 case ENV_ITEMIZE:
1837 para_flag = FALSE;
1838 if (*p != 0)
1839 fatal ("%s:%d: %citem of %citemize doesn't take an argument",
1840 input_fname, line_no, escape, escape);
1841 if (out)
1842 switch (mode)
1843 {
1844 case 'H':
1845 html_itemize_item ();
1846 break;
1847 case 'I':
1848 ipf_itemize_item ();
1849 break;
1850 case 'L':
1851 latex_itemize_item ();
1852 break;
1853 case 'T':
1854 text_itemize_item ();
1855 break;
1856 }
1857 break;
1858 case ENV_LIST:
1859 para_flag = FALSE;
1860 if (out)
1861 switch (mode)
1862 {
1863 case 'H':
1864 html_list_item (p);
1865 break;
1866 case 'I':
1867 ipf_list_item (p);
1868 break;
1869 case 'L':
1870 latex_list_item (p);
1871 break;
1872 case 'T':
1873 text_list_item (p);
1874 break;
1875 }
1876 break;
1877 default:
1878 fatal ("%s:%d: %citem outside environment",
1879 input_fname, line_no, escape);
1880 }
1881 read_line ();
1882}
1883
1884
1885static void do_prototype (void)
1886{
1887 int start_line, tmargin;
1888 const uchar *p;
1889 struct element *ep;
1890
1891 start_line = line_no;
1892 tmargin = env_stack[env_sp].tmargin;
1893 prototype_flag = TRUE;
1894 if (out)
1895 {
1896 make_elements_start ();
1897 switch (mode)
1898 {
1899 case 'H':
1900 html_prototype_start ();
1901 break;
1902 case 'I':
1903 ipf_prototype_start ();
1904 break;
1905 case 'L':
1906 latex_prototype_start ();
1907 break;
1908 case 'T':
1909 text_prototype_start (compat);
1910 break;
1911 }
1912 }
1913 for (;;)
1914 {
1915 read_line ();
1916 if (end_of_file)
1917 fatal ("%s:%d: Missing %cendprototype",
1918 input_fname, start_line, escape);
1919 p = input;
1920 if (parse_tag (&p))
1921 {
1922 if (tg_tag == TAG_ENDPROTOTYPE)
1923 break;
1924 else
1925 fatal ("%s:%d: %cendprototype expected",
1926 input_fname, line_no, escape);
1927 }
1928 if (out)
1929 {
1930 make_elements_internal (input);
1931 ep = add_element ();
1932 ep->el = EL_BREAK;
1933 ep->n = 1;
1934 }
1935 }
1936 if (out)
1937 {
1938 make_elements_end ();
1939 switch (mode)
1940 {
1941 case 'H':
1942 html_prototype_end (compat);
1943 break;
1944 case 'I':
1945 ipf_prototype_end (compat);
1946 break;
1947 case 'L':
1948 latex_prototype_end (compat);
1949 break;
1950 case 'T':
1951 text_prototype_end ();
1952 break;
1953 }
1954 }
1955 prototype_flag = FALSE;
1956 para_flag = TRUE;
1957 read_line ();
1958}
1959
1960
1961static void do_see_also (const uchar *p)
1962{
1963 uchar word[512], *d, *o;
1964
1965 if (out)
1966 {
1967 while (isspace (*p))
1968 ++p;
1969 o = output; *o = 0;
1970 switch (mode)
1971 {
1972 case 'H':
1973 html_see_also_start ();
1974 break;
1975 case 'I':
1976 ipf_see_also_start ();
1977 break;
1978 case 'L':
1979 latex_see_also_start ();
1980 break;
1981 case 'T':
1982 text_see_also_start ();
1983 break;
1984 }
1985 while (*p != 0)
1986 {
1987 d = word;
1988 while (*p != 0 && !isspace (*p))
1989 *d++ = *p++;
1990 *d = 0;
1991 while (isspace (*p))
1992 ++p;
1993 switch (mode)
1994 {
1995 case 'H':
1996 html_see_also_word (word, p);
1997 break;
1998 case 'I':
1999 ipf_see_also_word (word, p);
2000 break;
2001 case 'L':
2002 latex_see_also_word (word, p);
2003 break;
2004 case 'T':
2005 strcpy (o, word);
2006 if (*p != 0)
2007 strcat (o, ", ");
2008 o = strchr (o, 0);
2009 break;
2010 }
2011 }
2012 switch (mode)
2013 {
2014 case 'T':
2015 text_see_also_end (output);
2016 break;
2017 }
2018 para_flag = TRUE;
2019 }
2020 read_line ();
2021}
2022
2023
2024static void do_param (const uchar *p)
2025{
2026 uchar word[512], *d;
2027 struct word *wp;
2028
2029 if (out)
2030 {
2031 while (*p != 0)
2032 {
2033 d = word;
2034 while (*p != 0 && !isspace (*p))
2035 *d++ = *p++;
2036 *d = 0;
2037 while (isspace (*p))
2038 ++p;
2039 wp = word_add (word);
2040 local_add (wp);
2041 wp->style = STYLE_PARAM;
2042 }
2043 }
2044 read_line ();
2045}
2046
2047
2048static void do_sample_file (const uchar *p)
2049{
2050 if (out)
2051 {
2052 while (isspace (*p))
2053 ++p;
2054 switch (mode)
2055 {
2056 case 'H':
2057 html_sample_file (p);
2058 break;
2059 case 'I':
2060 ipf_sample_file (p);
2061 break;
2062 case 'L':
2063 latex_sample_file (p);
2064 break;
2065 case 'T':
2066 text_sample_file (p);
2067 break;
2068 }
2069 }
2070 read_line ();
2071}
2072
2073
2074static void do_libref_section (const uchar *text)
2075{
2076 if (out)
2077 {
2078 switch (mode)
2079 {
2080 case 'H':
2081 html_libref_section (text);
2082 break;
2083 case 'I':
2084 ipf_libref_section (text);
2085 break;
2086 case 'L':
2087 latex_libref_section (text);
2088 break;
2089 case 'T':
2090 text_libref_section (text);
2091 break;
2092 }
2093 }
2094 read_line ();
2095}
2096
2097
2098static void do_function (const uchar *p)
2099{
2100 uchar word[512], *d, *o;
2101 struct word *wp;
2102
2103 local_end ();
2104 local_begin ();
2105 if (out)
2106 {
2107 toc_ptr = (toc_ptr == NULL ? toc_head : toc_ptr->next);
2108 assert (toc_ptr != NULL);
2109 switch (mode)
2110 {
2111 case 'H':
2112 html_function_start (toc_ptr);
2113 break;
2114 case 'I':
2115 ipf_function_start (toc_ptr);
2116 break;
2117 case 'L':
2118 latex_function_start (toc_ptr);
2119 break;
2120 case 'T':
2121 text_function ();
2122 break;
2123 }
2124 para_flag = FALSE;
2125 }
2126 else
2127 new_section (2, 0);
2128
2129 o = output; *o = 0; function_count = 0;
2130 while (isspace (*p))
2131 ++p;
2132 while (*p != 0)
2133 {
2134 ++function_count;
2135 d = word;
2136 while (*p != 0 && !isspace (*p))
2137 *d++ = *p++;
2138 *d = 0;
2139 while (isspace (*p))
2140 ++p;
2141 switch (mode)
2142 {
2143 case 'H':
2144 html_function_function (toc_ptr, word);
2145 break;
2146 case 'I':
2147 ipf_function_function (word);
2148 break;
2149 case 'L':
2150 latex_function_function (word);
2151 break;
2152 }
2153 if (!out)
2154 {
2155 wp = define_label (word, toc_ptr->ref, "Function");
2156 /* Don't set format of variables, timezone! */
2157 if (strstr (word, "()") != NULL)
2158 wp->style = STYLE_TTY;
2159 if (o != output)
2160 {
2161 if (*p == 0)
2162 strcpy (o, " and ");
2163 else
2164 strcpy (o, ", ");
2165 }
2166 strcat (o, word);
2167 o = strchr (o, 0);
2168 switch (mode)
2169 {
2170 case 'K':
2171 write_keyword (word);
2172 break;
2173 }
2174 }
2175 }
2176 if (!out)
2177 toc_ptr->title = xstrdup (output);
2178 read_line ();
2179}
2180
2181
2182static void do_compat (const uchar *p)
2183{
2184 while (isspace (*p))
2185 ++p;
2186 strcpy (compat, p);
2187 read_line ();
2188}
2189
2190
2191static void do_tag (const uchar *p)
2192{
2193 switch (tg_tag)
2194 {
2195 case TAG_HEADING:
2196 local_end ();
2197 if (out)
2198 do_heading_out (p);
2199 else
2200 {
2201 if (env_sp != 0)
2202 nonfatal ("%s:%d: Heading within environment",
2203 input_fname, line_no);
2204 do_heading_def (p);
2205 }
2206 read_line ();
2207 break;
2208
2209 case TAG_TOC:
2210 if (out)
2211 do_toc_out (p);
2212 read_line ();
2213 break;
2214
2215 case TAG_HTMLFRAGMENT:
2216 if (out && mode == 'H')
2217 html_fragment (p);
2218 read_line ();
2219 break;
2220
2221 case TAG_IPFMINITOC:
2222 if (out && mode == 'I')
2223 ipf_minitoc (toc_ptr);
2224 read_line ();
2225 break;
2226
2227 case TAG_HTMLMINITOC:
2228 if (out && mode == 'H')
2229 html_minitoc (toc_ptr);
2230 read_line ();
2231 break;
2232
2233 case TAG_MINITOC:
2234 if (out)
2235 switch (mode)
2236 {
2237 case 'H':
2238 html_minitoc (toc_ptr);
2239 break;
2240 case 'I':
2241 ipf_minitoc (toc_ptr);
2242 break;
2243 }
2244 read_line ();
2245 break;
2246
2247 case TAG_TITLE:
2248 if (!out)
2249 title = xstrdup (p);
2250 read_line ();
2251 break;
2252
2253 case TAG_LANGUAGE:
2254 do_language (p);
2255 break;
2256
2257 case TAG_SYNTAX:
2258 do_syntax (p);
2259 break;
2260
2261 case TAG_ITEM:
2262 do_item (p);
2263 break;
2264
2265 case TAG_IPF:
2266 do_ipf ();
2267 break;
2268
2269 case TAG_TEXT:
2270 do_text ();
2271 break;
2272
2273 case TAG_LATEX:
2274 do_latex ();
2275 break;
2276
2277 case TAG_HTML:
2278 do_html ();
2279 break;
2280
2281 case TAG_LABEL:
2282 do_label (p);
2283 break;
2284
2285 case TAG_INDEX:
2286 do_index (p);
2287 break;
2288
2289 case TAG_KEYWORD:
2290 do_keyword (p);
2291 break;
2292
2293 case TAG_FORMAT:
2294 do_format (p);
2295 break;
2296
2297 case TAG_SPECIAL:
2298 do_special (p);
2299 break;
2300
2301 case TAG_REPLACE:
2302 do_replace (p);
2303 break;
2304
2305 case TAG_SET:
2306 do_set (p);
2307 break;
2308
2309 case TAG_DESCRIPTION:
2310 do_description ();
2311 break;
2312
2313 case TAG_ENDDESCRIPTION:
2314 do_end_env (ENV_DESCRIPTION);
2315 break;
2316
2317 case TAG_ENUMERATE:
2318 do_enumerate ();
2319 break;
2320
2321 case TAG_ENDENUMERATE:
2322 do_end_env (ENV_ENUMERATE);
2323 break;
2324
2325 case TAG_ITEMIZE:
2326 do_itemize ();
2327 break;
2328
2329 case TAG_ENDITEMIZE:
2330 do_end_env (ENV_ITEMIZE);
2331 break;
2332
2333 case TAG_LIST:
2334 do_list ();
2335 break;
2336
2337 case TAG_ENDLIST:
2338 do_end_env (ENV_LIST);
2339 break;
2340
2341 case TAG_INDENT:
2342 do_indent (ENV_INDENT);
2343 break;
2344
2345 case TAG_ENDINDENT:
2346 do_end_env (ENV_INDENT);
2347 break;
2348
2349 case TAG_TYPEWRITER:
2350 do_indent (ENV_TYPEWRITER);
2351 break;
2352
2353 case TAG_ENDTYPEWRITER:
2354 do_end_env (ENV_TYPEWRITER);
2355 break;
2356
2357 case TAG_EXAMPLE:
2358 do_verbatim (TAG_ENDEXAMPLE);
2359 break;
2360
2361 case TAG_SAMPLECODE:
2362 do_verbatim (TAG_ENDSAMPLECODE);
2363 break;
2364
2365 case TAG_HEADERS:
2366 do_verbatim (TAG_ENDHEADERS);
2367 break;
2368
2369 case TAG_PROTOTYPE:
2370 do_prototype ();
2371 break;
2372
2373 case TAG_VERBATIM:
2374 do_verbatim (TAG_ENDVERBATIM);
2375 break;
2376
2377 case TAG_TABLE:
2378 do_table (p);
2379 break;
2380
2381 case TAG_SEEALSO:
2382 do_see_also (p);
2383 break;
2384
2385 case TAG_FUNCTION:
2386 do_function (p);
2387 break;
2388
2389 case TAG_PARAM:
2390 do_param (p);
2391 break;
2392
2393 case TAG_COMPAT:
2394 do_compat (p);
2395 break;
2396
2397 case TAG_SAMPLEFILE:
2398 do_sample_file (p);
2399 break;
2400
2401 case TAG_RESTRICTIONS:
2402 do_libref_section ("Restrictions");
2403 break;
2404
2405 case TAG_IMPLEMENTATION:
2406 do_libref_section ("Implementation-defined behavior");
2407 break;
2408
2409 case TAG_BUGS:
2410 do_libref_section ("Bugs");
2411 break;
2412
2413 case TAG_ERRORS:
2414 do_libref_section ("Errors");
2415 break;
2416
2417 case TAG_HINTS:
2418 do_libref_section ("Hints");
2419 break;
2420
2421 case TAG_RETURNVALUE:
2422 do_libref_section ("Return value");
2423 break;
2424
2425 default:
2426 fatal ("%s:%d: Unexpected tag", input_fname, line_no);
2427 }
2428}
2429
2430
2431static void do_copy (void)
2432{
2433 size_t len;
2434 const uchar *p;
2435 int space, col1_warn;
2436
2437 line_len = 0; space = FALSE; col1_warn = FALSE;
2438 do
2439 {
2440 if (out)
2441 {
2442 p = input;
2443 while (isspace (*p))
2444 ++p;
2445 if (p == input && !col1_warn)
2446 {
2447 col1_warn = TRUE;
2448 warning (1, "%s:%d: Text starting in first column",
2449 input_fname, line_no);
2450 }
2451 len = strlen (p);
2452 while (len > 0 && isspace (p[len-1]))
2453 --len;
2454 if (len > 0)
2455 {
2456 if (space)
2457 line_add (" ", 1);
2458 line_add (p, len);
2459 }
2460 space = TRUE;
2461 }
2462 read_line ();
2463 p = input;
2464 } while (!end_of_file && input[0] != 0 && !parse_tag (&p));
2465 if (out)
2466 {
2467 make_elements (line);
2468 switch (mode)
2469 {
2470 case 'H':
2471 html_copy ();
2472 break;
2473 case 'I':
2474 ipf_copy ();
2475 break;
2476 case 'L':
2477 latex_copy ();
2478 break;
2479 case 'T':
2480 text_copy ();
2481 break;
2482 }
2483 }
2484 para_flag = TRUE; copy_flag = TRUE;
2485}
2486
2487
2488static void do_empty_line (void)
2489{
2490 read_line ();
2491}
2492
2493
2494void start_index (void)
2495{
2496 const char *text = "Index";
2497 local_end ();
2498 tg_level = 1; tg_flags = 0;
2499 if (out)
2500 do_heading_out (text);
2501 else
2502 do_heading_def (text);
2503}
2504
2505
2506static void init (void)
2507{
2508 word_top = wt_new (997);
2509}
2510
2511
2512void init_file (void)
2513{
2514 int i;
2515
2516 for (i = 0; i < SECTION_LEVELS; ++i)
2517 section_numbers[i] = 0;
2518 toc_ptr = NULL;
2519
2520 if (out)
2521 switch (mode)
2522 {
2523 case 'H':
2524 html_start ();
2525 break;
2526 case 'I':
2527 ipf_start ();
2528 break;
2529 case 'L':
2530 latex_start ();
2531 break;
2532 }
2533
2534 para_flag = FALSE;
2535 env_sp = 0;
2536 env_stack[env_sp].env = ENV_NONE;
2537 env_stack[env_sp].tmargin = 0;
2538 env_stack[env_sp].imargin = 1;
2539 env_stack[env_sp].start_line = 0;
2540 local_sp = 0;
2541 hl_ipf = 0;
2542 hl_ipf_no = 0;
2543 hl_sp = 0;
2544 hl_stack[hl_sp] = 0;
2545 output_x = 0; output_line_no = 1;
2546 compat[0] = 0;
2547 syntax_style = SYNTAX_EMX;
2548 copy_flag = TRUE;
2549}
2550
2551
2552static void end_file (void)
2553{
2554 switch (mode)
2555 {
2556 case 'H':
2557 html_end ();
2558 break;
2559 case 'I':
2560 ipf_end ();
2561 break;
2562 case 'L':
2563 latex_end ();
2564 break;
2565 }
2566 if (env_sp != 0)
2567 fatal ("%s:%d: Environment not terminated",
2568 input_fname, env_stack[env_sp].start_line);
2569}
2570
2571
2572static void read_file (const char *name)
2573{
2574 const uchar *p;
2575
2576 if (xref_fname != NULL)
2577 read_xref (xref_fname, toc_head);
2578 open_input (name);
2579 init_file ();
2580 read_line ();
2581 while (!end_of_file)
2582 {
2583 p = input;
2584 if (input[0] == 0)
2585 do_empty_line ();
2586 else if (parse_tag (&p))
2587 do_tag (p);
2588 else
2589 do_copy ();
2590 }
2591 end_file ();
2592 fclose (input_file);
2593}
2594
2595
2596static void cleanup (void)
2597{
2598 if (output_fname != NULL && output_file != stdout && output_file != NULL)
2599 {
2600 fclose (output_file);
2601 output_file = NULL;
2602 remove (output_fname);
2603 output_fname = NULL;
2604 }
2605}
2606
2607
2608static int opt_number (void)
2609{
2610 int result;
2611 char *tmp;
2612
2613 errno = 0;
2614 result = (int)strtol (optarg, &tmp, 0);
2615 if (errno != 0 || *tmp != 0)
2616 usage ();
2617 return result;
2618}
2619
2620static enum enc opt_encoding (void)
2621{
2622 if (strcmp (optarg, "cp850") == 0)
2623 return ENC_CP850;
2624 else if (strcmp (optarg, "iso8859-1") == 0)
2625 return ENC_ISO8859_1;
2626 else
2627 fatal ("Invalid encoding: %s", optarg);
2628}
2629
2630int main (int argc, char *argv[])
2631{
2632 int c, i;
2633
2634 init ();
2635
2636 while ((c = getopt (argc, argv, ":?HIKLMTab:ce:fgh:i:j:n:o:rw:x:")) != EOF)
2637 switch (c)
2638 {
2639 case '?':
2640 usage ();
2641 case 'H':
2642 case 'I':
2643 case 'K':
2644 case 'L':
2645 case 'M':
2646 case 'T':
2647 mode = (char)c;
2648 break;
2649 case 'a':
2650 opt_a = TRUE;
2651 break;
2652 case 'b':
2653 opt_b = opt_number ();
2654 if (opt_b < 0 || opt_b > 1)
2655 fatal ("Invalid argument for -b (line breaking algorithm)");
2656 break;
2657 case 'c':
2658 opt_c = TRUE;
2659 break;
2660 case 'e':
2661 if (strlen (optarg) == 1 && !isdigit ((uchar)*optarg))
2662 escape = *optarg;
2663 else
2664 {
2665 i = opt_number ();
2666 if (i < 1 || i > 255)
2667 fatal ("Invalid argument for -e (escape character)");
2668 escape = (uchar)i;
2669 }
2670 break;
2671 case 'f':
2672 opt_f = TRUE;
2673 break;
2674 case 'g':
2675 opt_g = TRUE;
2676 break;
2677 case 'h':
2678 hyphenation_fname = optarg;
2679 break;
2680 case 'i':
2681 input_encoding = opt_encoding ();
2682 break;
2683 case 'j':
2684 output_encoding = opt_encoding ();
2685 break;
2686 case 'n':
2687 ref_no = opt_number ();
2688 break;
2689 case 'o':
2690 output_fname = optarg;
2691 break;
2692 case 'r':
2693 opt_r = TRUE;
2694 break;
2695 case 'w':
2696 opt_w = opt_number ();
2697 break;
2698 case 'x':
2699 xref_fname = optarg;
2700 break;
2701 case ':':
2702 fatal ("Missing argument for option -%c", optopt);
2703 default:
2704 fatal ("Invalid option: -%c", optopt);
2705 }
2706
2707 if (mode == 0)
2708 usage ();
2709 if (mode != 'I' && (opt_c || opt_g))
2710 usage ();
2711 if (mode != 'I' && mode != 'H' && xref_fname != NULL)
2712 usage ();
2713 if ((mode == 'H' || mode == 'I') && output_encoding != ENC_DEFAULT)
2714 warning (0, "Output encoding ignored for -H and -I");
2715
2716 argv += optind;
2717 argc -= optind;
2718
2719 if (argc != 1 && mode != 'M')
2720 usage ();
2721
2722 atexit (cleanup);
2723
2724 switch (mode)
2725 {
2726 case 'T':
2727 max_width = 79;
2728 output_flag = TRUE;
2729 if (hyphenation_fname != NULL)
2730 text_hyphenation (hyphenation_fname);
2731 if (output_encoding == ENC_DEFAULT)
2732 output_encoding = input_encoding;
2733 break;
2734 case 'I':
2735 max_width = 250;
2736 output_flag = !opt_g;
2737 output_encoding = ENC_CP850;
2738 break;
2739 case 'H':
2740 max_width = 4096;
2741 output_flag = TRUE;
2742 output_encoding = ENC_ISO8859_1;
2743 break;
2744 case 'L':
2745 max_width = 4096;
2746 output_flag = TRUE;
2747 if (output_encoding == ENC_DEFAULT)
2748 output_encoding = input_encoding;
2749 break;
2750 case 'K':
2751 case 'M':
2752 output_flag = FALSE;
2753 if (output_encoding == ENC_DEFAULT)
2754 output_encoding = input_encoding;
2755 break;
2756 default:
2757 abort ();
2758 }
2759
2760 if (output_fname == NULL)
2761 {
2762 output_fname = "<stdout>";
2763 output_file = stdout;
2764 }
2765 else
2766 {
2767 if (opt_r)
2768 {
2769 chmod (output_fname, 0666);
2770 remove (output_fname);
2771 }
2772 output_file = fopen (output_fname, "wt");
2773 if (output_file == NULL)
2774 {
2775 perror (output_fname);
2776 return 1;
2777 }
2778 }
2779
2780 switch (mode)
2781 {
2782 case 'H':
2783 case 'I':
2784 case 'T':
2785 case 'L':
2786 out = FALSE;
2787 read_file (argv[0]);
2788 out = TRUE;
2789 read_file (argv[0]);
2790 break;
2791 case 'K':
2792 keywords_start (argv[0]);
2793 out = FALSE;
2794 read_file (argv[0]);
2795 break;
2796 case 'M':
2797 out = FALSE;
2798 for (i = 0; i < argc; ++i)
2799 make_global (argv[i]);
2800 out = TRUE;
2801 for (i = 0; i < argc; ++i)
2802 make_global (argv[i]);
2803 break;
2804 }
2805
2806 if (fflush (output_file) != 0 || fclose (output_file) != 0)
2807 {
2808 perror (output_fname);
2809 return 1;
2810 }
2811 output_file = NULL;
2812
2813 if (opt_r)
2814 chmod (output_fname, 0444);
2815
2816 return history;
2817}
Note: See TracBrowser for help on using the repository browser.