Fix previous commit.
[pwmd.git] / doc / yat2m.c
blob23fc6babd53af58b60fd19268c4b084bf4dd0673
1 /* yat2m.c - Yet Another Texi 2 Man converter
2 * Copyright (C) 2005, 2013, 2015, 2016 g10 Code GmbH
3 * Copyright (C) 2006, 2008, 2011 Free Software Foundation, Inc.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <https://www.gnu.org/licenses/>.
20 This is a simple texinfo to man page converter. It needs some
21 special markup in th e texinfo and tries best to get a create man
22 page. It has been designed for the GnuPG man pages and thus only
23 a few texinfo commands are supported.
25 To use this you need to add the following macros into your texinfo
26 source:
28 @macro manpage {a}
29 @end macro
30 @macro mansect {a}
31 @end macro
32 @macro manpause
33 @end macro
34 @macro mancont
35 @end macro
37 They are used by yat2m to select parts of the Texinfo which should
38 go into the man page. These macros need to be used without leading
39 left space. Processing starts after a "manpage" macro has been
40 seen. "mansect" identifies the section and yat2m make sure to
41 emit the sections in the proper order. Note that @mansect skips
42 the next input line if that line begins with @section, @subsection or
43 @chapheading.
45 To insert verbatim troff markup, the following texinfo code may be
46 used:
48 @ifset manverb
49 .B whateever you want
50 @end ifset
52 alternativly a special comment may be used:
54 @c man:.B whatever you want
56 This is useful in case you need just one line. If you want to
57 include parts only in the man page but keep the texinfo
58 translation you may use:
60 @ifset isman
61 stuff to be rendered only on man pages
62 @end ifset
64 or to exclude stuff from man pages:
66 @ifclear isman
67 stuff not to be rendered on man pages
68 @end ifclear
70 the keyword @section is ignored, however @subsection gets rendered
71 as ".SS". @menu is completely skipped. Several man pages may be
72 extracted from one file, either using the --store or the --select
73 option.
75 If you want to indent tables in the source use this style:
77 @table foo
78 @item
79 @item
80 @table
81 @item
82 @end
83 @end
85 Don't change the indentation within a table and keep the same
86 number of white space at the start of the line. yat2m simply
87 detects the number of white spaces in front of an @item and remove
88 this number of spaces from all following lines until a new @item
89 is found or there are less spaces than for the last @item.
91 Note that @* does only work correctly if used at the end of an
92 input line.
96 #include <stdio.h>
97 #include <stdlib.h>
98 #include <stddef.h>
99 #include <string.h>
100 #include <errno.h>
101 #include <stdarg.h>
102 #include <assert.h>
103 #include <ctype.h>
104 #include <time.h>
107 #if __GNUC__
108 # define MY_GCC_VERSION (__GNUC__ * 10000 \
109 + __GNUC_MINOR__ * 100 \
110 + __GNUC_PATCHLEVEL__)
111 #else
112 # define MY_GCC_VERSION 0
113 #endif
115 #if MY_GCC_VERSION >= 20500
116 # define ATTR_PRINTF(f, a) __attribute__ ((format(printf,f,a)))
117 # define ATTR_NR_PRINTF(f, a) __attribute__ ((noreturn, format(printf,f,a)))
118 #else
119 # define ATTR_PRINTF(f, a)
120 # define ATTR_NR_PRINTF(f, a)
121 #endif
122 #if MY_GCC_VERSION >= 30200
123 # define ATTR_MALLOC __attribute__ ((__malloc__))
124 #else
125 # define ATTR_MALLOC
126 #endif
130 #define PGM "yat2m"
131 #define VERSION "1.0"
133 /* The maximum length of a line including the linefeed and one extra
134 character. */
135 #define LINESIZE 1024
137 /* Number of allowed condition nestings. */
138 #define MAX_CONDITION_NESTING 10
140 /* Option flags. */
141 static int verbose;
142 static int quiet;
143 static int debug;
144 static const char *opt_source;
145 static const char *opt_release;
146 static const char *opt_date;
147 static const char *opt_select;
148 static const char *opt_include;
149 static int opt_store;
151 /* Flag to keep track whether any error occurred. */
152 static int any_error;
155 /* Object to keep macro definitions. */
156 struct macro_s
158 struct macro_s *next;
159 char *value; /* Malloced value. */
160 char name[1];
162 typedef struct macro_s *macro_t;
164 /* List of all defined macros. */
165 static macro_t macrolist;
167 /* List of variables set by @set. */
168 static macro_t variablelist;
170 /* List of global macro names. The value part is not used. */
171 static macro_t predefinedmacrolist;
173 /* Object to keep track of @isset and @ifclear. */
174 struct condition_s
176 int manverb; /* "manverb" needs special treatment. */
177 int isset; /* This is an @isset condition. */
178 char name[1]; /* Name of the condition macro. */
180 typedef struct condition_s *condition_t;
182 /* The stack used to evaluate conditions. And the current states. */
183 static condition_t condition_stack[MAX_CONDITION_NESTING];
184 static int condition_stack_idx;
185 static int cond_is_active; /* State of ifset/ifclear */
186 static int cond_in_verbatim; /* State of "manverb". */
189 /* Object to store one line of content. */
190 struct line_buffer_s
192 struct line_buffer_s *next;
193 int verbatim; /* True if LINE contains verbatim data. The default
194 is Texinfo source. */
195 char *line;
197 typedef struct line_buffer_s *line_buffer_t;
200 /* Object to collect the data of a section. */
201 struct section_buffer_s
203 char *name; /* Malloced name of the section. This may be
204 NULL to indicate this slot is not used. */
205 line_buffer_t lines; /* Linked list with the lines of the section. */
206 line_buffer_t *lines_tail; /* Helper for faster appending to the
207 linked list. */
208 line_buffer_t last_line; /* Points to the last line appended. */
210 typedef struct section_buffer_s *section_buffer_t;
212 /* Variable to keep info about the current page together. */
213 static struct
215 /* Filename of the current page or NULL if no page is active. Malloced. */
216 char *name;
218 /* Number of allocated elements in SECTIONS below. */
219 size_t n_sections;
220 /* Array with the data of the sections. */
221 section_buffer_t sections;
223 } thepage;
226 /* The list of standard section names. COMMANDS and ASSUAN are GnuPG
227 specific. */
228 static const char * const standard_sections[] =
229 { "NAME", "SYNOPSIS", "DESCRIPTION",
230 "RETURN VALUE", "EXIT STATUS", "ERROR HANDLING", "ERRORS",
231 "COMMANDS", "OPTIONS", "USAGE", "EXAMPLES", "FILES",
232 "ENVIRONMENT", "DIAGNOSTICS", "SECURITY", "CONFORMING TO",
233 "ASSUAN", "NOTES", "BUGS", "AUTHOR", "SEE ALSO", NULL };
236 /*-- Local prototypes. --*/
237 static void proc_texi_buffer (FILE *fp, const char *line, size_t len,
238 int *table_level, int *eol_action);
240 static void die (const char *format, ...) ATTR_NR_PRINTF(1,2);
241 static void err (const char *format, ...) ATTR_PRINTF(1,2);
242 static void inf (const char *format, ...) ATTR_PRINTF(1,2);
243 static void *xmalloc (size_t n) ATTR_MALLOC;
244 static void *xcalloc (size_t n, size_t m) ATTR_MALLOC;
248 /*-- Functions --*/
250 /* Print diagnostic message and exit with failure. */
251 static void
252 die (const char *format, ...)
254 va_list arg_ptr;
256 fflush (stdout);
257 fprintf (stderr, "%s: ", PGM);
259 va_start (arg_ptr, format);
260 vfprintf (stderr, format, arg_ptr);
261 va_end (arg_ptr);
262 putc ('\n', stderr);
264 exit (1);
268 /* Print diagnostic message. */
269 static void
270 err (const char *format, ...)
272 va_list arg_ptr;
274 fflush (stdout);
275 if (strncmp (format, "%s:%d:", 6))
276 fprintf (stderr, "%s: ", PGM);
278 va_start (arg_ptr, format);
279 vfprintf (stderr, format, arg_ptr);
280 va_end (arg_ptr);
281 putc ('\n', stderr);
282 any_error = 1;
285 /* Print diagnostic message. */
286 static void
287 inf (const char *format, ...)
289 va_list arg_ptr;
291 fflush (stdout);
292 fprintf (stderr, "%s: ", PGM);
294 va_start (arg_ptr, format);
295 vfprintf (stderr, format, arg_ptr);
296 va_end (arg_ptr);
297 putc ('\n', stderr);
301 static void *
302 xmalloc (size_t n)
304 void *p = malloc (n);
305 if (!p)
306 die ("out of core: %s", strerror (errno));
307 return p;
310 static void *
311 xcalloc (size_t n, size_t m)
313 void *p = calloc (n, m);
314 if (!p)
315 die ("out of core: %s", strerror (errno));
316 return p;
319 static void *
320 xrealloc (void *old, size_t n)
322 void *p = realloc (old, n);
323 if (!p)
324 die ("out of core: %s", strerror (errno));
325 return p;
328 static char *
329 xstrdup (const char *string)
331 void *p = malloc (strlen (string)+1);
332 if (!p)
333 die ("out of core: %s", strerror (errno));
334 strcpy (p, string);
335 return p;
339 /* Uppercase the ascii characters in STRING. */
340 static char *
341 ascii_strupr (char *string)
343 char *p;
345 for (p = string; *p; p++)
346 if (!(*p & 0x80))
347 *p = toupper (*p);
348 return string;
352 /* Return the current date as an ISO string. */
353 const char *
354 isodatestring (void)
356 static char buffer[11+5];
357 struct tm *tp;
358 time_t atime;
360 if (opt_date && *opt_date)
361 atime = strtoul (opt_date, NULL, 10);
362 else
363 atime = time (NULL);
364 if (atime < 0)
365 strcpy (buffer, "????" "-??" "-??");
366 else
368 tp = gmtime (&atime);
369 sprintf (buffer,"%04d-%02d-%02d",
370 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
372 return buffer;
376 /* Add NAME to the list of predefined macros which are global for all
377 files. */
378 static void
379 add_predefined_macro (const char *name)
381 macro_t m;
383 for (m=predefinedmacrolist; m; m = m->next)
384 if (!strcmp (m->name, name))
385 break;
386 if (!m)
388 m = xcalloc (1, sizeof *m + strlen (name));
389 strcpy (m->name, name);
390 m->next = predefinedmacrolist;
391 predefinedmacrolist = m;
396 /* Create or update a macro with name MACRONAME and set its values TO
397 MACROVALUE. Note that ownership of the macro value is transferred
398 to this function. */
399 static void
400 set_macro (const char *macroname, char *macrovalue)
402 macro_t m;
404 for (m=macrolist; m; m = m->next)
405 if (!strcmp (m->name, macroname))
406 break;
407 if (m)
408 free (m->value);
409 else
411 m = xcalloc (1, sizeof *m + strlen (macroname));
412 strcpy (m->name, macroname);
413 m->next = macrolist;
414 macrolist = m;
416 m->value = macrovalue;
417 macrovalue = NULL;
421 /* Create or update a variable with name and value given in NAMEANDVALUE. */
422 static void
423 set_variable (char *nameandvalue)
425 macro_t m;
426 const char *value;
427 char *p;
429 for (p = nameandvalue; *p && *p != ' ' && *p != '\t'; p++)
431 if (!*p)
432 value = "";
433 else
435 *p++ = 0;
436 while (*p == ' ' || *p == '\t')
437 p++;
438 value = p;
441 for (m=variablelist; m; m = m->next)
442 if (!strcmp (m->name, nameandvalue))
443 break;
444 if (m)
445 free (m->value);
446 else
448 m = xcalloc (1, sizeof *m + strlen (nameandvalue));
449 strcpy (m->name, nameandvalue);
450 m->next = variablelist;
451 variablelist = m;
453 m->value = xstrdup (value);
457 /* Return true if the macro or variable NAME is set, i.e. not the
458 empty string and not evaluating to 0. */
459 static int
460 macro_set_p (const char *name)
462 macro_t m;
464 for (m = macrolist; m ; m = m->next)
465 if (!strcmp (m->name, name))
466 break;
467 if (!m)
468 for (m = variablelist; m ; m = m->next)
469 if (!strcmp (m->name, name))
470 break;
471 if (!m || !m->value || !*m->value)
472 return 0;
473 if ((*m->value & 0x80) || !isdigit (*m->value))
474 return 1; /* Not a digit but some other string. */
475 return !!atoi (m->value);
479 /* Evaluate the current conditions. */
480 static void
481 evaluate_conditions (const char *fname, int lnr)
483 int i;
485 /* for (i=0; i < condition_stack_idx; i++) */
486 /* inf ("%s:%d: stack[%d] %s %s %c", */
487 /* fname, lnr, i, condition_stack[i]->isset? "set":"clr", */
488 /* condition_stack[i]->name, */
489 /* (macro_set_p (condition_stack[i]->name) */
490 /* ^ !condition_stack[i]->isset)? 't':'f'); */
492 cond_is_active = 1;
493 cond_in_verbatim = 0;
494 if (condition_stack_idx)
496 for (i=0; i < condition_stack_idx; i++)
498 if (condition_stack[i]->manverb)
499 cond_in_verbatim = (macro_set_p (condition_stack[i]->name)
500 ^ !condition_stack[i]->isset);
501 else if (!(macro_set_p (condition_stack[i]->name)
502 ^ !condition_stack[i]->isset))
504 cond_is_active = 0;
505 break;
510 /* inf ("%s:%d: active=%d verbatim=%d", */
511 /* fname, lnr, cond_is_active, cond_in_verbatim); */
515 /* Push a condition with condition macro NAME onto the stack. If
516 ISSET is true, a @isset condition is pushed. */
517 static void
518 push_condition (const char *name, int isset, const char *fname, int lnr)
520 condition_t cond;
521 int manverb = 0;
523 if (condition_stack_idx >= MAX_CONDITION_NESTING)
525 err ("%s:%d: condition nested too deep", fname, lnr);
526 return;
529 if (!strcmp (name, "manverb"))
531 if (!isset)
533 err ("%s:%d: using \"@ifclear manverb\" is not allowed", fname, lnr);
534 return;
536 manverb = 1;
539 cond = xcalloc (1, sizeof *cond + strlen (name));
540 cond->manverb = manverb;
541 cond->isset = isset;
542 strcpy (cond->name, name);
544 condition_stack[condition_stack_idx++] = cond;
545 evaluate_conditions (fname, lnr);
549 /* Remove the last condition from the stack. ISSET is used for error
550 reporting. */
551 static void
552 pop_condition (int isset, const char *fname, int lnr)
554 if (!condition_stack_idx)
556 err ("%s:%d: unbalanced \"@end %s\"",
557 fname, lnr, isset?"isset":"isclear");
558 return;
560 condition_stack_idx--;
561 free (condition_stack[condition_stack_idx]);
562 condition_stack[condition_stack_idx] = NULL;
563 evaluate_conditions (fname, lnr);
568 /* Return a section buffer for the section NAME. Allocate a new buffer
569 if this is a new section. Keep track of the sections in THEPAGE.
570 This function may reallocate the section array in THEPAGE. */
571 static section_buffer_t
572 get_section_buffer (const char *name)
574 int i;
575 section_buffer_t sect;
577 /* If there is no section we put everything into the required NAME
578 section. Given that this is the first one listed it is likely
579 that error are easily visible. */
580 if (!name)
581 name = "NAME";
583 for (i=0; i < thepage.n_sections; i++)
585 sect = thepage.sections + i;
586 if (sect->name && !strcmp (name, sect->name))
587 return sect;
589 for (i=0; i < thepage.n_sections; i++)
590 if (!thepage.sections[i].name)
591 break;
592 if (thepage.n_sections && i < thepage.n_sections)
593 sect = thepage.sections + i;
594 else
596 /* We need to allocate or reallocate the section array. */
597 size_t old_n = thepage.n_sections;
598 size_t new_n = 20;
600 if (!old_n)
601 thepage.sections = xcalloc (new_n, sizeof *thepage.sections);
602 else
604 thepage.sections = xrealloc (thepage.sections,
605 ((old_n + new_n)
606 * sizeof *thepage.sections));
607 memset (thepage.sections + old_n, 0,
608 new_n * sizeof *thepage.sections);
610 thepage.n_sections += new_n;
612 /* Setup the tail pointers. */
613 for (i=old_n; i < thepage.n_sections; i++)
615 sect = thepage.sections + i;
616 sect->lines_tail = &sect->lines;
618 sect = thepage.sections + old_n;
621 /* Store the name. */
622 assert (!sect->name);
623 sect->name = xstrdup (name);
624 return sect;
629 /* Add the content of LINE to the section named SECTNAME. */
630 static void
631 add_content (const char *sectname, char *line, int verbatim)
633 section_buffer_t sect;
634 line_buffer_t lb;
636 sect = get_section_buffer (sectname);
637 if (sect->last_line && !sect->last_line->verbatim == !verbatim)
639 /* Lets append that line to the last one. We do this to keep
640 all lines of the same kind (i.e.verbatim or not) together in
641 one large buffer. */
642 size_t n1, n;
644 lb = sect->last_line;
645 n1 = strlen (lb->line);
646 n = n1 + 1 + strlen (line) + 1;
647 lb->line = xrealloc (lb->line, n);
648 strcpy (lb->line+n1, "\n");
649 strcpy (lb->line+n1+1, line);
651 else
653 lb = xcalloc (1, sizeof *lb);
654 lb->verbatim = verbatim;
655 lb->line = xstrdup (line);
656 sect->last_line = lb;
657 *sect->lines_tail = lb;
658 sect->lines_tail = &lb->next;
663 /* Prepare for a new man page using the filename NAME. */
664 static void
665 start_page (char *name)
667 if (verbose)
668 inf ("starting page '%s'", name);
669 assert (!thepage.name);
670 thepage.name = xstrdup (name);
671 thepage.n_sections = 0;
675 /* Write the .TH entry of the current page. Return -1 if there is a
676 problem with the page. */
677 static int
678 write_th (FILE *fp)
680 char *name, *p;
682 fputs (".\\\" Created from Texinfo source by yat2m " VERSION "\n", fp);
684 name = ascii_strupr (xstrdup (thepage.name));
685 p = strrchr (name, '.');
686 if (!p || !p[1])
688 err ("no section name in man page '%s'", thepage.name);
689 free (name);
690 return -1;
692 *p++ = 0;
693 fprintf (fp, ".TH %s %s %s \"%s\" \"%s\"\n",
694 name, p, isodatestring (), opt_release, opt_source);
695 free (name);
696 return 0;
700 /* Process the texinfo command COMMAND (without the leading @) and
701 write output if needed to FP. REST is the remainer of the line
702 which should either point to an opening brace or to a white space.
703 The function returns the number of characters already processed
704 from REST. LEN is the usable length of REST. TABLE_LEVEL is used to
705 control the indentation of tables. */
706 static size_t
707 proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
708 int *table_level, int *eol_action)
710 static struct {
711 const char *name; /* Name of the command. */
712 int what; /* What to do with this command. */
713 const char *lead_in; /* String to print with a opening brace. */
714 const char *lead_out;/* String to print with the closing brace. */
715 } cmdtbl[] = {
716 { "command", 0, "\\fB", "\\fR" },
717 { "code", 0, "\\fB", "\\fR" },
718 { "url", 0, "\\fB", "\\fR" },
719 { "sc", 0, "\\fB", "\\fR" },
720 { "var", 0, "\\fI", "\\fR" },
721 { "samp", 0, "\\(aq", "\\(aq" },
722 { "file", 0, "\\(oq\\fI","\\fR\\(cq" },
723 { "env", 0, "\\(oq\\fI","\\fR\\(cq" },
724 { "acronym", 0 },
725 { "dfn", 0 },
726 { "option", 0, "\\fB", "\\fR" },
727 { "example", 1, ".RS 2\n.nf\n" },
728 { "smallexample", 1, ".RS 2\n.nf\n" },
729 { "asis", 7 },
730 { "anchor", 7 },
731 { "cartouche", 1 },
732 { "ref", 0, "[", "]" },
733 { "xref", 0, "See: [", "]" },
734 { "pxref", 0, "see: [", "]" },
735 { "uref", 0, "(\\fB", "\\fR)" },
736 { "footnote",0, " ([", "])" },
737 { "emph", 0, "\\fI", "\\fR" },
738 { "w", 1 },
739 { "c", 5 },
740 { "efindex", 1 },
741 { "opindex", 1 },
742 { "cpindex", 1 },
743 { "cindex", 1 },
744 { "noindent", 0 },
745 { "section", 1 },
746 { "chapter", 1 },
747 { "subsection", 6, "\n.SS " },
748 { "chapheading", 0},
749 { "item", 2, ".TP\n.B " },
750 { "itemx", 2, ".TQ\n.B " },
751 { "table", 3 },
752 { "itemize", 3 },
753 { "bullet", 0, "* " },
754 { "*", 0, "\n.br"},
755 { "/", 0 },
756 { "end", 4 },
757 { "quotation",1, ".RS\n\\fB" },
758 { "value", 8 },
759 { NULL }
761 size_t n;
762 int i;
763 const char *s;
764 const char *lead_out = NULL;
765 int ignore_args = 0;
767 for (i=0; cmdtbl[i].name && strcmp (cmdtbl[i].name, command); i++)
769 if (cmdtbl[i].name)
771 s = cmdtbl[i].lead_in;
772 if (s)
773 fputs (s, fp);
774 lead_out = cmdtbl[i].lead_out;
775 switch (cmdtbl[i].what)
777 case 1: /* Throw away the entire line. */
778 s = memchr (rest, '\n', len);
779 return s? (s-rest)+1 : len;
780 case 2: /* Handle @item. */
781 break;
782 case 3: /* Handle table. */
783 if (++(*table_level) > 1)
784 fputs (".RS\n", fp);
785 /* Now throw away the entire line. */
786 s = memchr (rest, '\n', len);
787 return s? (s-rest)+1 : len;
788 break;
789 case 4: /* Handle end. */
790 for (s=rest, n=len; n && (*s == ' ' || *s == '\t'); s++, n--)
792 if (n >= 5 && !memcmp (s, "table", 5)
793 && (!n || s[5] == ' ' || s[5] == '\t' || s[5] == '\n'))
795 if ((*table_level)-- > 1)
796 fputs (".RE\n", fp);
797 else
798 fputs (".P\n", fp);
800 else if (n >= 7 && !memcmp (s, "example", 7)
801 && (!n || s[7] == ' ' || s[7] == '\t' || s[7] == '\n'))
803 fputs (".fi\n.RE\n", fp);
805 else if (n >= 12 && !memcmp (s, "smallexample", 12)
806 && (!n || s[12] == ' ' || s[12] == '\t' || s[12] == '\n'))
808 fputs (".fi\n.RE\n", fp);
810 else if (n >= 9 && !memcmp (s, "quotation", 9)
811 && (!n || s[9] == ' ' || s[9] == '\t' || s[9] == '\n'))
813 fputs ("\\fR\n.RE\n", fp);
815 /* Now throw away the entire line. */
816 s = memchr (rest, '\n', len);
817 return s? (s-rest)+1 : len;
818 case 5: /* Handle special comments. */
819 for (s=rest, n=len; n && (*s == ' ' || *s == '\t'); s++, n--)
821 if (n >= 4 && !memcmp (s, "man:", 4))
823 for (s+=4, n-=4; n && *s != '\n'; n--, s++)
824 putc (*s, fp);
825 putc ('\n', fp);
827 /* Now throw away the entire line. */
828 s = memchr (rest, '\n', len);
829 return s? (s-rest)+1 : len;
830 case 6:
831 *eol_action = 1;
832 break;
833 case 7:
834 ignore_args = 1;
835 break;
836 case 8:
837 ignore_args = 1;
838 if (*rest != '{')
840 err ("opening brace for command '%s' missing", command);
841 return len;
843 else
845 /* Find closing brace. */
846 for (s=rest+1, n=1; *s && n < len; s++, n++)
847 if (*s == '}')
848 break;
849 if (*s != '}')
851 err ("closing brace for command '%s' not found", command);
852 return len;
854 else
856 size_t len = s - (rest + 1);
857 macro_t m;
859 for (m = variablelist; m; m = m->next)
860 if (strlen (m->name) == len
861 &&!strncmp (m->name, rest+1, len))
862 break;
863 if (m)
864 fputs (m->value, fp);
865 else
866 inf ("texinfo variable '%.*s' is not set",
867 (int)len, rest+1);
870 break;
871 default:
872 break;
875 else /* macro */
877 macro_t m;
879 for (m = macrolist; m ; m = m->next)
880 if (!strcmp (m->name, command))
881 break;
882 if (m)
884 proc_texi_buffer (fp, m->value, strlen (m->value),
885 table_level, eol_action);
886 ignore_args = 1; /* Parameterized macros are not yet supported. */
888 else
889 inf ("texinfo command '%s' not supported (%.*s)", command,
890 (int)((s = memchr (rest, '\n', len)), (s? (s-rest) : len)), rest);
893 if (*rest == '{')
895 /* Find matching closing brace. */
896 for (s=rest+1, n=1, i=1; i && *s && n < len; s++, n++)
897 if (*s == '{')
898 i++;
899 else if (*s == '}')
900 i--;
901 if (i)
903 err ("closing brace for command '%s' not found", command);
904 return len;
906 if (n > 2 && !ignore_args)
907 proc_texi_buffer (fp, rest+1, n-2, table_level, eol_action);
909 else
910 n = 0;
912 if (lead_out)
913 fputs (lead_out, fp);
915 return n;
920 /* Process the string LINE with LEN bytes of Texinfo content. */
921 static void
922 proc_texi_buffer (FILE *fp, const char *line, size_t len,
923 int *table_level, int *eol_action)
925 const char *s;
926 char cmdbuf[256];
927 int cmdidx = 0;
928 int in_cmd = 0;
929 size_t n;
931 for (s=line; *s && len; s++, len--)
933 if (in_cmd)
935 if (in_cmd == 1)
937 switch (*s)
939 case '@': case '{': case '}':
940 putc (*s, fp); in_cmd = 0;
941 break;
942 case ':': /* Not ending a sentence flag. */
943 in_cmd = 0;
944 break;
945 case '.': case '!': case '?': /* Ending a sentence. */
946 putc (*s, fp); in_cmd = 0;
947 break;
948 case ' ': case '\t': case '\n': /* Non collapsing spaces. */
949 putc (*s, fp); in_cmd = 0;
950 break;
951 default:
952 cmdidx = 0;
953 cmdbuf[cmdidx++] = *s;
954 in_cmd++;
955 break;
958 else if (*s == '{' || *s == ' ' || *s == '\t' || *s == '\n')
960 cmdbuf[cmdidx] = 0;
961 n = proc_texi_cmd (fp, cmdbuf, s, len, table_level, eol_action);
962 assert (n <= len);
963 s += n; len -= n;
964 s--; len++;
965 in_cmd = 0;
967 else if (cmdidx < sizeof cmdbuf -1)
968 cmdbuf[cmdidx++] = *s;
969 else
971 err ("texinfo command too long - ignored");
972 in_cmd = 0;
975 else if (*s == '@')
976 in_cmd = 1;
977 else if (*s == '\n')
979 switch (*eol_action)
981 case 1: /* Create a dummy paragraph. */
982 fputs ("\n\\ \n", fp);
983 break;
984 default:
985 putc (*s, fp);
987 *eol_action = 0;
989 else if (*s == '\\')
990 fputs ("\\\\", fp);
991 else
992 putc (*s, fp);
995 if (in_cmd > 1)
997 cmdbuf[cmdidx] = 0;
998 n = proc_texi_cmd (fp, cmdbuf, s, len, table_level, eol_action);
999 assert (n <= len);
1000 s += n; len -= n;
1001 s--; len++;
1002 /* in_cmd = 0; -- doc only */
1007 /* Do something with the Texinfo line LINE. */
1008 static void
1009 parse_texi_line (FILE *fp, const char *line, int *table_level)
1011 int eol_action = 0;
1013 /* A quick test whether there are any texinfo commands. */
1014 if (!strchr (line, '@'))
1016 fputs (line, fp);
1017 putc ('\n', fp);
1018 return;
1020 proc_texi_buffer (fp, line, strlen (line), table_level, &eol_action);
1021 putc ('\n', fp);
1025 /* Write all the lines LINES to FP. */
1026 static void
1027 write_content (FILE *fp, line_buffer_t lines)
1029 line_buffer_t line;
1030 int table_level = 0;
1032 for (line = lines; line; line = line->next)
1034 if (line->verbatim)
1036 fputs (line->line, fp);
1037 putc ('\n', fp);
1039 else
1041 /* fputs ("TEXI---", fp); */
1042 /* fputs (line->line, fp); */
1043 /* fputs ("---\n", fp); */
1044 parse_texi_line (fp, line->line, &table_level);
1051 static int
1052 is_standard_section (const char *name)
1054 int i;
1055 const char *s;
1057 for (i=0; (s=standard_sections[i]); i++)
1058 if (!strcmp (s, name))
1059 return 1;
1060 return 0;
1064 /* Finish a page; that is sort the data and write it out to the file. */
1065 static void
1066 finish_page (void)
1068 FILE *fp;
1069 section_buffer_t sect = NULL;
1070 int idx;
1071 const char *s;
1072 int i;
1074 if (!thepage.name)
1075 return; /* No page active. */
1077 if (verbose)
1078 inf ("finishing page '%s'", thepage.name);
1080 if (opt_select)
1082 if (!strcmp (opt_select, thepage.name))
1084 inf ("selected '%s'", thepage.name );
1085 fp = stdout;
1087 else
1089 fp = fopen ( "/dev/null", "w" );
1090 if (!fp)
1091 die ("failed to open /dev/null: %s\n", strerror (errno));
1094 else if (opt_store)
1096 inf ("writing '%s'", thepage.name );
1097 fp = fopen ( thepage.name, "w" );
1098 if (!fp)
1099 die ("failed to create '%s': %s\n", thepage.name, strerror (errno));
1101 else
1102 fp = stdout;
1104 if (write_th (fp))
1105 goto leave;
1107 for (idx=0; (s=standard_sections[idx]); idx++)
1109 for (i=0; i < thepage.n_sections; i++)
1111 sect = thepage.sections + i;
1112 if (sect->name && !strcmp (s, sect->name))
1113 break;
1115 if (i == thepage.n_sections)
1116 sect = NULL;
1118 if (sect)
1120 fprintf (fp, ".SH %s\n", sect->name);
1121 write_content (fp, sect->lines);
1122 /* Now continue with all non standard sections directly
1123 following this one. */
1124 for (i++; i < thepage.n_sections; i++)
1126 sect = thepage.sections + i;
1127 if (sect->name && is_standard_section (sect->name))
1128 break;
1129 if (sect->name)
1131 fprintf (fp, ".SH %s\n", sect->name);
1132 write_content (fp, sect->lines);
1140 leave:
1141 if (fp != stdout)
1142 fclose (fp);
1143 free (thepage.name);
1144 thepage.name = NULL;
1145 /* FIXME: Cleanup the content. */
1151 /* Parse one Texinfo file and create manpages according to the
1152 embedded instructions. */
1153 static void
1154 parse_file (const char *fname, FILE *fp, char **section_name, int in_pause)
1156 char *line;
1157 int lnr = 0;
1158 /* Fixme: The following state variables don't carry over to include
1159 files. */
1160 int skip_to_end = 0; /* Used to skip over menu entries. */
1161 int skip_sect_line = 0; /* Skip after @mansect. */
1162 int item_indent = 0; /* How far is the current @item indented. */
1164 /* Helper to define a macro. */
1165 char *macroname = NULL;
1166 char *macrovalue = NULL;
1167 size_t macrovaluesize = 0;
1168 size_t macrovalueused = 0;
1170 line = xmalloc (LINESIZE);
1171 while (fgets (line, LINESIZE, fp))
1173 size_t n = strlen (line);
1174 int got_line = 0;
1175 char *p, *pend;
1177 lnr++;
1178 if (!n || line[n-1] != '\n')
1180 err ("%s:%d: trailing linefeed missing, line too long or "
1181 "embedded Nul character", fname, lnr);
1182 break;
1184 line[--n] = 0;
1186 /* Kludge to allow indentation of tables. */
1187 for (p=line; *p == ' ' || *p == '\t'; p++)
1189 if (*p)
1191 if (*p == '@' && !strncmp (p+1, "item", 4))
1192 item_indent = p - line; /* Set a new indent level. */
1193 else if (p - line < item_indent)
1194 item_indent = 0; /* Switch off indention. */
1196 if (item_indent)
1198 memmove (line, line+item_indent, n - item_indent + 1);
1199 n -= item_indent;
1204 if (*line == '@')
1206 for (p=line+1, n=1; *p && *p != ' ' && *p != '\t'; p++)
1207 n++;
1208 while (*p == ' ' || *p == '\t')
1209 p++;
1211 else
1212 p = line;
1214 /* Take action on macro. */
1215 if (macroname)
1217 if (n == 4 && !memcmp (line, "@end", 4)
1218 && (line[4]==' '||line[4]=='\t'||!line[4])
1219 && !strncmp (p, "macro", 5)
1220 && (p[5]==' '||p[5]=='\t'||!p[5]))
1222 if (macrovalueused)
1223 macrovalue[--macrovalueused] = 0; /* Kill the last LF. */
1224 macrovalue[macrovalueused] = 0; /* Terminate macro. */
1225 macrovalue = xrealloc (macrovalue, macrovalueused+1);
1227 set_macro (macroname, macrovalue);
1228 macrovalue = NULL;
1229 free (macroname);
1230 macroname = NULL;
1232 else
1234 if (macrovalueused + strlen (line) + 2 >= macrovaluesize)
1236 macrovaluesize += strlen (line) + 256;
1237 macrovalue = xrealloc (macrovalue, macrovaluesize);
1239 strcpy (macrovalue+macrovalueused, line);
1240 macrovalueused += strlen (line);
1241 macrovalue[macrovalueused++] = '\n';
1243 continue;
1247 if (n >= 5 && !memcmp (line, "@node", 5)
1248 && (line[5]==' '||line[5]=='\t'||!line[5]))
1250 /* Completey ignore @node lines. */
1251 continue;
1255 if (skip_sect_line)
1257 skip_sect_line = 0;
1258 if (!strncmp (line, "@section", 8)
1259 || !strncmp (line, "@subsection", 11)
1260 || !strncmp (line, "@chapheading", 12))
1261 continue;
1264 /* We only parse lines we need and ignore the rest. There are a
1265 few macros used to control this as well as one @ifset
1266 command. Parts we know about are saved away into containers
1267 separate for each section. */
1269 /* First process ifset/ifclear commands. */
1270 if (*line == '@')
1272 if (n == 6 && !memcmp (line, "@ifset", 6)
1273 && (line[6]==' '||line[6]=='\t'))
1275 for (p=line+7; *p == ' ' || *p == '\t'; p++)
1277 if (!*p)
1279 err ("%s:%d: name missing after \"@ifset\"", fname, lnr);
1280 continue;
1282 for (pend=p; *pend && *pend != ' ' && *pend != '\t'; pend++)
1284 *pend = 0; /* Ignore rest of the line. */
1285 push_condition (p, 1, fname, lnr);
1286 continue;
1288 else if (n == 8 && !memcmp (line, "@ifclear", 8)
1289 && (line[8]==' '||line[8]=='\t'))
1291 for (p=line+9; *p == ' ' || *p == '\t'; p++)
1293 if (!*p)
1295 err ("%s:%d: name missing after \"@ifsclear\"", fname, lnr);
1296 continue;
1298 for (pend=p; *pend && *pend != ' ' && *pend != '\t'; pend++)
1300 *pend = 0; /* Ignore rest of the line. */
1301 push_condition (p, 0, fname, lnr);
1302 continue;
1304 else if (n == 4 && !memcmp (line, "@end", 4)
1305 && (line[4]==' '||line[4]=='\t')
1306 && !strncmp (p, "ifset", 5)
1307 && (p[5]==' '||p[5]=='\t'||!p[5]))
1309 pop_condition (1, fname, lnr);
1310 continue;
1312 else if (n == 4 && !memcmp (line, "@end", 4)
1313 && (line[4]==' '||line[4]=='\t')
1314 && !strncmp (p, "ifclear", 7)
1315 && (p[7]==' '||p[7]=='\t'||!p[7]))
1317 pop_condition (0, fname, lnr);
1318 continue;
1322 /* Take action on ifset/ifclear. */
1323 if (!cond_is_active)
1324 continue;
1326 /* Process commands. */
1327 if (*line == '@')
1329 if (skip_to_end
1330 && n == 4 && !memcmp (line, "@end", 4)
1331 && (line[4]==' '||line[4]=='\t'||!line[4]))
1333 skip_to_end = 0;
1335 else if (cond_in_verbatim)
1337 got_line = 1;
1339 else if (n == 6 && !memcmp (line, "@macro", 6))
1341 macroname = xstrdup (p);
1342 macrovalue = xmalloc ((macrovaluesize = 1024));
1343 macrovalueused = 0;
1345 else if (n == 4 && !memcmp (line, "@set", 4))
1347 set_variable (p);
1349 else if (n == 8 && !memcmp (line, "@manpage", 8))
1351 free (*section_name);
1352 *section_name = NULL;
1353 finish_page ();
1354 start_page (p);
1355 in_pause = 0;
1357 else if (n == 8 && !memcmp (line, "@mansect", 8))
1359 if (!thepage.name)
1360 err ("%s:%d: section outside of a man page", fname, lnr);
1361 else
1363 free (*section_name);
1364 *section_name = ascii_strupr (xstrdup (p));
1365 in_pause = 0;
1366 skip_sect_line = 1;
1369 else if (n == 9 && !memcmp (line, "@manpause", 9))
1371 if (!*section_name)
1372 err ("%s:%d: pausing outside of a man section", fname, lnr);
1373 else if (in_pause)
1374 err ("%s:%d: already pausing", fname, lnr);
1375 else
1376 in_pause = 1;
1378 else if (n == 8 && !memcmp (line, "@mancont", 8))
1380 if (!*section_name)
1381 err ("%s:%d: continue outside of a man section", fname, lnr);
1382 else if (!in_pause)
1383 err ("%s:%d: continue while not pausing", fname, lnr);
1384 else
1385 in_pause = 0;
1387 else if (n == 5 && !memcmp (line, "@menu", 5)
1388 && (line[5]==' '||line[5]=='\t'||!line[5]))
1390 skip_to_end = 1;
1392 else if (n == 8 && !memcmp (line, "@include", 8)
1393 && (line[8]==' '||line[8]=='\t'||!line[8]))
1395 char *incname = xstrdup (p);
1396 FILE *incfp = fopen (incname, "r");
1398 if (!incfp && opt_include && *opt_include && *p != '/')
1400 free (incname);
1401 incname = xmalloc (strlen (opt_include) + 1
1402 + strlen (p) + 1);
1403 strcpy (incname, opt_include);
1404 if ( incname[strlen (incname)-1] != '/' )
1405 strcat (incname, "/");
1406 strcat (incname, p);
1407 incfp = fopen (incname, "r");
1410 if (!incfp)
1411 err ("can't open include file '%s': %s",
1412 incname, strerror (errno));
1413 else
1415 parse_file (incname, incfp, section_name, in_pause);
1416 fclose (incfp);
1418 free (incname);
1420 else if (n == 4 && !memcmp (line, "@bye", 4)
1421 && (line[4]==' '||line[4]=='\t'||!line[4]))
1423 break;
1425 else if (!skip_to_end)
1426 got_line = 1;
1428 else if (!skip_to_end)
1429 got_line = 1;
1431 if (got_line && cond_in_verbatim)
1432 add_content (*section_name, line, 1);
1433 else if (got_line && thepage.name && *section_name && !in_pause)
1434 add_content (*section_name, line, 0);
1437 if (ferror (fp))
1438 err ("%s:%d: read error: %s", fname, lnr, strerror (errno));
1439 free (macroname);
1440 free (macrovalue);
1441 free (line);
1445 static void
1446 top_parse_file (const char *fname, FILE *fp)
1448 char *section_name = NULL; /* Name of the current section or NULL
1449 if not in a section. */
1450 macro_t m;
1452 while (macrolist)
1454 macro_t next = macrolist->next;
1455 free (macrolist->value);
1456 free (macrolist);
1457 macrolist = next;
1459 while (variablelist)
1461 macro_t next = variablelist->next;
1462 free (variablelist->value);
1463 free (variablelist);
1464 variablelist = next;
1466 for (m=predefinedmacrolist; m; m = m->next)
1467 set_macro (m->name, xstrdup ("1"));
1468 cond_is_active = 1;
1469 cond_in_verbatim = 0;
1471 parse_file (fname, fp, &section_name, 0);
1472 free (section_name);
1473 finish_page ();
1478 main (int argc, char **argv)
1480 int last_argc = -1;
1482 opt_source = "GNU";
1483 opt_release = "";
1485 /* Define default macros. The trick is that these macros are not
1486 defined when using the actual texinfo renderer. */
1487 add_predefined_macro ("isman");
1488 add_predefined_macro ("manverb");
1490 /* Option parsing. */
1491 if (argc)
1493 argc--; argv++;
1495 while (argc && last_argc != argc )
1497 last_argc = argc;
1498 if (!strcmp (*argv, "--"))
1500 argc--; argv++;
1501 break;
1503 else if (!strcmp (*argv, "--help"))
1505 puts (
1506 "Usage: " PGM " [OPTION] [FILE]\n"
1507 "Extract man pages from a Texinfo source.\n\n"
1508 " --source NAME use NAME as source field\n"
1509 " --release STRING use STRING as the release field\n"
1510 " --date EPOCH use EPOCH as publication date\n"
1511 " --store write output using @manpage name\n"
1512 " --select NAME only output pages with @manpage NAME\n"
1513 " --verbose enable extra informational output\n"
1514 " --debug enable additional debug output\n"
1515 " --help display this help and exit\n"
1516 " -I DIR also search in include DIR\n"
1517 " -D gpgone the only usable define\n\n"
1518 "With no FILE, or when FILE is -, read standard input.\n\n"
1519 "Report bugs to <bugs@g10code.com>.");
1520 exit (0);
1522 else if (!strcmp (*argv, "--version"))
1524 puts (PGM " " VERSION "\n"
1525 "Copyright (C) 2005 g10 Code GmbH\n"
1526 "This program comes with ABSOLUTELY NO WARRANTY.\n"
1527 "This is free software, and you are welcome to redistribute it\n"
1528 "under certain conditions. See the file COPYING for details.");
1529 exit (0);
1531 else if (!strcmp (*argv, "--verbose"))
1533 verbose = 1;
1534 argc--; argv++;
1536 else if (!strcmp (*argv, "--quiet"))
1538 quiet = 1;
1539 argc--; argv++;
1541 else if (!strcmp (*argv, "--debug"))
1543 verbose = debug = 1;
1544 argc--; argv++;
1546 else if (!strcmp (*argv, "--source"))
1548 argc--; argv++;
1549 if (argc)
1551 opt_source = *argv;
1552 argc--; argv++;
1555 else if (!strcmp (*argv, "--release"))
1557 argc--; argv++;
1558 if (argc)
1560 opt_release = *argv;
1561 argc--; argv++;
1564 else if (!strcmp (*argv, "--date"))
1566 argc--; argv++;
1567 if (argc)
1569 opt_date = *argv;
1570 argc--; argv++;
1573 else if (!strcmp (*argv, "--store"))
1575 opt_store = 1;
1576 argc--; argv++;
1578 else if (!strcmp (*argv, "--select"))
1580 argc--; argv++;
1581 if (argc)
1583 opt_select = strrchr (*argv, '/');
1584 if (opt_select)
1585 opt_select++;
1586 else
1587 opt_select = *argv;
1588 argc--; argv++;
1591 else if (!strcmp (*argv, "-I"))
1593 argc--; argv++;
1594 if (argc)
1596 opt_include = *argv;
1597 argc--; argv++;
1600 else if (!strcmp (*argv, "-D"))
1602 argc--; argv++;
1603 if (argc)
1605 add_predefined_macro (*argv);
1606 argc--; argv++;
1611 if (argc > 1)
1612 die ("usage: " PGM " [OPTION] [FILE] (try --help for more information)\n");
1614 /* Start processing. */
1615 if (argc && strcmp (*argv, "-"))
1617 FILE *fp = fopen (*argv, "rb");
1618 if (!fp)
1619 die ("%s:0: can't open file: %s", *argv, strerror (errno));
1620 top_parse_file (*argv, fp);
1621 fclose (fp);
1623 else
1624 top_parse_file ("-", stdin);
1626 return !!any_error;
1631 Local Variables:
1632 compile-command: "gcc -Wall -g -Wall -o yat2m yat2m.c"
1633 End: