\n"
"
%s
\n", name);
else
fprintf (fp, ".SH %s\n", name);
in_section = 1;
}
}
/* Render a @item line to HTML. (LINE,LEN) gives the arguments of
* @item. Use NULL for LINE to close a possible open
. ITEMX
* flags a @itemx line. */
static void
write_html_item (FILE *fp, const char *line, size_t len, int itemx)
{
static int in_li;
const char *rest;
size_t n, n0;
int eol_action = 0;
int table_level = 0;
if (!itemx && in_li)
{
fprintf (fp, "\n");
in_li = 0;
}
if (line)
{
/* Trim the LF and skip leading spaces. */
if (len && line[len-1] == '\n')
len--;
for (; len && (*line == ' ' || *line == '\t'); len--, line++)
;
if (len)
{
rest = line;
for (n=0; n < len && !(*rest == ' ' || *rest == '\t'); n++, rest++)
;
n0 = n;
for (; n < len && (*rest == ' ' || *rest == '\t'); n++, rest++)
;
len -= n;
/* Now the first word is (LINE,N0) and the args are (REST,LEN) */
fprintf (fp, "%s
%.*s",
itemx? " ":"", (int)n0, line);
if (len)
{
fputs (" ", fp);
proc_texi_buffer (fp, rest, len, &table_level, &eol_action);
fputs ("", fp);
}
fputs ("\n", fp);
in_li = 1;
}
}
}
/* Process the texinfo command COMMAND (without the leading @) and
write output if needed to FP. REST is the remainder 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. */
const char *html_in; /* Same as LEAD_IN but for HTML. */
const char *html_out;/* Same as LEAD_OUT but for HTML. */
} cmdtbl[] = {
{ "command", 0, "\\fB", "\\fR", "
", "" },
{ "code", 0, "\\fB", "\\fR", "
", "" },
{ "url", 0, "\\fB", "\\fR", "
", "" },
{ "sc", 0, "\\fB", "\\fR", "
", "" },
{ "var", 0, "\\fI", "\\fR", "
", "" },
{ "samp", 0, "\\(oq", "\\(cq" },
{ "kbd", 0, "\\(oq", "\\(cq" },
{ "file", 0, "\\(oq\\fI","\\fR\\(cq" },
{ "env", 0, "\\(oq\\fI","\\fR\\(cq" },
{ "acronym", 0 },
{ "dfn", 0 },
{ "option", 0, "\\fB", "\\fR", "
", "" },
{ "example", 1, ".RS 2\n.nf\n", NULL, "\n
\n", "\n
\n" },
{ "smallexample", 1, ".RS 2\n.nf\n", NULL, "\n
\n", "\n
\n" },
{ "asis", 7 },
{ "anchor", 7 },
{ "cartouche", 1 },
{ "ref", 0, "[", "]" },
{ "xref", 0, "See: [", "]" },
{ "pxref", 0, "see: [", "]" },
{ "uref", 0, "(\\fB", "\\fR)" },
{ "footnote",0, " ([", "])" },
{ "emph", 0, "\\fI", "\\fR", "
", "" },
{ "w", 1 },
{ "c", 5 },
{ "efindex", 1 },
{ "opindex", 1 },
{ "cpindex", 1 },
{ "cindex", 1 },
{ "noindent", 0 },
{ "section", 1 },
{ "chapter", 1 },
{ "subsection", 6, "\n.SS " },
{ "chapheading", 0},
{ "item", 2, ".TP\n.B " },
{ "itemx", 2, ".TQ\n.B " },
{ "table", 3, NULL, NULL, "
\n" },
{ "itemize", 3 },
{ "bullet", 0, "* " },
{ "*", 0, "\n.br"},
{ "/", 0 },
{ "end", 4 },
{ "quotation",1, ".RS\n\\fB" },
{ "value", 8 },
{ NULL }
};
size_t n;
int i;
const char *s;
const char *lead_out = NULL;
const char *html_out = NULL;
int ignore_args = 0;
for (i=0; cmdtbl[i].name && strcmp (cmdtbl[i].name, command); i++)
;
if (cmdtbl[i].name)
{
writestr (cmdtbl[i].lead_in, cmdtbl[i].html_in, fp);
lead_out = cmdtbl[i].lead_out;
html_out = cmdtbl[i].html_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. */
if (htmlmode)
{
s = memchr (rest, '\n', len);
n = s? (s-rest)+1 : len;
write_html_item (fp, rest, n, !strcmp(cmdtbl[i].name, "itemx"));
return n;
}
break;
case 3: /* Handle table. */
if (++(*table_level) > 1)
{
write_html_item (fp, NULL, 0, 0);
writestr (".RS\n", "
\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 (htmlmode)
write_html_item (fp, NULL, 0, 0);
if ((*table_level)-- > 1)
writestr (".RE\n", "
\n", fp);
else
writestr (".P\n", "\n", fp);
}
else if (n >= 7 && !memcmp (s, "example", 7)
&& (!n || s[7] == ' ' || s[7] == '\t' || s[7] == '\n'))
{
writestr (".fi\n.RE\n", "\n", fp);
}
else if (n >= 12 && !memcmp (s, "smallexample", 12)
&& (!n || s[12] == ' ' || s[12] == '\t' || s[12] == '\n'))
{
writestr (".fi\n.RE\n", "\n", fp);
}
else if (n >= 9 && !memcmp (s, "quotation", 9)
&& (!n || s[9] == ' ' || s[9] == '\t' || s[9] == '\n'))
{
writestr ("\\fR\n.RE\n", "xx", 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))
{
s += 4;
n -= 4;
if (htmlmode)
{
if (!strncmp (s, ".RE\n", 4)
|| !strncmp (s, ".RS\n", 4))
;
else
inf ("unknown special comment \"man:\"");
}
else
{
for (; n && *s != '\n'; n--, s++)
writechr (*s, fp);
writechr ('\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;
case 8:
ignore_args = 1;
if (*rest != '{')
{
err ("opening brace for command '%s' missing", command);
return len;
}
else
{
/* Find closing brace. */
for (s=rest+1, n=1; *s && n < len; s++, n++)
if (*s == '}')
break;
if (*s != '}')
{
err ("closing brace for command '%s' not found", command);
return len;
}
else
{
size_t rlen = s - (rest + 1);
macro_t m;
for (m = variablelist; m; m = m->next)
{
if (strlen (m->name) == rlen
&& !strncmp (m->name, rest+1, rlen))
break;
}
if (m)
writestr (m->value, m->value, fp);
else
inf ("texinfo variable '%.*s' is not set",
(int)rlen, rest+1);
}
}
break;
default:
break;
}
}
else /* macro */
{
macro_t m;
for (m = macrolist; m ; m = m->next)
if (!strcmp (m->name, command))
break;
if (m)
{
proc_texi_buffer (fp, m->value, strlen (m->value),
table_level, eol_action);
ignore_args = 1; /* Parameterized macros are not yet supported. */
}
else
inf ("texinfo command '%s' not supported (%.*s)", command,
(int)((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;
writestr (lead_out, html_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 '}':
writechr (*s, fp); in_cmd = 0;
break;
case ':': /* Not ending a sentence flag. */
in_cmd = 0;
break;
case '.': case '!': case '?': /* Ending a sentence. */
writechr (*s, fp); in_cmd = 0;
break;
case ' ': case '\t': case '\n': /* Non collapsing spaces. */
writechr (*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. */
writestr ("\n\\ \n", "\n<-- dummy par -->\n", fp);
break;
default:
writechr (*s, fp);
}
*eol_action = 0;
}
else if (*s == '\\')
writestr ("\\\\", "\\\\", fp);
else
writechr (*s, fp);
}
if (in_cmd > 1)
{
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; -- doc only */
}
}
/* 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, '@'))
{
/* FIXME: In html mode escape HTML stuff. */
writestr (line, line, fp);
writechr ('\n', fp);
return;
}
proc_texi_buffer (fp, line, strlen (line), table_level, &eol_action);
writechr ('\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)
{
/* FIXME: IN HTML mode we need to employ a parser for roff
* markup. */
writestr (line->line, line->line, fp);
writechr ('\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 = NULL;
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)
{
write_sh (fp, 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)
{
write_sh (fp, sect->name);
write_content (fp, sect->lines);
}
}
}
}
write_sh (fp, NULL);
if (write_bottom (fp))
goto leave;
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 **section_name, int in_pause)
{
char *line;
int lnr = 0;
/* Fixme: The following state variables don't carry over to include
files. */
int skip_to_end = 0; /* Used to skip over menu entries. */
int skip_sect_line = 0; /* Skip after @mansect. */
int item_indent = 0; /* How far is the current @item indented. */
/* Helper to define a macro. */
char *macroname = NULL;
char *macrovalue = NULL;
size_t macrovaluesize = 0;
size_t macrovalueused = 0;
line = xmalloc (LINESIZE);
while (fgets (line, LINESIZE, fp))
{
size_t n = strlen (line);
int got_line = 0;
char *p, *pend;
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;
/* Kludge to allow indentation of tables. */
for (p=line; *p == ' ' || *p == '\t'; p++)
;
if (*p)
{
if (*p == '@' && !strncmp (p+1, "item", 4))
item_indent = p - line; /* Set a new indent level. */
else if (p - line < item_indent)
item_indent = 0; /* Switch off indention. */
if (item_indent)
{
memmove (line, line+item_indent, n - item_indent + 1);
n -= item_indent;
}
}
if (*line == '@')
{
for (p=line+1, n=1; *p && *p != ' ' && *p != '\t'; p++)
n++;
while (*p == ' ' || *p == '\t')
p++;
}
else
p = line;
/* Take action on macro. */
if (macroname)
{
if (n == 4 && !memcmp (line, "@end", 4)
&& (line[4]==' '||line[4]=='\t'||!line[4])
&& !strncmp (p, "macro", 5)
&& (p[5]==' '||p[5]=='\t'||!p[5]))
{
if (macrovalueused)
macrovalue[--macrovalueused] = 0; /* Kill the last LF. */
macrovalue[macrovalueused] = 0; /* Terminate macro. */
macrovalue = xrealloc (macrovalue, macrovalueused+1);
set_macro (macroname, macrovalue);
macrovalue = NULL;
free (macroname);
macroname = NULL;
}
else
{
if (macrovalueused + strlen (line) + 2 >= macrovaluesize)
{
macrovaluesize += strlen (line) + 256;
macrovalue = xrealloc (macrovalue, macrovaluesize);
}
strcpy (macrovalue+macrovalueused, line);
macrovalueused += strlen (line);
macrovalue[macrovalueused++] = '\n';
}
continue;
}
if (n >= 5 && !memcmp (line, "@node", 5)
&& (line[5]==' '||line[5]=='\t'||!line[5]))
{
/* Completey ignore @node lines. */
continue;
}
if (skip_sect_line)
{
skip_sect_line = 0;
if (!strncmp (line, "@section", 8)
|| !strncmp (line, "@subsection", 11)
|| !strncmp (line, "@chapheading", 12))
continue;
}
/* 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. */
/* First process ifset/ifclear commands. */
if (*line == '@')
{
if (n == 6 && !memcmp (line, "@ifset", 6)
&& (line[6]==' '||line[6]=='\t'))
{
for (p=line+7; *p == ' ' || *p == '\t'; p++)
;
if (!*p)
{
err ("%s:%d: name missing after \"@ifset\"", fname, lnr);
continue;
}
for (pend=p; *pend && *pend != ' ' && *pend != '\t'; pend++)
;
*pend = 0; /* Ignore rest of the line. */
push_condition (p, 1, fname, lnr);
continue;
}
else if (n == 8 && !memcmp (line, "@ifclear", 8)
&& (line[8]==' '||line[8]=='\t'))
{
for (p=line+9; *p == ' ' || *p == '\t'; p++)
;
if (!*p)
{
err ("%s:%d: name missing after \"@ifsclear\"", fname, lnr);
continue;
}
for (pend=p; *pend && *pend != ' ' && *pend != '\t'; pend++)
;
*pend = 0; /* Ignore rest of the line. */
push_condition (p, 0, fname, lnr);
continue;
}
else if (n == 4 && !memcmp (line, "@end", 4)
&& (line[4]==' '||line[4]=='\t')
&& !strncmp (p, "ifset", 5)
&& (p[5]==' '||p[5]=='\t'||!p[5]))
{
pop_condition (1, fname, lnr);
continue;
}
else if (n == 4 && !memcmp (line, "@end", 4)
&& (line[4]==' '||line[4]=='\t')
&& !strncmp (p, "ifclear", 7)
&& (p[7]==' '||p[7]=='\t'||!p[7]))
{
pop_condition (0, fname, lnr);
continue;
}
}
/* Take action on ifset/ifclear. */
if (!cond_is_active)
continue;
/* Process commands. */
if (*line == '@')
{
if (skip_to_end
&& n == 4 && !memcmp (line, "@end", 4)
&& (line[4]==' '||line[4]=='\t'||!line[4]))
{
skip_to_end = 0;
}
else if (cond_in_verbatim)
{
got_line = 1;
}
else if (n == 6 && !memcmp (line, "@macro", 6))
{
macroname = xstrdup (p);
macrovalue = xmalloc ((macrovaluesize = 1024));
macrovalueused = 0;
}
else if (n == 4 && !memcmp (line, "@set", 4))
{
set_variable (p);
}
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;
skip_sect_line = 1;
}
}
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 if (n == 8 && !memcmp (line, "@include", 8)
&& (line[8]==' '||line[8]=='\t'||!line[8]))
{
char *incname = xstrdup (p);
FILE *incfp = fopen (incname, "r");
if (!incfp && opt_include && *opt_include && *p != '/')
{
free (incname);
incname = xmalloc (strlen (opt_include) + 1
+ strlen (p) + 1);
strcpy (incname, opt_include);
if ( incname[strlen (incname)-1] != '/' )
strcat (incname, "/");
strcat (incname, p);
incfp = fopen (incname, "r");
}
if (!incfp)
err ("can't open include file '%s': %s",
incname, strerror (errno));
else
{
parse_file (incname, incfp, section_name, in_pause);
fclose (incfp);
}
free (incname);
}
else if (n == 4 && !memcmp (line, "@bye", 4)
&& (line[4]==' '||line[4]=='\t'||!line[4]))
{
break;
}
else if (!skip_to_end)
got_line = 1;
}
else if (!skip_to_end)
got_line = 1;
if (got_line && cond_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));
free (macroname);
free (macrovalue);
free (line);
}
static void
top_parse_file (const char *fname, FILE *fp)
{
char *section_name = NULL; /* Name of the current section or NULL
if not in a section. */
macro_t m;
while (macrolist)
{
macro_t next = macrolist->next;
free (macrolist->value);
free (macrolist);
macrolist = next;
}
while (variablelist)
{
macro_t next = variablelist->next;
free (variablelist->value);
free (variablelist);
variablelist = next;
}
for (m=predefinedmacrolist; m; m = m->next)
set_macro (m->name, xstrdup ("1"));
cond_is_active = 1;
cond_in_verbatim = 0;
parse_file (fname, fp, §ion_name, 0);
free (section_name);
finish_page ();
}
int
main (int argc, char **argv)
{
int last_argc = -1;
const char *s;
opt_source = "GNU";
opt_release = "";
/* Define default macros. The trick is that these macros are not
defined when using the actual texinfo renderer. */
add_predefined_macro ("isman");
add_predefined_macro ("manverb");
/* Option parsing. */
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"
" --html render output as HTML\n"
" --source NAME use NAME as source field\n"
" --release STRING use STRING as the release field\n"
" --date EPOCH use EPOCH as publication date\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"
" -I DIR also search in include DIR\n"
" -D MACRO define MACRO to 1\n\n"
"With no FILE, or when FILE is -, read standard input.\n\n"
"Report bugs to
.");
exit (0);
}
else if (!strcmp (*argv, "--version"))
{
puts (PGM " " VERSION "\n"
"Copyright (C) 2005, 2017 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, "--html"))
{
htmlmode = 1;
argc--; argv++;
}
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, "--date"))
{
argc--; argv++;
if (argc)
{
opt_date = *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++;
}
}
else if (!strcmp (*argv, "-I"))
{
argc--; argv++;
if (argc)
{
opt_include = *argv;
argc--; argv++;
}
}
else if (!strcmp (*argv, "-D"))
{
argc--; argv++;
if (argc)
{
add_predefined_macro (*argv);
argc--; argv++;
}
}
}
if (argc > 1)
die ("usage: " PGM " [OPTION] [FILE] (try --help for more information)\n");
/* Take care of supplied timestamp for reproducible builds. See
* https://reproducible-builds.org/specs/source-date-epoch/ */
if (!opt_date && (s = getenv ("SOURCE_DATE_EPOCH")) && *s)
opt_date = s;
/* Start processing. */
if (argc && strcmp (*argv, "-"))
{
FILE *fp = fopen (*argv, "rb");
if (!fp)
die ("%s:0: can't open file: %s", *argv, strerror (errno));
top_parse_file (*argv, fp);
fclose (fp);
}
else
top_parse_file ("-", stdin);
return !!any_error;
}
/*
Local Variables:
compile-command: "gcc -Wall -g -Wall -o yat2m yat2m.c"
End:
*/