Back to index

tetex-bin  3.0
Classes | Defines | Enumerations | Functions | Variables
infokey.c File Reference
#include "info.h"
#include "infomap.h"
#include "infokey.h"
#include "key.h"
#include "getopt.h"

Go to the source code of this file.

Classes

struct  sect

Defines

#define To_seq(c)

Enumerations

enum  sect_e { info = 0, ea = 1, var = 2 }

Functions

static char * mkpath (const char *dir, const char *file)
static int compile (FILE *fp, const char *filename, struct sect *sections)
static int write_infokey_file (FILE *fp, struct sect *sections)
static void syntax_error (const char *filename, unsigned int linenum, const char *fmt, const void *a1, const void *a2, const void *a3, const void *a4)
static void error_message (int error_code, const char *fmt, const void *a1, const void *a2, const void *a3, const void *a4)
static void suggest_help (void)
static void short_help (void)
int main (int argc, char **argv)
static int add_to_section (struct sect *s, const char *str, unsigned int len)
static int lookup_action (const char *actname)
static int putint (int i, FILE *fp)
static int putsect (struct sect *s, int code, FILE *fp)

Variables

static char * program_name = "infokey"
static int print_version_p = 0
static int print_help_p = 0
static char * input_filename = (char *) NULL
static char * output_filename = (char *) NULL
static struct option []
static char * short_options = "o:"

Class Documentation

struct sect

Definition at line 65 of file infokey.c.

Class Members
unsigned int cur
unsigned char data

Define Documentation

#define To_seq (   c)
Value:
do { \
                  if (slen < sizeof seq) \
                    seq[slen++] = meta ? Meta(c) : (c); \
                  else \
                    { \
                     syntax_error(filename, lnum, _("key sequence too long"), \
                            NULL, NULL, NULL, NULL); \
                     error = 1; \
                    } \
                  meta = 0; \
                } while (0)

Enumeration Type Documentation

enum sect_e
Enumerator:
info 
ea 
var 

Definition at line 59 of file infokey.c.

  {
    info = 0,
    ea = 1,
    var = 2
  };

Function Documentation

static int add_to_section ( struct sect s,
const char *  str,
unsigned int  len 
) [static]

Definition at line 787 of file infokey.c.

{
  if (s->cur + len > sizeof s->data)
    return 0;
  strncpy ((char *) s->data + s->cur, str, len);
  s->cur += len;
  return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int compile ( FILE fp,
const char *  filename,
struct sect sections 
) [static]

Definition at line 385 of file infokey.c.

{
  int error = 0;
  char rescan = 0;
  unsigned int lnum = 0;
  int c = 0;

  /* This parser is a true state machine, with no sneaky fetching
     of input characters inside the main loop.  In other words, all
     state is fully represented by the following variables:
   */
  enum
    {
      start_of_line,
      start_of_comment,
      in_line_comment,
      in_trailing_comment,
      get_keyseq,
      got_keyseq,
      get_action,
      got_action,
      get_varname,
      got_varname,
      get_equals,
      got_equals,
      get_value
    }
  state = start_of_line;
  enum sect_e section = info;
  enum
    {
      normal,
      slosh,
      control,
      octal,
      special_key
    }
  seqstate;          /* used if state == get_keyseq */
  char meta = 0;
  char ocnt = 0;     /* used if state == get_keyseq && seqstate == octal */

  /* Data is accumulated in the following variables.  The code
     avoids overflowing these strings, and throws an error
     where appropriate if a string limit is exceeded.  These string
     lengths are arbitrary (and should be large enough) and their
     lengths are not hard-coded anywhere else, so increasing them
     here will not break anything.  */
  char oval = 0;
  char comment[10];
  unsigned int clen = 0;
  char seq[20];
  unsigned int slen = 0;
  char act[80];
  unsigned int alen = 0;
  char varn[80];
  unsigned int varlen = 0;
  char val[80];
  unsigned int vallen = 0;

#define       To_seq(c) \
                do { \
                  if (slen < sizeof seq) \
                    seq[slen++] = meta ? Meta(c) : (c); \
                  else \
                    { \
                     syntax_error(filename, lnum, _("key sequence too long"), \
                            NULL, NULL, NULL, NULL); \
                     error = 1; \
                    } \
                  meta = 0; \
                } while (0)

  sections[info].cur = 1;
  sections[info].data[0] = 0;
  sections[ea].cur = 1;
  sections[ea].data[0] = 0;
  sections[var].cur = 0;

  while (!error && (rescan || (c = fgetc (fp)) != EOF))
    {
      rescan = 0;
      switch (state)
       {
       case start_of_line:
         lnum++;
         if (c == '#')
           state = start_of_comment;
         else if (c != '\n')
           {
             switch (section)
              {
              case info:
              case ea:
                state = get_keyseq;
                seqstate = normal;
                slen = 0;
                break;
              case var:
                state = get_varname;
                varlen = 0;
                break;
              }
             rescan = 1;
           }
         break;

       case start_of_comment:
         clen = 0;
         state = in_line_comment;
         /* fall through */
       case in_line_comment:
         if (c == '\n')
           {
             state = start_of_line;
             comment[clen] = '\0';
             if (strcmp (comment, "info") == 0)
              section = info;
             else if (strcmp (comment, "echo-area") == 0)
              section = ea;
             else if (strcmp (comment, "var") == 0)
              section = var;
             else if (strcmp (comment, "stop") == 0
                     && (section == info || section == ea))
              sections[section].data[0] = 1;
           }
         else if (clen < sizeof comment - 1)
           comment[clen++] = c;
         break;

       case in_trailing_comment:
         if (c == '\n')
           state = start_of_line;
         break;

       case get_keyseq:
         switch (seqstate)
           {
           case normal:
             if (c == '\n' || isspace (c))
              {
                state = got_keyseq;
                rescan = 1;
                if (slen == 0)
                  {
                    syntax_error (filename, lnum, _("missing key sequence"),
                          NULL, NULL, NULL, NULL);
                    error = 1;
                  }
              }
             else if (c == '\\')
              seqstate = slosh;
             else if (c == '^')
              seqstate = control;
             else
              To_seq (c);
             break;

           case slosh:
             switch (c)
              {
              case '0': case '1': case '2': case '3':
              case '4': case '5': case '6': case '7':
                seqstate = octal;
                oval = c - '0';
                ocnt = 1;
                break;
              case 'b':
                To_seq ('\b');
                seqstate = normal;
                break;
              case 'e':
                To_seq ('\033');
                seqstate = normal;
                break;
              case 'n':
                To_seq ('\n');
                seqstate = normal;
                break;
              case 'r':
                To_seq ('\r');
                seqstate = normal;
                break;
              case 't':
                To_seq ('\t');
                seqstate = normal;
                break;
              case 'm':
                meta = 1;
                seqstate = normal;
                break;
              case 'k':
                seqstate = special_key;
                break;
              default:
                /* Backslash followed by any other char
                   just means that char.  */
                To_seq (c);
                seqstate = normal;
                break;
              }
             break;

           case octal:
             switch (c)
              {
              case '0': case '1': case '2': case '3':
              case '4': case '5': case '6': case '7':
                if (++ocnt <= 3)
                  oval = oval * 8 + c - '0';
                if (ocnt == 3)
                  seqstate = normal;
                break;
              default:
                ocnt = 4;
                seqstate = normal;
                rescan = 1;
                break;
              }
             if (seqstate != octal)
              {
                if (oval)
                  To_seq (oval);
                else
                  {
                    syntax_error (filename, lnum,
                          _("NUL character (\\000) not permitted"),
                          NULL, NULL, NULL, NULL);
                    error = 1;
                  }
              }
             break;

           case special_key:
             To_seq (SK_ESCAPE);
             switch (c)
              {
              case 'u': To_seq (SK_UP_ARROW); break;
              case 'd': To_seq (SK_DOWN_ARROW); break;
              case 'r': To_seq (SK_RIGHT_ARROW); break;
              case 'l': To_seq (SK_LEFT_ARROW); break;
              case 'U': To_seq (SK_PAGE_UP); break;
              case 'D': To_seq (SK_PAGE_DOWN); break;
              case 'h': To_seq (SK_HOME); break;
              case 'e': To_seq (SK_END); break;
              case 'x': To_seq (SK_DELETE); break;
              default:  To_seq (SK_LITERAL); rescan = 1; break;
              }
             seqstate = normal;
             break;

           case control:
             if (CONTROL (c))
              To_seq (CONTROL (c));
             else
              {
                syntax_error (filename, lnum,
                      (char *) _("NUL character (^%c) not permitted"),
                      (void *) (long) c, NULL, NULL, NULL);
                error = 1;
              }
             seqstate = normal;
             break;
           }
         break;

       case got_keyseq:
         if (isspace (c) && c != '\n')
           break;
         state = get_action;
         alen = 0;
         /* fall through */
       case get_action:
         if (c == '\n' || isspace (c))
           {
             int a;

             state = got_action;
             rescan = 1;
             if (alen == 0)
              {
                syntax_error (filename, lnum, (char *) _("missing action name"),
                            (void *) (long) c, NULL, NULL, NULL);
                error = 1;
              }
             else
              {
                act[alen] = '\0';
                a = lookup_action (act);
                if (a != -1)
                  {
                    char av = a;

                    if (!(add_to_section (&sections[section], seq, slen)
                         && add_to_section (&sections[section], "", 1)
                         && add_to_section (&sections[section], &av, 1)))
                     {
                       syntax_error (filename, lnum, _("section too long"),
                              NULL, NULL, NULL, NULL);
                       error = 1;
                     }
                  }
                else
                  {
                    syntax_error (filename, lnum, _("unknown action `%s'"),
                          act, NULL, NULL, NULL);
                    error = 1;
                  }
              }
           }
         else if (alen < sizeof act - 1)
           act[alen++] = c;
         else
           {
             syntax_error (filename, lnum, _("action name too long"),
                  NULL, NULL, NULL, NULL);
             error = 1;
           }
         break;

       case got_action:
         if (c == '#')
           state = in_trailing_comment;
         else if (c == '\n')
           state = start_of_line;
         else if (!isspace (c))
           {
             syntax_error (filename, lnum,
                  _("extra characters following action `%s'"),
                  act, NULL, NULL, NULL);
             error = 1;
           }
         break;

       case get_varname:
         if (c == '=')
           {
             if (varlen == 0)
              {
                syntax_error (filename, lnum, _("missing variable name"),
                      NULL, NULL, NULL, NULL);
                error = 1;
              }
             state = get_value;
             vallen = 0;
           }
         else if (c == '\n' || isspace (c))
           {
             syntax_error (filename, lnum,
                  _("missing `=' immediately after variable name"),
                  NULL, NULL, NULL, NULL);
             error = 1;
           }
         else if (varlen < sizeof varn)
           varn[varlen++] = c;
         else
           {
             syntax_error (filename, lnum, _("variable name too long"),
                  NULL, NULL, NULL, NULL);
             error = 1;
           }
         break;

       case get_value:
         if (c == '\n')
           {
             state = start_of_line;
             if (!(add_to_section (&sections[section], varn, varlen)
                  && add_to_section (&sections[section], "", 1)
                  && add_to_section (&sections[section], val, vallen)
                  && add_to_section (&sections[section], "", 1)))
              {
                syntax_error (filename, lnum, _("section too long"),
                      NULL, NULL, NULL, NULL);
                error = 1;
              }
           }
         else if (vallen < sizeof val)
           val[vallen++] = c;
         else
           {
             syntax_error (filename, lnum, _("value too long"),
                  NULL, NULL, NULL, NULL);
             error = 1;
           }
         break;

        case get_equals:
        case got_equals:
        case got_varname:
          break;
       }
    }

#undef To_seq

  return !error;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void error_message ( int  error_code,
const char *  fmt,
const void a1,
const void a2,
const void a3,
const void a4 
) [static]
static int lookup_action ( const char *  actname) [static]

Definition at line 800 of file infokey.c.

{
  int i;

  if (strcmp ("invalid", actname) == 0)
    return A_INVALID;
  for (i = 0; function_key_array[i].name != NULL; i++)
    if (strcmp (function_key_array[i].name, actname) == 0)
      return function_key_array[i].code;
  return -1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int main ( int  argc,
char **  argv 
)

Definition at line 91 of file infokey.c.

{
  int getopt_long_index;    /* Index returned by getopt_long (). */

#ifdef HAVE_SETLOCALE
  /* Set locale via LC_ALL.  */
  setlocale (LC_ALL, "");
#endif

#ifdef ENABLE_NLS
  /* Set the text message domain.  */
  bindtextdomain (PACKAGE, LOCALEDIR);
  textdomain (PACKAGE);
#endif

  while (1)
    {
      int option_character;

      option_character = getopt_long
       (argc, argv, short_options, long_options, &getopt_long_index);

      /* getopt_long () returns EOF when there are no more long options. */
      if (option_character == EOF)
       break;

      /* If this is a long option, then get the short version of it. */
      if (option_character == 0 && long_options[getopt_long_index].flag == 0)
       option_character = long_options[getopt_long_index].val;

      /* Case on the option that we have received. */
      switch (option_character)
       {
       case 0:
         break;

         /* User is specifying the name of a file to output to. */
       case 'o':
         if (output_filename)
           free (output_filename);
         output_filename = xstrdup (optarg);
         break;

       default:
         suggest_help ();
         xexit (1);
       }
    }

  /* If the user specified --version, then show the version and exit. */
  if (print_version_p)
    {
      printf ("%s (GNU %s) %s\n", program_name, PACKAGE, VERSION);
      puts ("");
      printf (_ ("Copyright (C) %s Free Software Foundation, Inc.\n\
There is NO warranty.  You may redistribute this software\n\
under the terms of the GNU General Public License.\n\
For more information about these matters, see the files named COPYING.\n"),
             "2003");
      xexit (0);
    }

  /* If the `--help' option was present, show the help and exit. */
  if (print_help_p)
    {
      short_help ();
      xexit (0);
    }

  /* If there is one argument remaining, it is the name of the input
     file. */
  if (optind == argc - 1)
    {
      if (input_filename)
       free (input_filename);
      input_filename = xstrdup (argv[optind]);
    }
  else if (optind != argc)
    {
      error_message (0, _("incorrect number of arguments"),
          NULL, NULL, NULL, NULL);
      suggest_help ();
      xexit (1);
    }

  /* Use default filenames where none given. */
  {
    char *homedir;

    homedir = getenv ("HOME");
#ifdef __MSDOS__
    if (!homedir)
      homedir = ".";
#endif
    if (!input_filename)
      input_filename = mkpath (homedir, INFOKEY_SRCFILE);
    if (!output_filename)
      output_filename = mkpath (homedir, INFOKEY_FILE);
  }

  {
    FILE *inf;
    FILE *outf;
    int write_error;
    static struct sect sections[3];

    /* Open the input file. */
    inf = fopen (input_filename, "r");
    if (!inf)
      {
       error_message (errno, _("cannot open input file `%s'"),
            input_filename, NULL, NULL, NULL);
       xexit (1);
      }

    /* Compile the input file to its verious sections, then write the
       section data to the output file. */

    if (compile (inf, input_filename, sections))
      {
       /* Open the output file. */
       outf = fopen (output_filename, FOPEN_WBIN);
       if (!outf)
         {
           error_message (errno, _("cannot create output file `%s'"),
                output_filename, NULL, NULL, NULL);
           xexit (1);
         }

       /* Write the contents of the output file and close it.  If there is
          an error writing to the file, delete it and exit with a failure
          status.  */
       write_error = 0;
       if (!write_infokey_file (outf, sections))
         {
           error_message (errno, _("error writing to `%s'"),
                output_filename, NULL, NULL, NULL);
           write_error = 1;
         }
       if (fclose (outf) == EOF)
         {
           error_message (errno, _("error closing output file `%s'"),
                output_filename, NULL, NULL, NULL);
           write_error = 1;
         }
       if (write_error)
         {
           unlink (output_filename);
           xexit (1);
         }
      }

    /* Close the input file. */
    fclose (inf);
  }

  return 0;
}

Here is the call graph for this function:

static char * mkpath ( const char *  dir,
const char *  file 
) [static]

Definition at line 251 of file infokey.c.

{
  char *p;

  p = xmalloc (strlen (dir) + 1 + strlen (file) + 2);
  strcpy (p, dir);
  strcat (p, "/");
  strcat (p, file);
  return p;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int putint ( int  i,
FILE fp 
) [static]

Definition at line 817 of file infokey.c.

{
  return fputc (i % INFOKEY_RADIX, fp) != EOF
    && fputc ((i / INFOKEY_RADIX) % INFOKEY_RADIX, fp) != EOF;
}

Here is the caller graph for this function:

static int putsect ( struct sect s,
int  code,
FILE fp 
) [static]

Definition at line 827 of file infokey.c.

{
  if (s->cur == 0)
    return 1;
  return fputc (code, fp) != EOF
    && putint (s->cur, fp)
    && fwrite (s->data, s->cur, 1, fp) == 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void short_help ( void  ) [static]

Definition at line 904 of file infokey.c.

{
  printf (_("\
Usage: %s [OPTION]... [INPUT-FILE]\n\
\n\
Compile infokey source file to infokey file.  Reads INPUT-FILE (default\n\
$HOME/.infokey) and writes compiled key file to (by default) $HOME/.info.\n\
\n\
Options:\n\
  --output FILE        output to FILE instead of $HOME/.info\n\
  --help               display this help and exit.\n\
  --version            display version information and exit.\n\
"), program_name);

  puts (_("\n\
Email bug reports to bug-texinfo@gnu.org,\n\
general questions and discussion to help-texinfo@gnu.org.\n\
Texinfo home page: http://www.gnu.org/software/texinfo/"));

  xexit (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void suggest_help ( void  ) [static]

Definition at line 897 of file infokey.c.

{
  fprintf (stderr, _("Try --help for more information.\n"));
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void syntax_error ( const char *  filename,
unsigned int  linenum,
const char *  fmt,
const void a1,
const void a2,
const void a3,
const void a4 
) [static]

Definition at line 885 of file infokey.c.

{
  fprintf (stderr, "%s: ", program_name);
  fprintf (stderr, _("\"%s\", line %u: "), filename, linenum);
  fprintf (stderr, fmt, a1, a2, a3, a4);
  fprintf (stderr, "\n");
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int write_infokey_file ( FILE fp,
struct sect sections 
) [static]

Definition at line 839 of file infokey.c.

{
  /* Get rid of sections with no effect. */
  if (sections[info].cur == 1 && sections[info].data[0] == 0)
    sections[info].cur = 0;
  if (sections[ea].cur == 1 && sections[ea].data[0] == 0)
    sections[ea].cur = 0;

  /* Write all parts of the file out in order (no lseeks),
     checking for errors all the way. */
  return fputc (INFOKEY_MAGIC_S0, fp) != EOF
    && fputc (INFOKEY_MAGIC_S1, fp) != EOF
    && fputc (INFOKEY_MAGIC_S2, fp) != EOF
    && fputc (INFOKEY_MAGIC_S3, fp) != EOF
    && fputs (VERSION, fp) != EOF
    && fputc ('\0', fp) != EOF
    && putsect (&sections[info], INFOKEY_SECTION_INFO, fp)
    && putsect (&sections[ea], INFOKEY_SECTION_EA, fp)
    && putsect (&sections[var], INFOKEY_SECTION_VAR, fp)
    && fputc (INFOKEY_MAGIC_E0, fp) != EOF
    && fputc (INFOKEY_MAGIC_E1, fp) != EOF
    && fputc (INFOKEY_MAGIC_E2, fp) != EOF
    && fputc (INFOKEY_MAGIC_E3, fp) != EOF;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

char* input_filename = (char *) NULL [static]

Definition at line 38 of file infokey.c.

struct option[] [static]
Initial value:
{
  {"output", 1, 0, 'o'},
  {"help", 0, &print_help_p, 1},
  {"version", 0, &print_version_p, 1},
  {NULL, 0, NULL, 0}
}

Definition at line 47 of file infokey.c.

char* output_filename = (char *) NULL [static]

Definition at line 42 of file infokey.c.

int print_help_p = 0 [static]

Definition at line 34 of file infokey.c.

int print_version_p = 0 [static]

Definition at line 31 of file infokey.c.

char* program_name = "infokey" [static]

Definition at line 28 of file infokey.c.

char* short_options = "o:" [static]

Definition at line 56 of file infokey.c.