Update doc/yat2m.c.
[pwmd.git] / doc / yat2m.c
blobe2ab86ea15346a402e7df993943d047476e5d75b
1 /* yat2m.c - Yet Another Texi 2 Man converter
2 * Copyright (C) 2005, 2013 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 <http://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 #define PGM "yat2m"
108 #define VERSION "1.0"
110 /* The maximum length of a line including the linefeed and one extra
111 character. */
112 #define LINESIZE 1024
114 /* Number of allowed condition nestings. */
115 #define MAX_CONDITION_NESTING 10
117 /* Option flags. */
118 static int verbose;
119 static int quiet;
120 static int debug;
121 static const char *opt_source;
122 static const char *opt_release;
123 static const char *opt_select;
124 static const char *opt_include;
125 static int opt_store;
127 /* Flag to keep track whether any error occurred. */
128 static int any_error;
131 /* Object to keep macro definitions. */
132 struct macro_s
134 struct macro_s *next;
135 char *value; /* Malloced value. */
136 char name[1];
138 typedef struct macro_s *macro_t;
140 /* List of all defined macros. */
141 static macro_t macrolist;
143 /* List of variables set by @set. */
144 static macro_t variablelist;
146 /* List of global macro names. The value part is not used. */
147 static macro_t predefinedmacrolist;
149 /* Object to keep track of @isset and @ifclear. */
150 struct condition_s
152 int manverb; /* "manverb" needs special treatment. */
153 int isset; /* This is an @isset condition. */
154 char name[1]; /* Name of the condition macro. */
156 typedef struct condition_s *condition_t;
158 /* The stack used to evaluate conditions. And the current states. */
159 static condition_t condition_stack[MAX_CONDITION_NESTING];
160 static int condition_stack_idx;
161 static int cond_is_active; /* State of ifset/ifclear */
162 static int cond_in_verbatim; /* State of "manverb". */
165 /* Object to store one line of content. */
166 struct line_buffer_s
168 struct line_buffer_s *next;
169 int verbatim; /* True if LINE contains verbatim data. The default
170 is Texinfo source. */
171 char *line;
173 typedef struct line_buffer_s *line_buffer_t;
176 /* Object to collect the data of a section. */
177 struct section_buffer_s
179 char *name; /* Malloced name of the section. This may be
180 NULL to indicate this slot is not used. */
181 line_buffer_t lines; /* Linked list with the lines of the section. */
182 line_buffer_t *lines_tail; /* Helper for faster appending to the
183 linked list. */
184 line_buffer_t last_line; /* Points to the last line appended. */
186 typedef struct section_buffer_s *section_buffer_t;
188 /* Variable to keep info about the current page together. */
189 static struct
191 /* Filename of the current page or NULL if no page is active. Malloced. */
192 char *name;
194 /* Number of allocated elements in SECTIONS below. */
195 size_t n_sections;
196 /* Array with the data of the sections. */
197 section_buffer_t sections;
199 } thepage;
202 /* The list of standard section names. COMMANDS and ASSUAN are GnuPG
203 specific. */
204 static const char * const standard_sections[] =
205 { "NAME", "SYNOPSIS", "DESCRIPTION",
206 "RETURN VALUE", "EXIT STATUS", "ERROR HANDLING", "ERRORS",
207 "COMMANDS", "OPTIONS", "USAGE", "EXAMPLES", "FILES",
208 "ENVIRONMENT", "DIAGNOSTICS", "SECURITY", "CONFORMING TO",
209 "ASSUAN", "NOTES", "BUGS", "AUTHOR", "SEE ALSO", NULL };
212 /*-- Local prototypes. --*/
213 static void proc_texi_buffer (FILE *fp, const char *line, size_t len,
214 int *table_level, int *eol_action);
218 /* Print diagnostic message and exit with failure. */
219 static void
220 die (const char *format, ...)
222 va_list arg_ptr;
224 fflush (stdout);
225 fprintf (stderr, "%s: ", PGM);
227 va_start (arg_ptr, format);
228 vfprintf (stderr, format, arg_ptr);
229 va_end (arg_ptr);
230 putc ('\n', stderr);
232 exit (1);
236 /* Print diagnostic message. */
237 static void
238 err (const char *format, ...)
240 va_list arg_ptr;
242 fflush (stdout);
243 if (strncmp (format, "%s:%d:", 6))
244 fprintf (stderr, "%s: ", PGM);
246 va_start (arg_ptr, format);
247 vfprintf (stderr, format, arg_ptr);
248 va_end (arg_ptr);
249 putc ('\n', stderr);
250 any_error = 1;
253 /* Print diagnostic message. */
254 static void
255 inf (const char *format, ...)
257 va_list arg_ptr;
259 fflush (stdout);
260 fprintf (stderr, "%s: ", PGM);
262 va_start (arg_ptr, format);
263 vfprintf (stderr, format, arg_ptr);
264 va_end (arg_ptr);
265 putc ('\n', stderr);
269 static void *
270 xmalloc (size_t n)
272 void *p = malloc (n);
273 if (!p)
274 die ("out of core: %s", strerror (errno));
275 return p;
278 static void *
279 xcalloc (size_t n, size_t m)
281 void *p = calloc (n, m);
282 if (!p)
283 die ("out of core: %s", strerror (errno));
284 return p;
287 static void *
288 xrealloc (void *old, size_t n)
290 void *p = realloc (old, n);
291 if (!p)
292 die ("out of core: %s", strerror (errno));
293 return p;
296 static char *
297 xstrdup (const char *string)
299 void *p = malloc (strlen (string)+1);
300 if (!p)
301 die ("out of core: %s", strerror (errno));
302 strcpy (p, string);
303 return p;
307 /* Uppercase the ascii characters in STRING. */
308 static char *
309 ascii_strupr (char *string)
311 char *p;
313 for (p = string; *p; p++)
314 if (!(*p & 0x80))
315 *p = toupper (*p);
316 return string;
320 /* Return the current date as an ISO string. */
321 const char *
322 isodatestring (void)
324 static char buffer[11+5];
325 struct tm *tp;
326 time_t atime = time (NULL);
328 if (atime < 0)
329 strcpy (buffer, "????" "-??" "-??");
330 else
332 tp = gmtime (&atime);
333 sprintf (buffer,"%04d-%02d-%02d",
334 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
336 return buffer;
340 /* Add NAME to the list of predefined macros which are global for all
341 files. */
342 static void
343 add_predefined_macro (const char *name)
345 macro_t m;
347 for (m=predefinedmacrolist; m; m = m->next)
348 if (!strcmp (m->name, name))
349 break;
350 if (!m)
352 m = xcalloc (1, sizeof *m + strlen (name));
353 strcpy (m->name, name);
354 m->next = predefinedmacrolist;
355 predefinedmacrolist = m;
360 /* Create or update a macro with name MACRONAME and set its values TO
361 MACROVALUE. Note that ownership of the macro value is transferred
362 to this function. */
363 static void
364 set_macro (const char *macroname, char *macrovalue)
366 macro_t m;
368 for (m=macrolist; m; m = m->next)
369 if (!strcmp (m->name, macroname))
370 break;
371 if (m)
372 free (m->value);
373 else
375 m = xcalloc (1, sizeof *m + strlen (macroname));
376 strcpy (m->name, macroname);
377 m->next = macrolist;
378 macrolist = m;
380 m->value = macrovalue;
381 macrovalue = NULL;
385 /* Create or update a variable with name and value given in NAMEANDVALUE. */
386 static void
387 set_variable (char *nameandvalue)
389 macro_t m;
390 const char *value;
391 char *p;
393 for (p = nameandvalue; *p && *p != ' ' && *p != '\t'; p++)
395 if (!*p)
396 value = "";
397 else
399 *p++ = 0;
400 while (*p == ' ' || *p == '\t')
401 p++;
402 value = p;
405 for (m=variablelist; m; m = m->next)
406 if (!strcmp (m->name, nameandvalue))
407 break;
408 if (m)
409 free (m->value);
410 else
412 m = xcalloc (1, sizeof *m + strlen (nameandvalue));
413 strcpy (m->name, nameandvalue);
414 m->next = variablelist;
415 variablelist = m;
417 m->value = xstrdup (value);
421 /* Return true if the macro or variable NAME is set, i.e. not the
422 empty string and not evaluating to 0. */
423 static int
424 macro_set_p (const char *name)
426 macro_t m;
428 for (m = macrolist; m ; m = m->next)
429 if (!strcmp (m->name, name))
430 break;
431 if (!m)
432 for (m = variablelist; m ; m = m->next)
433 if (!strcmp (m->name, name))
434 break;
435 if (!m || !m->value || !*m->value)
436 return 0;
437 if ((*m->value & 0x80) || !isdigit (*m->value))
438 return 1; /* Not a digit but some other string. */
439 return !!atoi (m->value);
443 /* Evaluate the current conditions. */
444 static void
445 evaluate_conditions (const char *fname, int lnr)
447 int i;
449 /* for (i=0; i < condition_stack_idx; i++) */
450 /* inf ("%s:%d: stack[%d] %s %s %c", */
451 /* fname, lnr, i, condition_stack[i]->isset? "set":"clr", */
452 /* condition_stack[i]->name, */
453 /* (macro_set_p (condition_stack[i]->name) */
454 /* ^ !condition_stack[i]->isset)? 't':'f'); */
456 cond_is_active = 1;
457 cond_in_verbatim = 0;
458 if (condition_stack_idx)
460 for (i=0; i < condition_stack_idx; i++)
462 if (condition_stack[i]->manverb)
463 cond_in_verbatim = (macro_set_p (condition_stack[i]->name)
464 ^ !condition_stack[i]->isset);
465 else if (!(macro_set_p (condition_stack[i]->name)
466 ^ !condition_stack[i]->isset))
468 cond_is_active = 0;
469 break;
474 /* inf ("%s:%d: active=%d verbatim=%d", */
475 /* fname, lnr, cond_is_active, cond_in_verbatim); */
479 /* Push a condition with condition macro NAME onto the stack. If
480 ISSET is true, a @isset condition is pushed. */
481 static void
482 push_condition (const char *name, int isset, const char *fname, int lnr)
484 condition_t cond;
485 int manverb = 0;
487 if (condition_stack_idx >= MAX_CONDITION_NESTING)
489 err ("%s:%d: condition nested too deep", fname, lnr);
490 return;
493 if (!strcmp (name, "manverb"))
495 if (!isset)
497 err ("%s:%d: using \"@ifclear manverb\" is not allowed", fname, lnr);
498 return;
500 manverb = 1;
503 cond = xcalloc (1, sizeof *cond + strlen (name));
504 cond->manverb = manverb;
505 cond->isset = isset;
506 strcpy (cond->name, name);
508 condition_stack[condition_stack_idx++] = cond;
509 evaluate_conditions (fname, lnr);
513 /* Remove the last condition from the stack. ISSET is used for error
514 reporting. */
515 static void
516 pop_condition (int isset, const char *fname, int lnr)
518 if (!condition_stack_idx)
520 err ("%s:%d: unbalanced \"@end %s\"",
521 fname, lnr, isset?"isset":"isclear");
522 return;
524 condition_stack_idx--;
525 free (condition_stack[condition_stack_idx]);
526 condition_stack[condition_stack_idx] = NULL;
527 evaluate_conditions (fname, lnr);
532 /* Return a section buffer for the section NAME. Allocate a new buffer
533 if this is a new section. Keep track of the sections in THEPAGE.
534 This function may reallocate the section array in THEPAGE. */
535 static section_buffer_t
536 get_section_buffer (const char *name)
538 int i;
539 section_buffer_t sect;
541 /* If there is no section we put everything into the required NAME
542 section. Given that this is the first one listed it is likely
543 that error are easily visible. */
544 if (!name)
545 name = "NAME";
547 for (i=0; i < thepage.n_sections; i++)
549 sect = thepage.sections + i;
550 if (sect->name && !strcmp (name, sect->name))
551 return sect;
553 for (i=0; i < thepage.n_sections; i++)
554 if (!thepage.sections[i].name)
555 break;
556 if (i < thepage.n_sections)
557 sect = thepage.sections + i;
558 else
560 /* We need to allocate or reallocate the section array. */
561 size_t old_n = thepage.n_sections;
562 size_t new_n = 20;
564 if (!old_n)
565 thepage.sections = xcalloc (new_n, sizeof *thepage.sections);
566 else
568 thepage.sections = xrealloc (thepage.sections,
569 ((old_n + new_n)
570 * sizeof *thepage.sections));
571 memset (thepage.sections + old_n, 0,
572 new_n * sizeof *thepage.sections);
574 thepage.n_sections += new_n;
576 /* Setup the tail pointers. */
577 for (i=old_n; i < thepage.n_sections; i++)
579 sect = thepage.sections + i;
580 sect->lines_tail = &sect->lines;
582 sect = thepage.sections + old_n;
585 /* Store the name. */
586 assert (!sect->name);
587 sect->name = xstrdup (name);
588 return sect;
593 /* Add the content of LINE to the section named SECTNAME. */
594 static void
595 add_content (const char *sectname, char *line, int verbatim)
597 section_buffer_t sect;
598 line_buffer_t lb;
600 sect = get_section_buffer (sectname);
601 if (sect->last_line && !sect->last_line->verbatim == !verbatim)
603 /* Lets append that line to the last one. We do this to keep
604 all lines of the same kind (i.e.verbatim or not) together in
605 one large buffer. */
606 size_t n1, n;
608 lb = sect->last_line;
609 n1 = strlen (lb->line);
610 n = n1 + 1 + strlen (line) + 1;
611 lb->line = xrealloc (lb->line, n);
612 strcpy (lb->line+n1, "\n");
613 strcpy (lb->line+n1+1, line);
615 else
617 lb = xcalloc (1, sizeof *lb);
618 lb->verbatim = verbatim;
619 lb->line = xstrdup (line);
620 sect->last_line = lb;
621 *sect->lines_tail = lb;
622 sect->lines_tail = &lb->next;
627 /* Prepare for a new man page using the filename NAME. */
628 static void
629 start_page (char *name)
631 if (verbose)
632 inf ("starting page '%s'", name);
633 assert (!thepage.name);
634 thepage.name = xstrdup (name);
635 thepage.n_sections = 0;
639 /* Write the .TH entry of the current page. Return -1 if there is a
640 problem with the page. */
641 static int
642 write_th (FILE *fp)
644 char *name, *p;
646 fputs (".\\\" Created from Texinfo source by yat2m " VERSION "\n", fp);
648 name = ascii_strupr (xstrdup (thepage.name));
649 p = strrchr (name, '.');
650 if (!p || !p[1])
652 err ("no section name in man page '%s'", thepage.name);
653 free (name);
654 return -1;
656 *p++ = 0;
657 fprintf (fp, ".TH %s %s %s \"%s\" \"%s\"\n",
658 name, p, isodatestring (), opt_release, opt_source);
659 free (name);
660 return 0;
664 /* Process the texinfo command COMMAND (without the leading @) and
665 write output if needed to FP. REST is the remainer of the line
666 which should either point to an opening brace or to a white space.
667 The function returns the number of characters already processed
668 from REST. LEN is the usable length of REST. TABLE_LEVEL is used to
669 control the indentation of tables. */
670 static size_t
671 proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
672 int *table_level, int *eol_action)
674 static struct {
675 const char *name; /* Name of the command. */
676 int what; /* What to do with this command. */
677 const char *lead_in; /* String to print with a opening brace. */
678 const char *lead_out;/* String to print with the closing brace. */
679 } cmdtbl[] = {
680 { "command", 0, "\\fB", "\\fR" },
681 { "code", 0, "\\fB", "\\fR" },
682 { "sc", 0, "\\fB", "\\fR" },
683 { "var", 0, "\\fI", "\\fR" },
684 { "samp", 0, "\\(aq", "\\(aq" },
685 { "file", 0, "\\(oq\\fI","\\fR\\(cq" },
686 { "env", 0, "\\(oq\\fI","\\fR\\(cq" },
687 { "acronym", 0 },
688 { "dfn", 0 },
689 { "option", 0, "\\fB", "\\fR" },
690 { "example", 1, ".RS 2\n.nf\n" },
691 { "smallexample", 1, ".RS 2\n.nf\n" },
692 { "asis", 7 },
693 { "anchor", 7 },
694 { "cartouche", 1 },
695 { "xref", 0, "see: [", "]" },
696 { "pxref", 0, "see: [", "]" },
697 { "uref", 0, "(\\fB", "\\fR)" },
698 { "footnote",0, " ([", "])" },
699 { "emph", 0, "\\fI", "\\fR" },
700 { "w", 1 },
701 { "c", 5 },
702 { "opindex", 1 },
703 { "cpindex", 1 },
704 { "cindex", 1 },
705 { "noindent", 0 },
706 { "section", 1 },
707 { "chapter", 1 },
708 { "subsection", 6, "\n.SS " },
709 { "chapheading", 0},
710 { "item", 2, ".TP\n.B " },
711 { "itemx", 2, ".TP\n.B " },
712 { "table", 3 },
713 { "itemize", 3 },
714 { "bullet", 0, "* " },
715 { "*", 0, "\n.br"},
716 { "/", 0 },
717 { "end", 4 },
718 { "quotation",1, ".RS\n\\fB" },
719 { "value", 8 },
720 { NULL }
722 size_t n;
723 int i;
724 const char *s;
725 const char *lead_out = NULL;
726 int ignore_args = 0;
728 for (i=0; cmdtbl[i].name && strcmp (cmdtbl[i].name, command); i++)
730 if (cmdtbl[i].name)
732 s = cmdtbl[i].lead_in;
733 if (s)
734 fputs (s, fp);
735 lead_out = cmdtbl[i].lead_out;
736 switch (cmdtbl[i].what)
738 case 1: /* Throw away the entire line. */
739 s = memchr (rest, '\n', len);
740 return s? (s-rest)+1 : len;
741 case 2: /* Handle @item. */
742 break;
743 case 3: /* Handle table. */
744 if (++(*table_level) > 1)
745 fputs (".RS\n", fp);
746 /* Now throw away the entire line. */
747 s = memchr (rest, '\n', len);
748 return s? (s-rest)+1 : len;
749 break;
750 case 4: /* Handle end. */
751 for (s=rest, n=len; n && (*s == ' ' || *s == '\t'); s++, n--)
753 if (n >= 5 && !memcmp (s, "table", 5)
754 && (!n || s[5] == ' ' || s[5] == '\t' || s[5] == '\n'))
756 if ((*table_level)-- > 1)
757 fputs (".RE\n", fp);
759 else if (n >= 7 && !memcmp (s, "example", 7)
760 && (!n || s[7] == ' ' || s[7] == '\t' || s[7] == '\n'))
762 fputs (".fi\n.RE\n", fp);
764 else if (n >= 12 && !memcmp (s, "smallexample", 12)
765 && (!n || s[12] == ' ' || s[12] == '\t' || s[12] == '\n'))
767 fputs (".fi\n.RE\n", fp);
769 else if (n >= 9 && !memcmp (s, "quotation", 9)
770 && (!n || s[9] == ' ' || s[9] == '\t' || s[9] == '\n'))
772 fputs ("\\fR\n.RE\n", fp);
774 /* Now throw away the entire line. */
775 s = memchr (rest, '\n', len);
776 return s? (s-rest)+1 : len;
777 case 5: /* Handle special comments. */
778 for (s=rest, n=len; n && (*s == ' ' || *s == '\t'); s++, n--)
780 if (n >= 4 && !memcmp (s, "man:", 4))
782 for (s+=4, n-=4; n && *s != '\n'; n--, s++)
783 putc (*s, fp);
784 putc ('\n', fp);
786 /* Now throw away the entire line. */
787 s = memchr (rest, '\n', len);
788 return s? (s-rest)+1 : len;
789 case 6:
790 *eol_action = 1;
791 break;
792 case 7:
793 ignore_args = 1;
794 break;
795 case 8:
796 ignore_args = 1;
797 if (*rest != '{')
799 err ("opening brace for command '%s' missing", command);
800 return len;
802 else
804 /* Find closing brace. */
805 for (s=rest+1, n=1; *s && n < len; s++, n++)
806 if (*s == '}')
807 break;
808 if (*s != '}')
810 err ("closing brace for command '%s' not found", command);
811 return len;
813 else
815 size_t len = s - (rest + 1);
816 macro_t m;
818 for (m = variablelist; m; m = m->next)
819 if (strlen (m->name) == len
820 &&!strncmp (m->name, rest+1, len))
821 break;
822 if (m)
823 fputs (m->value, fp);
824 else
825 inf ("texinfo variable '%.*s' is not set",
826 (int)len, rest+1);
829 break;
830 default:
831 break;
834 else /* macro */
836 macro_t m;
838 for (m = macrolist; m ; m = m->next)
839 if (!strcmp (m->name, command))
840 break;
841 if (m)
843 proc_texi_buffer (fp, m->value, strlen (m->value),
844 table_level, eol_action);
845 ignore_args = 1; /* Parameterized macros are not yet supported. */
847 else
848 inf ("texinfo command '%s' not supported (%.*s)", command,
849 ((s = memchr (rest, '\n', len)), (s? (s-rest) : len)), rest);
852 if (*rest == '{')
854 /* Find matching closing brace. */
855 for (s=rest+1, n=1, i=1; i && *s && n < len; s++, n++)
856 if (*s == '{')
857 i++;
858 else if (*s == '}')
859 i--;
860 if (i)
862 err ("closing brace for command '%s' not found", command);
863 return len;
865 if (n > 2 && !ignore_args)
866 proc_texi_buffer (fp, rest+1, n-2, table_level, eol_action);
868 else
869 n = 0;
871 if (lead_out)
872 fputs (lead_out, fp);
874 return n;
879 /* Process the string LINE with LEN bytes of Texinfo content. */
880 static void
881 proc_texi_buffer (FILE *fp, const char *line, size_t len,
882 int *table_level, int *eol_action)
884 const char *s;
885 char cmdbuf[256];
886 int cmdidx = 0;
887 int in_cmd = 0;
888 size_t n;
890 for (s=line; *s && len; s++, len--)
892 if (in_cmd)
894 if (in_cmd == 1)
896 switch (*s)
898 case '@': case '{': case '}':
899 putc (*s, fp); in_cmd = 0;
900 break;
901 case ':': /* Not ending a sentence flag. */
902 in_cmd = 0;
903 break;
904 case '.': case '!': case '?': /* Ending a sentence. */
905 putc (*s, fp); in_cmd = 0;
906 break;
907 case ' ': case '\t': case '\n': /* Non collapsing spaces. */
908 putc (*s, fp); in_cmd = 0;
909 break;
910 default:
911 cmdidx = 0;
912 cmdbuf[cmdidx++] = *s;
913 in_cmd++;
914 break;
917 else if (*s == '{' || *s == ' ' || *s == '\t' || *s == '\n')
919 cmdbuf[cmdidx] = 0;
920 n = proc_texi_cmd (fp, cmdbuf, s, len, table_level, eol_action);
921 assert (n <= len);
922 s += n; len -= n;
923 s--; len++;
924 in_cmd = 0;
926 else if (cmdidx < sizeof cmdbuf -1)
927 cmdbuf[cmdidx++] = *s;
928 else
930 err ("texinfo command too long - ignored");
931 in_cmd = 0;
934 else if (*s == '@')
935 in_cmd = 1;
936 else if (*s == '\n')
938 switch (*eol_action)
940 case 1: /* Create a dummy paragraph. */
941 fputs ("\n\\ \n", fp);
942 break;
943 default:
944 putc (*s, fp);
946 *eol_action = 0;
948 else if (*s == '\\')
949 fputs ("\\\\", fp);
950 else
951 putc (*s, fp);
954 if (in_cmd > 1)
956 cmdbuf[cmdidx] = 0;
957 n = proc_texi_cmd (fp, cmdbuf, s, len, table_level, eol_action);
958 assert (n <= len);
959 s += n; len -= n;
960 s--; len++;
961 in_cmd = 0;
966 /* Do something with the Texinfo line LINE. */
967 static void
968 parse_texi_line (FILE *fp, const char *line, int *table_level)
970 int eol_action = 0;
972 /* A quick test whether there are any texinfo commands. */
973 if (!strchr (line, '@'))
975 fputs (line, fp);
976 putc ('\n', fp);
977 return;
979 proc_texi_buffer (fp, line, strlen (line), table_level, &eol_action);
980 putc ('\n', fp);
984 /* Write all the lines LINES to FP. */
985 static void
986 write_content (FILE *fp, line_buffer_t lines)
988 line_buffer_t line;
989 int table_level = 0;
991 for (line = lines; line; line = line->next)
993 if (line->verbatim)
995 fputs (line->line, fp);
996 putc ('\n', fp);
998 else
1000 /* fputs ("TEXI---", fp); */
1001 /* fputs (line->line, fp); */
1002 /* fputs ("---\n", fp); */
1003 parse_texi_line (fp, line->line, &table_level);
1010 static int
1011 is_standard_section (const char *name)
1013 int i;
1014 const char *s;
1016 for (i=0; (s=standard_sections[i]); i++)
1017 if (!strcmp (s, name))
1018 return 1;
1019 return 0;
1023 /* Finish a page; that is sort the data and write it out to the file. */
1024 static void
1025 finish_page (void)
1027 FILE *fp;
1028 section_buffer_t sect = NULL;
1029 int idx;
1030 const char *s;
1031 int i;
1033 if (!thepage.name)
1034 return; /* No page active. */
1036 if (verbose)
1037 inf ("finishing page '%s'", thepage.name);
1039 if (opt_select)
1041 if (!strcmp (opt_select, thepage.name))
1043 inf ("selected '%s'", thepage.name );
1044 fp = stdout;
1046 else
1048 fp = fopen ( "/dev/null", "w" );
1049 if (!fp)
1050 die ("failed to open /dev/null: %s\n", strerror (errno));
1053 else if (opt_store)
1055 inf ("writing '%s'", thepage.name );
1056 fp = fopen ( thepage.name, "w" );
1057 if (!fp)
1058 die ("failed to create '%s': %s\n", thepage.name, strerror (errno));
1060 else
1061 fp = stdout;
1063 if (write_th (fp))
1064 goto leave;
1066 for (idx=0; (s=standard_sections[idx]); idx++)
1068 for (i=0; i < thepage.n_sections; i++)
1070 sect = thepage.sections + i;
1071 if (sect->name && !strcmp (s, sect->name))
1072 break;
1074 if (i == thepage.n_sections)
1075 sect = NULL;
1077 if (sect)
1079 fprintf (fp, ".SH %s\n", sect->name);
1080 write_content (fp, sect->lines);
1081 /* Now continue with all non standard sections directly
1082 following this one. */
1083 for (i++; i < thepage.n_sections; i++)
1085 sect = thepage.sections + i;
1086 if (sect->name && is_standard_section (sect->name))
1087 break;
1088 if (sect->name)
1090 fprintf (fp, ".SH %s\n", sect->name);
1091 write_content (fp, sect->lines);
1099 leave:
1100 if (fp != stdout)
1101 fclose (fp);
1102 free (thepage.name);
1103 thepage.name = NULL;
1104 /* FIXME: Cleanup the content. */
1110 /* Parse one Texinfo file and create manpages according to the
1111 embedded instructions. */
1112 static void
1113 parse_file (const char *fname, FILE *fp, char **section_name, int in_pause)
1115 char *line;
1116 int lnr = 0;
1117 /* Fixme: The following state variables don't carry over to include
1118 files. */
1119 int skip_to_end = 0; /* Used to skip over menu entries. */
1120 int skip_sect_line = 0; /* Skip after @mansect. */
1121 int item_indent = 0; /* How far is the current @item indented. */
1123 /* Helper to define a macro. */
1124 char *macroname = NULL;
1125 char *macrovalue = NULL;
1126 size_t macrovaluesize = 0;
1127 size_t macrovalueused = 0;
1129 line = xmalloc (LINESIZE);
1130 while (fgets (line, LINESIZE, fp))
1132 size_t n = strlen (line);
1133 int got_line = 0;
1134 char *p, *pend;
1136 lnr++;
1137 if (!n || line[n-1] != '\n')
1139 err ("%s:%d: trailing linefeed missing, line too long or "
1140 "embedded Nul character", fname, lnr);
1141 break;
1143 line[--n] = 0;
1145 /* Kludge to allow indentation of tables. */
1146 for (p=line; *p == ' ' || *p == '\t'; p++)
1148 if (*p)
1150 if (*p == '@' && !strncmp (p+1, "item", 4))
1151 item_indent = p - line; /* Set a new indent level. */
1152 else if (p - line < item_indent)
1153 item_indent = 0; /* Switch off indention. */
1155 if (item_indent)
1157 memmove (line, line+item_indent, n - item_indent + 1);
1158 n -= item_indent;
1163 if (*line == '@')
1165 for (p=line+1, n=1; *p && *p != ' ' && *p != '\t'; p++)
1166 n++;
1167 while (*p == ' ' || *p == '\t')
1168 p++;
1170 else
1171 p = line;
1173 /* Take action on macro. */
1174 if (macroname)
1176 if (n == 4 && !memcmp (line, "@end", 4)
1177 && (line[4]==' '||line[4]=='\t'||!line[4])
1178 && !strncmp (p, "macro", 5)
1179 && (p[5]==' '||p[5]=='\t'||!p[5]))
1181 if (macrovalueused)
1182 macrovalue[--macrovalueused] = 0; /* Kill the last LF. */
1183 macrovalue[macrovalueused] = 0; /* Terminate macro. */
1184 macrovalue = xrealloc (macrovalue, macrovalueused+1);
1186 set_macro (macroname, macrovalue);
1187 macrovalue = NULL;
1188 free (macroname);
1189 macroname = NULL;
1191 else
1193 if (macrovalueused + strlen (line) + 2 >= macrovaluesize)
1195 macrovaluesize += strlen (line) + 256;
1196 macrovalue = xrealloc (macrovalue, macrovaluesize);
1198 strcpy (macrovalue+macrovalueused, line);
1199 macrovalueused += strlen (line);
1200 macrovalue[macrovalueused++] = '\n';
1202 continue;
1206 if (n >= 5 && !memcmp (line, "@node", 5)
1207 && (line[5]==' '||line[5]=='\t'||!line[5]))
1209 /* Completey ignore @node lines. */
1210 continue;
1214 if (skip_sect_line)
1216 skip_sect_line = 0;
1217 if (!strncmp (line, "@section", 8)
1218 || !strncmp (line, "@subsection", 11)
1219 || !strncmp (line, "@chapheading", 12))
1220 continue;
1223 /* We only parse lines we need and ignore the rest. There are a
1224 few macros used to control this as well as one @ifset
1225 command. Parts we know about are saved away into containers
1226 separate for each section. */
1228 /* First process ifset/ifclear commands. */
1229 if (*line == '@')
1231 if (n == 6 && !memcmp (line, "@ifset", 6)
1232 && (line[6]==' '||line[6]=='\t'))
1234 for (p=line+7; *p == ' ' || *p == '\t'; p++)
1236 if (!*p)
1238 err ("%s:%d: name missing after \"@ifset\"", fname, lnr);
1239 continue;
1241 for (pend=p; *pend && *pend != ' ' && *pend != '\t'; pend++)
1243 *pend = 0; /* Ignore rest of the line. */
1244 push_condition (p, 1, fname, lnr);
1245 continue;
1247 else if (n == 8 && !memcmp (line, "@ifclear", 8)
1248 && (line[8]==' '||line[8]=='\t'))
1250 for (p=line+9; *p == ' ' || *p == '\t'; p++)
1252 if (!*p)
1254 err ("%s:%d: name missing after \"@ifsclear\"", fname, lnr);
1255 continue;
1257 for (pend=p; *pend && *pend != ' ' && *pend != '\t'; pend++)
1259 *pend = 0; /* Ignore rest of the line. */
1260 push_condition (p, 0, fname, lnr);
1261 continue;
1263 else if (n == 4 && !memcmp (line, "@end", 4)
1264 && (line[4]==' '||line[4]=='\t')
1265 && !strncmp (p, "ifset", 5)
1266 && (p[5]==' '||p[5]=='\t'||!p[5]))
1268 pop_condition (1, fname, lnr);
1269 continue;
1271 else if (n == 4 && !memcmp (line, "@end", 4)
1272 && (line[4]==' '||line[4]=='\t')
1273 && !strncmp (p, "ifclear", 7)
1274 && (p[7]==' '||p[7]=='\t'||!p[7]))
1276 pop_condition (0, fname, lnr);
1277 continue;
1281 /* Take action on ifset/ifclear. */
1282 if (!cond_is_active)
1283 continue;
1285 /* Process commands. */
1286 if (*line == '@')
1288 if (skip_to_end
1289 && n == 4 && !memcmp (line, "@end", 4)
1290 && (line[4]==' '||line[4]=='\t'||!line[4]))
1292 skip_to_end = 0;
1294 else if (cond_in_verbatim)
1296 got_line = 1;
1298 else if (n == 6 && !memcmp (line, "@macro", 6))
1300 macroname = xstrdup (p);
1301 macrovalue = xmalloc ((macrovaluesize = 1024));
1302 macrovalueused = 0;
1304 else if (n == 4 && !memcmp (line, "@set", 4))
1306 set_variable (p);
1308 else if (n == 8 && !memcmp (line, "@manpage", 8))
1310 free (*section_name);
1311 *section_name = NULL;
1312 finish_page ();
1313 start_page (p);
1314 in_pause = 0;
1316 else if (n == 8 && !memcmp (line, "@mansect", 8))
1318 if (!thepage.name)
1319 err ("%s:%d: section outside of a man page", fname, lnr);
1320 else
1322 free (*section_name);
1323 *section_name = ascii_strupr (xstrdup (p));
1324 in_pause = 0;
1325 skip_sect_line = 1;
1328 else if (n == 9 && !memcmp (line, "@manpause", 9))
1330 if (!*section_name)
1331 err ("%s:%d: pausing outside of a man section", fname, lnr);
1332 else if (in_pause)
1333 err ("%s:%d: already pausing", fname, lnr);
1334 else
1335 in_pause = 1;
1337 else if (n == 8 && !memcmp (line, "@mancont", 8))
1339 if (!*section_name)
1340 err ("%s:%d: continue outside of a man section", fname, lnr);
1341 else if (!in_pause)
1342 err ("%s:%d: continue while not pausing", fname, lnr);
1343 else
1344 in_pause = 0;
1346 else if (n == 5 && !memcmp (line, "@menu", 5)
1347 && (line[5]==' '||line[5]=='\t'||!line[5]))
1349 skip_to_end = 1;
1351 else if (n == 8 && !memcmp (line, "@include", 8)
1352 && (line[8]==' '||line[8]=='\t'||!line[8]))
1354 char *incname = xstrdup (p);
1355 FILE *incfp = fopen (incname, "r");
1357 if (!incfp && opt_include && *opt_include && *p != '/')
1359 free (incname);
1360 incname = xmalloc (strlen (opt_include) + 1
1361 + strlen (p) + 1);
1362 strcpy (incname, opt_include);
1363 if ( incname[strlen (incname)-1] != '/' )
1364 strcat (incname, "/");
1365 strcat (incname, p);
1366 incfp = fopen (incname, "r");
1369 if (!incfp)
1370 err ("can't open include file '%s': %s",
1371 incname, strerror (errno));
1372 else
1374 parse_file (incname, incfp, section_name, in_pause);
1375 fclose (incfp);
1377 free (incname);
1379 else if (n == 4 && !memcmp (line, "@bye", 4)
1380 && (line[4]==' '||line[4]=='\t'||!line[4]))
1382 break;
1384 else if (!skip_to_end)
1385 got_line = 1;
1387 else if (!skip_to_end)
1388 got_line = 1;
1390 if (got_line && cond_in_verbatim)
1391 add_content (*section_name, line, 1);
1392 else if (got_line && thepage.name && *section_name && !in_pause)
1393 add_content (*section_name, line, 0);
1396 if (ferror (fp))
1397 err ("%s:%d: read error: %s", fname, lnr, strerror (errno));
1398 free (macroname);
1399 free (macrovalue);
1400 free (line);
1404 static void
1405 top_parse_file (const char *fname, FILE *fp)
1407 char *section_name = NULL; /* Name of the current section or NULL
1408 if not in a section. */
1409 macro_t m;
1411 while (macrolist)
1413 macro_t next = macrolist->next;
1414 free (macrolist->value);
1415 free (macrolist);
1416 macrolist = next;
1418 while (variablelist)
1420 macro_t next = variablelist->next;
1421 free (variablelist->value);
1422 free (variablelist);
1423 variablelist = next;
1425 for (m=predefinedmacrolist; m; m = m->next)
1426 set_macro (m->name, xstrdup ("1"));
1427 cond_is_active = 1;
1428 cond_in_verbatim = 0;
1430 parse_file (fname, fp, &section_name, 0);
1431 free (section_name);
1432 finish_page ();
1437 main (int argc, char **argv)
1439 int last_argc = -1;
1441 opt_source = "GNU";
1442 opt_release = "";
1444 /* Define default macros. The trick is that these macros are not
1445 defined when using the actual texinfo renderer. */
1446 add_predefined_macro ("isman");
1447 add_predefined_macro ("manverb");
1449 /* Option parsing. */
1450 if (argc)
1452 argc--; argv++;
1454 while (argc && last_argc != argc )
1456 last_argc = argc;
1457 if (!strcmp (*argv, "--"))
1459 argc--; argv++;
1460 break;
1462 else if (!strcmp (*argv, "--help"))
1464 puts (
1465 "Usage: " PGM " [OPTION] [FILE]\n"
1466 "Extract man pages from a Texinfo source.\n\n"
1467 " --source NAME use NAME as source field\n"
1468 " --release STRING use STRING as the release field\n"
1469 " --store write output using @manpage name\n"
1470 " --select NAME only output pages with @manpage NAME\n"
1471 " --verbose enable extra informational output\n"
1472 " --debug enable additional debug output\n"
1473 " --help display this help and exit\n"
1474 " -I DIR also search in include DIR\n"
1475 " -D gpgone the only useable define\n\n"
1476 "With no FILE, or when FILE is -, read standard input.\n\n"
1477 "Report bugs to <bugs@g10code.com>.");
1478 exit (0);
1480 else if (!strcmp (*argv, "--version"))
1482 puts (PGM " " VERSION "\n"
1483 "Copyright (C) 2005 g10 Code GmbH\n"
1484 "This program comes with ABSOLUTELY NO WARRANTY.\n"
1485 "This is free software, and you are welcome to redistribute it\n"
1486 "under certain conditions. See the file COPYING for details.");
1487 exit (0);
1489 else if (!strcmp (*argv, "--verbose"))
1491 verbose = 1;
1492 argc--; argv++;
1494 else if (!strcmp (*argv, "--quiet"))
1496 quiet = 1;
1497 argc--; argv++;
1499 else if (!strcmp (*argv, "--debug"))
1501 verbose = debug = 1;
1502 argc--; argv++;
1504 else if (!strcmp (*argv, "--source"))
1506 argc--; argv++;
1507 if (argc)
1509 opt_source = *argv;
1510 argc--; argv++;
1513 else if (!strcmp (*argv, "--release"))
1515 argc--; argv++;
1516 if (argc)
1518 opt_release = *argv;
1519 argc--; argv++;
1522 else if (!strcmp (*argv, "--store"))
1524 opt_store = 1;
1525 argc--; argv++;
1527 else if (!strcmp (*argv, "--select"))
1529 argc--; argv++;
1530 if (argc)
1532 opt_select = strrchr (*argv, '/');
1533 if (opt_select)
1534 opt_select++;
1535 else
1536 opt_select = *argv;
1537 argc--; argv++;
1540 else if (!strcmp (*argv, "-I"))
1542 argc--; argv++;
1543 if (argc)
1545 opt_include = *argv;
1546 argc--; argv++;
1549 else if (!strcmp (*argv, "-D"))
1551 argc--; argv++;
1552 if (argc)
1554 add_predefined_macro (*argv);
1555 argc--; argv++;
1560 if (argc > 1)
1561 die ("usage: " PGM " [OPTION] [FILE] (try --help for more information)\n");
1563 /* Start processing. */
1564 if (argc && strcmp (*argv, "-"))
1566 FILE *fp = fopen (*argv, "rb");
1567 if (!fp)
1568 die ("%s:0: can't open file: %s", *argv, strerror (errno));
1569 top_parse_file (*argv, fp);
1570 fclose (fp);
1572 else
1573 top_parse_file ("-", stdin);
1575 return !!any_error;
1580 Local Variables:
1581 compile-command: "gcc -Wall -g -Wall -o yat2m yat2m.c"
1582 End: