2006-10-24 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / doc / yat2m.c
blobe250db4d5a7a2bb9696ddbaa367c6ed05a33001a
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 2 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, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA.
22 This is a simple textinfo to man page converter. It needs some
23 special markup in th e texinfo and tries best to get a create man
24 page. It has been designed for the GnuPG man pages and thus only
25 a few texinfo commands are supported.
27 To use this you need to add the following macros into your texinfo
28 source:
30 @macro manpage {a}
31 @end macro
32 @macro mansect {a}
33 @end macro
34 @macro manpause
35 @end macro
36 @macro mancont
37 @end macro
39 They are used by yat2m to select parts of the Texinfo which should
40 go into the man page. These macros need to be used without leading
41 left space. Processing starts after a "manpage" macro has been
42 seen. "mansect" identifies the section and yat2m make sure to
43 emit the sections in the proper order. Note that @mansect skips
44 the next input line if that line begins with @section, @subsection or
45 @chapheading.
47 To insert verbatim troff markup, the follwing texinfo code may be
48 used:
50 @ifset manverb
51 .B whateever you want
52 @end ifset
54 alternativly a special comment may be used:
56 @c man:.B whatever you want
58 This is useful in case you need just one line. If you want to
59 include parts only in the man page but keep the texinfo
60 translation you may use:
62 @ifset isman
63 stuff to be rendered only on man pages
64 @end ifset
66 or to exclude stuff from man pages:
68 @ifclear isman
69 stuff not to be rendered on man pages
70 @end ifclear
72 the keyword @section is ignored, however @subsection gets rendered
73 as ".SS". @menu is completely skipped. Several man pages may be
74 extracted from one file, either using the --store or the --select
75 option.
80 #include <stdio.h>
81 #include <stdlib.h>
82 #include <stddef.h>
83 #include <string.h>
84 #include <errno.h>
85 #include <stdarg.h>
86 #include <assert.h>
87 #include <ctype.h>
88 #include <time.h>
91 #define PGM "yat2m"
92 #define VERSION "0.5"
94 /* The maximum length of a line including the linefeed and one extra
95 character. */
96 #define LINESIZE 1024
98 /* Option flags. */
99 static int verbose;
100 static int quiet;
101 static int debug;
102 static const char *opt_source;
103 static const char *opt_release;
104 static const char *opt_select;
105 static const char *opt_include;
106 static int opt_store;
108 /* The only define we understand is -D gpgone. Thus we need a simple
109 boolean tro track it. */
110 static int gpgone_defined;
112 /* Flag to keep track whether any error occurred. */
113 static int any_error;
116 /* Object to keep macro definitions. */
117 struct macro_s
119 struct macro_s *next;
120 char *value; /* Malloced value. */
121 char name[1];
123 typedef struct macro_s *macro_t;
125 /* List of all defined macros. */
126 static macro_t macrolist;
129 /* Object to store one line of content. */
130 struct line_buffer_s
132 struct line_buffer_s *next;
133 int verbatim; /* True if LINE contains verbatim data. The default
134 is Texinfo source. */
135 char *line;
137 typedef struct line_buffer_s *line_buffer_t;
140 /* Object to collect the data of a section. */
141 struct section_buffer_s
143 char *name; /* Malloced name of the section. This may be
144 NULL to indicate this slot is not used. */
145 line_buffer_t lines; /* Linked list with the lines of the section. */
146 line_buffer_t *lines_tail; /* Helper for faster appending to the
147 linked list. */
148 line_buffer_t last_line; /* Points to the last line appended. */
150 typedef struct section_buffer_s *section_buffer_t;
152 /* Variable to keep info about the current page together. */
153 static struct
155 /* Filename of the current page or NULL if no page is active. Malloced. */
156 char *name;
158 /* Number of allocated elements in SECTIONS below. */
159 size_t n_sections;
160 /* Array with the data of the sections. */
161 section_buffer_t sections;
163 } thepage;
166 /* The list of standard section names. COMMANDS and ASSUAN are GnuPG
167 specific. */
168 static const char * const standard_sections[] =
169 { "NAME", "SYNOPSIS", "DESCRIPTION",
170 "RETURN VALUE", "EXIT STATUS", "ERROR HANDLING", "ERRORS",
171 "COMMANDS", "OPTIONS", "USAGE", "EXAMPLES", "FILES",
172 "ENVIRONMENT", "DIAGNOSTICS", "SECURITY", "CONFORMING TO",
173 "ASSUAN", "NOTES", "BUGS", "AUTHOR", "SEE ALSO", NULL };
176 /*-- Local prototypes. --*/
177 static void proc_texi_buffer (FILE *fp, const char *line, size_t len,
178 int *table_level, int *eol_action);
182 /* Print diagnostic message and exit with failure. */
183 static void
184 die (const char *format, ...)
186 va_list arg_ptr;
188 fflush (stdout);
189 fprintf (stderr, "%s: ", PGM);
191 va_start (arg_ptr, format);
192 vfprintf (stderr, format, arg_ptr);
193 va_end (arg_ptr);
194 putc ('\n', stderr);
196 exit (1);
200 /* Print diagnostic message. */
201 static void
202 err (const char *format, ...)
204 va_list arg_ptr;
206 fflush (stdout);
207 if (strncmp (format, "%s:%d:", 6))
208 fprintf (stderr, "%s: ", PGM);
210 va_start (arg_ptr, format);
211 vfprintf (stderr, format, arg_ptr);
212 va_end (arg_ptr);
213 putc ('\n', stderr);
214 any_error = 1;
217 /* Print diagnostic message. */
218 static void
219 inf (const char *format, ...)
221 va_list arg_ptr;
223 fflush (stdout);
224 fprintf (stderr, "%s: ", PGM);
226 va_start (arg_ptr, format);
227 vfprintf (stderr, format, arg_ptr);
228 va_end (arg_ptr);
229 putc ('\n', stderr);
233 static void *
234 xmalloc (size_t n)
236 void *p = malloc (n);
237 if (!p)
238 die ("out of core: %s", strerror (errno));
239 return p;
242 static void *
243 xcalloc (size_t n, size_t m)
245 void *p = calloc (n, m);
246 if (!p)
247 die ("out of core: %s", strerror (errno));
248 return p;
251 static void *
252 xrealloc (void *old, size_t n)
254 void *p = realloc (old, n);
255 if (!p)
256 die ("out of core: %s", strerror (errno));
257 return p;
260 static char *
261 xstrdup (const char *string)
263 void *p = malloc (strlen (string)+1);
264 if (!p)
265 die ("out of core: %s", strerror (errno));
266 strcpy (p, string);
267 return p;
271 /* Uppercase the ascii characters in STRING. */
272 static char *
273 ascii_strupr (char *string)
275 char *p;
277 for (p = string; *p; p++)
278 if (!(*p & 0x80))
279 *p = toupper (*p);
280 return string;
284 /* Return the current date as an ISO string. */
285 const char *
286 isodatestring (void)
288 static char buffer[11+5];
289 struct tm *tp;
290 time_t atime = time (NULL);
292 if (atime < 0)
293 strcpy (buffer, "????" "-??" "-??");
294 else
296 tp = gmtime (&atime);
297 sprintf (buffer,"%04d-%02d-%02d",
298 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
300 return buffer;
305 /* Return a section buffer for the section NAME. Allocate a new buffer
306 if this is a new section. Keep track of the sections in THEPAGE.
307 This function may reallocate the section array in THEPAGE. */
308 static section_buffer_t
309 get_section_buffer (const char *name)
311 int i;
312 section_buffer_t sect;
314 /* If there is no section we put everything into the required NAME
315 section. Given that this is the first one listed it is likely
316 that error are easily visible. */
317 if (!name)
318 name = "NAME";
320 for (i=0; i < thepage.n_sections; i++)
322 sect = thepage.sections + i;
323 if (sect->name && !strcmp (name, sect->name))
324 return sect;
326 for (i=0; i < thepage.n_sections; i++)
327 if (!thepage.sections[i].name)
328 break;
329 if (i < thepage.n_sections)
330 sect = thepage.sections + i;
331 else
333 /* We need to allocate or reallocate the section array. */
334 size_t old_n = thepage.n_sections;
335 size_t new_n = 20;
337 if (!old_n)
338 thepage.sections = xcalloc (new_n, sizeof *thepage.sections);
339 else
341 thepage.sections = xrealloc (thepage.sections,
342 ((old_n + new_n)
343 * sizeof *thepage.sections));
344 memset (thepage.sections + old_n, 0,
345 new_n * sizeof *thepage.sections);
347 thepage.n_sections += new_n;
349 /* Setup the tail pointers. */
350 for (i=old_n; i < thepage.n_sections; i++)
352 sect = thepage.sections + i;
353 sect->lines_tail = &sect->lines;
355 sect = thepage.sections + old_n;
358 /* Store the name. */
359 assert (!sect->name);
360 sect->name = xstrdup (name);
361 return sect;
366 /* Add the content of LINE to the section named SECTNAME. */
367 static void
368 add_content (const char *sectname, char *line, int verbatim)
370 section_buffer_t sect;
371 line_buffer_t lb;
373 sect = get_section_buffer (sectname);
374 if (sect->last_line && !sect->last_line->verbatim == !verbatim)
376 /* Lets append that line to the last one. We do this to keep
377 all lines of the same kind (i.e.verbatim or not) together in
378 one large buffer. */
379 size_t n1, n;
381 lb = sect->last_line;
382 n1 = strlen (lb->line);
383 n = n1 + 1 + strlen (line) + 1;
384 lb->line = xrealloc (lb->line, n);
385 strcpy (lb->line+n1, "\n");
386 strcpy (lb->line+n1+1, line);
388 else
390 lb = xcalloc (1, sizeof *lb);
391 lb->verbatim = verbatim;
392 lb->line = xstrdup (line);
393 sect->last_line = lb;
394 *sect->lines_tail = lb;
395 sect->lines_tail = &lb->next;
400 /* Prepare for a new man page using the filename NAME. */
401 static void
402 start_page (char *name)
404 if (verbose)
405 inf ("starting page `%s'", name);
406 assert (!thepage.name);
407 thepage.name = xstrdup (name);
408 thepage.n_sections = 0;
412 /* Write the .TH entry of the current page. Return -1 if there is a
413 problem with the page. */
414 static int
415 write_th (FILE *fp)
417 char *name, *p;
419 name = ascii_strupr (xstrdup (thepage.name));
420 p = strrchr (name, '.');
421 if (!p || !p[1])
423 err ("no section name in man page `%s'", thepage.name);
424 free (name);
425 return -1;
427 *p++ = 0;
428 fprintf (fp, ".TH %s %s %s \"%s\" \"%s\"\n",
429 name, p, isodatestring (), opt_release, opt_source);
430 return 0;
434 /* Process the texinfo command COMMAND (without the leading @) and
435 write output if needed to FP. REST is the remainer of the line
436 which should either point to an opening brace or to a white space.
437 The function returns the number of characters already processed
438 from REST. LEN is the usable length of REST. TABLE_LEVEL is used to
439 control the indentation of tables. */
440 static size_t
441 proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
442 int *table_level, int *eol_action)
444 static struct {
445 const char *name; /* Name of the command. */
446 int what; /* What to do with this command. */
447 const char *lead_in; /* String to print with a opening brace. */
448 const char *lead_out;/* String to print with the closing brace. */
449 } cmdtbl[] = {
450 { "command", 0, "\\fB", "\\fR" },
451 { "code", 0, "\\fB", "\\fR" },
452 { "sc", 0, "\\fB", "\\fR" },
453 { "var", 0, "\\fI", "\\fR" },
454 { "samp", 0, "\n'", "'\n" },
455 { "file", 0, "`\\fI","\\fR'" },
456 { "env", 0, "`\\fI","\\fR'" },
457 { "acronym", 0 },
458 { "dfn", 0 },
459 { "option", 0, "\\fB", "\\fR" },
460 { "example", 1, ".RS 2\n.nf\n" },
461 { "smallexample", 1, ".RS 2\n.nf\n" },
462 { "asis", 7 },
463 { "anchor", 7 },
464 { "cartouche", 1 },
465 { "xref", 0, "see: [", "]" },
466 { "pxref", 0, "see: [", "]" },
467 { "uref", 0, "(\\fB", "\\fR)" },
468 { "footnote",0, " ([", "])" },
469 { "emph", 0, "\\fI", "\\fR" },
470 { "w", 1 },
471 { "c", 5 },
472 { "opindex", 1 },
473 { "cpindex", 1 },
474 { "cindex", 1 },
475 { "noindent", 0 },
476 { "section", 1 },
477 { "chapter", 1 },
478 { "subsection", 6, "\n.SS " },
479 { "chapheading", 0},
480 { "item", 2, ".TP\n.B " },
481 { "itemx", 2, ".TP\n.B " },
482 { "table", 3 },
483 { "itemize", 3 },
484 { "bullet", 0, "* " },
485 { "end", 4 },
486 { "quotation",1, ".RS\n\\fB" },
487 { NULL }
489 size_t n;
490 int i;
491 const char *s;
492 const char *lead_out = NULL;
493 int ignore_args = 0;
495 for (i=0; cmdtbl[i].name && strcmp (cmdtbl[i].name, command); i++)
497 if (cmdtbl[i].name)
499 s = cmdtbl[i].lead_in;
500 if (s)
501 fputs (s, fp);
502 lead_out = cmdtbl[i].lead_out;
503 switch (cmdtbl[i].what)
505 case 1: /* Throw away the entire line. */
506 s = memchr (rest, '\n', len);
507 return s? (s-rest)+1 : len;
508 case 2: /* Handle @item. */
509 break;
510 case 3: /* Handle table. */
511 if (++(*table_level) > 1)
512 fputs (".RS\n", fp);
513 /* Now throw away the entire line. */
514 s = memchr (rest, '\n', len);
515 return s? (s-rest)+1 : len;
516 break;
517 case 4: /* Handle end. */
518 for (s=rest, n=len; n && (*s == ' ' || *s == '\t'); s++, n--)
520 if (n >= 5 && !memcmp (s, "table", 5)
521 && (!n || s[5] == ' ' || s[5] == '\t' || s[5] == '\n'))
523 if ((*table_level)-- > 1)
524 fputs (".RE\n", fp);
526 else if (n >= 7 && !memcmp (s, "example", 7)
527 && (!n || s[7] == ' ' || s[7] == '\t' || s[7] == '\n'))
529 fputs (".fi\n.RE\n", fp);
531 else if (n >= 12 && !memcmp (s, "smallexample", 12)
532 && (!n || s[12] == ' ' || s[12] == '\t' || s[12] == '\n'))
534 fputs (".fi\n.RE\n", fp);
536 else if (n >= 9 && !memcmp (s, "quotation", 9)
537 && (!n || s[9] == ' ' || s[9] == '\t' || s[9] == '\n'))
539 fputs ("\\fR\n.RE\n", fp);
541 /* Now throw away the entire line. */
542 s = memchr (rest, '\n', len);
543 return s? (s-rest)+1 : len;
544 case 5: /* Handle special comments. */
545 for (s=rest, n=len; n && (*s == ' ' || *s == '\t'); s++, n--)
547 if (n >= 4 && !memcmp (s, "man:", 4))
549 for (s+=4, n-=4; n && *s != '\n'; n--, s++)
550 putc (*s, fp);
551 putc ('\n', fp);
553 /* Now throw away the entire line. */
554 s = memchr (rest, '\n', len);
555 return s? (s-rest)+1 : len;
556 case 6:
557 *eol_action = 1;
558 break;
559 case 7:
560 ignore_args = 1;
561 break;
562 default:
563 break;
566 else
568 macro_t m;
570 for (m = macrolist; m ; m = m->next)
571 if (!strcmp (m->name, command))
572 break;
573 if (m)
575 proc_texi_buffer (fp, m->value, strlen (m->value),
576 table_level, eol_action);
577 ignore_args = 1; /* Parameterized macros are not yet supported. */
579 else
580 inf ("texinfo command `%s' not supported (%.*s)", command,
581 ((s = memchr (rest, '\n', len)), (s? (s-rest) : len)), rest);
584 if (*rest == '{')
586 /* Find matching closing brace. */
587 for (s=rest+1, n=1, i=1; i && *s && n < len; s++, n++)
588 if (*s == '{')
589 i++;
590 else if (*s == '}')
591 i--;
592 if (i)
594 err ("closing brace for command `%s' not found", command);
595 return len;
597 if (n > 2 && !ignore_args)
598 proc_texi_buffer (fp, rest+1, n-2, table_level, eol_action);
600 else
601 n = 0;
603 if (lead_out)
604 fputs (lead_out, fp);
606 return n;
611 /* Process the string LINE with LEN bytes of Texinfo content. */
612 static void
613 proc_texi_buffer (FILE *fp, const char *line, size_t len,
614 int *table_level, int *eol_action)
616 const char *s;
617 char cmdbuf[256];
618 int cmdidx = 0;
619 int in_cmd = 0;
620 size_t n;
622 for (s=line; *s && len; s++, len--)
624 if (in_cmd)
626 if (in_cmd == 1)
628 switch (*s)
630 case '@': case '{': case '}':
631 putc (*s, fp); in_cmd = 0;
632 break;
633 case ':': /* Not ending a sentence flag. */
634 in_cmd = 0;
635 break;
636 case '.': case '!': case '?': /* Ending a sentence. */
637 putc (*s, fp); in_cmd = 0;
638 break;
639 case ' ': case '\t': case '\n': /* Non collapsing spaces. */
640 putc (*s, fp); in_cmd = 0;
641 break;
642 default:
643 cmdidx = 0;
644 cmdbuf[cmdidx++] = *s;
645 in_cmd++;
646 break;
649 else if (*s == '{' || *s == ' ' || *s == '\t' || *s == '\n')
651 cmdbuf[cmdidx] = 0;
652 n = proc_texi_cmd (fp, cmdbuf, s, len, table_level, eol_action);
653 assert (n <= len);
654 s += n; len -= n;
655 s--; len++;
656 in_cmd = 0;
658 else if (cmdidx < sizeof cmdbuf -1)
659 cmdbuf[cmdidx++] = *s;
660 else
662 err ("texinfo command too long - ignored");
663 in_cmd = 0;
666 else if (*s == '@')
667 in_cmd = 1;
668 else if (*s == '\n')
670 switch (*eol_action)
672 case 1: /* Create a dummy paragraph. */
673 fputs ("\n\\ \n", fp);
674 break;
675 default:
676 putc (*s, fp);
678 *eol_action = 0;
680 else
681 putc (*s, fp);
684 if (in_cmd > 1)
686 cmdbuf[cmdidx] = 0;
687 n = proc_texi_cmd (fp, cmdbuf, s, len, table_level, eol_action);
688 assert (n <= len);
689 s += n; len -= n;
690 s--; len++;
691 in_cmd = 0;
696 /* Do something with the Texinfo line LINE. */
697 static void
698 parse_texi_line (FILE *fp, const char *line, int *table_level)
700 int eol_action = 0;
702 /* A quick test whether there are any texinfo commands. */
703 if (!strchr (line, '@'))
705 fputs (line, fp);
706 putc ('\n', fp);
707 return;
709 proc_texi_buffer (fp, line, strlen (line), table_level, &eol_action);
710 putc ('\n', fp);
714 /* Write all the lines LINES to FP. */
715 static void
716 write_content (FILE *fp, line_buffer_t lines)
718 line_buffer_t line;
719 int table_level = 0;
721 for (line = lines; line; line = line->next)
723 if (line->verbatim)
725 fputs (line->line, fp);
726 putc ('\n', fp);
728 else
730 /* fputs ("TEXI---", fp); */
731 /* fputs (line->line, fp); */
732 /* fputs ("---\n", fp); */
733 parse_texi_line (fp, line->line, &table_level);
740 static int
741 is_standard_section (const char *name)
743 int i;
744 const char *s;
746 for (i=0; (s=standard_sections[i]); i++)
747 if (!strcmp (s, name))
748 return 1;
749 return 0;
753 /* Finish a page; that is sort the data and write it out to the file. */
754 static void
755 finish_page (void)
757 FILE *fp;
758 section_buffer_t sect;
759 int idx;
760 const char *s;
761 int i;
763 if (!thepage.name)
764 return; /* No page active. */
766 if (verbose)
767 inf ("finishing page `%s'", thepage.name);
769 if (opt_select)
771 if (!strcmp (opt_select, thepage.name))
773 inf ("selected `%s'", thepage.name );
774 fp = stdout;
776 else
778 fp = fopen ( "/dev/null", "w" );
779 if (!fp)
780 die ("failed to open /dev/null: %s\n", strerror (errno));
783 else if (opt_store)
785 inf ("writing `%s'", thepage.name );
786 fp = fopen ( thepage.name, "w" );
787 if (!fp)
788 die ("failed to create `%s': %s\n", thepage.name, strerror (errno));
790 else
791 fp = stdout;
793 if (write_th (fp))
794 goto leave;
796 for (idx=0; (s=standard_sections[idx]); idx++)
798 for (i=0; i < thepage.n_sections; i++)
800 sect = thepage.sections + i;
801 if (sect->name && !strcmp (s, sect->name))
802 break;
804 if (i == thepage.n_sections)
805 sect = NULL;
807 if (sect)
809 fprintf (fp, ".SH %s\n", sect->name);
810 write_content (fp, sect->lines);
811 /* Now continue with all non standard sections directly
812 following this one. */
813 for (i++; i < thepage.n_sections; i++)
815 sect = thepage.sections + i;
816 if (sect->name && is_standard_section (sect->name))
817 break;
818 if (sect->name)
820 fprintf (fp, ".SH %s\n", sect->name);
821 write_content (fp, sect->lines);
829 leave:
830 if (fp != stdout)
831 fclose (fp);
832 free (thepage.name);
833 thepage.name = NULL;
834 /* FIXME: Cleanup the content. */
840 /* Parse one Texinfo file and create manpages according to the
841 embedded instructions. */
842 static void
843 parse_file (const char *fname, FILE *fp, char **section_name, int in_pause)
845 char *line;
846 int lnr = 0;
847 /* Fixme: The follwing state variables don't carry over to include
848 files. */
849 int in_verbatim = 0;
850 int skip_to_end = 0; /* Used to skip over menu entries. */
851 int skip_sect_line = 0; /* Skip after @mansect. */
852 int ifset_nesting = 0; /* How often a ifset has been seen. */
853 int ifclear_nesting = 0; /* How often a ifclear has been seen. */
854 int in_gpgone = 0; /* Keep track of "@ifset gpgone" parts. */
855 int not_in_gpgone = 0; /* Keep track of "@ifclear gpgone" parts. */
856 int not_in_man = 0; /* Keep track of "@ifclear isman" parts. */
858 /* Helper to define a macro. */
859 char *macroname = NULL;
860 char *macrovalue = NULL;
861 size_t macrovaluesize = 0;
862 size_t macrovalueused = 0;
864 line = xmalloc (LINESIZE);
865 while (fgets (line, LINESIZE, fp))
867 size_t n = strlen (line);
868 int got_line = 0;
869 char *p;
871 lnr++;
872 if (!n || line[n-1] != '\n')
874 err ("%s:%d: trailing linefeed missing, line too long or "
875 "embedded Nul character", fname, lnr);
876 break;
878 line[--n] = 0;
880 if (*line == '@')
882 for (p=line+1, n=1; *p && *p != ' ' && *p != '\t'; p++)
883 n++;
884 while (*p == ' ' || *p == '\t')
885 p++;
887 else
888 p = line;
890 /* Take action on macro. */
891 if (macroname)
893 if (n == 4 && !memcmp (line, "@end", 4)
894 && (line[4]==' '||line[4]=='\t'||!line[4])
895 && !strncmp (p, "macro", 5)
896 && (p[5]==' '||p[5]=='\t'||!p[5]))
898 macro_t m;
900 if (macrovalueused)
901 macrovalue[--macrovalueused] = 0; /* Kill the last LF. */
902 macrovalue[macrovalueused] = 0; /* Terminate macro. */
903 macrovalue = xrealloc (macrovalue, macrovalueused+1);
905 for (m= macrolist; m; m = m->next)
906 if (!strcmp (m->name, macroname))
907 break;
908 if (m)
909 free (m->value);
910 else
912 m = xcalloc (1, sizeof *m + strlen (macroname));
913 strcpy (m->name, macroname);
914 m->next = macrolist;
915 macrolist = m;
917 m->value = macrovalue;
918 macrovalue = NULL;
919 free (macroname);
920 macroname = NULL;
922 else
924 if (macrovalueused + strlen (line) + 2 >= macrovaluesize)
926 macrovaluesize += strlen (line) + 256;
927 macrovalue = xrealloc (macrovalue, macrovaluesize);
929 strcpy (macrovalue+macrovalueused, line);
930 macrovalueused += strlen (line);
931 macrovalue[macrovalueused++] = '\n';
933 continue;
937 if (n >= 5 && !memcmp (line, "@node", 5)
938 && (line[5]==' '||line[5]=='\t'||!line[5]))
940 /* Completey ignore @node lines. */
941 continue;
945 if (skip_sect_line)
947 skip_sect_line = 0;
948 if (!strncmp (line, "@section", 8)
949 || !strncmp (line, "@subsection", 11)
950 || !strncmp (line, "@chapheading", 12))
951 continue;
954 /* We only parse lines we need and ignore the rest. There are a
955 few macros used to control this as well as one @ifset
956 command. Parts we know about are saved away into containers
957 separate for each section. */
959 /* First process ifset/ifclear commands. */
960 if (*line == '@')
962 if (n == 6 && !memcmp (line, "@ifset", 6)
963 && (line[6]==' '||line[6]=='\t'))
965 ifset_nesting++;
967 if (!strncmp (p, "manverb", 7) && (p[7]==' '||p[7]=='\t'||!p[7]))
969 if (in_verbatim)
970 err ("%s:%d: nested \"@ifset manverb\"", fname, lnr);
971 else
972 in_verbatim = ifset_nesting;
974 else if (!strncmp (p, "gpgone", 6)
975 && (p[6]==' '||p[6]=='\t'||!p[6]))
977 if (in_gpgone)
978 err ("%s:%d: nested \"@ifset gpgone\"", fname, lnr);
979 else
980 in_gpgone = ifset_nesting;
982 continue;
984 else if (n == 4 && !memcmp (line, "@end", 4)
985 && (line[4]==' '||line[4]=='\t')
986 && !strncmp (p, "ifset", 5)
987 && (p[5]==' '||p[5]=='\t'||!p[5]))
989 if (in_verbatim && ifset_nesting == in_verbatim)
990 in_verbatim = 0;
991 if (in_gpgone && ifset_nesting == in_gpgone)
992 in_gpgone = 0;
994 if (ifset_nesting)
995 ifset_nesting--;
996 else
997 err ("%s:%d: unbalanced \"@end ifset\"", fname, lnr);
998 continue;
1000 else if (n == 8 && !memcmp (line, "@ifclear", 8)
1001 && (line[8]==' '||line[8]=='\t'))
1003 ifclear_nesting++;
1005 if (!strncmp (p, "gpgone", 6)
1006 && (p[6]==' '||p[6]=='\t'||!p[6]))
1008 if (not_in_gpgone)
1009 err ("%s:%d: nested \"@ifclear gpgone\"", fname, lnr);
1010 else
1011 not_in_gpgone = ifclear_nesting;
1014 else if (!strncmp (p, "isman", 5)
1015 && (p[5]==' '||p[5]=='\t'||!p[5]))
1017 if (not_in_man)
1018 err ("%s:%d: nested \"@ifclear isman\"", fname, lnr);
1019 else
1020 not_in_man = ifclear_nesting;
1023 continue;
1025 else if (n == 4 && !memcmp (line, "@end", 4)
1026 && (line[4]==' '||line[4]=='\t')
1027 && !strncmp (p, "ifclear", 7)
1028 && (p[7]==' '||p[7]=='\t'||!p[7]))
1030 if (not_in_gpgone && ifclear_nesting == not_in_gpgone)
1031 not_in_gpgone = 0;
1032 if (not_in_man && ifclear_nesting == not_in_man)
1033 not_in_man = 0;
1035 if (ifclear_nesting)
1036 ifclear_nesting--;
1037 else
1038 err ("%s:%d: unbalanced \"@end ifclear\"", fname, lnr);
1039 continue;
1043 /* Take action on ifset/ifclear. */
1044 if ( (in_gpgone && !gpgone_defined)
1045 || (not_in_gpgone && gpgone_defined)
1046 || not_in_man)
1047 continue;
1049 /* Process commands. */
1050 if (*line == '@')
1052 if (skip_to_end
1053 && n == 4 && !memcmp (line, "@end", 4)
1054 && (line[4]==' '||line[4]=='\t'||!line[4]))
1056 skip_to_end = 0;
1058 else if (in_verbatim)
1060 got_line = 1;
1062 else if (n == 6 && !memcmp (line, "@macro", 6))
1064 macroname = xstrdup (p);
1065 macrovalue = xmalloc ((macrovaluesize = 1024));
1066 macrovalueused = 0;
1068 else if (n == 8 && !memcmp (line, "@manpage", 8))
1070 free (*section_name);
1071 *section_name = NULL;
1072 finish_page ();
1073 start_page (p);
1074 in_pause = 0;
1076 else if (n == 8 && !memcmp (line, "@mansect", 8))
1078 if (!thepage.name)
1079 err ("%s:%d: section outside of a man page", fname, lnr);
1080 else
1082 free (*section_name);
1083 *section_name = ascii_strupr (xstrdup (p));
1084 in_pause = 0;
1085 skip_sect_line = 1;
1088 else if (n == 9 && !memcmp (line, "@manpause", 9))
1090 if (!*section_name)
1091 err ("%s:%d: pausing outside of a man section", fname, lnr);
1092 else if (in_pause)
1093 err ("%s:%d: already pausing", fname, lnr);
1094 else
1095 in_pause = 1;
1097 else if (n == 8 && !memcmp (line, "@mancont", 8))
1099 if (!*section_name)
1100 err ("%s:%d: continue outside of a man section", fname, lnr);
1101 else if (!in_pause)
1102 err ("%s:%d: continue while not pausing", fname, lnr);
1103 else
1104 in_pause = 0;
1106 else if (n == 5 && !memcmp (line, "@menu", 5)
1107 && (line[5]==' '||line[5]=='\t'||!line[5]))
1109 skip_to_end = 1;
1111 else if (n == 8 && !memcmp (line, "@include", 8)
1112 && (line[8]==' '||line[8]=='\t'||!line[8]))
1114 char *incname = xstrdup (p);
1115 FILE *incfp = fopen (incname, "r");
1117 if (!incfp && opt_include && *opt_include && *p != '/')
1119 free (incname);
1120 incname = xmalloc (strlen (opt_include) + 1
1121 + strlen (p) + 1);
1122 strcpy (incname, opt_include);
1123 if ( incname[strlen (incname)-1] != '/' )
1124 strcat (incname, "/");
1125 strcat (incname, p);
1126 incfp = fopen (incname, "r");
1129 if (!incfp)
1130 err ("can't open include file `%s':%s",
1131 incname, strerror (errno));
1132 else
1134 parse_file (incname, incfp, section_name, in_pause);
1135 fclose (incfp);
1137 free (incname);
1139 else if (n == 4 && !memcmp (line, "@bye", 4)
1140 && (line[4]==' '||line[4]=='\t'||!line[4]))
1142 break;
1144 else if (!skip_to_end)
1145 got_line = 1;
1147 else if (!skip_to_end)
1148 got_line = 1;
1150 if (got_line && in_verbatim)
1151 add_content (*section_name, line, 1);
1152 else if (got_line && thepage.name && *section_name && !in_pause)
1153 add_content (*section_name, line, 0);
1156 if (ferror (fp))
1157 err ("%s:%d: read error: %s", fname, lnr, strerror (errno));
1158 free (macroname);
1159 free (macrovalue);
1160 free (line);
1164 static void
1165 top_parse_file (const char *fname, FILE *fp)
1167 char *section_name = NULL; /* Name of the current section or NULL
1168 if not in a section. */
1169 while (macrolist)
1171 macro_t m = macrolist->next;
1172 free (m->value);
1173 free (m);
1174 macrolist = m;
1177 parse_file (fname, fp, &section_name, 0);
1178 free (section_name);
1179 finish_page ();
1183 int
1184 main (int argc, char **argv)
1186 int last_argc = -1;
1188 opt_source = "GNU";
1189 opt_release = "";
1191 if (argc)
1193 argc--; argv++;
1195 while (argc && last_argc != argc )
1197 last_argc = argc;
1198 if (!strcmp (*argv, "--"))
1200 argc--; argv++;
1201 break;
1203 else if (!strcmp (*argv, "--help"))
1205 puts (
1206 "Usage: " PGM " [OPTION] [FILE]\n"
1207 "Extract man pages from a Texinfo source.\n\n"
1208 " --source NAME use NAME as source field\n"
1209 " --release STRING use STRING as the release field\n"
1210 " --store write output using @manpage name\n"
1211 " --select NAME only output pages with @manpage NAME\n"
1212 " --verbose enable extra informational output\n"
1213 " --debug enable additional debug output\n"
1214 " --help display this help and exit\n"
1215 " -I DIR also search in include DIR\n"
1216 " -D gpgone the only useable define\n\n"
1217 "With no FILE, or when FILE is -, read standard input.\n\n"
1218 "Report bugs to <bugs@g10code.com>.");
1219 exit (0);
1221 else if (!strcmp (*argv, "--version"))
1223 puts (PGM " " VERSION "\n"
1224 "Copyright (C) 2005 g10 Code GmbH\n"
1225 "This program comes with ABSOLUTELY NO WARRANTY.\n"
1226 "This is free software, and you are welcome to redistribute it\n"
1227 "under certain conditions. See the file COPYING for details.");
1228 exit (0);
1230 else if (!strcmp (*argv, "--verbose"))
1232 verbose = 1;
1233 argc--; argv++;
1235 else if (!strcmp (*argv, "--quiet"))
1237 quiet = 1;
1238 argc--; argv++;
1240 else if (!strcmp (*argv, "--debug"))
1242 verbose = debug = 1;
1243 argc--; argv++;
1245 else if (!strcmp (*argv, "--source"))
1247 argc--; argv++;
1248 if (argc)
1250 opt_source = *argv;
1251 argc--; argv++;
1254 else if (!strcmp (*argv, "--release"))
1256 argc--; argv++;
1257 if (argc)
1259 opt_release = *argv;
1260 argc--; argv++;
1263 else if (!strcmp (*argv, "--store"))
1265 opt_store = 1;
1266 argc--; argv++;
1268 else if (!strcmp (*argv, "--select"))
1270 argc--; argv++;
1271 if (argc)
1273 opt_select = strrchr (*argv, '/');
1274 if (opt_select)
1275 opt_select++;
1276 else
1277 opt_select = *argv;
1278 argc--; argv++;
1281 else if (!strcmp (*argv, "-I"))
1283 argc--; argv++;
1284 if (argc)
1286 opt_include = *argv;
1287 argc--; argv++;
1290 else if (!strcmp (*argv, "-D"))
1292 argc--; argv++;
1293 if (argc)
1295 if (!strcmp (*argv, "gpgone"))
1296 gpgone_defined = 1;
1297 argc--; argv++;
1302 if (argc > 1)
1303 die ("usage: " PGM " [OPTION] [FILE] (try --help for more information)\n");
1305 /* Start processing. */
1306 if (argc && strcmp (*argv, "-"))
1308 FILE *fp = fopen (*argv, "rb");
1309 if (!fp)
1310 die ("%s:0: can't open file: %s", *argv, strerror (errno));
1311 top_parse_file (*argv, fp);
1312 fclose (fp);
1314 else
1315 top_parse_file ("-", stdin);
1317 return !!any_error;
1322 Local Variables:
1323 compile-command: "gcc -Wall -g -Wall -o yat2m yat2m.c"
1324 End: