diff options
author | Werner Koch <[email protected]> | 2006-08-17 18:01:25 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2006-08-17 18:01:25 +0000 |
commit | 6e3e2513d8ae9396cc5d504404863d9fe51a2313 (patch) | |
tree | 31943ccacb2d9e4a5234794ca0ffaf9923b28e93 /doc/yat2m.c | |
parent | Copied gpg.texi over from 1.4.5 and started to restructure it into a proper (diff) | |
download | gnupg-6e3e2513d8ae9396cc5d504404863d9fe51a2313.tar.gz gnupg-6e3e2513d8ae9396cc5d504404863d9fe51a2313.zip |
More man pages.
Diffstat (limited to 'doc/yat2m.c')
-rw-r--r-- | doc/yat2m.c | 1031 |
1 files changed, 1031 insertions, 0 deletions
diff --git a/doc/yat2m.c b/doc/yat2m.c new file mode 100644 index 000000000..703ac658c --- /dev/null +++ b/doc/yat2m.c @@ -0,0 +1,1031 @@ +/* yat2m.c - Yet Another Texi 2 Man converter + * Copyright (C) 2005 g10 Code GmbH + * Copyright (C) 2006 2006 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/* + This is a simple textinfo to man page converter. It needs some + special markup in th e texinfo and tries best to get a create man + page. It has been designed for the GnuPG man pages and thus only + a few texinfo commands are supported. + + To use this you need to add the following macros into your texinfo + source: + + @macro manpage {a} + @end macro + @macro mansect {a} + @end macro + @macro manpause + @end macro + @macro mancont + @end macro + + They are used by yat2m to select parts of the Texinfo which should + go into the man page. These macros need to be used without leading + left space. Processing starts after a "manpage" macro has been + seen. "mansect" identifies the section and yat2m make sure to + emit the sections in the proper order. To insert verbatim troff + markup, the follwing texinfo code may be used: + + @ifset manverb + .B whateever you want + @end ifset + + alternativly a special comment may be used: + + @c man:.B whatever you want + + This is useful in case you need just one line. @section is + ignored, however @subsection gets rendered as ".SS". @menu is + completely skipped. Several man pages may be extracted from one + file, either using the --store or the --select option. + Makefile snippet from GnuPG: + + +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <errno.h> +#include <stdarg.h> +#include <assert.h> +#include <ctype.h> +#include <time.h> + + +#define PGM "yat2m" +#define VERSION "0.5" + +/* The maximum length of a line including the linefeed and one extra + character. */ +#define LINESIZE 1024 + +/* Option flags. */ +static int verbose; +static int quiet; +static int debug; +static const char *opt_source; +static const char *opt_release; +static const char *opt_select; +static int opt_store; + + +/* Flag to keep track whether any error occurred. */ +static int any_error; + + +/* Object to store one line of content. */ +struct line_buffer_s +{ + struct line_buffer_s *next; + int verbatim; /* True if LINE contains verbatim data. The default + is Texinfo source. */ + char *line; +}; +typedef struct line_buffer_s *line_buffer_t; + + +/* Object to collect the data of a section. */ +struct section_buffer_s +{ + char *name; /* Malloced name of the section. This may be + NULL to indicate this slot is not used. */ + line_buffer_t lines; /* Linked list with the lines of the section. */ + line_buffer_t *lines_tail; /* Helper for faster appending to the + linked list. */ + line_buffer_t last_line; /* Points to the last line appended. */ +}; +typedef struct section_buffer_s *section_buffer_t; + +/* Variable to keep info about the current page together. */ +static struct +{ + /* Filename of the current page or NULL if no page is active. Malloced. */ + char *name; + + /* Number of allocated elements in SECTIONS below. */ + size_t n_sections; + /* Array with the data of the sections. */ + section_buffer_t sections; + +} thepage; + + +/* The list of standard section names. */ +static const char * const standard_sections[] = + { "NAME", "SYNOPSIS", "DESCRIPTION", + "RETURN VALUE", "EXIT STATUS", "ERROR HANDLING", "ERRORS", + "OPTIONS", "USAGE", "EXAMPLES", "FILES", + "ENVIRONMENT", "DIAGNOSTICS", "SECURITY", "CONFORMING TO", + "NOTES", "BUGS", "AUTHOR", "SEE ALSO", NULL }; + + +/*-- Local prototypes. --*/ +static void proc_texi_buffer (FILE *fp, const char *line, size_t len, + int *table_level, int *eol_action); + + + +/* Print diagnostic message and exit with failure. */ +static void +die (const char *format, ...) +{ + va_list arg_ptr; + + fflush (stdout); + fprintf (stderr, "%s: ", PGM); + + va_start (arg_ptr, format); + vfprintf (stderr, format, arg_ptr); + va_end (arg_ptr); + putc ('\n', stderr); + + exit (1); +} + + +/* Print diagnostic message. */ +static void +err (const char *format, ...) +{ + va_list arg_ptr; + + fflush (stdout); + if (strncmp (format, "%s:%d:", 6)) + fprintf (stderr, "%s: ", PGM); + + va_start (arg_ptr, format); + vfprintf (stderr, format, arg_ptr); + va_end (arg_ptr); + putc ('\n', stderr); + any_error = 1; +} + +/* Print diagnostic message. */ +static void +inf (const char *format, ...) +{ + va_list arg_ptr; + + fflush (stdout); + fprintf (stderr, "%s: ", PGM); + + va_start (arg_ptr, format); + vfprintf (stderr, format, arg_ptr); + va_end (arg_ptr); + putc ('\n', stderr); +} + + +static void * +xmalloc (size_t n) +{ + void *p = malloc (n); + if (!p) + die ("out of core: %s", strerror (errno)); + return p; +} + +static void * +xcalloc (size_t n, size_t m) +{ + void *p = calloc (n, m); + if (!p) + die ("out of core: %s", strerror (errno)); + return p; +} + +static void * +xrealloc (void *old, size_t n) +{ + void *p = realloc (old, n); + if (!p) + die ("out of core: %s", strerror (errno)); + return p; +} + +static char * +xstrdup (const char *string) +{ + void *p = malloc (strlen (string)+1); + if (!p) + die ("out of core: %s", strerror (errno)); + strcpy (p, string); + return p; +} + + +/* Uppercase the ascii characters in STRING. */ +static char * +ascii_strupr (char *string) +{ + char *p; + + for (p = string; *p; p++) + if (!(*p & 0x80)) + *p = toupper (*p); + return string; +} + + +/* Return the current date as an ISO string. */ +const char * +isodatestring (void) +{ + static char buffer[11+5]; + struct tm *tp; + time_t atime = time (NULL); + + if (atime < 0) + strcpy (buffer, "????" "-??" "-??"); + else + { + tp = gmtime (&atime); + sprintf (buffer,"%04d-%02d-%02d", + 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday ); + } + return buffer; +} + + + +/* Return a section buffer for the section NAME. Allocate a new buffer + if this is a new section. Keep track of the sections in THEPAGE. + This function may reallocate the section array in THEPAGE. */ +static section_buffer_t +get_section_buffer (const char *name) +{ + int i; + section_buffer_t sect; + + /* If there is no section we put everything into the required NAME + section. Given that this is the first one listed it is likely + that error are easily visible. */ + if (!name) + name = "NAME"; + + for (i=0; i < thepage.n_sections; i++) + { + sect = thepage.sections + i; + if (sect->name && !strcmp (name, sect->name)) + return sect; + } + for (i=0; i < thepage.n_sections; i++) + if (!thepage.sections[i].name) + break; + if (i < thepage.n_sections) + sect = thepage.sections + i; + else + { + /* We need to allocate or reallocate the section array. */ + size_t old_n = thepage.n_sections; + size_t new_n = 20; + + if (!old_n) + thepage.sections = xcalloc (new_n, sizeof *thepage.sections); + else + { + thepage.sections = xrealloc (thepage.sections, + ((old_n + new_n) + * sizeof *thepage.sections)); + memset (thepage.sections + old_n, 0, + new_n * sizeof *thepage.sections); + } + thepage.n_sections += new_n; + + /* Setup the tail pointers. */ + for (i=old_n; i < thepage.n_sections; i++) + { + sect = thepage.sections + i; + sect->lines_tail = §->lines; + } + sect = thepage.sections + old_n; + } + + /* Store the name. */ + assert (!sect->name); + sect->name = xstrdup (name); + return sect; +} + + + +/* Add the content of LINE to the section named SECTNAME. */ +static void +add_content (const char *sectname, char *line, int verbatim) +{ + section_buffer_t sect; + line_buffer_t lb; + + + sect = get_section_buffer (sectname); + if (sect->last_line && !sect->last_line->verbatim == !verbatim) + { + /* Lets append that line to the last one. We do this to keep + all lines of the same kind (i.e.verbatim or not) together in + one large buffer. */ + size_t n1, n; + + lb = sect->last_line; + n1 = strlen (lb->line); + n = n1 + 1 + strlen (line) + 1; + lb->line = xrealloc (lb->line, n); + strcpy (lb->line+n1, "\n"); + strcpy (lb->line+n1+1, line); + } + else + { + lb = xcalloc (1, sizeof *lb); + lb->verbatim = verbatim; + lb->line = xstrdup (line); + sect->last_line = lb; + *sect->lines_tail = lb; + sect->lines_tail = &lb->next; + } +} + + +/* Prepare for a new man page using the filename NAME. */ +static void +start_page (char *name) +{ + if (verbose) + inf ("starting page `%s'", name); + assert (!thepage.name); + thepage.name = xstrdup (name); + thepage.n_sections = 0; +} + + +/* Write the .TH entry of the current page. Return -1 if there is a + problem with the page. */ +static int +write_th (FILE *fp) +{ + char *name, *p; + + name = ascii_strupr (xstrdup (thepage.name)); + p = strrchr (name, '.'); + if (!p || !p[1]) + { + err ("no section name in man page `%s'", thepage.name); + free (name); + return -1; + } + *p++ = 0; + fprintf (fp, ".TH %s %s %s \"%s\" \"%s\"\n", + name, p, isodatestring (), opt_release, opt_source); + return 0; +} + + +/* Process the texinfo command COMMAND (without the leading @) and + write output if needed to FP. REST is the remainer of the line + which should either point to an opening brace or to a white space. + The function returns the number of characters already processed + from REST. LEN is the usable length of REST. TABLE_LEVEL is used to + control the indentation of tables. */ +static size_t +proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len, + int *table_level, int *eol_action) +{ + static struct { + const char *name; /* Name of the command. */ + int what; /* What to do with this command. */ + const char *lead_in; /* String to print with a opening brace. */ + const char *lead_out;/* String to print with the closing brace. */ + } cmdtbl[] = { + { "command", 0, "\\fB", "\\fR" }, + { "code", 0, "\\fB", "\\fR" }, + { "var", 0, "\\fI", "\\fR" }, + { "samp", 0, "\n'", "'\n" }, + { "file", 0, "`\\fI","\\fR'" }, + { "env", 0, "`\\fI","\\fR'" }, + { "acronym", 0 }, + { "option", 0, "\\fB", "\\fR" }, + { "example", 1, ".RS 2\n.nf\n" }, + { "smallexample", 1, ".RS 2\n.nf\n" }, + { "asis", 7 }, + { "anchor", 7 }, + { "cartouche", 1 }, + { "xref", 0, "see: [", "]" }, + { "pxref", 0, "see: [", "]" }, + { "uref", 0, "(\\fB", "\\fR)" }, + { "footnote",0, " ([", "])" }, + { "emph", 0, "\\fI", "\\fR" }, + { "w", 1 }, + { "c", 5 }, + { "opindex", 1 }, + { "cpindex", 1 }, + { "cindex", 1 }, + { "node", 1 }, + { "noindent", 0 }, + { "section", 1 }, + { "subsection", 6, "\n.SS " }, + { "chapheading", 0}, + { "item", 2, ".TP\n.B " }, + { "itemx", 2, ".TP\n.B " }, + { "table", 3 }, + { "end", 4 }, + { "quotation",1, ".RS\n\\fB" }, + { NULL } + }; + size_t n; + int i; + const char *s; + const char *lead_out = NULL; + int ignore_args = 0; + + for (i=0; cmdtbl[i].name && strcmp (cmdtbl[i].name, command); i++) + ; + if (cmdtbl[i].name) + { + s = cmdtbl[i].lead_in; + if (s) + fputs (s, fp); + lead_out = cmdtbl[i].lead_out; + switch (cmdtbl[i].what) + { + case 1: /* Throw away the entire line. */ + s = memchr (rest, '\n', len); + return s? (s-rest)+1 : len; + case 2: /* Handle @item. */ + break; + case 3: /* Handle table. */ + if (++(*table_level) > 1) + fputs (".RS\n", fp); + /* Now throw away the entire line. */ + s = memchr (rest, '\n', len); + return s? (s-rest)+1 : len; + break; + case 4: /* Handle end. */ + for (s=rest, n=len; n && (*s == ' ' || *s == '\t'); s++, n--) + ; + if (n >= 5 && !memcmp (s, "table", 5) + && (!n || s[5] == ' ' || s[5] == '\t' || s[5] == '\n')) + { + if ((*table_level)-- > 1) + fputs (".RE\n", fp); + } + else if (n >= 7 && !memcmp (s, "example", 7) + && (!n || s[7] == ' ' || s[7] == '\t' || s[7] == '\n')) + { + fputs (".fi\n.RE\n", fp); + } + else if (n >= 12 && !memcmp (s, "smallexample", 12) + && (!n || s[12] == ' ' || s[12] == '\t' || s[12] == '\n')) + { + fputs (".fi\n.RE\n", fp); + } + else if (n >= 9 && !memcmp (s, "quotation", 9) + && (!n || s[9] == ' ' || s[9] == '\t' || s[9] == '\n')) + { + fputs ("\\fR\n.RE\n", fp); + } + /* Now throw away the entire line. */ + s = memchr (rest, '\n', len); + return s? (s-rest)+1 : len; + case 5: /* Handle special comments. */ + for (s=rest, n=len; n && (*s == ' ' || *s == '\t'); s++, n--) + ; + if (n >= 4 && !memcmp (s, "man:", 4)) + { + for (s+=4, n-=4; n && *s != '\n'; n--, s++) + putc (*s, fp); + putc ('\n', fp); + } + /* Now throw away the entire line. */ + s = memchr (rest, '\n', len); + return s? (s-rest)+1 : len; + case 6: + *eol_action = 1; + break; + case 7: + ignore_args = 1; + break; + default: + break; + } + } + else + { + inf ("texinfo command `%s' not supported (%.*s)", command, + ((s = memchr (rest, '\n', len)), (s? (s-rest) : len)), rest); + } + + if (*rest == '{') + { + /* Find matching closing brace. */ + for (s=rest+1, n=1, i=1; i && *s && n < len; s++, n++) + if (*s == '{') + i++; + else if (*s == '}') + i--; + if (i) + { + err ("closing brace for command `%s' not found", command); + return len; + } + if (n > 2 && !ignore_args) + proc_texi_buffer (fp, rest+1, n-2, table_level, eol_action); + } + else + n = 0; + + if (lead_out) + fputs (lead_out, fp); + + return n; +} + + + +/* Process the string LINE with LEN bytes of Texinfo content. */ +static void +proc_texi_buffer (FILE *fp, const char *line, size_t len, + int *table_level, int *eol_action) +{ + const char *s; + char cmdbuf[256]; + int cmdidx = 0; + int in_cmd = 0; + size_t n; + + for (s=line; *s && len; s++, len--) + { + if (in_cmd) + { + if (in_cmd == 1) + { + switch (*s) + { + case '@': case '{': case '}': + putc (*s, fp); in_cmd = 0; + break; + case ':': /* Not ending a sentence flag. */ + in_cmd = 0; + break; + case '.': case '!': case '?': /* Ending a sentence. */ + putc (*s, fp); in_cmd = 0; + break; + case ' ': case '\t': case '\n': /* Non collapsing spaces. */ + putc (*s, fp); in_cmd = 0; + break; + default: + cmdidx = 0; + cmdbuf[cmdidx++] = *s; + in_cmd++; + break; + } + } + else if (*s == '{' || *s == ' ' || *s == '\t' || *s == '\n') + { + cmdbuf[cmdidx] = 0; + n = proc_texi_cmd (fp, cmdbuf, s, len, table_level, eol_action); + assert (n <= len); + s += n; len -= n; + s--; len++; + in_cmd = 0; + } + else if (cmdidx < sizeof cmdbuf -1) + cmdbuf[cmdidx++] = *s; + else + { + err ("texinfo command too long - ignored"); + in_cmd = 0; + } + } + else if (*s == '@') + in_cmd = 1; + else if (*s == '\n') + { + switch (*eol_action) + { + case 1: /* Create a dummy paragraph. */ + fputs ("\n\\ \n", fp); + break; + default: + putc (*s, fp); + } + *eol_action = 0; + } + else + putc (*s, fp); + } +} + + +/* Do something with the Texinfo line LINE. */ +static void +parse_texi_line (FILE *fp, const char *line, int *table_level) +{ + int eol_action = 0; + + /* A quick test whether there are any texinfo commands. */ + if (!strchr (line, '@')) + { + fputs (line, fp); + putc ('\n', fp); + return; + } + proc_texi_buffer (fp, line, strlen (line), table_level, &eol_action); + putc ('\n', fp); +} + + +/* Write all the lines LINES to FP. */ +static void +write_content (FILE *fp, line_buffer_t lines) +{ + line_buffer_t line; + int table_level = 0; + + for (line = lines; line; line = line->next) + { + if (line->verbatim) + { + fputs (line->line, fp); + putc ('\n', fp); + } + else + { +/* fputs ("TEXI---", fp); */ +/* fputs (line->line, fp); */ +/* fputs ("---\n", fp); */ + parse_texi_line (fp, line->line, &table_level); + } + } +} + + + +static int +is_standard_section (const char *name) +{ + int i; + const char *s; + + for (i=0; (s=standard_sections[i]); i++) + if (!strcmp (s, name)) + return 1; + return 0; +} + + +/* Finish a page; that is sort the data and write it out to the file. */ +static void +finish_page (void) +{ + FILE *fp; + section_buffer_t sect; + int idx; + const char *s; + int i; + + if (!thepage.name) + return; /* No page active. */ + + if (verbose) + inf ("finishing page `%s'", thepage.name); + + if (opt_select) + { + if (!strcmp (opt_select, thepage.name)) + { + inf ("selected `%s'", thepage.name ); + fp = stdout; + } + else + { + fp = fopen ( "/dev/null", "w" ); + if (!fp) + die ("failed to open /dev/null: %s\n", strerror (errno)); + } + } + else if (opt_store) + { + inf ("writing `%s'", thepage.name ); + fp = fopen ( thepage.name, "w" ); + if (!fp) + die ("failed to create `%s': %s\n", thepage.name, strerror (errno)); + } + else + fp = stdout; + + if (write_th (fp)) + goto leave; + + for (idx=0; (s=standard_sections[idx]); idx++) + { + for (i=0; i < thepage.n_sections; i++) + { + sect = thepage.sections + i; + if (sect->name && !strcmp (s, sect->name)) + break; + } + if (i == thepage.n_sections) + sect = NULL; + + if (sect) + { + fprintf (fp, ".SH %s\n", sect->name); + write_content (fp, sect->lines); + /* Now continue with all non standard sections directly + following this one. */ + for (i++; i < thepage.n_sections; i++) + { + sect = thepage.sections + i; + if (sect->name && is_standard_section (sect->name)) + break; + if (sect->name) + { + fprintf (fp, ".SH %s\n", sect->name); + write_content (fp, sect->lines); + } + } + + } + } + + + leave: + if (fp != stdout) + fclose (fp); + free (thepage.name); + thepage.name = NULL; + /* FIXME: Cleanup the content. */ +} + + + + +/* Parse one Texinfo file and create manpages according to the + embedded instructions. */ +static void +parse_file (const char *fname, FILE *fp) +{ + char *line; + int lnr = 0; + int in_verbatim = 0; + int in_pause = 0; + char *section_name = NULL; /* Name of the current section or NULL + if not in a section. */ + int skip_to_end = 0; /* Used to skip over menu entries. */ + + line = xmalloc (LINESIZE); + while (fgets (line, LINESIZE, fp)) + { + size_t n = strlen (line); + int got_line = 0; + char *p; + + lnr++; + if (!n || line[n-1] != '\n') + { + err ("%s:$d: trailing linefeed missing, line too long or " + "embedded Nul character", fname, lnr); + break; + } + line[--n] = 0; + /* We only parse lines we need and ignore the rest. There are a + few macros used to control this as well as one @ifset + command. Parts we know about are saved away into containers + separate for each section. */ + if (*line == '@') + { + for (p=line+1, n=1; *p && *p != ' ' && *p != '\t'; p++) + n++; + while (*p == ' ' || *p == '\t') + p++; + + if (skip_to_end + &&n == 4 && !memcmp (line, "@end", 4) + && (line[4]==' '||line[4]=='\t'||!line[4])) + { + skip_to_end = 0; + } + else if (n == 6 && !memcmp (line, "@ifset", 6) + && !strncmp (p, "manverb", 7) && (p[7]==' '||p[7]=='\t'||!p[7])) + { + if (in_verbatim) + err ("%s:%d: nested \"@ifset manverb\"", fname, lnr); + else + in_verbatim = 1; + } + else if (in_verbatim && n == 4 && !memcmp (line, "@end", 4) + && !strncmp (p, "ifset", 5) + && (p[5]==' '||p[5]=='\t'||!p[5])) + { + in_verbatim = 0; + } + else if (in_verbatim) + { + got_line = 1; + } + else if (n == 8 && !memcmp (line, "@manpage", 8)) + { + free (section_name); + section_name = NULL; + finish_page (); + start_page (p); + in_pause = 0; + } + else if (n == 8 && !memcmp (line, "@mansect", 8)) + { + if (!thepage.name) + err ("%s:%d: section outside of a man page", fname, lnr); + else + { + free (section_name); + section_name = ascii_strupr (xstrdup (p)); + in_pause = 0; + } + } + else if (n == 9 && !memcmp (line, "@manpause", 9)) + { + if (!section_name) + err ("%s:%d: pausing outside of a man section", fname, lnr); + else if (in_pause) + err ("%s:%d: already pausing", fname, lnr); + else + in_pause = 1; + } + else if (n == 8 && !memcmp (line, "@mancont", 8)) + { + if (!section_name) + err ("%s:%d: continue outside of a man section", fname, lnr); + else if (!in_pause) + err ("%s:%d: continue while not pausing", fname, lnr); + else + in_pause = 0; + } + else if (n == 5 && !memcmp (line, "@menu", 5) + && (line[5]==' '||line[5]=='\t'||!line[5])) + { + skip_to_end = 1; + } + else + got_line = 1; + } + else if (!skip_to_end) + got_line = 1; + + if (got_line && in_verbatim) + add_content (section_name, line, 1); + else if (got_line && thepage.name && section_name && !in_pause) + add_content (section_name, line, 0); + + } + if (ferror (fp)) + err ("%s:%d: read error: %s", fname, lnr, strerror (errno)); + finish_page (); + free (section_name); + free (line); +} + + + + + + + +int +main (int argc, char **argv) +{ + int last_argc = -1; + + opt_source = "GNU"; + opt_release = ""; + + if (argc) + { + argc--; argv++; + } + while (argc && last_argc != argc ) + { + last_argc = argc; + if (!strcmp (*argv, "--")) + { + argc--; argv++; + break; + } + else if (!strcmp (*argv, "--help")) + { + puts ( + "Usage: " PGM " [OPTION] [FILE]\n" + "Extract man pages from a Texinfo source.\n\n" + " --source NAME use NAME as source field\n" + " --release STRING use STRING as the release field\n" + " --store write output using @manpage name\n" + " --select NAME only output pages with @manpage NAME\n" + " --verbose enable extra informational output\n" + " --debug enable additional debug output\n" + " --help display this help and exit\n\n" + "With no FILE, or when FILE is -, read standard input.\n\n" + "Report bugs to <[email protected]>."); + exit (0); + } + else if (!strcmp (*argv, "--version")) + { + puts (PGM " " VERSION "\n" + "Copyright (C) 2005 g10 Code GmbH\n" + "This program comes with ABSOLUTELY NO WARRANTY.\n" + "This is free software, and you are welcome to redistribute it\n" + "under certain conditions. See the file COPYING for details."); + exit (0); + } + else if (!strcmp (*argv, "--verbose")) + { + verbose = 1; + argc--; argv++; + } + else if (!strcmp (*argv, "--quiet")) + { + quiet = 1; + argc--; argv++; + } + else if (!strcmp (*argv, "--debug")) + { + verbose = debug = 1; + argc--; argv++; + } + else if (!strcmp (*argv, "--source")) + { + argc--; argv++; + if (argc) + { + opt_source = *argv; + argc--; argv++; + } + } + else if (!strcmp (*argv, "--release")) + { + argc--; argv++; + if (argc) + { + opt_release = *argv; + argc--; argv++; + } + } + else if (!strcmp (*argv, "--store")) + { + opt_store = 1; + argc--; argv++; + } + else if (!strcmp (*argv, "--select")) + { + argc--; argv++; + if (argc) + { + opt_select = strrchr (*argv, '/'); + if (opt_select) + opt_select++; + else + opt_select = *argv; + argc--; argv++; + } + } + } + + if (argc > 1) + die ("usage: " PGM " [OPTION] [FILE] (try --help for more information)\n"); + + /* Start processing. */ + if (argc && strcmp (*argv, "-")) + { + FILE *fp = fopen (*argv, "rb"); + if (!fp) + die ("%s:0: can't open file: %s", *argv, strerror (errno)); + parse_file (*argv, fp); + fclose (fp); + } + else + parse_file ("-", stdin); + + return !!any_error; +} + + +/* +Local Variables: +compile-command: "gcc -Wall -g -Wall -o yat2m yat2m.c" +End: +*/ |