source: trunk/emx/src/emxdoc/emxdoc.c

Last change on this file was 244, checked in by bird, 22 years ago

Branding/buildtimestamp.

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