Back to index

tetex-bin  3.0
Defines | Functions | Variables
comp_scan.c File Reference
#include <curses.priv.h>
#include <ctype.h>
#include <term_entry.h>
#include <tic.h>

Go to the source code of this file.

Defines

#define MAXCAPLEN   600
#define iswhite(ch)   (ch == ' ' || ch == '\t')
#define LEXBUFSIZ   1024

Functions

 _nc_reset_input (FILE *fp, char *buf)
static int last_char (void)
static int next_char (void)
static void push_back (char c)
static long stream_pos (void)
static bool end_of_stream (void)
static int eat_escaped_newline (int ch)
 _nc_get_token (bool silent)
 _nc_trans_string (char *ptr, char *last)
 _nc_push_token (int tokclass)
 _nc_panic_mode (char ch)

Variables

 _nc_syntax = 0
 _nc_curr_file_pos = 0
 _nc_comment_start = 0
 _nc_comment_end = 0
 _nc_start_line = 0
 _nc_curr_token
static bool first_column
static bool had_newline
static char separator
static int pushtype
static char * pushname
static char * bufptr
static char * bufstart
static FILEyyin

Define Documentation

#define iswhite (   ch)    (ch == ' ' || ch == '\t')

Definition at line 62 of file comp_scan.c.

#define LEXBUFSIZ   1024

Definition at line 104 of file comp_scan.c.

#define MAXCAPLEN   600

Definition at line 60 of file comp_scan.c.


Function Documentation

_nc_get_token ( bool  silent)

Definition at line 319 of file comp_scan.c.

{
    static const char terminfo_punct[] = "@%&*!#";
    static char *buffer;

    char *after_list;
    char *after_name;
    char *numchk;
    char *ptr;
    char *s;
    char numbuf[80];
    int ch;
    int dot_flag = FALSE;
    int type;
    long number;
    long token_start;
    unsigned found;

    if (pushtype != NO_PUSHBACK) {
       int retval = pushtype;

       _nc_set_type(pushname != 0 ? pushname : "");
       DEBUG(3, ("pushed-back token: `%s', class %d",
                _nc_curr_token.tk_name, pushtype));

       pushtype = NO_PUSHBACK;
       if (pushname != 0)
           pushname[0] = '\0';

       /* currtok wasn't altered by _nc_push_token() */
       return (retval);
    }

    if (end_of_stream()) {
       yyin = 0;
       next_char();         /* frees its allocated memory */
       if (buffer != 0) {
           FreeAndNull(buffer);
       }
       return (EOF);
    }

  start_token:
    token_start = stream_pos();
    while ((ch = next_char()) == '\n' || iswhite(ch)) {
       if (ch == '\n')
           had_newline = TRUE;
       continue;
    }

    ch = eat_escaped_newline(ch);

    if (ch == EOF)
       type = EOF;
    else {
       /* if this is a termcap entry, skip a leading separator */
       if (separator == ':' && ch == ':')
           ch = next_char();

       if (ch == '.'
#if NCURSES_EXT_FUNCS
           && !_nc_disable_period
#endif
           ) {
           dot_flag = TRUE;
           DEBUG(8, ("dot-flag set"));

           while ((ch = next_char()) == '.' || iswhite(ch))
              continue;
       }

       if (ch == EOF) {
           type = EOF;
           goto end_of_token;
       }

       /* have to make some punctuation chars legal for terminfo */
       if (!isalnum(UChar(ch))
#if NCURSES_EXT_FUNCS
           && !(ch == '.' && _nc_disable_period)
#endif
           && !strchr(terminfo_punct, (char) ch)) {
           if (!silent)
              _nc_warning("Illegal character (expected alphanumeric or %s) - %s",
                         terminfo_punct, unctrl((chtype) ch));
           _nc_panic_mode(separator);
           goto start_token;
       }

       if (buffer == 0)
           buffer = typeMalloc(char, MAX_ENTRY_SIZE);

       ptr = buffer;
       *(ptr++) = ch;

       if (first_column) {
           _nc_comment_start = token_start;
           _nc_comment_end = _nc_curr_file_pos;
           _nc_start_line = _nc_curr_line;

           _nc_syntax = ERR;
           after_name = 0;
           after_list = 0;
           while ((ch = next_char()) != '\n') {
              if (ch == EOF) {
                  _nc_err_abort(MSG_NO_MEMORY);
              } else if (ch == '|') {
                  after_list = ptr;
                  if (after_name == 0)
                     after_name = ptr;
              } else if (ch == ':' && last_char() != ',') {
                  _nc_syntax = SYN_TERMCAP;
                  separator = ':';
                  break;
              } else if (ch == ',') {
                  _nc_syntax = SYN_TERMINFO;
                  separator = ',';
                  /*
                   * If we did not see a '|', then we found a name with no
                   * aliases or description.
                   */
                  if (after_name == 0)
                     break;
                  /*
                   * If we see a comma, we assume this is terminfo unless we
                   * subsequently run into a colon.  But we don't stop
                   * looking for a colon until hitting a newline.  This
                   * allows commas to be embedded in description fields of
                   * either syntax.
                   */
              } else
                  ch = eat_escaped_newline(ch);

              *ptr++ = ch;
           }
           ptr[0] = '\0';
           if (_nc_syntax == ERR) {
              /*
               * Grrr...what we ought to do here is barf, complaining that
               * the entry is malformed.  But because a couple of name fields
               * in the 8.2 termcap file end with |\, we just have to assume
               * it's termcap syntax.
               */
              _nc_syntax = SYN_TERMCAP;
              separator = ':';
           } else if (_nc_syntax == SYN_TERMINFO) {
              /* throw away trailing /, *$/ */
              for (--ptr; iswhite(*ptr) || *ptr == ','; ptr--)
                  continue;
              ptr[1] = '\0';
           }

           /*
            * This is the soonest we have the terminal name fetched.  Set up
            * for following warning messages.  If there's no '|', then there
            * is no description.
            */
           if (after_name != 0) {
              ch = *after_name;
              *after_name = '\0';
              _nc_set_type(buffer);
              *after_name = ch;
           }

           /*
            * Compute the boundary between the aliases and the description
            * field for syntax-checking purposes.
            */
           if (after_list != 0) {
              if (!silent) {
                  if (*after_list == '\0')
                     _nc_warning("empty longname field");
                  else if (strchr(after_list, ' ') == 0)
                     _nc_warning("older tic versions may treat the description field as an alias");
              }
           } else {
              after_list = buffer + strlen(buffer);
              DEBUG(1, ("missing description"));
           }

           /*
            * Whitespace in a name field other than the long name can confuse
            * rdist and some termcap tools.  Slashes are a no-no.  Other
            * special characters can be dangerous due to shell expansion.
            */
           for (s = buffer; s < after_list; ++s) {
              if (isspace(UChar(*s))) {
                  if (!silent)
                     _nc_warning("whitespace in name or alias field");
                  break;
              } else if (*s == '/') {
                  if (!silent)
                     _nc_warning("slashes aren't allowed in names or aliases");
                  break;
              } else if (strchr("$[]!*?", *s)) {
                  if (!silent)
                     _nc_warning("dubious character `%c' in name or alias field", *s);
                  break;
              }
           }

           _nc_curr_token.tk_name = buffer;
           type = NAMES;
       } else {
           if (had_newline && _nc_syntax == SYN_TERMCAP) {
              _nc_warning("Missing backslash before newline");
              had_newline = FALSE;
           }
           while ((ch = next_char()) != EOF) {
              if (!isalnum(UChar(ch))) {
                  if (_nc_syntax == SYN_TERMINFO) {
                     if (ch != '_')
                         break;
                  } else {  /* allow ';' for "k;" */
                     if (ch != ';')
                         break;
                  }
              }
              *(ptr++) = ch;
           }

           *ptr++ = '\0';
           switch (ch) {
           case ',':
           case ':':
              if (ch != separator)
                  _nc_err_abort("Separator inconsistent with syntax");
              _nc_curr_token.tk_name = buffer;
              type = BOOLEAN;
              break;
           case '@':
              if ((ch = next_char()) != separator && !silent)
                  _nc_warning("Missing separator after `%s', have %s",
                            buffer, unctrl((chtype) ch));
              _nc_curr_token.tk_name = buffer;
              type = CANCEL;
              break;

           case '#':
              found = 0;
              while (isalnum(ch = next_char())) {
                  numbuf[found++] = ch;
                  if (found >= sizeof(numbuf) - 1)
                     break;
              }
              numbuf[found] = '\0';
              number = strtol(numbuf, &numchk, 0);
              if (!silent) {
                  if (numchk == numbuf)
                     _nc_warning("no value given for `%s'", buffer);
                  if ((*numchk != '\0') || (ch != separator))
                     _nc_warning("Missing separator");
              }
              _nc_curr_token.tk_name = buffer;
              _nc_curr_token.tk_valnumber = number;
              type = NUMBER;
              break;

           case '=':
              ch = _nc_trans_string(ptr, buffer + MAX_ENTRY_SIZE);
              if (!silent && ch != separator)
                  _nc_warning("Missing separator");
              _nc_curr_token.tk_name = buffer;
              _nc_curr_token.tk_valstring = ptr;
              type = STRING;
              break;

           case EOF:
              type = EOF;
              break;
           default:
              /* just to get rid of the compiler warning */
              type = UNDEF;
              if (!silent)
                  _nc_warning("Illegal character - %s", unctrl((chtype) ch));
           }
       }                    /* end else (first_column == FALSE) */
    }                       /* end else (ch != EOF) */

  end_of_token:

#ifdef TRACE
    if (dot_flag == TRUE)
       DEBUG(8, ("Commented out "));

    if (_nc_tracing >= DEBUG_LEVEL(7)) {
       switch (type) {
       case BOOLEAN:
           _tracef("Token: Boolean; name='%s'",
                  _nc_curr_token.tk_name);
           break;

       case NUMBER:
           _tracef("Token: Number;  name='%s', value=%d",
                  _nc_curr_token.tk_name,
                  _nc_curr_token.tk_valnumber);
           break;

       case STRING:
           _tracef("Token: String;  name='%s', value=%s",
                  _nc_curr_token.tk_name,
                  _nc_visbuf(_nc_curr_token.tk_valstring));
           break;

       case CANCEL:
           _tracef("Token: Cancel; name='%s'",
                  _nc_curr_token.tk_name);
           break;

       case NAMES:

           _tracef("Token: Names; value='%s'",
                  _nc_curr_token.tk_name);
           break;

       case EOF:
           _tracef("Token: End of file");
           break;

       default:
           _nc_warning("Bad token type");
       }
    }
#endif

    if (dot_flag == TRUE)   /* if commented out, use the next one */
       type = _nc_get_token(silent);

    DEBUG(3, ("token: `%s', class %d",
             _nc_curr_token.tk_name != 0 ? _nc_curr_token.tk_name :
             "<null>",
             type));

    return (type);
}

Here is the call graph for this function:

Here is the caller graph for this function:

_nc_panic_mode ( char  ch)

Definition at line 852 of file comp_scan.c.

{
    int c;

    for (;;) {
       c = next_char();
       if (c == ch)
           return;
       if (c == EOF)
           return;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

_nc_push_token ( int  tokclass)

Definition at line 831 of file comp_scan.c.

{
    /*
     * This implementation is kind of bogus, it will fail if we ever do more
     * than one pushback at a time between get_token() calls.  It relies on the
     * fact that _nc_curr_token is static storage that nothing but
     * _nc_get_token() touches.
     */
    pushtype = tokclass;
    if (pushname == 0)
       pushname = typeMalloc(char, MAX_NAME_SIZE + 1);
    _nc_get_type(pushname);

    DEBUG(3, ("pushing token: `%s', class %d",
             _nc_curr_token.tk_name, pushtype));
}

Here is the call graph for this function:

Here is the caller graph for this function:

_nc_reset_input ( FILE fp,
char *  buf 
)

Definition at line 119 of file comp_scan.c.

{
    pushtype = NO_PUSHBACK;
    if (pushname != 0)
       pushname[0] = '\0';
    yyin = fp;
    bufstart = bufptr = buf;
    _nc_curr_file_pos = 0L;
    if (fp != 0)
       _nc_curr_line = 0;
    _nc_curr_col = 0;
}

Here is the caller graph for this function:

_nc_trans_string ( char *  ptr,
char *  last 
)

Definition at line 675 of file comp_scan.c.

{
    int count = 0;
    int number = 0;
    int i, c;
    chtype ch, last_ch = '\0';
    bool ignored = FALSE;
    bool long_warning = FALSE;

    while ((ch = c = next_char()) != (chtype) separator && c != EOF) {
       if (ptr == (last - 1))
           break;
       if ((_nc_syntax == SYN_TERMCAP) && c == '\n')
           break;
       if (ch == '^' && last_ch != '%') {
           ch = c = next_char();
           if (c == EOF)
              _nc_err_abort(MSG_NO_INPUTS);

           if (!(is7bits(ch) && isprint(ch))) {
              _nc_warning("Illegal ^ character - %s", unctrl(ch));
           }
           if (ch == '?') {
              *(ptr++) = '\177';
              if (_nc_tracing)
                  _nc_warning("Allow ^? as synonym for \\177");
           } else {
              if ((ch &= 037) == 0)
                  ch = 128;
              *(ptr++) = (char) (ch);
           }
       } else if (ch == '\\') {
           ch = c = next_char();
           if (c == EOF)
              _nc_err_abort(MSG_NO_INPUTS);

           if (ch >= '0' && ch <= '7') {
              number = ch - '0';
              for (i = 0; i < 2; i++) {
                  ch = c = next_char();
                  if (c == EOF)
                     _nc_err_abort(MSG_NO_INPUTS);

                  if (c < '0' || c > '7') {
                     if (isdigit(c)) {
                         _nc_warning("Non-octal digit `%c' in \\ sequence", c);
                         /* allow the digit; it'll do less harm */
                     } else {
                         push_back((char) c);
                         break;
                     }
                  }

                  number = number * 8 + c - '0';
              }

              if (number == 0)
                  number = 0200;
              *(ptr++) = (char) number;
           } else {
              switch (c) {
              case 'E':
              case 'e':
                  *(ptr++) = '\033';
                  break;

              case 'a':
                  *(ptr++) = '\007';
                  break;

              case 'l':
              case 'n':
                  *(ptr++) = '\n';
                  break;

              case 'r':
                  *(ptr++) = '\r';
                  break;

              case 'b':
                  *(ptr++) = '\010';
                  break;

              case 's':
                  *(ptr++) = ' ';
                  break;

              case 'f':
                  *(ptr++) = '\014';
                  break;

              case 't':
                  *(ptr++) = '\t';
                  break;

              case '\\':
                  *(ptr++) = '\\';
                  break;

              case '^':
                  *(ptr++) = '^';
                  break;

              case ',':
                  *(ptr++) = ',';
                  break;

              case ':':
                  *(ptr++) = ':';
                  break;

              case '\n':
                  continue;

              default:
                  _nc_warning("Illegal character %s in \\ sequence",
                            unctrl(ch));
                  /* FALLTHRU */
              case '|':
                  *(ptr++) = (char) ch;
              }             /* endswitch (ch) */
           }                /* endelse (ch < '0' ||  ch > '7') */
       }
       /* end else if (ch == '\\') */
       else if (ch == '\n' && (_nc_syntax == SYN_TERMINFO)) {
           /* newlines embedded in a terminfo string are ignored */
           ignored = TRUE;
       } else {
           *(ptr++) = (char) ch;
       }

       if (!ignored) {
           last_ch = ch;
           count++;
       }
       ignored = FALSE;

       if (count > MAXCAPLEN && !long_warning) {
           _nc_warning("Very long string found.  Missing separator?");
           long_warning = TRUE;
       }
    }                       /* end while */

    *ptr = '\0';

    return (ch);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int eat_escaped_newline ( int  ch) [inline, static]

Definition at line 277 of file comp_scan.c.

{
    if (ch == '\\')
       while ((ch = next_char()) == '\n' || iswhite(ch))
           continue;
    return ch;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static bool end_of_stream ( void  ) [static]

Definition at line 268 of file comp_scan.c.

{
    return ((yyin ? feof(yyin) : (bufptr && *bufptr == '\0'))
           ? TRUE : FALSE);
}

Here is the caller graph for this function:

static int last_char ( void  ) [static]

Definition at line 138 of file comp_scan.c.

{
    size_t len = strlen(bufptr);
    while (len--) {
       if (!isspace(UChar(bufptr[len])))
           return bufptr[len];
    }
    return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int next_char ( void  ) [static]

Definition at line 163 of file comp_scan.c.

{
    static char *result;
    static size_t allocated;
    int the_char;

    if (!yyin) {
       if (result != 0) {
           FreeAndNull(result);
           FreeAndNull(pushname);
           allocated = 0;
       }
       /*
        * An string with an embedded null will truncate the input.  This is
        * intentional (we don't read binary files here).
        */
       if (bufptr == 0 || *bufptr == '\0')
           return (EOF);
       if (*bufptr == '\n') {
           _nc_curr_line++;
           _nc_curr_col = 0;
       }
    } else if (!bufptr || !*bufptr) {
       /*
        * In theory this could be recoded to do its I/O one character at a
        * time, saving the buffer space.  In practice, this turns out to be
        * quite hard to get completely right.  Try it and see.  If you
        * succeed, don't forget to hack push_back() correspondingly.
        */
       size_t used;
       size_t len;

       do {
           bufstart = 0;
           used = 0;
           do {
              if (used + (LEXBUFSIZ / 4) >= allocated) {
                  allocated += (allocated + LEXBUFSIZ);
                  result = typeRealloc(char, allocated, result);
                  if (result == 0)
                     return (EOF);
              }
              if (used == 0)
                  _nc_curr_file_pos = ftell(yyin);

              if (fgets(result + used, allocated - used, yyin) != 0) {
                  bufstart = result;
                  if (used == 0) {
                     _nc_curr_line++;
                     _nc_curr_col = 0;
                  }
              } else {
                  if (used != 0)
                     strcat(result, "\n");
              }
              if ((bufptr = bufstart) != 0) {
                  used = strlen(bufptr);
                  while (iswhite(*bufptr))
                     bufptr++;

                  /*
                   * Treat a trailing <cr><lf> the same as a <newline> so we
                   * can read files on OS/2, etc.
                   */
                  if ((len = strlen(bufptr)) > 1) {
                     if (bufptr[len - 1] == '\n'
                         && bufptr[len - 2] == '\r') {
                         len--;
                         bufptr[len - 1] = '\n';
                         bufptr[len] = '\0';
                     }
                  }
              } else {
                  return (EOF);
              }
           } while (bufptr[len - 1] != '\n');    /* complete a line */
       } while (result[0] == '#'); /* ignore comments */
    }

    first_column = (bufptr == bufstart);
    if (first_column)
       had_newline = FALSE;

    _nc_curr_col++;
    the_char = *bufptr++;
    return UChar(the_char);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void push_back ( char  c) [static]

Definition at line 252 of file comp_scan.c.

{
    if (bufptr == bufstart)
       _nc_syserr_abort("Can't backspace off beginning of line");
    *--bufptr = c;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static long stream_pos ( void  ) [static]

Definition at line 261 of file comp_scan.c.

{
    return (yyin ? ftell(yyin) : (bufptr ? bufptr - bufstart : 0));
}

Here is the caller graph for this function:


Variable Documentation

Definition at line 71 of file comp_scan.c.

Definition at line 69 of file comp_scan.c.

Definition at line 67 of file comp_scan.c.

Initial value:
{
    0, 0, 0
}

Definition at line 76 of file comp_scan.c.

Definition at line 73 of file comp_scan.c.

Definition at line 65 of file comp_scan.c.

char* bufptr [static]

Definition at line 106 of file comp_scan.c.

char* bufstart [static]

Definition at line 107 of file comp_scan.c.

bool first_column [static]

Definition at line 87 of file comp_scan.c.

bool had_newline [static]

Definition at line 88 of file comp_scan.c.

char* pushname [static]

Definition at line 91 of file comp_scan.c.

int pushtype [static]

Definition at line 90 of file comp_scan.c.

char separator [static]

Definition at line 89 of file comp_scan.c.

FILE* yyin [static]

Definition at line 108 of file comp_scan.c.