2008-01-15 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / doc / yat2m.c
blob9411e3419bdccff3d9444d2765c4094b2aba0f21
1 /* yat2m.c - Yet Another Texi 2 Man converter
2 * Copyright (C) 2005 g10 Code GmbH
3 * Copyright (C) 2006 2006 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 textinfo 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 follwing 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.
78 #include <stdio.h>
79 #include <stdlib.h>
80 #include <stddef.h>
81 #include <string.h>
82 #include <errno.h>
83 #include <stdarg.h>
84 #include <assert.h>
85 #include <ctype.h>
86 #include <time.h>
89 #define PGM "yat2m"
90 #define VERSION "0.5"
92 /* The maximum length of a line including the linefeed and one extra
93 character. */
94 #define LINESIZE 1024
96 /* Option flags. */
97 static int verbose;
98 static int quiet;
99 static int debug;
100 static const char *opt_source;
101 static const char *opt_release;
102 static const char *opt_select;
103 static const char *opt_include;
104 static int opt_store;
106 /* The only define we understand is -D gpgone. Thus we need a simple
107 boolean tro track it. */
108 static int gpgone_defined;
110 /* Flag to keep track whether any error occurred. */
111 static int any_error;
114 /* Object to keep macro definitions. */
115 struct macro_s
117 struct macro_s *next;
118 char *value; /* Malloced value. */
119 char name[1];
121 typedef struct macro_s *macro_t;
123 /* List of all defined macros. */
124 static macro_t macrolist;
127 /* Object to store one line of content. */
128 struct line_buffer_s
130 struct line_buffer_s *next;
131 int verbatim; /* True if LINE contains verbatim data. The default
132 is Texinfo source. */
133 char *line;
135 typedef struct line_buffer_s *line_buffer_t;
138 /* Object to collect the data of a section. */
139 struct section_buffer_s
141 char *name; /* Malloced name of the section. This may be
142 NULL to indicate this slot is not used. */
143 line_buffer_t lines; /* Linked list with the lines of the section. */
144 line_buffer_t *lines_tail; /* Helper for faster appending to the
145 linked list. */
146 line_buffer_t last_line; /* Points to the last line appended. */
148 typedef struct section_buffer_s *section_buffer_t;
150 /* Variable to keep info about the current page together. */
151 static struct
153 /* Filename of the current page or NULL if no page is active. Malloced. */
154 char *name;
156 /* Number of allocated elements in SECTIONS below. */
157 size_t n_sections;
158 /* Array with the data of the sections. */
159 section_buffer_t sections;
161 } thepage;
164 /* The list of standard section names. COMMANDS and ASSUAN are GnuPG
165 specific. */
166 static const char * const standard_sections[] =
167 { "NAME", "SYNOPSIS", "DESCRIPTION",
168 "RETURN VALUE", "EXIT STATUS", "ERROR HANDLING", "ERRORS",
169 "COMMANDS", "OPTIONS", "USAGE", "EXAMPLES", "FILES",
170 "ENVIRONMENT", "DIAGNOSTICS", "SECURITY", "CONFORMING TO",
171 "ASSUAN", "NOTES", "BUGS", "AUTHOR", "SEE ALSO", NULL };
174 /*-- Local prototypes. --*/
175 static void proc_texi_buffer (FILE *fp, const char *line, size_t len,
176 int *table_level, int *eol_action);
180 /* Print diagnostic message and exit with failure. */
181 static void
182 die (const char *format, ...)
184 va_list arg_ptr;
186 fflush (stdout);
187 fprintf (stderr, "%s: ", PGM);
189 va_start (arg_ptr, format);
190 vfprintf (stderr, format, arg_ptr);
191 va_end (arg_ptr);
192 putc ('\n', stderr);
194 exit (1);
198 /* Print diagnostic message. */
199 static void
200 err (const char *format, ...)
202 va_list arg_ptr;
204 fflush (stdout);
205 if (strncmp (format, "%s:%d:", 6))
206 fprintf (stderr, "%s: ", PGM);
208 va_start (arg_ptr, format);
209 vfprintf (stderr, format, arg_ptr);
210 va_end (arg_ptr);
211 putc ('\n', stderr);
212 any_error = 1;
215 /* Print diagnostic message. */
216 static void
217 inf (const char *format, ...)
219 va_list arg_ptr;
221 fflush (stdout);
222 fprintf (stderr, "%s: ", PGM);
224 va_start (arg_ptr, format);
225 vfprintf (stderr, format, arg_ptr);
226 va_end (arg_ptr);
227 putc ('\n', stderr);
231 static void *
232 xmalloc (size_t n)
234 void *p = malloc (n);
235 if (!p)
236 die ("out of core: %s", strerror (errno));
237 return p;
240 static void *
241 xcalloc (size_t n, size_t m)
243 void *p = calloc (n, m);
244 if (!p)
245 die ("out of core: %s", strerror (errno));
246 return p;
249 static void *
250 xrealloc (void *old, size_t n)
252 void *p = realloc (old, n);
253 if (!p)
254 die ("out of core: %s", strerror (errno));
255 return p;
258 static char *
259 xstrdup (const char *string)
261 void *p = malloc (strlen (string)+1);
262 if (!p)
263 die ("out of core: %s", strerror (errno));
264 strcpy (p, string);
265 return p;
269 /* Uppercase the ascii characters in STRING. */
270 static char *
271 ascii_strupr (char *string)
273 char *p;
275 for (p = string; *p; p++)
276 if (!(*p & 0x80))
277 *p = toupper (*p);
278 return string;
282 /* Return the current date as an ISO string. */
283 const char *
284 isodatestring (void)
286 static char buffer[11+5];
287 struct tm *tp;
288 time_t atime = time (NULL);
290 if (atime < 0)
291 strcpy (buffer, "????" "-??" "-??");
292 else
294 tp = gmtime (&atime);
295 sprintf (buffer,"%04d-%02d-%02d",
296 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
298 return buffer;
303 /* Return a section buffer for the section NAME. Allocate a new buffer
304 if this is a new section. Keep track of the sections in THEPAGE.
305 This function may reallocate the section array in THEPAGE. */
306 static section_buffer_t
307 get_section_buffer (const char *name)
309 int i;
310 section_buffer_t sect;
312 /* If there is no section we put everything into the required NAME
313 section. Given that this is the first one listed it is likely
314 that error are easily visible. */
315 if (!name)
316 name = "NAME";
318 for (i=0; i < thepage.n_sections; i++)
320 sect = thepage.sections + i;
321 if (sect->name && !strcmp (name, sect->name))
322 return sect;
324 for (i=0; i < thepage.n_sections; i++)
325 if (!thepage.sections[i].name)
326 break;
327 if (i < thepage.n_sections)
328 sect = thepage.sections + i;
329 else
331 /* We need to allocate or reallocate the section array. */
332 size_t old_n = thepage.n_sections;
333 size_t new_n = 20;
335 if (!old_n)
336 thepage.sections = xcalloc (new_n, sizeof *thepage.sections);
337 else
339 thepage.sections = xrealloc (thepage.sections,
340 ((old_n + new_n)
341 * sizeof *thepage.sections));
342 memset (thepage.sections + old_n, 0,
343 new_n * sizeof *thepage.sections);
345 thepage.n_sections += new_n;
347 /* Setup the tail pointers. */
348 for (i=old_n; i < thepage.n_sections; i++)
350 sect = thepage.sections + i;
351 sect->lines_tail = &sect->lines;
353 sect = thepage.sections + old_n;
356 /* Store the name. */
357 assert (!sect->name);
358 sect->name = xstrdup (name);
359 return sect;
364 /* Add the content of LINE to the section named SECTNAME. */
365 static void
366 add_content (const char *sectname, char *line, int verbatim)
368 section_buffer_t sect;
369 line_buffer_t lb;
371 sect = get_section_buffer (sectname);
372 if (sect->last_line && !sect->last_line->verbatim == !verbatim)
374 /* Lets append that line to the last one. We do this to keep
375 all lines of the same kind (i.e.verbatim or not) together in
376 one large buffer. */
377 size_t n1, n;
379 lb = sect->last_line;
380 n1 = strlen (lb->line);
381 n = n1 + 1 + strlen (line) + 1;
382 lb->line = xrealloc (lb->line, n);
383 strcpy (lb->line+n1, "\n");
384 strcpy (lb->line+n1+1, line);
386 else
388 lb = xcalloc (1, sizeof *lb);
389 lb->verbatim = verbatim;
390 lb->line = xstrdup (line);
391 sect->last_line = lb;
392 *sect->lines_tail = lb;
393 sect->lines_tail = &lb->next;
398 /* Prepare for a new man page using the filename NAME. */
399 static void
400 start_page (char *name)
402 if (verbose)
403 inf ("starting page `%s'", name);
404 assert (!thepage.name);
405 thepage.name = xstrdup (name);
406 thepage.n_sections = 0;
410 /* Write the .TH entry of the current page. Return -1 if there is a
411 problem with the page. */
412 static int
413 write_th (FILE *fp)
415 char *name, *p;
417 name = ascii_strupr (xstrdup (thepage.name));
418 p = strrchr (name, '.');
419 if (!p || !p[1])
421 err ("no section name in man page `%s'", thepage.name);
422 free (name);
423 return -1;
425 *p++ = 0;
426 fprintf (fp, ".TH %s %s %s \"%s\" \"%s\"\n",
427 name, p, isodatestring (), opt_release, opt_source);
428 return 0;
432 /* Process the texinfo command COMMAND (without the leading @) and
433 write output if needed to FP. REST is the remainer of the line
434 which should either point to an opening brace or to a white space.
435 The function returns the number of characters already processed
436 from REST. LEN is the usable length of REST. TABLE_LEVEL is used to
437 control the indentation of tables. */
438 static size_t
439 proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
440 int *table_level, int *eol_action)
442 static struct {
443 const char *name; /* Name of the command. */
444 int what; /* What to do with this command. */
445 const char *lead_in; /* String to print with a opening brace. */
446 const char *lead_out;/* String to print with the closing brace. */
447 } cmdtbl[] = {
448 { "command", 0, "\\fB", "\\fR" },
449 { "code", 0, "\\fB", "\\fR" },
450 { "sc", 0, "\\fB", "\\fR" },
451 { "var", 0, "\\fI", "\\fR" },
452 { "samp", 0, "'", "'" },
453 { "file", 0, "`\\fI","\\fR'" },
454 { "env", 0, "`\\fI","\\fR'" },
455 { "acronym", 0 },
456 { "dfn", 0 },
457 { "option", 0, "\\fB", "\\fR" },
458 { "example", 1, ".RS 2\n.nf\n" },
459 { "smallexample", 1, ".RS 2\n.nf\n" },
460 { "asis", 7 },
461 { "anchor", 7 },
462 { "cartouche", 1 },
463 { "xref", 0, "see: [", "]" },
464 { "pxref", 0, "see: [", "]" },
465 { "uref", 0, "(\\fB", "\\fR)" },
466 { "footnote",0, " ([", "])" },
467 { "emph", 0, "\\fI", "\\fR" },
468 { "w", 1 },
469 { "c", 5 },
470 { "opindex", 1 },
471 { "cpindex", 1 },
472 { "cindex", 1 },
473 { "noindent", 0 },
474 { "section", 1 },
475 { "chapter", 1 },
476 { "subsection", 6, "\n.SS " },
477 { "chapheading", 0},
478 { "item", 2, ".TP\n.B " },
479 { "itemx", 2, ".TP\n.B " },
480 { "table", 3 },
481 { "itemize", 3 },
482 { "bullet", 0, "* " },
483 { "end", 4 },
484 { "quotation",1, ".RS\n\\fB" },
485 { NULL }
487 size_t n;
488 int i;
489 const char *s;
490 const char *lead_out = NULL;
491 int ignore_args = 0;
493 for (i=0; cmdtbl[i].name && strcmp (cmdtbl[i].name, command); i++)
495 if (cmdtbl[i].name)
497 s = cmdtbl[i].lead_in;
498 if (s)
499 fputs (s, fp);
500 lead_out = cmdtbl[i].lead_out;
501 switch (cmdtbl[i].what)
503 case 1: /* Throw away the entire line. */
504 s = memchr (rest, '\n', len);
505 return s? (s-rest)+1 : len;
506 case 2: /* Handle @item. */
507 break;
508 case 3: /* Handle table. */
509 if (++(*table_level) > 1)
510 fputs (".RS\n", fp);
511 /* Now throw away the entire line. */
512 s = memchr (rest, '\n', len);
513 return s? (s-rest)+1 : len;
514 break;
515 case 4: /* Handle end. */
516 for (s=rest, n=len; n && (*s == ' ' || *s == '\t'); s++, n--)
518 if (n >= 5 && !memcmp (s, "table", 5)
519 && (!n || s[5] == ' ' || s[5] == '\t' || s[5] == '\n'))
521 if ((*table_level)-- > 1)
522 fputs (".RE\n", fp);
524 else if (n >= 7 && !memcmp (s, "example", 7)
525 && (!n || s[7] == ' ' || s[7] == '\t' || s[7] == '\n'))
527 fputs (".fi\n.RE\n", fp);
529 else if (n >= 12 && !memcmp (s, "smallexample", 12)
530 && (!n || s[12] == ' ' || s[12] == '\t' || s[12] == '\n'))
532 fputs (".fi\n.RE\n", fp);
534 else if (n >= 9 && !memcmp (s, "quotation", 9)
535 && (!n || s[9] == ' ' || s[9] == '\t' || s[9] == '\n'))
537 fputs ("\\fR\n.RE\n", fp);
539 /* Now throw away the entire line. */
540 s = memchr (rest, '\n', len);
541 return s? (s-rest)+1 : len;
542 case 5: /* Handle special comments. */
543 for (s=rest, n=len; n && (*s == ' ' || *s == '\t'); s++, n--)
545 if (n >= 4 && !memcmp (s, "man:", 4))
547 for (s+=4, n-=4; n && *s != '\n'; n--, s++)
548 putc (*s, fp);
549 putc ('\n', fp);
551 /* Now throw away the entire line. */
552 s = memchr (rest, '\n', len);
553 return s? (s-rest)+1 : len;
554 case 6:
555 *eol_action = 1;
556 break;
557 case 7:
558 ignore_args = 1;
559 break;
560 default:
561 break;
564 else
566 macro_t m;
568 for (m = macrolist; m ; m = m->next)
569 if (!strcmp (m->name, command))
570 break;
571 if (m)
573 proc_texi_buffer (fp, m->value, strlen (m->value),
574 table_level, eol_action);
575 ignore_args = 1; /* Parameterized macros are not yet supported. */
577 else
578 inf ("texinfo command `%s' not supported (%.*s)", command,
579 ((s = memchr (rest, '\n', len)), (s? (s-rest) : len)), rest);
582 if (*rest == '{')
584 /* Find matching closing brace. */
585 for (s=rest+1, n=1, i=1; i && *s && n < len; s++, n++)
586 if (*s == '{')
587 i++;
588 else if (*s == '}')
589 i--;
590 if (i)
592 err ("closing brace for command `%s' not found", command);
593 return len;
595 if (n > 2 && !ignore_args)
596 proc_texi_buffer (fp, rest+1, n-2, table_level, eol_action);
598 else
599 n = 0;
601 if (lead_out)
602 fputs (lead_out, fp);
604 return n;
609 /* Process the string LINE with LEN bytes of Texinfo content. */
610 static void
611 proc_texi_buffer (FILE *fp, const char *line, size_t len,
612 int *table_level, int *eol_action)
614 const char *s;
615 char cmdbuf[256];
616 int cmdidx = 0;
617 int in_cmd = 0;
618 size_t n;
620 for (s=line; *s && len; s++, len--)
622 if (in_cmd)
624 if (in_cmd == 1)
626 switch (*s)
628 case '@': case '{': case '}':
629 putc (*s, fp); in_cmd = 0;
630 break;
631 case ':': /* Not ending a sentence flag. */
632 in_cmd = 0;
633 break;
634 case '.': case '!': case '?': /* Ending a sentence. */
635 putc (*s, fp); in_cmd = 0;
636 break;
637 case ' ': case '\t': case '\n': /* Non collapsing spaces. */
638 putc (*s, fp); in_cmd = 0;
639 break;
640 default:
641 cmdidx = 0;
642 cmdbuf[cmdidx++] = *s;
643 in_cmd++;
644 break;
647 else if (*s == '{' || *s == ' ' || *s == '\t' || *s == '\n')
649 cmdbuf[cmdidx] = 0;
650 n = proc_texi_cmd (fp, cmdbuf, s, len, table_level, eol_action);
651 assert (n <= len);
652 s += n; len -= n;
653 s--; len++;
654 in_cmd = 0;
656 else if (cmdidx < sizeof cmdbuf -1)
657 cmdbuf[cmdidx++] = *s;
658 else
660 err ("texinfo command too long - ignored");
661 in_cmd = 0;
664 else if (*s == '@')
665 in_cmd = 1;
666 else if (*s == '\n')
668 switch (*eol_action)
670 case 1: /* Create a dummy paragraph. */
671 fputs ("\n\\ \n", fp);
672 break;
673 default:
674 putc (*s, fp);
676 *eol_action = 0;
678 else
679 putc (*s, fp);
682 if (in_cmd > 1)
684 cmdbuf[cmdidx] = 0;
685 n = proc_texi_cmd (fp, cmdbuf, s, len, table_level, eol_action);
686 assert (n <= len);
687 s += n; len -= n;
688 s--; len++;
689 in_cmd = 0;
694 /* Do something with the Texinfo line LINE. */
695 static void
696 parse_texi_line (FILE *fp, const char *line, int *table_level)
698 int eol_action = 0;
700 /* A quick test whether there are any texinfo commands. */
701 if (!strchr (line, '@'))
703 fputs (line, fp);
704 putc ('\n', fp);
705 return;
707 proc_texi_buffer (fp, line, strlen (line), table_level, &eol_action);
708 putc ('\n', fp);
712 /* Write all the lines LINES to FP. */
713 static void
714 write_content (FILE *fp, line_buffer_t lines)
716 line_buffer_t line;
717 int table_level = 0;
719 for (line = lines; line; line = line->next)
721 if (line->verbatim)
723 fputs (line->line, fp);
724 putc ('\n', fp);
726 else
728 /* fputs ("TEXI---", fp); */
729 /* fputs (line->line, fp); */
730 /* fputs ("---\n", fp); */
731 parse_texi_line (fp, line->line, &table_level);
738 static int
739 is_standard_section (const char *name)
741 int i;
742 const char *s;
744 for (i=0; (s=standard_sections[i]); i++)
745 if (!strcmp (s, name))
746 return 1;
747 return 0;
751 /* Finish a page; that is sort the data and write it out to the file. */
752 static void
753 finish_page (void)
755 FILE *fp;
756 section_buffer_t sect = NULL;
757 int idx;
758 const char *s;
759 int i;
761 if (!thepage.name)
762 return; /* No page active. */
764 if (verbose)
765 inf ("finishing page `%s'", thepage.name);
767 if (opt_select)
769 if (!strcmp (opt_select, thepage.name))
771 inf ("selected `%s'", thepage.name );
772 fp = stdout;
774 else
776 fp = fopen ( "/dev/null", "w" );
777 if (!fp)
778 die ("failed to open /dev/null: %s\n", strerror (errno));
781 else if (opt_store)
783 inf ("writing `%s'", thepage.name );
784 fp = fopen ( thepage.name, "w" );
785 if (!fp)
786 die ("failed to create `%s': %s\n", thepage.name, strerror (errno));
788 else
789 fp = stdout;
791 if (write_th (fp))
792 goto leave;
794 for (idx=0; (s=standard_sections[idx]); idx++)
796 for (i=0; i < thepage.n_sections; i++)
798 sect = thepage.sections + i;
799 if (sect->name && !strcmp (s, sect->name))
800 break;
802 if (i == thepage.n_sections)
803 sect = NULL;
805 if (sect)
807 fprintf (fp, ".SH %s\n", sect->name);
808 write_content (fp, sect->lines);
809 /* Now continue with all non standard sections directly
810 following this one. */
811 for (i++; i < thepage.n_sections; i++)
813 sect = thepage.sections + i;
814 if (sect->name && is_standard_section (sect->name))
815 break;
816 if (sect->name)
818 fprintf (fp, ".SH %s\n", sect->name);
819 write_content (fp, sect->lines);
827 leave:
828 if (fp != stdout)
829 fclose (fp);
830 free (thepage.name);
831 thepage.name = NULL;
832 /* FIXME: Cleanup the content. */
838 /* Parse one Texinfo file and create manpages according to the
839 embedded instructions. */
840 static void
841 parse_file (const char *fname, FILE *fp, char **section_name, int in_pause)
843 char *line;
844 int lnr = 0;
845 /* Fixme: The follwing state variables don't carry over to include
846 files. */
847 int in_verbatim = 0;
848 int skip_to_end = 0; /* Used to skip over menu entries. */
849 int skip_sect_line = 0; /* Skip after @mansect. */
850 int ifset_nesting = 0; /* How often a ifset has been seen. */
851 int ifclear_nesting = 0; /* How often a ifclear has been seen. */
852 int in_gpgone = 0; /* Keep track of "@ifset gpgone" parts. */
853 int not_in_gpgone = 0; /* Keep track of "@ifclear gpgone" parts. */
854 int not_in_man = 0; /* Keep track of "@ifclear isman" parts. */
856 /* Helper to define a macro. */
857 char *macroname = NULL;
858 char *macrovalue = NULL;
859 size_t macrovaluesize = 0;
860 size_t macrovalueused = 0;
862 line = xmalloc (LINESIZE);
863 while (fgets (line, LINESIZE, fp))
865 size_t n = strlen (line);
866 int got_line = 0;
867 char *p;
869 lnr++;
870 if (!n || line[n-1] != '\n')
872 err ("%s:%d: trailing linefeed missing, line too long or "
873 "embedded Nul character", fname, lnr);
874 break;
876 line[--n] = 0;
878 if (*line == '@')
880 for (p=line+1, n=1; *p && *p != ' ' && *p != '\t'; p++)
881 n++;
882 while (*p == ' ' || *p == '\t')
883 p++;
885 else
886 p = line;
888 /* Take action on macro. */
889 if (macroname)
891 if (n == 4 && !memcmp (line, "@end", 4)
892 && (line[4]==' '||line[4]=='\t'||!line[4])
893 && !strncmp (p, "macro", 5)
894 && (p[5]==' '||p[5]=='\t'||!p[5]))
896 macro_t m;
898 if (macrovalueused)
899 macrovalue[--macrovalueused] = 0; /* Kill the last LF. */
900 macrovalue[macrovalueused] = 0; /* Terminate macro. */
901 macrovalue = xrealloc (macrovalue, macrovalueused+1);
903 for (m= macrolist; m; m = m->next)
904 if (!strcmp (m->name, macroname))
905 break;
906 if (m)
907 free (m->value);
908 else
910 m = xcalloc (1, sizeof *m + strlen (macroname));
911 strcpy (m->name, macroname);
912 m->next = macrolist;
913 macrolist = m;
915 m->value = macrovalue;
916 macrovalue = NULL;
917 free (macroname);
918 macroname = NULL;
920 else
922 if (macrovalueused + strlen (line) + 2 >= macrovaluesize)
924 macrovaluesize += strlen (line) + 256;
925 macrovalue = xrealloc (macrovalue, macrovaluesize);
927 strcpy (macrovalue+macrovalueused, line);
928 macrovalueused += strlen (line);
929 macrovalue[macrovalueused++] = '\n';
931 continue;
935 if (n >= 5 && !memcmp (line, "@node", 5)
936 && (line[5]==' '||line[5]=='\t'||!line[5]))
938 /* Completey ignore @node lines. */
939 continue;
943 if (skip_sect_line)
945 skip_sect_line = 0;
946 if (!strncmp (line, "@section", 8)
947 || !strncmp (line, "@subsection", 11)
948 || !strncmp (line, "@chapheading", 12))
949 continue;
952 /* We only parse lines we need and ignore the rest. There are a
953 few macros used to control this as well as one @ifset
954 command. Parts we know about are saved away into containers
955 separate for each section. */
957 /* First process ifset/ifclear commands. */
958 if (*line == '@')
960 if (n == 6 && !memcmp (line, "@ifset", 6)
961 && (line[6]==' '||line[6]=='\t'))
963 ifset_nesting++;
965 if (!strncmp (p, "manverb", 7) && (p[7]==' '||p[7]=='\t'||!p[7]))
967 if (in_verbatim)
968 err ("%s:%d: nested \"@ifset manverb\"", fname, lnr);
969 else
970 in_verbatim = ifset_nesting;
972 else if (!strncmp (p, "gpgone", 6)
973 && (p[6]==' '||p[6]=='\t'||!p[6]))
975 if (in_gpgone)
976 err ("%s:%d: nested \"@ifset gpgone\"", fname, lnr);
977 else
978 in_gpgone = ifset_nesting;
980 continue;
982 else if (n == 4 && !memcmp (line, "@end", 4)
983 && (line[4]==' '||line[4]=='\t')
984 && !strncmp (p, "ifset", 5)
985 && (p[5]==' '||p[5]=='\t'||!p[5]))
987 if (in_verbatim && ifset_nesting == in_verbatim)
988 in_verbatim = 0;
989 if (in_gpgone && ifset_nesting == in_gpgone)
990 in_gpgone = 0;
992 if (ifset_nesting)
993 ifset_nesting--;
994 else
995 err ("%s:%d: unbalanced \"@end ifset\"", fname, lnr);
996 continue;
998 else if (n == 8 && !memcmp (line, "@ifclear", 8)
999 && (line[8]==' '||line[8]=='\t'))
1001 ifclear_nesting++;
1003 if (!strncmp (p, "gpgone", 6)
1004 && (p[6]==' '||p[6]=='\t'||!p[6]))
1006 if (not_in_gpgone)
1007 err ("%s:%d: nested \"@ifclear gpgone\"", fname, lnr);
1008 else
1009 not_in_gpgone = ifclear_nesting;
1012 else if (!strncmp (p, "isman", 5)
1013 && (p[5]==' '||p[5]=='\t'||!p[5]))
1015 if (not_in_man)
1016 err ("%s:%d: nested \"@ifclear isman\"", fname, lnr);
1017 else
1018 not_in_man = ifclear_nesting;
1021 continue;
1023 else if (n == 4 && !memcmp (line, "@end", 4)
1024 && (line[4]==' '||line[4]=='\t')
1025 && !strncmp (p, "ifclear", 7)
1026 && (p[7]==' '||p[7]=='\t'||!p[7]))
1028 if (not_in_gpgone && ifclear_nesting == not_in_gpgone)
1029 not_in_gpgone = 0;
1030 if (not_in_man && ifclear_nesting == not_in_man)
1031 not_in_man = 0;
1033 if (ifclear_nesting)
1034 ifclear_nesting--;
1035 else
1036 err ("%s:%d: unbalanced \"@end ifclear\"", fname, lnr);
1037 continue;
1041 /* Take action on ifset/ifclear. */
1042 if ( (in_gpgone && !gpgone_defined)
1043 || (not_in_gpgone && gpgone_defined)
1044 || not_in_man)
1045 continue;
1047 /* Process commands. */
1048 if (*line == '@')
1050 if (skip_to_end
1051 && n == 4 && !memcmp (line, "@end", 4)
1052 && (line[4]==' '||line[4]=='\t'||!line[4]))
1054 skip_to_end = 0;
1056 else if (in_verbatim)
1058 got_line = 1;
1060 else if (n == 6 && !memcmp (line, "@macro", 6))
1062 macroname = xstrdup (p);
1063 macrovalue = xmalloc ((macrovaluesize = 1024));
1064 macrovalueused = 0;
1066 else if (n == 8 && !memcmp (line, "@manpage", 8))
1068 free (*section_name);
1069 *section_name = NULL;
1070 finish_page ();
1071 start_page (p);
1072 in_pause = 0;
1074 else if (n == 8 && !memcmp (line, "@mansect", 8))
1076 if (!thepage.name)
1077 err ("%s:%d: section outside of a man page", fname, lnr);
1078 else
1080 free (*section_name);
1081 *section_name = ascii_strupr (xstrdup (p));
1082 in_pause = 0;
1083 skip_sect_line = 1;
1086 else if (n == 9 && !memcmp (line, "@manpause", 9))
1088 if (!*section_name)
1089 err ("%s:%d: pausing outside of a man section", fname, lnr);
1090 else if (in_pause)
1091 err ("%s:%d: already pausing", fname, lnr);
1092 else
1093 in_pause = 1;
1095 else if (n == 8 && !memcmp (line, "@mancont", 8))
1097 if (!*section_name)
1098 err ("%s:%d: continue outside of a man section", fname, lnr);
1099 else if (!in_pause)
1100 err ("%s:%d: continue while not pausing", fname, lnr);
1101 else
1102 in_pause = 0;
1104 else if (n == 5 && !memcmp (line, "@menu", 5)
1105 && (line[5]==' '||line[5]=='\t'||!line[5]))
1107 skip_to_end = 1;
1109 else if (n == 8 && !memcmp (line, "@include", 8)
1110 && (line[8]==' '||line[8]=='\t'||!line[8]))
1112 char *incname = xstrdup (p);
1113 FILE *incfp = fopen (incname, "r");
1115 if (!incfp && opt_include && *opt_include && *p != '/')
1117 free (incname);
1118 incname = xmalloc (strlen (opt_include) + 1
1119 + strlen (p) + 1);
1120 strcpy (incname, opt_include);
1121 if ( incname[strlen (incname)-1] != '/' )
1122 strcat (incname, "/");
1123 strcat (incname, p);
1124 incfp = fopen (incname, "r");
1127 if (!incfp)
1128 err ("can't open include file `%s':%s",
1129 incname, strerror (errno));
1130 else
1132 parse_file (incname, incfp, section_name, in_pause);
1133 fclose (incfp);
1135 free (incname);
1137 else if (n == 4 && !memcmp (line, "@bye", 4)
1138 && (line[4]==' '||line[4]=='\t'||!line[4]))
1140 break;
1142 else if (!skip_to_end)
1143 got_line = 1;
1145 else if (!skip_to_end)
1146 got_line = 1;
1148 if (got_line && in_verbatim)
1149 add_content (*section_name, line, 1);
1150 else if (got_line && thepage.name && *section_name && !in_pause)
1151 add_content (*section_name, line, 0);
1154 if (ferror (fp))
1155 err ("%s:%d: read error: %s", fname, lnr, strerror (errno));
1156 free (macroname);
1157 free (macrovalue);
1158 free (line);
1162 static void
1163 top_parse_file (const char *fname, FILE *fp)
1165 char *section_name = NULL; /* Name of the current section or NULL
1166 if not in a section. */
1167 while (macrolist)
1169 macro_t m = macrolist->next;
1170 free (m->value);
1171 free (m);
1172 macrolist = m;
1175 parse_file (fname, fp, &section_name, 0);
1176 free (section_name);
1177 finish_page ();
1181 int
1182 main (int argc, char **argv)
1184 int last_argc = -1;
1186 opt_source = "GNU";
1187 opt_release = "";
1189 if (argc)
1191 argc--; argv++;
1193 while (argc && last_argc != argc )
1195 last_argc = argc;
1196 if (!strcmp (*argv, "--"))
1198 argc--; argv++;
1199 break;
1201 else if (!strcmp (*argv, "--help"))
1203 puts (
1204 "Usage: " PGM " [OPTION] [FILE]\n"
1205 "Extract man pages from a Texinfo source.\n\n"
1206 " --source NAME use NAME as source field\n"
1207 " --release STRING use STRING as the release field\n"
1208 " --store write output using @manpage name\n"
1209 " --select NAME only output pages with @manpage NAME\n"
1210 " --verbose enable extra informational output\n"
1211 " --debug enable additional debug output\n"
1212 " --help display this help and exit\n"
1213 " -I DIR also search in include DIR\n"
1214 " -D gpgone the only useable define\n\n"
1215 "With no FILE, or when FILE is -, read standard input.\n\n"
1216 "Report bugs to <bugs@g10code.com>.");
1217 exit (0);
1219 else if (!strcmp (*argv, "--version"))
1221 puts (PGM " " VERSION "\n"
1222 "Copyright (C) 2005 g10 Code GmbH\n"
1223 "This program comes with ABSOLUTELY NO WARRANTY.\n"
1224 "This is free software, and you are welcome to redistribute it\n"
1225 "under certain conditions. See the file COPYING for details.");
1226 exit (0);
1228 else if (!strcmp (*argv, "--verbose"))
1230 verbose = 1;
1231 argc--; argv++;
1233 else if (!strcmp (*argv, "--quiet"))
1235 quiet = 1;
1236 argc--; argv++;
1238 else if (!strcmp (*argv, "--debug"))
1240 verbose = debug = 1;
1241 argc--; argv++;
1243 else if (!strcmp (*argv, "--source"))
1245 argc--; argv++;
1246 if (argc)
1248 opt_source = *argv;
1249 argc--; argv++;
1252 else if (!strcmp (*argv, "--release"))
1254 argc--; argv++;
1255 if (argc)
1257 opt_release = *argv;
1258 argc--; argv++;
1261 else if (!strcmp (*argv, "--store"))
1263 opt_store = 1;
1264 argc--; argv++;
1266 else if (!strcmp (*argv, "--select"))
1268 argc--; argv++;
1269 if (argc)
1271 opt_select = strrchr (*argv, '/');
1272 if (opt_select)
1273 opt_select++;
1274 else
1275 opt_select = *argv;
1276 argc--; argv++;
1279 else if (!strcmp (*argv, "-I"))
1281 argc--; argv++;
1282 if (argc)
1284 opt_include = *argv;
1285 argc--; argv++;
1288 else if (!strcmp (*argv, "-D"))
1290 argc--; argv++;
1291 if (argc)
1293 if (!strcmp (*argv, "gpgone"))
1294 gpgone_defined = 1;
1295 argc--; argv++;
1300 if (argc > 1)
1301 die ("usage: " PGM " [OPTION] [FILE] (try --help for more information)\n");
1303 /* Start processing. */
1304 if (argc && strcmp (*argv, "-"))
1306 FILE *fp = fopen (*argv, "rb");
1307 if (!fp)
1308 die ("%s:0: can't open file: %s", *argv, strerror (errno));
1309 top_parse_file (*argv, fp);
1310 fclose (fp);
1312 else
1313 top_parse_file ("-", stdin);
1315 return !!any_error;
1320 Local Variables:
1321 compile-command: "gcc -Wall -g -Wall -o yat2m yat2m.c"
1322 End: