Blame doc/yat2m.c

Packit fc043f
/* yat2m.c - Yet Another Texi 2 Man converter
Packit fc043f
 *	Copyright (C) 2005, 2013, 2015, 2016, 2017 g10 Code GmbH
Packit fc043f
 *      Copyright (C) 2006, 2008, 2011 Free Software Foundation, Inc.
Packit fc043f
 *
Packit fc043f
 * This program is free software; you can redistribute it and/or modify
Packit fc043f
 * it under the terms of the GNU General Public License as published by
Packit fc043f
 * the Free Software Foundation; either version 3 of the License, or
Packit fc043f
 * (at your option) any later version.
Packit fc043f
 *
Packit fc043f
 * This program is distributed in the hope that it will be useful,
Packit fc043f
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit fc043f
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit fc043f
 * GNU General Public License for more details.
Packit fc043f
 *
Packit fc043f
 * You should have received a copy of the GNU General Public License
Packit fc043f
 * along with this program; if not, see <https://www.gnu.org/licenses/>.
Packit fc043f
 */
Packit fc043f
Packit fc043f
/*
Packit fc043f
    This is a simple texinfo to man page converter.  It needs some
Packit fc043f
    special markup in th e texinfo and tries best to get a create man
Packit fc043f
    page.  It has been designed for the GnuPG man pages and thus only
Packit fc043f
    a few texinfo commands are supported.
Packit fc043f
Packit fc043f
    To use this you need to add the following macros into your texinfo
Packit fc043f
    source:
Packit fc043f
Packit fc043f
      @macro manpage {a}
Packit fc043f
      @end macro
Packit fc043f
      @macro mansect {a}
Packit fc043f
      @end macro
Packit fc043f
      @macro manpause
Packit fc043f
      @end macro
Packit fc043f
      @macro mancont
Packit fc043f
      @end macro
Packit fc043f
Packit fc043f
    They are used by yat2m to select parts of the Texinfo which should
Packit fc043f
    go into the man page. These macros need to be used without leading
Packit fc043f
    left space. Processing starts after a "manpage" macro has been
Packit fc043f
    seen.  "mansect" identifies the section and yat2m make sure to
Packit fc043f
    emit the sections in the proper order.  Note that @mansect skips
Packit fc043f
    the next input line if that line begins with @section, @subsection or
Packit fc043f
    @chapheading.
Packit fc043f
Packit fc043f
    To insert verbatim troff markup, the following texinfo code may be
Packit fc043f
    used:
Packit fc043f
Packit fc043f
      @ifset manverb
Packit fc043f
      .B whateever you want
Packit fc043f
      @end ifset
Packit fc043f
Packit fc043f
    alternativly a special comment may be used:
Packit fc043f
Packit fc043f
      @c man:.B whatever you want
Packit fc043f
Packit fc043f
    This is useful in case you need just one line. If you want to
Packit fc043f
    include parts only in the man page but keep the texinfo
Packit fc043f
    translation you may use:
Packit fc043f
Packit fc043f
      @ifset isman
Packit fc043f
      stuff to be rendered only on man pages
Packit fc043f
      @end ifset
Packit fc043f
Packit fc043f
    or to exclude stuff from man pages:
Packit fc043f
Packit fc043f
      @ifclear isman
Packit fc043f
      stuff not to be rendered on man pages
Packit fc043f
      @end ifclear
Packit fc043f
Packit fc043f
    the keyword @section is ignored, however @subsection gets rendered
Packit fc043f
    as ".SS".  @menu is completely skipped. Several man pages may be
Packit fc043f
    extracted from one file, either using the --store or the --select
Packit fc043f
    option.
Packit fc043f
Packit fc043f
    If you want to indent tables in the source use this style:
Packit fc043f
Packit fc043f
      @table foo
Packit fc043f
        @item
Packit fc043f
        @item
Packit fc043f
        @table
Packit fc043f
          @item
Packit fc043f
        @end
Packit fc043f
      @end
Packit fc043f
Packit fc043f
    Don't change the indentation within a table and keep the same
Packit fc043f
    number of white space at the start of the line.  yat2m simply
Packit fc043f
    detects the number of white spaces in front of an @item and remove
Packit fc043f
    this number of spaces from all following lines until a new @item
Packit fc043f
    is found or there are less spaces than for the last @item.
Packit fc043f
Packit fc043f
    Note that @* does only work correctly if used at the end of an
Packit fc043f
    input line.
Packit fc043f
Packit fc043f
*/
Packit fc043f
Packit fc043f
#include <stdio.h>
Packit fc043f
#include <stdlib.h>
Packit fc043f
#include <stddef.h>
Packit fc043f
#include <string.h>
Packit fc043f
#include <errno.h>
Packit fc043f
#include <stdarg.h>
Packit fc043f
#include <assert.h>
Packit fc043f
#include <ctype.h>
Packit fc043f
#include <time.h>
Packit fc043f
Packit fc043f
Packit fc043f
#if __GNUC__
Packit fc043f
# define MY_GCC_VERSION (__GNUC__ * 10000 \
Packit fc043f
                         + __GNUC_MINOR__ * 100         \
Packit fc043f
                         + __GNUC_PATCHLEVEL__)
Packit fc043f
#else
Packit fc043f
# define MY_GCC_VERSION 0
Packit fc043f
#endif
Packit fc043f
Packit fc043f
#if MY_GCC_VERSION >= 20500
Packit fc043f
# define ATTR_PRINTF(f, a) __attribute__ ((format(printf,f,a)))
Packit fc043f
# define ATTR_NR_PRINTF(f, a) __attribute__ ((noreturn, format(printf,f,a)))
Packit fc043f
#else
Packit fc043f
# define ATTR_PRINTF(f, a)
Packit fc043f
# define ATTR_NR_PRINTF(f, a)
Packit fc043f
#endif
Packit fc043f
#if MY_GCC_VERSION >= 30200
Packit fc043f
# define ATTR_MALLOC  __attribute__ ((__malloc__))
Packit fc043f
#else
Packit fc043f
# define ATTR_MALLOC
Packit fc043f
#endif
Packit fc043f
Packit fc043f
Packit fc043f
Packit fc043f
#define PGM "yat2m"
Packit fc043f
#ifdef PACKAGE_VERSION
Packit fc043f
# define VERSION PACKAGE_VERSION
Packit fc043f
#else
Packit fc043f
# define VERSION "1.0"
Packit fc043f
#endif
Packit fc043f
Packit fc043f
/* The maximum length of a line including the linefeed and one extra
Packit fc043f
   character. */
Packit fc043f
#define LINESIZE 1024
Packit fc043f
Packit fc043f
/* Number of allowed condition nestings.  */
Packit fc043f
#define MAX_CONDITION_NESTING  10
Packit fc043f
Packit fc043f
/* Option flags. */
Packit fc043f
static int verbose;
Packit fc043f
static int quiet;
Packit fc043f
static int debug;
Packit fc043f
static const char *opt_source;
Packit fc043f
static const char *opt_release;
Packit fc043f
static const char *opt_date;
Packit fc043f
static const char *opt_select;
Packit fc043f
static const char *opt_include;
Packit fc043f
static int opt_store;
Packit fc043f
Packit fc043f
/* Flag to keep track whether any error occurred.  */
Packit fc043f
static int any_error;
Packit fc043f
Packit fc043f
Packit fc043f
/* Object to keep macro definitions.  */
Packit fc043f
struct macro_s
Packit fc043f
{
Packit fc043f
  struct macro_s *next;
Packit fc043f
  char *value;    /* Malloced value. */
Packit fc043f
  char name[1];
Packit fc043f
};
Packit fc043f
typedef struct macro_s *macro_t;
Packit fc043f
Packit fc043f
/* List of all defined macros. */
Packit fc043f
static macro_t macrolist;
Packit fc043f
Packit fc043f
/* List of variables set by @set. */
Packit fc043f
static macro_t variablelist;
Packit fc043f
Packit fc043f
/* List of global macro names.  The value part is not used.  */
Packit fc043f
static macro_t predefinedmacrolist;
Packit fc043f
Packit fc043f
/* Object to keep track of @isset and @ifclear.  */
Packit fc043f
struct condition_s
Packit fc043f
{
Packit fc043f
  int manverb;   /* "manverb" needs special treatment.  */
Packit fc043f
  int isset;     /* This is an @isset condition.  */
Packit fc043f
  char name[1];  /* Name of the condition macro.  */
Packit fc043f
};
Packit fc043f
typedef struct condition_s *condition_t;
Packit fc043f
Packit fc043f
/* The stack used to evaluate conditions.  And the current states. */
Packit fc043f
static condition_t condition_stack[MAX_CONDITION_NESTING];
Packit fc043f
static int condition_stack_idx;
Packit fc043f
static int cond_is_active;     /* State of ifset/ifclear */
Packit fc043f
static int cond_in_verbatim;   /* State of "manverb".  */
Packit fc043f
Packit fc043f
Packit fc043f
/* Object to store one line of content.  */
Packit fc043f
struct line_buffer_s
Packit fc043f
{
Packit fc043f
  struct line_buffer_s *next;
Packit fc043f
  int verbatim;  /* True if LINE contains verbatim data.  The default
Packit fc043f
                    is Texinfo source.  */
Packit fc043f
  char *line;
Packit fc043f
};
Packit fc043f
typedef struct line_buffer_s *line_buffer_t;
Packit fc043f
Packit fc043f
Packit fc043f
/* Object to collect the data of a section.  */
Packit fc043f
struct section_buffer_s
Packit fc043f
{
Packit fc043f
  char *name;           /* Malloced name of the section. This may be
Packit fc043f
                           NULL to indicate this slot is not used.  */
Packit fc043f
  line_buffer_t lines;  /* Linked list with the lines of the section.  */
Packit fc043f
  line_buffer_t *lines_tail; /* Helper for faster appending to the
Packit fc043f
                                linked list.  */
Packit fc043f
  line_buffer_t last_line;   /* Points to the last line appended.  */
Packit fc043f
};
Packit fc043f
typedef struct section_buffer_s *section_buffer_t;
Packit fc043f
Packit fc043f
/* Variable to keep info about the current page together.  */
Packit fc043f
static struct
Packit fc043f
{
Packit fc043f
  /* Filename of the current page or NULL if no page is active.  Malloced. */
Packit fc043f
  char *name;
Packit fc043f
Packit fc043f
  /* Number of allocated elements in SECTIONS below.  */
Packit fc043f
  size_t n_sections;
Packit fc043f
  /* Array with the data of the sections.  */
Packit fc043f
  section_buffer_t sections;
Packit fc043f
Packit fc043f
} thepage;
Packit fc043f
Packit fc043f
Packit fc043f
/* The list of standard section names.  COMMANDS and ASSUAN are GnuPG
Packit fc043f
   specific. */
Packit fc043f
static const char * const standard_sections[] =
Packit fc043f
  { "NAME",  "SYNOPSIS",  "DESCRIPTION",
Packit fc043f
    "RETURN VALUE", "EXIT STATUS", "ERROR HANDLING", "ERRORS",
Packit fc043f
    "COMMANDS", "OPTIONS", "USAGE", "EXAMPLES", "FILES",
Packit fc043f
    "ENVIRONMENT", "DIAGNOSTICS", "SECURITY", "CONFORMING TO",
Packit fc043f
    "ASSUAN", "NOTES", "BUGS", "AUTHOR", "SEE ALSO", NULL };
Packit fc043f
Packit fc043f
Packit fc043f
/*-- Local prototypes.  --*/
Packit fc043f
static void proc_texi_buffer (FILE *fp, const char *line, size_t len,
Packit fc043f
                              int *table_level, int *eol_action);
Packit fc043f
Packit fc043f
static void die (const char *format, ...) ATTR_NR_PRINTF(1,2);
Packit fc043f
static void err (const char *format, ...) ATTR_PRINTF(1,2);
Packit fc043f
static void inf (const char *format, ...) ATTR_PRINTF(1,2);
Packit fc043f
static void *xmalloc (size_t n) ATTR_MALLOC;
Packit fc043f
static void *xcalloc (size_t n, size_t m) ATTR_MALLOC;
Packit fc043f
Packit fc043f
Packit fc043f
Packit fc043f
/*-- Functions --*/
Packit fc043f
Packit fc043f
/* Print diagnostic message and exit with failure. */
Packit fc043f
static void
Packit fc043f
die (const char *format, ...)
Packit fc043f
{
Packit fc043f
  va_list arg_ptr;
Packit fc043f
Packit fc043f
  fflush (stdout);
Packit fc043f
  fprintf (stderr, "%s: ", PGM);
Packit fc043f
Packit fc043f
  va_start (arg_ptr, format);
Packit fc043f
  vfprintf (stderr, format, arg_ptr);
Packit fc043f
  va_end (arg_ptr);
Packit fc043f
  putc ('\n', stderr);
Packit fc043f
Packit fc043f
  exit (1);
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Print diagnostic message. */
Packit fc043f
static void
Packit fc043f
err (const char *format, ...)
Packit fc043f
{
Packit fc043f
  va_list arg_ptr;
Packit fc043f
Packit fc043f
  fflush (stdout);
Packit fc043f
  if (strncmp (format, "%s:%d:", 6))
Packit fc043f
    fprintf (stderr, "%s: ", PGM);
Packit fc043f
Packit fc043f
  va_start (arg_ptr, format);
Packit fc043f
  vfprintf (stderr, format, arg_ptr);
Packit fc043f
  va_end (arg_ptr);
Packit fc043f
  putc ('\n', stderr);
Packit fc043f
  any_error = 1;
Packit fc043f
}
Packit fc043f
Packit fc043f
/* Print diagnostic message. */
Packit fc043f
static void
Packit fc043f
inf (const char *format, ...)
Packit fc043f
{
Packit fc043f
  va_list arg_ptr;
Packit fc043f
Packit fc043f
  fflush (stdout);
Packit fc043f
  fprintf (stderr, "%s: ", PGM);
Packit fc043f
Packit fc043f
  va_start (arg_ptr, format);
Packit fc043f
  vfprintf (stderr, format, arg_ptr);
Packit fc043f
  va_end (arg_ptr);
Packit fc043f
  putc ('\n', stderr);
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
static void *
Packit fc043f
xmalloc (size_t n)
Packit fc043f
{
Packit fc043f
  void *p = malloc (n);
Packit fc043f
  if (!p)
Packit fc043f
    die ("out of core: %s", strerror (errno));
Packit fc043f
  return p;
Packit fc043f
}
Packit fc043f
Packit fc043f
static void *
Packit fc043f
xcalloc (size_t n, size_t m)
Packit fc043f
{
Packit fc043f
  void *p = calloc (n, m);
Packit fc043f
  if (!p)
Packit fc043f
    die ("out of core: %s", strerror (errno));
Packit fc043f
  return p;
Packit fc043f
}
Packit fc043f
Packit fc043f
static void *
Packit fc043f
xrealloc (void *old, size_t n)
Packit fc043f
{
Packit fc043f
  void *p = realloc (old, n);
Packit fc043f
  if (!p)
Packit fc043f
    die ("out of core: %s", strerror (errno));
Packit fc043f
  return p;
Packit fc043f
}
Packit fc043f
Packit fc043f
static char *
Packit fc043f
xstrdup (const char *string)
Packit fc043f
{
Packit fc043f
  void *p = malloc (strlen (string)+1);
Packit fc043f
  if (!p)
Packit fc043f
    die ("out of core: %s", strerror (errno));
Packit fc043f
  strcpy (p, string);
Packit fc043f
  return p;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Uppercase the ascii characters in STRING.  */
Packit fc043f
static char *
Packit fc043f
ascii_strupr (char *string)
Packit fc043f
{
Packit fc043f
  char *p;
Packit fc043f
Packit fc043f
  for (p = string; *p; p++)
Packit fc043f
    if (!(*p & 0x80))
Packit fc043f
      *p = toupper (*p);
Packit fc043f
  return string;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Return the current date as an ISO string.  */
Packit fc043f
const char *
Packit fc043f
isodatestring (void)
Packit fc043f
{
Packit fc043f
  static char buffer[11+5];
Packit fc043f
  struct tm *tp;
Packit fc043f
  time_t atime;
Packit fc043f
Packit fc043f
  if (opt_date && *opt_date)
Packit fc043f
    atime = strtoul (opt_date, NULL, 10);
Packit fc043f
  else
Packit fc043f
    atime = time (NULL);
Packit fc043f
  if (atime < 0)
Packit fc043f
    strcpy (buffer, "????" "-??" "-??");
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
      tp = gmtime (&atime);
Packit fc043f
      sprintf (buffer,"%04d-%02d-%02d",
Packit fc043f
               1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
Packit fc043f
    }
Packit fc043f
  return buffer;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Add NAME to the list of predefined macros which are global for all
Packit fc043f
   files.  */
Packit fc043f
static void
Packit fc043f
add_predefined_macro (const char *name)
Packit fc043f
{
Packit fc043f
  macro_t m;
Packit fc043f
Packit fc043f
  for (m=predefinedmacrolist; m; m = m->next)
Packit fc043f
    if (!strcmp (m->name, name))
Packit fc043f
      break;
Packit fc043f
  if (!m)
Packit fc043f
    {
Packit fc043f
      m = xcalloc (1, sizeof *m + strlen (name));
Packit fc043f
      strcpy (m->name, name);
Packit fc043f
      m->next = predefinedmacrolist;
Packit fc043f
      predefinedmacrolist = m;
Packit fc043f
    }
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Create or update a macro with name MACRONAME and set its values TO
Packit fc043f
   MACROVALUE.  Note that ownership of the macro value is transferred
Packit fc043f
   to this function.  */
Packit fc043f
static void
Packit fc043f
set_macro (const char *macroname, char *macrovalue)
Packit fc043f
{
Packit fc043f
  macro_t m;
Packit fc043f
Packit fc043f
  for (m=macrolist; m; m = m->next)
Packit fc043f
    if (!strcmp (m->name, macroname))
Packit fc043f
      break;
Packit fc043f
  if (m)
Packit fc043f
    free (m->value);
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
      m = xcalloc (1, sizeof *m + strlen (macroname));
Packit fc043f
      strcpy (m->name, macroname);
Packit fc043f
      m->next = macrolist;
Packit fc043f
      macrolist = m;
Packit fc043f
    }
Packit fc043f
  m->value = macrovalue;
Packit fc043f
  macrovalue = NULL;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Create or update a variable with name and value given in NAMEANDVALUE.  */
Packit fc043f
static void
Packit fc043f
set_variable (char *nameandvalue)
Packit fc043f
{
Packit fc043f
  macro_t m;
Packit fc043f
  const char *value;
Packit fc043f
  char *p;
Packit fc043f
Packit fc043f
  for (p = nameandvalue; *p && *p != ' ' && *p != '\t'; p++)
Packit fc043f
    ;
Packit fc043f
  if (!*p)
Packit fc043f
    value = "";
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
      *p++ = 0;
Packit fc043f
      while (*p == ' ' || *p == '\t')
Packit fc043f
        p++;
Packit fc043f
      value = p;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  for (m=variablelist; m; m = m->next)
Packit fc043f
    if (!strcmp (m->name, nameandvalue))
Packit fc043f
      break;
Packit fc043f
  if (m)
Packit fc043f
    free (m->value);
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
      m = xcalloc (1, sizeof *m + strlen (nameandvalue));
Packit fc043f
      strcpy (m->name, nameandvalue);
Packit fc043f
      m->next = variablelist;
Packit fc043f
      variablelist = m;
Packit fc043f
    }
Packit fc043f
  m->value = xstrdup (value);
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Return true if the macro or variable NAME is set, i.e. not the
Packit fc043f
   empty string and not evaluating to 0.  */
Packit fc043f
static int
Packit fc043f
macro_set_p (const char *name)
Packit fc043f
{
Packit fc043f
  macro_t m;
Packit fc043f
Packit fc043f
  for (m = macrolist; m ; m = m->next)
Packit fc043f
    if (!strcmp (m->name, name))
Packit fc043f
      break;
Packit fc043f
  if (!m)
Packit fc043f
    for (m = variablelist; m ; m = m->next)
Packit fc043f
      if (!strcmp (m->name, name))
Packit fc043f
        break;
Packit fc043f
  if (!m || !m->value || !*m->value)
Packit fc043f
    return 0;
Packit fc043f
  if ((*m->value & 0x80) || !isdigit (*m->value))
Packit fc043f
    return 1; /* Not a digit but some other string.  */
Packit fc043f
  return !!atoi (m->value);
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Evaluate the current conditions.  */
Packit fc043f
static void
Packit fc043f
evaluate_conditions (const char *fname, int lnr)
Packit fc043f
{
Packit fc043f
  int i;
Packit fc043f
Packit fc043f
  (void)fname;
Packit fc043f
  (void)lnr;
Packit fc043f
Packit fc043f
  /* for (i=0; i < condition_stack_idx; i++) */
Packit fc043f
  /*   inf ("%s:%d:   stack[%d] %s %s %c", */
Packit fc043f
  /*        fname, lnr, i, condition_stack[i]->isset? "set":"clr", */
Packit fc043f
  /*        condition_stack[i]->name, */
Packit fc043f
  /*        (macro_set_p (condition_stack[i]->name) */
Packit fc043f
  /*         ^ !condition_stack[i]->isset)? 't':'f'); */
Packit fc043f
Packit fc043f
  cond_is_active = 1;
Packit fc043f
  cond_in_verbatim = 0;
Packit fc043f
  if (condition_stack_idx)
Packit fc043f
    {
Packit fc043f
      for (i=0; i < condition_stack_idx; i++)
Packit fc043f
        {
Packit fc043f
          if (condition_stack[i]->manverb)
Packit fc043f
            cond_in_verbatim = (macro_set_p (condition_stack[i]->name)
Packit fc043f
                                ^ !condition_stack[i]->isset);
Packit fc043f
          else if (!(macro_set_p (condition_stack[i]->name)
Packit fc043f
                     ^ !condition_stack[i]->isset))
Packit fc043f
            {
Packit fc043f
              cond_is_active = 0;
Packit fc043f
              break;
Packit fc043f
            }
Packit fc043f
        }
Packit fc043f
    }
Packit fc043f
Packit fc043f
  /* inf ("%s:%d:   active=%d verbatim=%d", */
Packit fc043f
  /*      fname, lnr, cond_is_active, cond_in_verbatim); */
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Push a condition with condition macro NAME onto the stack.  If
Packit fc043f
   ISSET is true, a @isset condition is pushed.  */
Packit fc043f
static void
Packit fc043f
push_condition (const char *name, int isset, const char *fname, int lnr)
Packit fc043f
{
Packit fc043f
  condition_t cond;
Packit fc043f
  int manverb = 0;
Packit fc043f
Packit fc043f
  if (condition_stack_idx >= MAX_CONDITION_NESTING)
Packit fc043f
    {
Packit fc043f
      err ("%s:%d: condition nested too deep", fname, lnr);
Packit fc043f
      return;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (!strcmp (name, "manverb"))
Packit fc043f
    {
Packit fc043f
      if (!isset)
Packit fc043f
        {
Packit fc043f
          err ("%s:%d: using \"@ifclear manverb\" is not allowed", fname, lnr);
Packit fc043f
          return;
Packit fc043f
        }
Packit fc043f
      manverb = 1;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  cond = xcalloc (1, sizeof *cond + strlen (name));
Packit fc043f
  cond->manverb = manverb;
Packit fc043f
  cond->isset = isset;
Packit fc043f
  strcpy (cond->name, name);
Packit fc043f
Packit fc043f
  condition_stack[condition_stack_idx++] = cond;
Packit fc043f
  evaluate_conditions (fname, lnr);
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Remove the last condition from the stack.  ISSET is used for error
Packit fc043f
   reporting.  */
Packit fc043f
static void
Packit fc043f
pop_condition (int isset, const char *fname, int lnr)
Packit fc043f
{
Packit fc043f
  if (!condition_stack_idx)
Packit fc043f
    {
Packit fc043f
      err ("%s:%d: unbalanced \"@end %s\"",
Packit fc043f
           fname, lnr, isset?"isset":"isclear");
Packit fc043f
      return;
Packit fc043f
    }
Packit fc043f
  condition_stack_idx--;
Packit fc043f
  free (condition_stack[condition_stack_idx]);
Packit fc043f
  condition_stack[condition_stack_idx] = NULL;
Packit fc043f
  evaluate_conditions (fname, lnr);
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f

Packit fc043f
/* Return a section buffer for the section NAME.  Allocate a new buffer
Packit fc043f
   if this is a new section.  Keep track of the sections in THEPAGE.
Packit fc043f
   This function may reallocate the section array in THEPAGE.  */
Packit fc043f
static section_buffer_t
Packit fc043f
get_section_buffer (const char *name)
Packit fc043f
{
Packit fc043f
  int i;
Packit fc043f
  section_buffer_t sect;
Packit fc043f
Packit fc043f
  /* If there is no section we put everything into the required NAME
Packit fc043f
     section.  Given that this is the first one listed it is likely
Packit fc043f
     that error are easily visible.  */
Packit fc043f
  if (!name)
Packit fc043f
    name = "NAME";
Packit fc043f
Packit fc043f
  for (i=0; i < thepage.n_sections; i++)
Packit fc043f
    {
Packit fc043f
      sect = thepage.sections + i;
Packit fc043f
      if (sect->name && !strcmp (name, sect->name))
Packit fc043f
        return sect;
Packit fc043f
    }
Packit fc043f
  for (i=0; i < thepage.n_sections; i++)
Packit fc043f
    if (!thepage.sections[i].name)
Packit fc043f
      break;
Packit fc043f
  if (thepage.n_sections && i < thepage.n_sections)
Packit fc043f
    sect = thepage.sections + i;
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
      /* We need to allocate or reallocate the section array.  */
Packit fc043f
      size_t old_n = thepage.n_sections;
Packit fc043f
      size_t new_n = 20;
Packit fc043f
Packit fc043f
      if (!old_n)
Packit fc043f
        thepage.sections = xcalloc (new_n, sizeof *thepage.sections);
Packit fc043f
      else
Packit fc043f
        {
Packit fc043f
          thepage.sections = xrealloc (thepage.sections,
Packit fc043f
                                       ((old_n + new_n)
Packit fc043f
                                        * sizeof *thepage.sections));
Packit fc043f
          memset (thepage.sections + old_n, 0,
Packit fc043f
                  new_n * sizeof *thepage.sections);
Packit fc043f
        }
Packit fc043f
      thepage.n_sections += new_n;
Packit fc043f
Packit fc043f
      /* Setup the tail pointers.  */
Packit fc043f
      for (i=old_n; i < thepage.n_sections; i++)
Packit fc043f
        {
Packit fc043f
          sect = thepage.sections + i;
Packit fc043f
          sect->lines_tail = &sect->lines;
Packit fc043f
        }
Packit fc043f
      sect = thepage.sections + old_n;
Packit fc043f
    }
Packit fc043f
Packit fc043f
  /* Store the name.  */
Packit fc043f
  assert (!sect->name);
Packit fc043f
  sect->name = xstrdup (name);
Packit fc043f
  return sect;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
Packit fc043f
/* Add the content of LINE to the section named SECTNAME.  */
Packit fc043f
static void
Packit fc043f
add_content (const char *sectname, char *line, int verbatim)
Packit fc043f
{
Packit fc043f
  section_buffer_t sect;
Packit fc043f
  line_buffer_t lb;
Packit fc043f
Packit fc043f
  sect = get_section_buffer (sectname);
Packit fc043f
  if (sect->last_line && !sect->last_line->verbatim == !verbatim)
Packit fc043f
    {
Packit fc043f
      /* Lets append that line to the last one.  We do this to keep
Packit fc043f
         all lines of the same kind (i.e.verbatim or not) together in
Packit fc043f
         one large buffer.  */
Packit fc043f
      size_t n1, n;
Packit fc043f
Packit fc043f
      lb = sect->last_line;
Packit fc043f
      n1 = strlen (lb->line);
Packit fc043f
      n = n1 + 1 + strlen (line) + 1;
Packit fc043f
      lb->line = xrealloc (lb->line, n);
Packit fc043f
      strcpy (lb->line+n1, "\n");
Packit fc043f
      strcpy (lb->line+n1+1, line);
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    {
Packit fc043f
      lb = xcalloc (1, sizeof *lb);
Packit fc043f
      lb->verbatim = verbatim;
Packit fc043f
      lb->line = xstrdup (line);
Packit fc043f
      sect->last_line = lb;
Packit fc043f
      *sect->lines_tail = lb;
Packit fc043f
      sect->lines_tail = &lb->next;
Packit fc043f
    }
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Prepare for a new man page using the filename NAME. */
Packit fc043f
static void
Packit fc043f
start_page (char *name)
Packit fc043f
{
Packit fc043f
  if (verbose)
Packit fc043f
    inf ("starting page '%s'", name);
Packit fc043f
  assert (!thepage.name);
Packit fc043f
  thepage.name = xstrdup (name);
Packit fc043f
  thepage.n_sections = 0;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Write the .TH entry of the current page.  Return -1 if there is a
Packit fc043f
   problem with the page. */
Packit fc043f
static int
Packit fc043f
write_th (FILE *fp)
Packit fc043f
{
Packit fc043f
  char *name, *p;
Packit fc043f
Packit fc043f
  fputs (".\\\" Created from Texinfo source by yat2m " VERSION "\n", fp);
Packit fc043f
Packit fc043f
  name = ascii_strupr (xstrdup (thepage.name));
Packit fc043f
  p = strrchr (name, '.');
Packit fc043f
  if (!p || !p[1])
Packit fc043f
    {
Packit fc043f
      err ("no section name in man page '%s'", thepage.name);
Packit fc043f
      free (name);
Packit fc043f
      return -1;
Packit fc043f
    }
Packit fc043f
  *p++ = 0;
Packit fc043f
  fprintf (fp, ".TH %s %s %s \"%s\" \"%s\"\n",
Packit fc043f
           name, p, isodatestring (), opt_release, opt_source);
Packit fc043f
  free (name);
Packit fc043f
  return 0;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Process the texinfo command COMMAND (without the leading @) and
Packit fc043f
   write output if needed to FP. REST is the remainer of the line
Packit fc043f
   which should either point to an opening brace or to a white space.
Packit fc043f
   The function returns the number of characters already processed
Packit fc043f
   from REST.  LEN is the usable length of REST.  TABLE_LEVEL is used to
Packit fc043f
   control the indentation of tables.  */
Packit fc043f
static size_t
Packit fc043f
proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
Packit fc043f
               int *table_level, int *eol_action)
Packit fc043f
{
Packit fc043f
  static struct {
Packit fc043f
    const char *name;    /* Name of the command.  */
Packit fc043f
    int what;            /* What to do with this command. */
Packit fc043f
    const char *lead_in; /* String to print with a opening brace.  */
Packit fc043f
    const char *lead_out;/* String to print with the closing brace. */
Packit fc043f
  } cmdtbl[] = {
Packit fc043f
    { "command", 0, "\\fB", "\\fR" },
Packit fc043f
    { "code",    0, "\\fB", "\\fR" },
Packit fc043f
    { "url",     0, "\\fB", "\\fR" },
Packit fc043f
    { "sc",      0, "\\fB", "\\fR" },
Packit fc043f
    { "var",     0, "\\fI", "\\fR" },
Packit fc043f
    { "samp",    0, "\\(aq", "\\(aq"  },
Packit fc043f
    { "file",    0, "\\(oq\\fI","\\fR\\(cq" },
Packit fc043f
    { "env",     0, "\\(oq\\fI","\\fR\\(cq" },
Packit fc043f
    { "acronym", 0 },
Packit fc043f
    { "dfn",     0 },
Packit fc043f
    { "option",  0, "\\fB", "\\fR"   },
Packit fc043f
    { "example", 1, ".RS 2\n.nf\n" },
Packit fc043f
    { "smallexample", 1, ".RS 2\n.nf\n" },
Packit fc043f
    { "asis",    7 },
Packit fc043f
    { "anchor",  7 },
Packit fc043f
    { "cartouche", 1 },
Packit fc043f
    { "ref",     0, "[", "]" },
Packit fc043f
    { "xref",    0, "See: [", "]" },
Packit fc043f
    { "pxref",   0, "see: [", "]" },
Packit fc043f
    { "uref",    0, "(\\fB", "\\fR)" },
Packit fc043f
    { "footnote",0, " ([", "])" },
Packit fc043f
    { "emph",    0, "\\fI", "\\fR" },
Packit fc043f
    { "w",       1 },
Packit fc043f
    { "c",       5 },
Packit fc043f
    { "efindex", 1 },
Packit fc043f
    { "opindex", 1 },
Packit fc043f
    { "cpindex", 1 },
Packit fc043f
    { "cindex",  1 },
Packit fc043f
    { "noindent", 0 },
Packit fc043f
    { "section", 1 },
Packit fc043f
    { "chapter", 1 },
Packit fc043f
    { "subsection", 6, "\n.SS " },
Packit fc043f
    { "chapheading", 0},
Packit fc043f
    { "item",    2, ".TP\n.B " },
Packit fc043f
    { "itemx",   2, ".TQ\n.B " },
Packit fc043f
    { "table",   3 },
Packit fc043f
    { "itemize",   3 },
Packit fc043f
    { "bullet",  0, "* " },
Packit fc043f
    { "*",       0, "\n.br"},
Packit fc043f
    { "/",       0 },
Packit fc043f
    { "end",     4 },
Packit fc043f
    { "quotation",1, ".RS\n\\fB" },
Packit fc043f
    { "value", 8 },
Packit fc043f
    { NULL }
Packit fc043f
  };
Packit fc043f
  size_t n;
Packit fc043f
  int i;
Packit fc043f
  const char *s;
Packit fc043f
  const char *lead_out = NULL;
Packit fc043f
  int ignore_args = 0;
Packit fc043f
Packit fc043f
  for (i=0; cmdtbl[i].name && strcmp (cmdtbl[i].name, command); i++)
Packit fc043f
    ;
Packit fc043f
  if (cmdtbl[i].name)
Packit fc043f
    {
Packit fc043f
      s = cmdtbl[i].lead_in;
Packit fc043f
      if (s)
Packit fc043f
        fputs (s, fp);
Packit fc043f
      lead_out = cmdtbl[i].lead_out;
Packit fc043f
      switch (cmdtbl[i].what)
Packit fc043f
        {
Packit fc043f
        case 1: /* Throw away the entire line.  */
Packit fc043f
          s = memchr (rest, '\n', len);
Packit fc043f
          return s? (s-rest)+1 : len;
Packit fc043f
        case 2: /* Handle @item.  */
Packit fc043f
          break;
Packit fc043f
        case 3: /* Handle table.  */
Packit fc043f
          if (++(*table_level) > 1)
Packit fc043f
            fputs (".RS\n", fp);
Packit fc043f
          /* Now throw away the entire line. */
Packit fc043f
          s = memchr (rest, '\n', len);
Packit fc043f
          return s? (s-rest)+1 : len;
Packit fc043f
          break;
Packit fc043f
        case 4: /* Handle end.  */
Packit fc043f
          for (s=rest, n=len; n && (*s == ' ' || *s == '\t'); s++, n--)
Packit fc043f
            ;
Packit fc043f
          if (n >= 5 && !memcmp (s, "table", 5)
Packit fc043f
              && (!n || s[5] == ' ' || s[5] == '\t' || s[5] == '\n'))
Packit fc043f
            {
Packit fc043f
              if ((*table_level)-- > 1)
Packit fc043f
                fputs (".RE\n", fp);
Packit fc043f
              else
Packit fc043f
                fputs (".P\n", fp);
Packit fc043f
            }
Packit fc043f
          else if (n >= 7 && !memcmp (s, "example", 7)
Packit fc043f
              && (!n || s[7] == ' ' || s[7] == '\t' || s[7] == '\n'))
Packit fc043f
            {
Packit fc043f
              fputs (".fi\n.RE\n", fp);
Packit fc043f
            }
Packit fc043f
          else if (n >= 12 && !memcmp (s, "smallexample", 12)
Packit fc043f
              && (!n || s[12] == ' ' || s[12] == '\t' || s[12] == '\n'))
Packit fc043f
            {
Packit fc043f
              fputs (".fi\n.RE\n", fp);
Packit fc043f
            }
Packit fc043f
          else if (n >= 9 && !memcmp (s, "quotation", 9)
Packit fc043f
              && (!n || s[9] == ' ' || s[9] == '\t' || s[9] == '\n'))
Packit fc043f
            {
Packit fc043f
              fputs ("\\fR\n.RE\n", fp);
Packit fc043f
            }
Packit fc043f
          /* Now throw away the entire line. */
Packit fc043f
          s = memchr (rest, '\n', len);
Packit fc043f
          return s? (s-rest)+1 : len;
Packit fc043f
        case 5: /* Handle special comments. */
Packit fc043f
          for (s=rest, n=len; n && (*s == ' ' || *s == '\t'); s++, n--)
Packit fc043f
            ;
Packit fc043f
          if (n >= 4 && !memcmp (s, "man:", 4))
Packit fc043f
            {
Packit fc043f
              for (s+=4, n-=4; n && *s != '\n'; n--, s++)
Packit fc043f
                putc (*s, fp);
Packit fc043f
              putc ('\n', fp);
Packit fc043f
            }
Packit fc043f
          /* Now throw away the entire line. */
Packit fc043f
          s = memchr (rest, '\n', len);
Packit fc043f
          return s? (s-rest)+1 : len;
Packit fc043f
        case 6:
Packit fc043f
          *eol_action = 1;
Packit fc043f
          break;
Packit fc043f
        case 7:
Packit fc043f
          ignore_args = 1;
Packit fc043f
          break;
Packit fc043f
        case 8:
Packit fc043f
          ignore_args = 1;
Packit fc043f
          if (*rest != '{')
Packit fc043f
            {
Packit fc043f
              err ("opening brace for command '%s' missing", command);
Packit fc043f
              return len;
Packit fc043f
            }
Packit fc043f
          else
Packit fc043f
            {
Packit fc043f
              /* Find closing brace.  */
Packit fc043f
              for (s=rest+1, n=1; *s && n < len; s++, n++)
Packit fc043f
                if (*s == '}')
Packit fc043f
                  break;
Packit fc043f
              if (*s != '}')
Packit fc043f
                {
Packit fc043f
                  err ("closing brace for command '%s' not found", command);
Packit fc043f
                  return len;
Packit fc043f
                }
Packit fc043f
              else
Packit fc043f
                {
Packit fc043f
                  size_t rlen = s - (rest + 1);
Packit fc043f
                  macro_t m;
Packit fc043f
Packit fc043f
                  for (m = variablelist; m; m = m->next)
Packit fc043f
                    {
Packit fc043f
                      if (strlen (m->name) == rlen
Packit fc043f
                          && !strncmp (m->name, rest+1, rlen))
Packit fc043f
                        break;
Packit fc043f
                    }
Packit fc043f
                  if (m)
Packit fc043f
                    fputs (m->value, fp);
Packit fc043f
                  else
Packit fc043f
                    inf ("texinfo variable '%.*s' is not set",
Packit fc043f
                         (int)rlen, rest+1);
Packit fc043f
                }
Packit fc043f
            }
Packit fc043f
          break;
Packit fc043f
        default:
Packit fc043f
          break;
Packit fc043f
        }
Packit fc043f
    }
Packit fc043f
  else /* macro */
Packit fc043f
    {
Packit fc043f
      macro_t m;
Packit fc043f
Packit fc043f
      for (m = macrolist; m ; m = m->next)
Packit fc043f
        if (!strcmp (m->name, command))
Packit fc043f
            break;
Packit fc043f
      if (m)
Packit fc043f
        {
Packit fc043f
          proc_texi_buffer (fp, m->value, strlen (m->value),
Packit fc043f
                            table_level, eol_action);
Packit fc043f
          ignore_args = 1; /* Parameterized macros are not yet supported. */
Packit fc043f
        }
Packit fc043f
      else
Packit fc043f
        inf ("texinfo command '%s' not supported (%.*s)", command,
Packit fc043f
             (int)((s = memchr (rest, '\n', len)), (s? (s-rest) : len)), rest);
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (*rest == '{')
Packit fc043f
    {
Packit fc043f
      /* Find matching closing brace.  */
Packit fc043f
      for (s=rest+1, n=1, i=1; i && *s && n < len; s++, n++)
Packit fc043f
        if (*s == '{')
Packit fc043f
          i++;
Packit fc043f
        else if (*s == '}')
Packit fc043f
          i--;
Packit fc043f
      if (i)
Packit fc043f
        {
Packit fc043f
          err ("closing brace for command '%s' not found", command);
Packit fc043f
          return len;
Packit fc043f
        }
Packit fc043f
      if (n > 2 && !ignore_args)
Packit fc043f
        proc_texi_buffer (fp, rest+1, n-2, table_level, eol_action);
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    n = 0;
Packit fc043f
Packit fc043f
  if (lead_out)
Packit fc043f
    fputs (lead_out, fp);
Packit fc043f
Packit fc043f
  return n;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
Packit fc043f
/* Process the string LINE with LEN bytes of Texinfo content. */
Packit fc043f
static void
Packit fc043f
proc_texi_buffer (FILE *fp, const char *line, size_t len,
Packit fc043f
                  int *table_level, int *eol_action)
Packit fc043f
{
Packit fc043f
  const char *s;
Packit fc043f
  char cmdbuf[256];
Packit fc043f
  int cmdidx = 0;
Packit fc043f
  int in_cmd = 0;
Packit fc043f
  size_t n;
Packit fc043f
Packit fc043f
  for (s=line; *s && len; s++, len--)
Packit fc043f
    {
Packit fc043f
      if (in_cmd)
Packit fc043f
        {
Packit fc043f
          if (in_cmd == 1)
Packit fc043f
            {
Packit fc043f
              switch (*s)
Packit fc043f
                {
Packit fc043f
                case '@': case '{': case '}':
Packit fc043f
                  putc (*s, fp); in_cmd = 0;
Packit fc043f
                  break;
Packit fc043f
                case ':': /* Not ending a sentence flag.  */
Packit fc043f
                  in_cmd = 0;
Packit fc043f
                  break;
Packit fc043f
                case '.': case '!': case '?': /* Ending a sentence. */
Packit fc043f
                  putc (*s, fp); in_cmd = 0;
Packit fc043f
                  break;
Packit fc043f
                case ' ': case '\t': case '\n': /* Non collapsing spaces.  */
Packit fc043f
                  putc (*s, fp); in_cmd = 0;
Packit fc043f
                  break;
Packit fc043f
                default:
Packit fc043f
                  cmdidx = 0;
Packit fc043f
                  cmdbuf[cmdidx++] = *s;
Packit fc043f
                  in_cmd++;
Packit fc043f
                  break;
Packit fc043f
                }
Packit fc043f
            }
Packit fc043f
          else if (*s == '{' || *s == ' ' || *s == '\t' || *s == '\n')
Packit fc043f
            {
Packit fc043f
              cmdbuf[cmdidx] = 0;
Packit fc043f
              n = proc_texi_cmd (fp, cmdbuf, s, len, table_level, eol_action);
Packit fc043f
              assert (n <= len);
Packit fc043f
              s += n; len -= n;
Packit fc043f
              s--; len++;
Packit fc043f
              in_cmd = 0;
Packit fc043f
            }
Packit fc043f
          else if (cmdidx < sizeof cmdbuf -1)
Packit fc043f
            cmdbuf[cmdidx++] = *s;
Packit fc043f
          else
Packit fc043f
            {
Packit fc043f
              err ("texinfo command too long - ignored");
Packit fc043f
              in_cmd = 0;
Packit fc043f
            }
Packit fc043f
        }
Packit fc043f
      else if (*s == '@')
Packit fc043f
        in_cmd = 1;
Packit fc043f
      else if (*s == '\n')
Packit fc043f
        {
Packit fc043f
          switch (*eol_action)
Packit fc043f
            {
Packit fc043f
            case 1: /* Create a dummy paragraph. */
Packit fc043f
              fputs ("\n\\ \n", fp);
Packit fc043f
              break;
Packit fc043f
            default:
Packit fc043f
              putc (*s, fp);
Packit fc043f
            }
Packit fc043f
          *eol_action = 0;
Packit fc043f
        }
Packit fc043f
      else if (*s == '\\')
Packit fc043f
        fputs ("\\\\", fp);
Packit fc043f
      else
Packit fc043f
        putc (*s, fp);
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (in_cmd > 1)
Packit fc043f
    {
Packit fc043f
      cmdbuf[cmdidx] = 0;
Packit fc043f
      n = proc_texi_cmd (fp, cmdbuf, s, len, table_level, eol_action);
Packit fc043f
      assert (n <= len);
Packit fc043f
      s += n; len -= n;
Packit fc043f
      s--; len++;
Packit fc043f
      /* in_cmd = 0; -- doc only */
Packit fc043f
    }
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Do something with the Texinfo line LINE.  */
Packit fc043f
static void
Packit fc043f
parse_texi_line (FILE *fp, const char *line, int *table_level)
Packit fc043f
{
Packit fc043f
  int eol_action = 0;
Packit fc043f
Packit fc043f
  /* A quick test whether there are any texinfo commands.  */
Packit fc043f
  if (!strchr (line, '@'))
Packit fc043f
    {
Packit fc043f
      fputs (line, fp);
Packit fc043f
      putc ('\n', fp);
Packit fc043f
      return;
Packit fc043f
    }
Packit fc043f
  proc_texi_buffer (fp, line, strlen (line), table_level, &eol_action);
Packit fc043f
  putc ('\n', fp);
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Write all the lines LINES to FP.  */
Packit fc043f
static void
Packit fc043f
write_content (FILE *fp, line_buffer_t lines)
Packit fc043f
{
Packit fc043f
  line_buffer_t line;
Packit fc043f
  int table_level = 0;
Packit fc043f
Packit fc043f
  for (line = lines; line; line = line->next)
Packit fc043f
    {
Packit fc043f
      if (line->verbatim)
Packit fc043f
        {
Packit fc043f
          fputs (line->line, fp);
Packit fc043f
          putc ('\n', fp);
Packit fc043f
        }
Packit fc043f
      else
Packit fc043f
        {
Packit fc043f
/*           fputs ("TEXI---", fp); */
Packit fc043f
/*           fputs (line->line, fp); */
Packit fc043f
/*           fputs ("---\n", fp); */
Packit fc043f
          parse_texi_line (fp, line->line, &table_level);
Packit fc043f
        }
Packit fc043f
    }
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
Packit fc043f
static int
Packit fc043f
is_standard_section (const char *name)
Packit fc043f
{
Packit fc043f
  int i;
Packit fc043f
  const char *s;
Packit fc043f
Packit fc043f
  for (i=0; (s=standard_sections[i]); i++)
Packit fc043f
    if (!strcmp (s, name))
Packit fc043f
      return 1;
Packit fc043f
  return 0;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Finish a page; that is sort the data and write it out to the file.  */
Packit fc043f
static void
Packit fc043f
finish_page (void)
Packit fc043f
{
Packit fc043f
  FILE *fp;
Packit fc043f
  section_buffer_t sect = NULL;
Packit fc043f
  int idx;
Packit fc043f
  const char *s;
Packit fc043f
  int i;
Packit fc043f
Packit fc043f
  if (!thepage.name)
Packit fc043f
    return; /* No page active.  */
Packit fc043f
Packit fc043f
  if (verbose)
Packit fc043f
    inf ("finishing page '%s'", thepage.name);
Packit fc043f
Packit fc043f
  if (opt_select)
Packit fc043f
    {
Packit fc043f
      if (!strcmp (opt_select, thepage.name))
Packit fc043f
        {
Packit fc043f
          inf ("selected '%s'", thepage.name );
Packit fc043f
          fp = stdout;
Packit fc043f
        }
Packit fc043f
      else
Packit fc043f
        {
Packit fc043f
          fp = fopen ( "/dev/null", "w" );
Packit fc043f
          if (!fp)
Packit fc043f
            die ("failed to open /dev/null: %s\n", strerror (errno));
Packit fc043f
        }
Packit fc043f
    }
Packit fc043f
  else if (opt_store)
Packit fc043f
    {
Packit fc043f
      inf ("writing '%s'", thepage.name );
Packit fc043f
      fp = fopen ( thepage.name, "w" );
Packit fc043f
      if (!fp)
Packit fc043f
        die ("failed to create '%s': %s\n", thepage.name, strerror (errno));
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    fp = stdout;
Packit fc043f
Packit fc043f
  if (write_th (fp))
Packit fc043f
    goto leave;
Packit fc043f
Packit fc043f
  for (idx=0; (s=standard_sections[idx]); idx++)
Packit fc043f
    {
Packit fc043f
      for (i=0; i < thepage.n_sections; i++)
Packit fc043f
        {
Packit fc043f
          sect = thepage.sections + i;
Packit fc043f
          if (sect->name && !strcmp (s, sect->name))
Packit fc043f
            break;
Packit fc043f
        }
Packit fc043f
      if (i == thepage.n_sections)
Packit fc043f
        sect = NULL;
Packit fc043f
Packit fc043f
      if (sect)
Packit fc043f
        {
Packit fc043f
          fprintf (fp, ".SH %s\n", sect->name);
Packit fc043f
          write_content (fp, sect->lines);
Packit fc043f
          /* Now continue with all non standard sections directly
Packit fc043f
             following this one. */
Packit fc043f
          for (i++; i < thepage.n_sections; i++)
Packit fc043f
            {
Packit fc043f
              sect = thepage.sections + i;
Packit fc043f
              if (sect->name && is_standard_section (sect->name))
Packit fc043f
                break;
Packit fc043f
              if (sect->name)
Packit fc043f
                {
Packit fc043f
                  fprintf (fp, ".SH %s\n", sect->name);
Packit fc043f
                  write_content (fp, sect->lines);
Packit fc043f
                }
Packit fc043f
            }
Packit fc043f
Packit fc043f
        }
Packit fc043f
    }
Packit fc043f
Packit fc043f
Packit fc043f
 leave:
Packit fc043f
  if (fp != stdout)
Packit fc043f
    fclose (fp);
Packit fc043f
  free (thepage.name);
Packit fc043f
  thepage.name = NULL;
Packit fc043f
  /* FIXME: Cleanup the content.  */
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
Packit fc043f
Packit fc043f
/* Parse one Texinfo file and create manpages according to the
Packit fc043f
   embedded instructions.  */
Packit fc043f
static void
Packit fc043f
parse_file (const char *fname, FILE *fp, char **section_name, int in_pause)
Packit fc043f
{
Packit fc043f
  char *line;
Packit fc043f
  int lnr = 0;
Packit fc043f
  /* Fixme: The following state variables don't carry over to include
Packit fc043f
     files. */
Packit fc043f
  int skip_to_end = 0;        /* Used to skip over menu entries. */
Packit fc043f
  int skip_sect_line = 0;     /* Skip after @mansect.  */
Packit fc043f
  int item_indent = 0;        /* How far is the current @item indented.  */
Packit fc043f
Packit fc043f
  /* Helper to define a macro. */
Packit fc043f
  char *macroname = NULL;
Packit fc043f
  char *macrovalue = NULL;
Packit fc043f
  size_t macrovaluesize = 0;
Packit fc043f
  size_t macrovalueused = 0;
Packit fc043f
Packit fc043f
  line = xmalloc (LINESIZE);
Packit fc043f
  while (fgets (line, LINESIZE, fp))
Packit fc043f
    {
Packit fc043f
      size_t n = strlen (line);
Packit fc043f
      int got_line = 0;
Packit fc043f
      char *p, *pend;
Packit fc043f
Packit fc043f
      lnr++;
Packit fc043f
      if (!n || line[n-1] != '\n')
Packit fc043f
        {
Packit fc043f
          err ("%s:%d: trailing linefeed missing, line too long or "
Packit fc043f
               "embedded Nul character", fname, lnr);
Packit fc043f
          break;
Packit fc043f
        }
Packit fc043f
      line[--n] = 0;
Packit fc043f
Packit fc043f
      /* Kludge to allow indentation of tables.  */
Packit fc043f
      for (p=line; *p == ' ' || *p == '\t'; p++)
Packit fc043f
        ;
Packit fc043f
      if (*p)
Packit fc043f
        {
Packit fc043f
          if (*p == '@' && !strncmp (p+1, "item", 4))
Packit fc043f
            item_indent = p - line;  /* Set a new indent level.  */
Packit fc043f
          else if (p - line < item_indent)
Packit fc043f
            item_indent = 0;         /* Switch off indention.  */
Packit fc043f
Packit fc043f
          if (item_indent)
Packit fc043f
            {
Packit fc043f
              memmove (line, line+item_indent, n - item_indent + 1);
Packit fc043f
              n -= item_indent;
Packit fc043f
            }
Packit fc043f
        }
Packit fc043f
Packit fc043f
Packit fc043f
      if (*line == '@')
Packit fc043f
        {
Packit fc043f
          for (p=line+1, n=1; *p && *p != ' ' && *p != '\t'; p++)
Packit fc043f
            n++;
Packit fc043f
          while (*p == ' ' || *p == '\t')
Packit fc043f
            p++;
Packit fc043f
        }
Packit fc043f
      else
Packit fc043f
        p = line;
Packit fc043f
Packit fc043f
      /* Take action on macro.  */
Packit fc043f
      if (macroname)
Packit fc043f
        {
Packit fc043f
          if (n == 4 && !memcmp (line, "@end", 4)
Packit fc043f
              && (line[4]==' '||line[4]=='\t'||!line[4])
Packit fc043f
              && !strncmp (p, "macro", 5)
Packit fc043f
              && (p[5]==' '||p[5]=='\t'||!p[5]))
Packit fc043f
            {
Packit fc043f
              if (macrovalueused)
Packit fc043f
                macrovalue[--macrovalueused] = 0; /* Kill the last LF. */
Packit fc043f
              macrovalue[macrovalueused] = 0;     /* Terminate macro. */
Packit fc043f
              macrovalue = xrealloc (macrovalue, macrovalueused+1);
Packit fc043f
Packit fc043f
              set_macro (macroname, macrovalue);
Packit fc043f
              macrovalue = NULL;
Packit fc043f
              free (macroname);
Packit fc043f
              macroname = NULL;
Packit fc043f
            }
Packit fc043f
          else
Packit fc043f
            {
Packit fc043f
              if (macrovalueused + strlen (line) + 2 >= macrovaluesize)
Packit fc043f
                {
Packit fc043f
                  macrovaluesize += strlen (line) + 256;
Packit fc043f
                  macrovalue = xrealloc (macrovalue,  macrovaluesize);
Packit fc043f
                }
Packit fc043f
              strcpy (macrovalue+macrovalueused, line);
Packit fc043f
              macrovalueused += strlen (line);
Packit fc043f
              macrovalue[macrovalueused++] = '\n';
Packit fc043f
            }
Packit fc043f
          continue;
Packit fc043f
        }
Packit fc043f
Packit fc043f
Packit fc043f
      if (n >= 5 && !memcmp (line, "@node", 5)
Packit fc043f
          && (line[5]==' '||line[5]=='\t'||!line[5]))
Packit fc043f
        {
Packit fc043f
          /* Completey ignore @node lines.  */
Packit fc043f
          continue;
Packit fc043f
        }
Packit fc043f
Packit fc043f
Packit fc043f
      if (skip_sect_line)
Packit fc043f
        {
Packit fc043f
          skip_sect_line = 0;
Packit fc043f
          if (!strncmp (line, "@section", 8)
Packit fc043f
              || !strncmp (line, "@subsection", 11)
Packit fc043f
              || !strncmp (line, "@chapheading", 12))
Packit fc043f
            continue;
Packit fc043f
        }
Packit fc043f
Packit fc043f
      /* We only parse lines we need and ignore the rest.  There are a
Packit fc043f
         few macros used to control this as well as one @ifset
Packit fc043f
         command.  Parts we know about are saved away into containers
Packit fc043f
         separate for each section. */
Packit fc043f
Packit fc043f
      /* First process ifset/ifclear commands. */
Packit fc043f
      if (*line == '@')
Packit fc043f
        {
Packit fc043f
          if (n == 6 && !memcmp (line, "@ifset", 6)
Packit fc043f
                   && (line[6]==' '||line[6]=='\t'))
Packit fc043f
            {
Packit fc043f
              for (p=line+7; *p == ' ' || *p == '\t'; p++)
Packit fc043f
                ;
Packit fc043f
              if (!*p)
Packit fc043f
                {
Packit fc043f
                  err ("%s:%d: name missing after \"@ifset\"", fname, lnr);
Packit fc043f
                  continue;
Packit fc043f
                }
Packit fc043f
              for (pend=p; *pend && *pend != ' ' && *pend != '\t'; pend++)
Packit fc043f
                ;
Packit fc043f
              *pend = 0;  /* Ignore rest of the line.  */
Packit fc043f
              push_condition (p, 1, fname, lnr);
Packit fc043f
              continue;
Packit fc043f
            }
Packit fc043f
          else if (n == 8 && !memcmp (line, "@ifclear", 8)
Packit fc043f
                   && (line[8]==' '||line[8]=='\t'))
Packit fc043f
            {
Packit fc043f
              for (p=line+9; *p == ' ' || *p == '\t'; p++)
Packit fc043f
                ;
Packit fc043f
              if (!*p)
Packit fc043f
                {
Packit fc043f
                  err ("%s:%d: name missing after \"@ifsclear\"", fname, lnr);
Packit fc043f
                  continue;
Packit fc043f
                }
Packit fc043f
              for (pend=p; *pend && *pend != ' ' && *pend != '\t'; pend++)
Packit fc043f
                ;
Packit fc043f
              *pend = 0;  /* Ignore rest of the line.  */
Packit fc043f
              push_condition (p, 0, fname, lnr);
Packit fc043f
              continue;
Packit fc043f
            }
Packit fc043f
          else if (n == 4 && !memcmp (line, "@end", 4)
Packit fc043f
                   && (line[4]==' '||line[4]=='\t')
Packit fc043f
                   && !strncmp (p, "ifset", 5)
Packit fc043f
                   && (p[5]==' '||p[5]=='\t'||!p[5]))
Packit fc043f
            {
Packit fc043f
              pop_condition (1, fname, lnr);
Packit fc043f
              continue;
Packit fc043f
            }
Packit fc043f
          else if (n == 4 && !memcmp (line, "@end", 4)
Packit fc043f
                   && (line[4]==' '||line[4]=='\t')
Packit fc043f
                   && !strncmp (p, "ifclear", 7)
Packit fc043f
                   && (p[7]==' '||p[7]=='\t'||!p[7]))
Packit fc043f
            {
Packit fc043f
              pop_condition (0, fname, lnr);
Packit fc043f
              continue;
Packit fc043f
            }
Packit fc043f
        }
Packit fc043f
Packit fc043f
      /* Take action on ifset/ifclear.  */
Packit fc043f
      if (!cond_is_active)
Packit fc043f
        continue;
Packit fc043f
Packit fc043f
      /* Process commands. */
Packit fc043f
      if (*line == '@')
Packit fc043f
        {
Packit fc043f
          if (skip_to_end
Packit fc043f
              && n == 4 && !memcmp (line, "@end", 4)
Packit fc043f
              && (line[4]==' '||line[4]=='\t'||!line[4]))
Packit fc043f
            {
Packit fc043f
              skip_to_end = 0;
Packit fc043f
            }
Packit fc043f
          else if (cond_in_verbatim)
Packit fc043f
            {
Packit fc043f
                got_line = 1;
Packit fc043f
            }
Packit fc043f
          else if (n == 6 && !memcmp (line, "@macro", 6))
Packit fc043f
            {
Packit fc043f
              macroname = xstrdup (p);
Packit fc043f
              macrovalue = xmalloc ((macrovaluesize = 1024));
Packit fc043f
              macrovalueused = 0;
Packit fc043f
            }
Packit fc043f
          else if (n == 4 && !memcmp (line, "@set", 4))
Packit fc043f
            {
Packit fc043f
              set_variable (p);
Packit fc043f
            }
Packit fc043f
          else if (n == 8 && !memcmp (line, "@manpage", 8))
Packit fc043f
            {
Packit fc043f
              free (*section_name);
Packit fc043f
              *section_name = NULL;
Packit fc043f
              finish_page ();
Packit fc043f
              start_page (p);
Packit fc043f
              in_pause = 0;
Packit fc043f
            }
Packit fc043f
          else if (n == 8 && !memcmp (line, "@mansect", 8))
Packit fc043f
            {
Packit fc043f
              if (!thepage.name)
Packit fc043f
                err ("%s:%d: section outside of a man page", fname, lnr);
Packit fc043f
              else
Packit fc043f
                {
Packit fc043f
                  free (*section_name);
Packit fc043f
                  *section_name = ascii_strupr (xstrdup (p));
Packit fc043f
                  in_pause = 0;
Packit fc043f
                  skip_sect_line = 1;
Packit fc043f
                }
Packit fc043f
            }
Packit fc043f
          else if (n == 9 && !memcmp (line, "@manpause", 9))
Packit fc043f
            {
Packit fc043f
              if (!*section_name)
Packit fc043f
                err ("%s:%d: pausing outside of a man section", fname, lnr);
Packit fc043f
              else if (in_pause)
Packit fc043f
                err ("%s:%d: already pausing", fname, lnr);
Packit fc043f
              else
Packit fc043f
                in_pause = 1;
Packit fc043f
            }
Packit fc043f
          else if (n == 8 && !memcmp (line, "@mancont", 8))
Packit fc043f
            {
Packit fc043f
              if (!*section_name)
Packit fc043f
                err ("%s:%d: continue outside of a man section", fname, lnr);
Packit fc043f
              else if (!in_pause)
Packit fc043f
                err ("%s:%d: continue while not pausing", fname, lnr);
Packit fc043f
              else
Packit fc043f
                in_pause = 0;
Packit fc043f
            }
Packit fc043f
          else if (n == 5 && !memcmp (line, "@menu", 5)
Packit fc043f
                   && (line[5]==' '||line[5]=='\t'||!line[5]))
Packit fc043f
            {
Packit fc043f
              skip_to_end = 1;
Packit fc043f
            }
Packit fc043f
          else if (n == 8 && !memcmp (line, "@include", 8)
Packit fc043f
                   && (line[8]==' '||line[8]=='\t'||!line[8]))
Packit fc043f
            {
Packit fc043f
              char *incname = xstrdup (p);
Packit fc043f
              FILE *incfp = fopen (incname, "r");
Packit fc043f
Packit fc043f
              if (!incfp && opt_include && *opt_include && *p != '/')
Packit fc043f
                {
Packit fc043f
                  free (incname);
Packit fc043f
                  incname = xmalloc (strlen (opt_include) + 1
Packit fc043f
                                     + strlen (p) + 1);
Packit fc043f
                  strcpy (incname, opt_include);
Packit fc043f
                  if ( incname[strlen (incname)-1] != '/' )
Packit fc043f
                    strcat (incname, "/");
Packit fc043f
                  strcat (incname, p);
Packit fc043f
                  incfp = fopen (incname, "r");
Packit fc043f
                }
Packit fc043f
Packit fc043f
              if (!incfp)
Packit fc043f
                err ("can't open include file '%s': %s",
Packit fc043f
                     incname, strerror (errno));
Packit fc043f
              else
Packit fc043f
                {
Packit fc043f
                  parse_file (incname, incfp, section_name, in_pause);
Packit fc043f
                  fclose (incfp);
Packit fc043f
                }
Packit fc043f
              free (incname);
Packit fc043f
            }
Packit fc043f
          else if (n == 4 && !memcmp (line, "@bye", 4)
Packit fc043f
                   && (line[4]==' '||line[4]=='\t'||!line[4]))
Packit fc043f
            {
Packit fc043f
              break;
Packit fc043f
            }
Packit fc043f
          else if (!skip_to_end)
Packit fc043f
            got_line = 1;
Packit fc043f
        }
Packit fc043f
      else if (!skip_to_end)
Packit fc043f
        got_line = 1;
Packit fc043f
Packit fc043f
      if (got_line && cond_in_verbatim)
Packit fc043f
        add_content (*section_name, line, 1);
Packit fc043f
      else if (got_line && thepage.name && *section_name && !in_pause)
Packit fc043f
        add_content (*section_name, line, 0);
Packit fc043f
Packit fc043f
    }
Packit fc043f
  if (ferror (fp))
Packit fc043f
    err ("%s:%d: read error: %s", fname, lnr, strerror (errno));
Packit fc043f
  free (macroname);
Packit fc043f
  free (macrovalue);
Packit fc043f
  free (line);
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
static void
Packit fc043f
top_parse_file (const char *fname, FILE *fp)
Packit fc043f
{
Packit fc043f
  char *section_name = NULL;  /* Name of the current section or NULL
Packit fc043f
                                 if not in a section.  */
Packit fc043f
  macro_t m;
Packit fc043f
Packit fc043f
  while (macrolist)
Packit fc043f
    {
Packit fc043f
      macro_t next = macrolist->next;
Packit fc043f
      free (macrolist->value);
Packit fc043f
      free (macrolist);
Packit fc043f
      macrolist = next;
Packit fc043f
    }
Packit fc043f
  while (variablelist)
Packit fc043f
    {
Packit fc043f
      macro_t next = variablelist->next;
Packit fc043f
      free (variablelist->value);
Packit fc043f
      free (variablelist);
Packit fc043f
      variablelist = next;
Packit fc043f
    }
Packit fc043f
  for (m=predefinedmacrolist; m; m = m->next)
Packit fc043f
    set_macro (m->name, xstrdup ("1"));
Packit fc043f
  cond_is_active = 1;
Packit fc043f
  cond_in_verbatim = 0;
Packit fc043f
Packit fc043f
  parse_file (fname, fp, &section_name, 0);
Packit fc043f
  free (section_name);
Packit fc043f
  finish_page ();
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
int
Packit fc043f
main (int argc, char **argv)
Packit fc043f
{
Packit fc043f
  int last_argc = -1;
Packit fc043f
  const char *s;
Packit fc043f
Packit fc043f
  opt_source = "GNU";
Packit fc043f
  opt_release = "";
Packit fc043f
Packit fc043f
  /* Define default macros.  The trick is that these macros are not
Packit fc043f
     defined when using the actual texinfo renderer. */
Packit fc043f
  add_predefined_macro ("isman");
Packit fc043f
  add_predefined_macro ("manverb");
Packit fc043f
Packit fc043f
  /* Option parsing.  */
Packit fc043f
  if (argc)
Packit fc043f
    {
Packit fc043f
      argc--; argv++;
Packit fc043f
    }
Packit fc043f
  while (argc && last_argc != argc )
Packit fc043f
    {
Packit fc043f
      last_argc = argc;
Packit fc043f
      if (!strcmp (*argv, "--"))
Packit fc043f
        {
Packit fc043f
          argc--; argv++;
Packit fc043f
          break;
Packit fc043f
        }
Packit fc043f
      else if (!strcmp (*argv, "--help"))
Packit fc043f
        {
Packit fc043f
          puts (
Packit fc043f
                "Usage: " PGM " [OPTION] [FILE]\n"
Packit fc043f
                "Extract man pages from a Texinfo source.\n\n"
Packit fc043f
                "  --source NAME    use NAME as source field\n"
Packit fc043f
                "  --release STRING use STRING as the release field\n"
Packit fc043f
                "  --date EPOCH     use EPOCH as publication date\n"
Packit fc043f
                "  --store          write output using @manpage name\n"
Packit fc043f
                "  --select NAME    only output pages with @manpage NAME\n"
Packit fc043f
                "  --verbose        enable extra informational output\n"
Packit fc043f
                "  --debug          enable additional debug output\n"
Packit fc043f
                "  --help           display this help and exit\n"
Packit fc043f
                "  -I DIR           also search in include DIR\n"
Packit fc043f
                "  -D gpgone        the only usable define\n\n"
Packit fc043f
                "With no FILE, or when FILE is -, read standard input.\n\n"
Packit fc043f
                "Report bugs to <https://bugs.gnupg.org>.");
Packit fc043f
          exit (0);
Packit fc043f
        }
Packit fc043f
      else if (!strcmp (*argv, "--version"))
Packit fc043f
        {
Packit fc043f
          puts (PGM " " VERSION "\n"
Packit fc043f
               "Copyright (C) 2005, 2017 g10 Code GmbH\n"
Packit fc043f
               "This program comes with ABSOLUTELY NO WARRANTY.\n"
Packit fc043f
               "This is free software, and you are welcome to redistribute it\n"
Packit fc043f
                "under certain conditions. See the file COPYING for details.");
Packit fc043f
          exit (0);
Packit fc043f
        }
Packit fc043f
      else if (!strcmp (*argv, "--verbose"))
Packit fc043f
        {
Packit fc043f
          verbose = 1;
Packit fc043f
          argc--; argv++;
Packit fc043f
        }
Packit fc043f
      else if (!strcmp (*argv, "--quiet"))
Packit fc043f
        {
Packit fc043f
          quiet = 1;
Packit fc043f
          argc--; argv++;
Packit fc043f
        }
Packit fc043f
      else if (!strcmp (*argv, "--debug"))
Packit fc043f
        {
Packit fc043f
          verbose = debug = 1;
Packit fc043f
          argc--; argv++;
Packit fc043f
        }
Packit fc043f
      else if (!strcmp (*argv, "--source"))
Packit fc043f
        {
Packit fc043f
          argc--; argv++;
Packit fc043f
          if (argc)
Packit fc043f
            {
Packit fc043f
              opt_source = *argv;
Packit fc043f
              argc--; argv++;
Packit fc043f
            }
Packit fc043f
        }
Packit fc043f
      else if (!strcmp (*argv, "--release"))
Packit fc043f
        {
Packit fc043f
          argc--; argv++;
Packit fc043f
          if (argc)
Packit fc043f
            {
Packit fc043f
              opt_release = *argv;
Packit fc043f
              argc--; argv++;
Packit fc043f
            }
Packit fc043f
        }
Packit fc043f
      else if (!strcmp (*argv, "--date"))
Packit fc043f
        {
Packit fc043f
          argc--; argv++;
Packit fc043f
          if (argc)
Packit fc043f
            {
Packit fc043f
              opt_date = *argv;
Packit fc043f
              argc--; argv++;
Packit fc043f
            }
Packit fc043f
        }
Packit fc043f
      else if (!strcmp (*argv, "--store"))
Packit fc043f
        {
Packit fc043f
          opt_store = 1;
Packit fc043f
          argc--; argv++;
Packit fc043f
        }
Packit fc043f
      else if (!strcmp (*argv, "--select"))
Packit fc043f
        {
Packit fc043f
          argc--; argv++;
Packit fc043f
          if (argc)
Packit fc043f
            {
Packit fc043f
              opt_select = strrchr (*argv, '/');
Packit fc043f
              if (opt_select)
Packit fc043f
                opt_select++;
Packit fc043f
              else
Packit fc043f
                opt_select = *argv;
Packit fc043f
              argc--; argv++;
Packit fc043f
            }
Packit fc043f
        }
Packit fc043f
      else if (!strcmp (*argv, "-I"))
Packit fc043f
        {
Packit fc043f
          argc--; argv++;
Packit fc043f
          if (argc)
Packit fc043f
            {
Packit fc043f
              opt_include = *argv;
Packit fc043f
              argc--; argv++;
Packit fc043f
            }
Packit fc043f
        }
Packit fc043f
      else if (!strcmp (*argv, "-D"))
Packit fc043f
        {
Packit fc043f
          argc--; argv++;
Packit fc043f
          if (argc)
Packit fc043f
            {
Packit fc043f
              add_predefined_macro (*argv);
Packit fc043f
              argc--; argv++;
Packit fc043f
            }
Packit fc043f
        }
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (argc > 1)
Packit fc043f
    die ("usage: " PGM " [OPTION] [FILE] (try --help for more information)\n");
Packit fc043f
Packit fc043f
  /* Take care of supplied timestamp for reproducible builds.  See
Packit fc043f
   * https://reproducible-builds.org/specs/source-date-epoch/  */
Packit fc043f
  if (!opt_date && (s = getenv ("SOURCE_DATE_EPOCH")) && *s)
Packit fc043f
    opt_date = s;
Packit fc043f
Packit fc043f
  /* Start processing. */
Packit fc043f
  if (argc && strcmp (*argv, "-"))
Packit fc043f
    {
Packit fc043f
      FILE *fp = fopen (*argv, "rb");
Packit fc043f
      if (!fp)
Packit fc043f
        die ("%s:0: can't open file: %s", *argv, strerror (errno));
Packit fc043f
      top_parse_file (*argv, fp);
Packit fc043f
      fclose (fp);
Packit fc043f
    }
Packit fc043f
  else
Packit fc043f
    top_parse_file ("-", stdin);
Packit fc043f
Packit fc043f
  return !!any_error;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/*
Packit fc043f
Local Variables:
Packit fc043f
compile-command: "gcc -Wall -g -Wall -o yat2m yat2m.c"
Packit fc043f
End:
Packit fc043f
*/