Avoid catch-22 with README.main not being distributed but having the
[gnupg.git] / doc / yat2m.c
bloba936fefa940193d794b7d4226fc49cd644b3c79d
1 /* yat2m.c - Yet Another Texi 2 Man converter
2 * Copyright (C) 2005 g10 Code GmbH
3 * Copyright (C) 2006, 2008 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 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.
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 "1.0"
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 fputs (".\\\" Created from Texinfo source by yat2m " VERSION "\n", fp);
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, "\\(aq", "\\(aq" },
455 { "file", 0, "\\(oq\\fI","\\fR\\(cq" },
456 { "env", 0, "\\(oq\\fI","\\fR\\(cq" },
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 if (*s == '\\')
681 fputs ("\\\\", fp);
682 else
683 putc (*s, fp);
686 if (in_cmd > 1)
688 cmdbuf[cmdidx] = 0;
689 n = proc_texi_cmd (fp, cmdbuf, s, len, table_level, eol_action);
690 assert (n <= len);
691 s += n; len -= n;
692 s--; len++;
693 in_cmd = 0;
698 /* Do something with the Texinfo line LINE. */
699 static void
700 parse_texi_line (FILE *fp, const char *line, int *table_level)
702 int eol_action = 0;
704 /* A quick test whether there are any texinfo commands. */
705 if (!strchr (line, '@'))
707 fputs (line, fp);
708 putc ('\n', fp);
709 return;
711 proc_texi_buffer (fp, line, strlen (line), table_level, &eol_action);
712 putc ('\n', fp);
716 /* Write all the lines LINES to FP. */
717 static void
718 write_content (FILE *fp, line_buffer_t lines)
720 line_buffer_t line;
721 int table_level = 0;
723 for (line = lines; line; line = line->next)
725 if (line->verbatim)
727 fputs (line->line, fp);
728 putc ('\n', fp);
730 else
732 /* fputs ("TEXI---", fp); */
733 /* fputs (line->line, fp); */
734 /* fputs ("---\n", fp); */
735 parse_texi_line (fp, line->line, &table_level);
742 static int
743 is_standard_section (const char *name)
745 int i;
746 const char *s;
748 for (i=0; (s=standard_sections[i]); i++)
749 if (!strcmp (s, name))
750 return 1;
751 return 0;
755 /* Finish a page; that is sort the data and write it out to the file. */
756 static void
757 finish_page (void)
759 FILE *fp;
760 section_buffer_t sect = NULL;
761 int idx;
762 const char *s;
763 int i;
765 if (!thepage.name)
766 return; /* No page active. */
768 if (verbose)
769 inf ("finishing page `%s'", thepage.name);
771 if (opt_select)
773 if (!strcmp (opt_select, thepage.name))
775 inf ("selected `%s'", thepage.name );
776 fp = stdout;
778 else
780 fp = fopen ( "/dev/null", "w" );
781 if (!fp)
782 die ("failed to open /dev/null: %s\n", strerror (errno));
785 else if (opt_store)
787 inf ("writing `%s'", thepage.name );
788 fp = fopen ( thepage.name, "w" );
789 if (!fp)
790 die ("failed to create `%s': %s\n", thepage.name, strerror (errno));
792 else
793 fp = stdout;
795 if (write_th (fp))
796 goto leave;
798 for (idx=0; (s=standard_sections[idx]); idx++)
800 for (i=0; i < thepage.n_sections; i++)
802 sect = thepage.sections + i;
803 if (sect->name && !strcmp (s, sect->name))
804 break;
806 if (i == thepage.n_sections)
807 sect = NULL;
809 if (sect)
811 fprintf (fp, ".SH %s\n", sect->name);
812 write_content (fp, sect->lines);
813 /* Now continue with all non standard sections directly
814 following this one. */
815 for (i++; i < thepage.n_sections; i++)
817 sect = thepage.sections + i;
818 if (sect->name && is_standard_section (sect->name))
819 break;
820 if (sect->name)
822 fprintf (fp, ".SH %s\n", sect->name);
823 write_content (fp, sect->lines);
831 leave:
832 if (fp != stdout)
833 fclose (fp);
834 free (thepage.name);
835 thepage.name = NULL;
836 /* FIXME: Cleanup the content. */
842 /* Parse one Texinfo file and create manpages according to the
843 embedded instructions. */
844 static void
845 parse_file (const char *fname, FILE *fp, char **section_name, int in_pause)
847 char *line;
848 int lnr = 0;
849 /* Fixme: The following state variables don't carry over to include
850 files. */
851 int in_verbatim = 0;
852 int skip_to_end = 0; /* Used to skip over menu entries. */
853 int skip_sect_line = 0; /* Skip after @mansect. */
854 int ifset_nesting = 0; /* How often a ifset has been seen. */
855 int ifclear_nesting = 0; /* How often a ifclear has been seen. */
856 int in_gpgone = 0; /* Keep track of "@ifset gpgone" parts. */
857 int not_in_gpgone = 0; /* Keep track of "@ifclear gpgone" parts. */
858 int not_in_man = 0; /* Keep track of "@ifclear isman" parts. */
860 /* Helper to define a macro. */
861 char *macroname = NULL;
862 char *macrovalue = NULL;
863 size_t macrovaluesize = 0;
864 size_t macrovalueused = 0;
866 line = xmalloc (LINESIZE);
867 while (fgets (line, LINESIZE, fp))
869 size_t n = strlen (line);
870 int got_line = 0;
871 char *p;
873 lnr++;
874 if (!n || line[n-1] != '\n')
876 err ("%s:%d: trailing linefeed missing, line too long or "
877 "embedded Nul character", fname, lnr);
878 break;
880 line[--n] = 0;
882 if (*line == '@')
884 for (p=line+1, n=1; *p && *p != ' ' && *p != '\t'; p++)
885 n++;
886 while (*p == ' ' || *p == '\t')
887 p++;
889 else
890 p = line;
892 /* Take action on macro. */
893 if (macroname)
895 if (n == 4 && !memcmp (line, "@end", 4)
896 && (line[4]==' '||line[4]=='\t'||!line[4])
897 && !strncmp (p, "macro", 5)
898 && (p[5]==' '||p[5]=='\t'||!p[5]))
900 macro_t m;
902 if (macrovalueused)
903 macrovalue[--macrovalueused] = 0; /* Kill the last LF. */
904 macrovalue[macrovalueused] = 0; /* Terminate macro. */
905 macrovalue = xrealloc (macrovalue, macrovalueused+1);
907 for (m= macrolist; m; m = m->next)
908 if (!strcmp (m->name, macroname))
909 break;
910 if (m)
911 free (m->value);
912 else
914 m = xcalloc (1, sizeof *m + strlen (macroname));
915 strcpy (m->name, macroname);
916 m->next = macrolist;
917 macrolist = m;
919 m->value = macrovalue;
920 macrovalue = NULL;
921 free (macroname);
922 macroname = NULL;
924 else
926 if (macrovalueused + strlen (line) + 2 >= macrovaluesize)
928 macrovaluesize += strlen (line) + 256;
929 macrovalue = xrealloc (macrovalue, macrovaluesize);
931 strcpy (macrovalue+macrovalueused, line);
932 macrovalueused += strlen (line);
933 macrovalue[macrovalueused++] = '\n';
935 continue;
939 if (n >= 5 && !memcmp (line, "@node", 5)
940 && (line[5]==' '||line[5]=='\t'||!line[5]))
942 /* Completey ignore @node lines. */
943 continue;
947 if (skip_sect_line)
949 skip_sect_line = 0;
950 if (!strncmp (line, "@section", 8)
951 || !strncmp (line, "@subsection", 11)
952 || !strncmp (line, "@chapheading", 12))
953 continue;
956 /* We only parse lines we need and ignore the rest. There are a
957 few macros used to control this as well as one @ifset
958 command. Parts we know about are saved away into containers
959 separate for each section. */
961 /* First process ifset/ifclear commands. */
962 if (*line == '@')
964 if (n == 6 && !memcmp (line, "@ifset", 6)
965 && (line[6]==' '||line[6]=='\t'))
967 ifset_nesting++;
969 if (!strncmp (p, "manverb", 7) && (p[7]==' '||p[7]=='\t'||!p[7]))
971 if (in_verbatim)
972 err ("%s:%d: nested \"@ifset manverb\"", fname, lnr);
973 else
974 in_verbatim = ifset_nesting;
976 else if (!strncmp (p, "gpgone", 6)
977 && (p[6]==' '||p[6]=='\t'||!p[6]))
979 if (in_gpgone)
980 err ("%s:%d: nested \"@ifset gpgone\"", fname, lnr);
981 else
982 in_gpgone = ifset_nesting;
984 continue;
986 else if (n == 4 && !memcmp (line, "@end", 4)
987 && (line[4]==' '||line[4]=='\t')
988 && !strncmp (p, "ifset", 5)
989 && (p[5]==' '||p[5]=='\t'||!p[5]))
991 if (in_verbatim && ifset_nesting == in_verbatim)
992 in_verbatim = 0;
993 if (in_gpgone && ifset_nesting == in_gpgone)
994 in_gpgone = 0;
996 if (ifset_nesting)
997 ifset_nesting--;
998 else
999 err ("%s:%d: unbalanced \"@end ifset\"", fname, lnr);
1000 continue;
1002 else if (n == 8 && !memcmp (line, "@ifclear", 8)
1003 && (line[8]==' '||line[8]=='\t'))
1005 ifclear_nesting++;
1007 if (!strncmp (p, "gpgone", 6)
1008 && (p[6]==' '||p[6]=='\t'||!p[6]))
1010 if (not_in_gpgone)
1011 err ("%s:%d: nested \"@ifclear gpgone\"", fname, lnr);
1012 else
1013 not_in_gpgone = ifclear_nesting;
1016 else if (!strncmp (p, "isman", 5)
1017 && (p[5]==' '||p[5]=='\t'||!p[5]))
1019 if (not_in_man)
1020 err ("%s:%d: nested \"@ifclear isman\"", fname, lnr);
1021 else
1022 not_in_man = ifclear_nesting;
1025 continue;
1027 else if (n == 4 && !memcmp (line, "@end", 4)
1028 && (line[4]==' '||line[4]=='\t')
1029 && !strncmp (p, "ifclear", 7)
1030 && (p[7]==' '||p[7]=='\t'||!p[7]))
1032 if (not_in_gpgone && ifclear_nesting == not_in_gpgone)
1033 not_in_gpgone = 0;
1034 if (not_in_man && ifclear_nesting == not_in_man)
1035 not_in_man = 0;
1037 if (ifclear_nesting)
1038 ifclear_nesting--;
1039 else
1040 err ("%s:%d: unbalanced \"@end ifclear\"", fname, lnr);
1041 continue;
1045 /* Take action on ifset/ifclear. */
1046 if ( (in_gpgone && !gpgone_defined)
1047 || (not_in_gpgone && gpgone_defined)
1048 || not_in_man)
1049 continue;
1051 /* Process commands. */
1052 if (*line == '@')
1054 if (skip_to_end
1055 && n == 4 && !memcmp (line, "@end", 4)
1056 && (line[4]==' '||line[4]=='\t'||!line[4]))
1058 skip_to_end = 0;
1060 else if (in_verbatim)
1062 got_line = 1;
1064 else if (n == 6 && !memcmp (line, "@macro", 6))
1066 macroname = xstrdup (p);
1067 macrovalue = xmalloc ((macrovaluesize = 1024));
1068 macrovalueused = 0;
1070 else if (n == 8 && !memcmp (line, "@manpage", 8))
1072 free (*section_name);
1073 *section_name = NULL;
1074 finish_page ();
1075 start_page (p);
1076 in_pause = 0;
1078 else if (n == 8 && !memcmp (line, "@mansect", 8))
1080 if (!thepage.name)
1081 err ("%s:%d: section outside of a man page", fname, lnr);
1082 else
1084 free (*section_name);
1085 *section_name = ascii_strupr (xstrdup (p));
1086 in_pause = 0;
1087 skip_sect_line = 1;
1090 else if (n == 9 && !memcmp (line, "@manpause", 9))
1092 if (!*section_name)
1093 err ("%s:%d: pausing outside of a man section", fname, lnr);
1094 else if (in_pause)
1095 err ("%s:%d: already pausing", fname, lnr);
1096 else
1097 in_pause = 1;
1099 else if (n == 8 && !memcmp (line, "@mancont", 8))
1101 if (!*section_name)
1102 err ("%s:%d: continue outside of a man section", fname, lnr);
1103 else if (!in_pause)
1104 err ("%s:%d: continue while not pausing", fname, lnr);
1105 else
1106 in_pause = 0;
1108 else if (n == 5 && !memcmp (line, "@menu", 5)
1109 && (line[5]==' '||line[5]=='\t'||!line[5]))
1111 skip_to_end = 1;
1113 else if (n == 8 && !memcmp (line, "@include", 8)
1114 && (line[8]==' '||line[8]=='\t'||!line[8]))
1116 char *incname = xstrdup (p);
1117 FILE *incfp = fopen (incname, "r");
1119 if (!incfp && opt_include && *opt_include && *p != '/')
1121 free (incname);
1122 incname = xmalloc (strlen (opt_include) + 1
1123 + strlen (p) + 1);
1124 strcpy (incname, opt_include);
1125 if ( incname[strlen (incname)-1] != '/' )
1126 strcat (incname, "/");
1127 strcat (incname, p);
1128 incfp = fopen (incname, "r");
1131 if (!incfp)
1132 err ("can't open include file `%s':%s",
1133 incname, strerror (errno));
1134 else
1136 parse_file (incname, incfp, section_name, in_pause);
1137 fclose (incfp);
1139 free (incname);
1141 else if (n == 4 && !memcmp (line, "@bye", 4)
1142 && (line[4]==' '||line[4]=='\t'||!line[4]))
1144 break;
1146 else if (!skip_to_end)
1147 got_line = 1;
1149 else if (!skip_to_end)
1150 got_line = 1;
1152 if (got_line && in_verbatim)
1153 add_content (*section_name, line, 1);
1154 else if (got_line && thepage.name && *section_name && !in_pause)
1155 add_content (*section_name, line, 0);
1158 if (ferror (fp))
1159 err ("%s:%d: read error: %s", fname, lnr, strerror (errno));
1160 free (macroname);
1161 free (macrovalue);
1162 free (line);
1166 static void
1167 top_parse_file (const char *fname, FILE *fp)
1169 char *section_name = NULL; /* Name of the current section or NULL
1170 if not in a section. */
1171 while (macrolist)
1173 macro_t m = macrolist->next;
1174 free (m->value);
1175 free (m);
1176 macrolist = m;
1179 parse_file (fname, fp, &section_name, 0);
1180 free (section_name);
1181 finish_page ();
1185 int
1186 main (int argc, char **argv)
1188 int last_argc = -1;
1190 opt_source = "GNU";
1191 opt_release = "";
1193 if (argc)
1195 argc--; argv++;
1197 while (argc && last_argc != argc )
1199 last_argc = argc;
1200 if (!strcmp (*argv, "--"))
1202 argc--; argv++;
1203 break;
1205 else if (!strcmp (*argv, "--help"))
1207 puts (
1208 "Usage: " PGM " [OPTION] [FILE]\n"
1209 "Extract man pages from a Texinfo source.\n\n"
1210 " --source NAME use NAME as source field\n"
1211 " --release STRING use STRING as the release field\n"
1212 " --store write output using @manpage name\n"
1213 " --select NAME only output pages with @manpage NAME\n"
1214 " --verbose enable extra informational output\n"
1215 " --debug enable additional debug output\n"
1216 " --help display this help and exit\n"
1217 " -I DIR also search in include DIR\n"
1218 " -D gpgone the only useable define\n\n"
1219 "With no FILE, or when FILE is -, read standard input.\n\n"
1220 "Report bugs to <bugs@g10code.com>.");
1221 exit (0);
1223 else if (!strcmp (*argv, "--version"))
1225 puts (PGM " " VERSION "\n"
1226 "Copyright (C) 2005 g10 Code GmbH\n"
1227 "This program comes with ABSOLUTELY NO WARRANTY.\n"
1228 "This is free software, and you are welcome to redistribute it\n"
1229 "under certain conditions. See the file COPYING for details.");
1230 exit (0);
1232 else if (!strcmp (*argv, "--verbose"))
1234 verbose = 1;
1235 argc--; argv++;
1237 else if (!strcmp (*argv, "--quiet"))
1239 quiet = 1;
1240 argc--; argv++;
1242 else if (!strcmp (*argv, "--debug"))
1244 verbose = debug = 1;
1245 argc--; argv++;
1247 else if (!strcmp (*argv, "--source"))
1249 argc--; argv++;
1250 if (argc)
1252 opt_source = *argv;
1253 argc--; argv++;
1256 else if (!strcmp (*argv, "--release"))
1258 argc--; argv++;
1259 if (argc)
1261 opt_release = *argv;
1262 argc--; argv++;
1265 else if (!strcmp (*argv, "--store"))
1267 opt_store = 1;
1268 argc--; argv++;
1270 else if (!strcmp (*argv, "--select"))
1272 argc--; argv++;
1273 if (argc)
1275 opt_select = strrchr (*argv, '/');
1276 if (opt_select)
1277 opt_select++;
1278 else
1279 opt_select = *argv;
1280 argc--; argv++;
1283 else if (!strcmp (*argv, "-I"))
1285 argc--; argv++;
1286 if (argc)
1288 opt_include = *argv;
1289 argc--; argv++;
1292 else if (!strcmp (*argv, "-D"))
1294 argc--; argv++;
1295 if (argc)
1297 if (!strcmp (*argv, "gpgone"))
1298 gpgone_defined = 1;
1299 argc--; argv++;
1304 if (argc > 1)
1305 die ("usage: " PGM " [OPTION] [FILE] (try --help for more information)\n");
1307 /* Start processing. */
1308 if (argc && strcmp (*argv, "-"))
1310 FILE *fp = fopen (*argv, "rb");
1311 if (!fp)
1312 die ("%s:0: can't open file: %s", *argv, strerror (errno));
1313 top_parse_file (*argv, fp);
1314 fclose (fp);
1316 else
1317 top_parse_file ("-", stdin);
1319 return !!any_error;
1324 Local Variables:
1325 compile-command: "gcc -Wall -g -Wall -o yat2m yat2m.c"
1326 End: