Back to index

tetex-bin  3.0
comp_scan.c
Go to the documentation of this file.
00001 /****************************************************************************
00002  * Copyright (c) 1998-2003,2004 Free Software Foundation, Inc.              *
00003  *                                                                          *
00004  * Permission is hereby granted, free of charge, to any person obtaining a  *
00005  * copy of this software and associated documentation files (the            *
00006  * "Software"), to deal in the Software without restriction, including      *
00007  * without limitation the rights to use, copy, modify, merge, publish,      *
00008  * distribute, distribute with modifications, sublicense, and/or sell       *
00009  * copies of the Software, and to permit persons to whom the Software is    *
00010  * furnished to do so, subject to the following conditions:                 *
00011  *                                                                          *
00012  * The above copyright notice and this permission notice shall be included  *
00013  * in all copies or substantial portions of the Software.                   *
00014  *                                                                          *
00015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
00016  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
00017  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
00018  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
00019  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
00020  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
00021  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
00022  *                                                                          *
00023  * Except as contained in this notice, the name(s) of the above copyright   *
00024  * holders shall not be used in advertising or otherwise to promote the     *
00025  * sale, use or other dealings in this Software without prior written       *
00026  * authorization.                                                           *
00027  ****************************************************************************/
00028 
00029 /****************************************************************************
00030  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
00031  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
00032  *     and: Thomas E. Dickey                        1996 on                 *
00033  ****************************************************************************/
00034 
00035 /*
00036  *     comp_scan.c --- Lexical scanner for terminfo compiler.
00037  *
00038  *     _nc_reset_input()
00039  *     _nc_get_token()
00040  *     _nc_panic_mode()
00041  *     int _nc_syntax;
00042  *     int _nc_curr_line;
00043  *     long _nc_curr_file_pos;
00044  *     long _nc_comment_start;
00045  *     long _nc_comment_end;
00046  */
00047 
00048 #include <curses.priv.h>
00049 
00050 #include <ctype.h>
00051 #include <term_entry.h>
00052 #include <tic.h>
00053 
00054 MODULE_ID("$Id: comp_scan.c,v 1.68 2004/04/17 22:14:55 tom Exp $")
00055 
00056 /*
00057  * Maximum length of string capability we'll accept before raising an error.
00058  * Yes, there is a real capability in /etc/termcap this long, an "is".
00059  */
00060 #define MAXCAPLEN    600
00061 
00062 #define iswhite(ch)  (ch == ' '  ||  ch == '\t')
00063 
00064 NCURSES_EXPORT_VAR(int)
00065 _nc_syntax = 0;                    /* termcap or terminfo? */
00066 NCURSES_EXPORT_VAR(long)
00067 _nc_curr_file_pos = 0;             /* file offset of current line */
00068 NCURSES_EXPORT_VAR(long)
00069 _nc_comment_start = 0;             /* start of comment range before name */
00070 NCURSES_EXPORT_VAR(long)
00071 _nc_comment_end = 0;        /* end of comment range before name */
00072 NCURSES_EXPORT_VAR(long)
00073 _nc_start_line = 0;         /* start line of current entry */
00074 
00075 NCURSES_EXPORT_VAR(struct token)
00076 _nc_curr_token =
00077 {
00078     0, 0, 0
00079 };
00080 
00081 /*****************************************************************************
00082  *
00083  * Token-grabbing machinery
00084  *
00085  *****************************************************************************/
00086 
00087 static bool first_column;   /* See 'next_char()' below */
00088 static bool had_newline;
00089 static char separator;             /* capability separator */
00090 static int pushtype;        /* type of pushback token */
00091 static char *pushname;
00092 
00093 #if NCURSES_EXT_FUNCS
00094 NCURSES_EXPORT_VAR(bool)
00095 _nc_disable_period = FALSE; /* used by tic -a option */
00096 #endif
00097 
00098 /*****************************************************************************
00099  *
00100  * Character-stream handling
00101  *
00102  *****************************************************************************/
00103 
00104 #define LEXBUFSIZ    1024
00105 
00106 static char *bufptr;        /* otherwise, the input buffer pointer */
00107 static char *bufstart;             /* start of buffer so we can compute offsets */
00108 static FILE *yyin;          /* scanner's input file descriptor */
00109 
00110 /*
00111  *     _nc_reset_input()
00112  *
00113  *     Resets the input-reading routines.  Used on initialization,
00114  *     or after a seek has been done.  Exactly one argument must be
00115  *     non-null.
00116  */
00117 
00118 NCURSES_EXPORT(void)
00119 _nc_reset_input(FILE *fp, char *buf)
00120 {
00121     pushtype = NO_PUSHBACK;
00122     if (pushname != 0)
00123        pushname[0] = '\0';
00124     yyin = fp;
00125     bufstart = bufptr = buf;
00126     _nc_curr_file_pos = 0L;
00127     if (fp != 0)
00128        _nc_curr_line = 0;
00129     _nc_curr_col = 0;
00130 }
00131 
00132 /*
00133  *     int last_char()
00134  *
00135  *     Returns the final nonblank character on the current input buffer
00136  */
00137 static int
00138 last_char(void)
00139 {
00140     size_t len = strlen(bufptr);
00141     while (len--) {
00142        if (!isspace(UChar(bufptr[len])))
00143            return bufptr[len];
00144     }
00145     return 0;
00146 }
00147 
00148 /*
00149  *     int next_char()
00150  *
00151  *     Returns the next character in the input stream.  Comments and leading
00152  *     white space are stripped.
00153  *
00154  *     The global state variable 'firstcolumn' is set TRUE if the character
00155  *     returned is from the first column of the input line.
00156  *
00157  *     The global variable _nc_curr_line is incremented for each new line.
00158  *     The global variable _nc_curr_file_pos is set to the file offset of the
00159  *     beginning of each line.
00160  */
00161 
00162 static int
00163 next_char(void)
00164 {
00165     static char *result;
00166     static size_t allocated;
00167     int the_char;
00168 
00169     if (!yyin) {
00170        if (result != 0) {
00171            FreeAndNull(result);
00172            FreeAndNull(pushname);
00173            allocated = 0;
00174        }
00175        /*
00176         * An string with an embedded null will truncate the input.  This is
00177         * intentional (we don't read binary files here).
00178         */
00179        if (bufptr == 0 || *bufptr == '\0')
00180            return (EOF);
00181        if (*bufptr == '\n') {
00182            _nc_curr_line++;
00183            _nc_curr_col = 0;
00184        }
00185     } else if (!bufptr || !*bufptr) {
00186        /*
00187         * In theory this could be recoded to do its I/O one character at a
00188         * time, saving the buffer space.  In practice, this turns out to be
00189         * quite hard to get completely right.  Try it and see.  If you
00190         * succeed, don't forget to hack push_back() correspondingly.
00191         */
00192        size_t used;
00193        size_t len;
00194 
00195        do {
00196            bufstart = 0;
00197            used = 0;
00198            do {
00199               if (used + (LEXBUFSIZ / 4) >= allocated) {
00200                   allocated += (allocated + LEXBUFSIZ);
00201                   result = typeRealloc(char, allocated, result);
00202                   if (result == 0)
00203                      return (EOF);
00204               }
00205               if (used == 0)
00206                   _nc_curr_file_pos = ftell(yyin);
00207 
00208               if (fgets(result + used, allocated - used, yyin) != 0) {
00209                   bufstart = result;
00210                   if (used == 0) {
00211                      _nc_curr_line++;
00212                      _nc_curr_col = 0;
00213                   }
00214               } else {
00215                   if (used != 0)
00216                      strcat(result, "\n");
00217               }
00218               if ((bufptr = bufstart) != 0) {
00219                   used = strlen(bufptr);
00220                   while (iswhite(*bufptr))
00221                      bufptr++;
00222 
00223                   /*
00224                    * Treat a trailing <cr><lf> the same as a <newline> so we
00225                    * can read files on OS/2, etc.
00226                    */
00227                   if ((len = strlen(bufptr)) > 1) {
00228                      if (bufptr[len - 1] == '\n'
00229                          && bufptr[len - 2] == '\r') {
00230                          len--;
00231                          bufptr[len - 1] = '\n';
00232                          bufptr[len] = '\0';
00233                      }
00234                   }
00235               } else {
00236                   return (EOF);
00237               }
00238            } while (bufptr[len - 1] != '\n');    /* complete a line */
00239        } while (result[0] == '#'); /* ignore comments */
00240     }
00241 
00242     first_column = (bufptr == bufstart);
00243     if (first_column)
00244        had_newline = FALSE;
00245 
00246     _nc_curr_col++;
00247     the_char = *bufptr++;
00248     return UChar(the_char);
00249 }
00250 
00251 static void
00252 push_back(char c)
00253 /* push a character back onto the input stream */
00254 {
00255     if (bufptr == bufstart)
00256        _nc_syserr_abort("Can't backspace off beginning of line");
00257     *--bufptr = c;
00258 }
00259 
00260 static long
00261 stream_pos(void)
00262 /* return our current character position in the input stream */
00263 {
00264     return (yyin ? ftell(yyin) : (bufptr ? bufptr - bufstart : 0));
00265 }
00266 
00267 static bool
00268 end_of_stream(void)
00269 /* are we at end of input? */
00270 {
00271     return ((yyin ? feof(yyin) : (bufptr && *bufptr == '\0'))
00272            ? TRUE : FALSE);
00273 }
00274 
00275 /* Assume we may be looking at a termcap-style continuation */
00276 static inline int
00277 eat_escaped_newline(int ch)
00278 {
00279     if (ch == '\\')
00280        while ((ch = next_char()) == '\n' || iswhite(ch))
00281            continue;
00282     return ch;
00283 }
00284 
00285 /*
00286  *     int
00287  *     get_token()
00288  *
00289  *     Scans the input for the next token, storing the specifics in the
00290  *     global structure 'curr_token' and returning one of the following:
00291  *
00292  *            NAMES         A line beginning in column 1.  'name'
00293  *                          will be set to point to everything up to but
00294  *                          not including the first separator on the line.
00295  *            BOOLEAN              An entry consisting of a name followed by
00296  *                          a separator.  'name' will be set to point to
00297  *                          the name of the capability.
00298  *            NUMBER        An entry of the form
00299  *                                 name#digits,
00300  *                          'name' will be set to point to the capability
00301  *                          name and 'valnumber' to the number given.
00302  *            STRING        An entry of the form
00303  *                                 name=characters,
00304  *                          'name' is set to the capability name and
00305  *                          'valstring' to the string of characters, with
00306  *                          input translations done.
00307  *            CANCEL        An entry of the form
00308  *                                 name@,
00309  *                          'name' is set to the capability name and
00310  *                          'valnumber' to -1.
00311  *            EOF           The end of the file has been reached.
00312  *
00313  *     A `separator' is either a comma or a semicolon, depending on whether
00314  *     we are in termcap or terminfo mode.
00315  *
00316  */
00317 
00318 NCURSES_EXPORT(int)
00319 _nc_get_token(bool silent)
00320 {
00321     static const char terminfo_punct[] = "@%&*!#";
00322     static char *buffer;
00323 
00324     char *after_list;
00325     char *after_name;
00326     char *numchk;
00327     char *ptr;
00328     char *s;
00329     char numbuf[80];
00330     int ch;
00331     int dot_flag = FALSE;
00332     int type;
00333     long number;
00334     long token_start;
00335     unsigned found;
00336 
00337     if (pushtype != NO_PUSHBACK) {
00338        int retval = pushtype;
00339 
00340        _nc_set_type(pushname != 0 ? pushname : "");
00341        DEBUG(3, ("pushed-back token: `%s', class %d",
00342                 _nc_curr_token.tk_name, pushtype));
00343 
00344        pushtype = NO_PUSHBACK;
00345        if (pushname != 0)
00346            pushname[0] = '\0';
00347 
00348        /* currtok wasn't altered by _nc_push_token() */
00349        return (retval);
00350     }
00351 
00352     if (end_of_stream()) {
00353        yyin = 0;
00354        next_char();         /* frees its allocated memory */
00355        if (buffer != 0) {
00356            FreeAndNull(buffer);
00357        }
00358        return (EOF);
00359     }
00360 
00361   start_token:
00362     token_start = stream_pos();
00363     while ((ch = next_char()) == '\n' || iswhite(ch)) {
00364        if (ch == '\n')
00365            had_newline = TRUE;
00366        continue;
00367     }
00368 
00369     ch = eat_escaped_newline(ch);
00370 
00371     if (ch == EOF)
00372        type = EOF;
00373     else {
00374        /* if this is a termcap entry, skip a leading separator */
00375        if (separator == ':' && ch == ':')
00376            ch = next_char();
00377 
00378        if (ch == '.'
00379 #if NCURSES_EXT_FUNCS
00380            && !_nc_disable_period
00381 #endif
00382            ) {
00383            dot_flag = TRUE;
00384            DEBUG(8, ("dot-flag set"));
00385 
00386            while ((ch = next_char()) == '.' || iswhite(ch))
00387               continue;
00388        }
00389 
00390        if (ch == EOF) {
00391            type = EOF;
00392            goto end_of_token;
00393        }
00394 
00395        /* have to make some punctuation chars legal for terminfo */
00396        if (!isalnum(UChar(ch))
00397 #if NCURSES_EXT_FUNCS
00398            && !(ch == '.' && _nc_disable_period)
00399 #endif
00400            && !strchr(terminfo_punct, (char) ch)) {
00401            if (!silent)
00402               _nc_warning("Illegal character (expected alphanumeric or %s) - %s",
00403                          terminfo_punct, unctrl((chtype) ch));
00404            _nc_panic_mode(separator);
00405            goto start_token;
00406        }
00407 
00408        if (buffer == 0)
00409            buffer = typeMalloc(char, MAX_ENTRY_SIZE);
00410 
00411        ptr = buffer;
00412        *(ptr++) = ch;
00413 
00414        if (first_column) {
00415            _nc_comment_start = token_start;
00416            _nc_comment_end = _nc_curr_file_pos;
00417            _nc_start_line = _nc_curr_line;
00418 
00419            _nc_syntax = ERR;
00420            after_name = 0;
00421            after_list = 0;
00422            while ((ch = next_char()) != '\n') {
00423               if (ch == EOF) {
00424                   _nc_err_abort(MSG_NO_MEMORY);
00425               } else if (ch == '|') {
00426                   after_list = ptr;
00427                   if (after_name == 0)
00428                      after_name = ptr;
00429               } else if (ch == ':' && last_char() != ',') {
00430                   _nc_syntax = SYN_TERMCAP;
00431                   separator = ':';
00432                   break;
00433               } else if (ch == ',') {
00434                   _nc_syntax = SYN_TERMINFO;
00435                   separator = ',';
00436                   /*
00437                    * If we did not see a '|', then we found a name with no
00438                    * aliases or description.
00439                    */
00440                   if (after_name == 0)
00441                      break;
00442                   /*
00443                    * If we see a comma, we assume this is terminfo unless we
00444                    * subsequently run into a colon.  But we don't stop
00445                    * looking for a colon until hitting a newline.  This
00446                    * allows commas to be embedded in description fields of
00447                    * either syntax.
00448                    */
00449               } else
00450                   ch = eat_escaped_newline(ch);
00451 
00452               *ptr++ = ch;
00453            }
00454            ptr[0] = '\0';
00455            if (_nc_syntax == ERR) {
00456               /*
00457                * Grrr...what we ought to do here is barf, complaining that
00458                * the entry is malformed.  But because a couple of name fields
00459                * in the 8.2 termcap file end with |\, we just have to assume
00460                * it's termcap syntax.
00461                */
00462               _nc_syntax = SYN_TERMCAP;
00463               separator = ':';
00464            } else if (_nc_syntax == SYN_TERMINFO) {
00465               /* throw away trailing /, *$/ */
00466               for (--ptr; iswhite(*ptr) || *ptr == ','; ptr--)
00467                   continue;
00468               ptr[1] = '\0';
00469            }
00470 
00471            /*
00472             * This is the soonest we have the terminal name fetched.  Set up
00473             * for following warning messages.  If there's no '|', then there
00474             * is no description.
00475             */
00476            if (after_name != 0) {
00477               ch = *after_name;
00478               *after_name = '\0';
00479               _nc_set_type(buffer);
00480               *after_name = ch;
00481            }
00482 
00483            /*
00484             * Compute the boundary between the aliases and the description
00485             * field for syntax-checking purposes.
00486             */
00487            if (after_list != 0) {
00488               if (!silent) {
00489                   if (*after_list == '\0')
00490                      _nc_warning("empty longname field");
00491                   else if (strchr(after_list, ' ') == 0)
00492                      _nc_warning("older tic versions may treat the description field as an alias");
00493               }
00494            } else {
00495               after_list = buffer + strlen(buffer);
00496               DEBUG(1, ("missing description"));
00497            }
00498 
00499            /*
00500             * Whitespace in a name field other than the long name can confuse
00501             * rdist and some termcap tools.  Slashes are a no-no.  Other
00502             * special characters can be dangerous due to shell expansion.
00503             */
00504            for (s = buffer; s < after_list; ++s) {
00505               if (isspace(UChar(*s))) {
00506                   if (!silent)
00507                      _nc_warning("whitespace in name or alias field");
00508                   break;
00509               } else if (*s == '/') {
00510                   if (!silent)
00511                      _nc_warning("slashes aren't allowed in names or aliases");
00512                   break;
00513               } else if (strchr("$[]!*?", *s)) {
00514                   if (!silent)
00515                      _nc_warning("dubious character `%c' in name or alias field", *s);
00516                   break;
00517               }
00518            }
00519 
00520            _nc_curr_token.tk_name = buffer;
00521            type = NAMES;
00522        } else {
00523            if (had_newline && _nc_syntax == SYN_TERMCAP) {
00524               _nc_warning("Missing backslash before newline");
00525               had_newline = FALSE;
00526            }
00527            while ((ch = next_char()) != EOF) {
00528               if (!isalnum(UChar(ch))) {
00529                   if (_nc_syntax == SYN_TERMINFO) {
00530                      if (ch != '_')
00531                          break;
00532                   } else {  /* allow ';' for "k;" */
00533                      if (ch != ';')
00534                          break;
00535                   }
00536               }
00537               *(ptr++) = ch;
00538            }
00539 
00540            *ptr++ = '\0';
00541            switch (ch) {
00542            case ',':
00543            case ':':
00544               if (ch != separator)
00545                   _nc_err_abort("Separator inconsistent with syntax");
00546               _nc_curr_token.tk_name = buffer;
00547               type = BOOLEAN;
00548               break;
00549            case '@':
00550               if ((ch = next_char()) != separator && !silent)
00551                   _nc_warning("Missing separator after `%s', have %s",
00552                             buffer, unctrl((chtype) ch));
00553               _nc_curr_token.tk_name = buffer;
00554               type = CANCEL;
00555               break;
00556 
00557            case '#':
00558               found = 0;
00559               while (isalnum(ch = next_char())) {
00560                   numbuf[found++] = ch;
00561                   if (found >= sizeof(numbuf) - 1)
00562                      break;
00563               }
00564               numbuf[found] = '\0';
00565               number = strtol(numbuf, &numchk, 0);
00566               if (!silent) {
00567                   if (numchk == numbuf)
00568                      _nc_warning("no value given for `%s'", buffer);
00569                   if ((*numchk != '\0') || (ch != separator))
00570                      _nc_warning("Missing separator");
00571               }
00572               _nc_curr_token.tk_name = buffer;
00573               _nc_curr_token.tk_valnumber = number;
00574               type = NUMBER;
00575               break;
00576 
00577            case '=':
00578               ch = _nc_trans_string(ptr, buffer + MAX_ENTRY_SIZE);
00579               if (!silent && ch != separator)
00580                   _nc_warning("Missing separator");
00581               _nc_curr_token.tk_name = buffer;
00582               _nc_curr_token.tk_valstring = ptr;
00583               type = STRING;
00584               break;
00585 
00586            case EOF:
00587               type = EOF;
00588               break;
00589            default:
00590               /* just to get rid of the compiler warning */
00591               type = UNDEF;
00592               if (!silent)
00593                   _nc_warning("Illegal character - %s", unctrl((chtype) ch));
00594            }
00595        }                    /* end else (first_column == FALSE) */
00596     }                       /* end else (ch != EOF) */
00597 
00598   end_of_token:
00599 
00600 #ifdef TRACE
00601     if (dot_flag == TRUE)
00602        DEBUG(8, ("Commented out "));
00603 
00604     if (_nc_tracing >= DEBUG_LEVEL(7)) {
00605        switch (type) {
00606        case BOOLEAN:
00607            _tracef("Token: Boolean; name='%s'",
00608                   _nc_curr_token.tk_name);
00609            break;
00610 
00611        case NUMBER:
00612            _tracef("Token: Number;  name='%s', value=%d",
00613                   _nc_curr_token.tk_name,
00614                   _nc_curr_token.tk_valnumber);
00615            break;
00616 
00617        case STRING:
00618            _tracef("Token: String;  name='%s', value=%s",
00619                   _nc_curr_token.tk_name,
00620                   _nc_visbuf(_nc_curr_token.tk_valstring));
00621            break;
00622 
00623        case CANCEL:
00624            _tracef("Token: Cancel; name='%s'",
00625                   _nc_curr_token.tk_name);
00626            break;
00627 
00628        case NAMES:
00629 
00630            _tracef("Token: Names; value='%s'",
00631                   _nc_curr_token.tk_name);
00632            break;
00633 
00634        case EOF:
00635            _tracef("Token: End of file");
00636            break;
00637 
00638        default:
00639            _nc_warning("Bad token type");
00640        }
00641     }
00642 #endif
00643 
00644     if (dot_flag == TRUE)   /* if commented out, use the next one */
00645        type = _nc_get_token(silent);
00646 
00647     DEBUG(3, ("token: `%s', class %d",
00648              _nc_curr_token.tk_name != 0 ? _nc_curr_token.tk_name :
00649              "<null>",
00650              type));
00651 
00652     return (type);
00653 }
00654 
00655 /*
00656  *     char
00657  *     trans_string(ptr)
00658  *
00659  *     Reads characters using next_char() until encountering a separator, nl,
00660  *     or end-of-file.  The returned value is the character which caused
00661  *     reading to stop.  The following translations are done on the input:
00662  *
00663  *            ^X  goes to  ctrl-X (i.e. X & 037)
00664  *            {\E,\n,\r,\b,\t,\f}  go to
00665  *                   {ESCAPE,newline,carriage-return,backspace,tab,formfeed}
00666  *            {\^,\\}  go to  {carat,backslash}
00667  *            \ddd (for ddd = up to three octal digits)  goes to the character ddd
00668  *
00669  *            \e == \E
00670  *            \0 == \200
00671  *
00672  */
00673 
00674 NCURSES_EXPORT(int)
00675 _nc_trans_string(char *ptr, char *last)
00676 {
00677     int count = 0;
00678     int number = 0;
00679     int i, c;
00680     chtype ch, last_ch = '\0';
00681     bool ignored = FALSE;
00682     bool long_warning = FALSE;
00683 
00684     while ((ch = c = next_char()) != (chtype) separator && c != EOF) {
00685        if (ptr == (last - 1))
00686            break;
00687        if ((_nc_syntax == SYN_TERMCAP) && c == '\n')
00688            break;
00689        if (ch == '^' && last_ch != '%') {
00690            ch = c = next_char();
00691            if (c == EOF)
00692               _nc_err_abort(MSG_NO_INPUTS);
00693 
00694            if (!(is7bits(ch) && isprint(ch))) {
00695               _nc_warning("Illegal ^ character - %s", unctrl(ch));
00696            }
00697            if (ch == '?') {
00698               *(ptr++) = '\177';
00699               if (_nc_tracing)
00700                   _nc_warning("Allow ^? as synonym for \\177");
00701            } else {
00702               if ((ch &= 037) == 0)
00703                   ch = 128;
00704               *(ptr++) = (char) (ch);
00705            }
00706        } else if (ch == '\\') {
00707            ch = c = next_char();
00708            if (c == EOF)
00709               _nc_err_abort(MSG_NO_INPUTS);
00710 
00711            if (ch >= '0' && ch <= '7') {
00712               number = ch - '0';
00713               for (i = 0; i < 2; i++) {
00714                   ch = c = next_char();
00715                   if (c == EOF)
00716                      _nc_err_abort(MSG_NO_INPUTS);
00717 
00718                   if (c < '0' || c > '7') {
00719                      if (isdigit(c)) {
00720                          _nc_warning("Non-octal digit `%c' in \\ sequence", c);
00721                          /* allow the digit; it'll do less harm */
00722                      } else {
00723                          push_back((char) c);
00724                          break;
00725                      }
00726                   }
00727 
00728                   number = number * 8 + c - '0';
00729               }
00730 
00731               if (number == 0)
00732                   number = 0200;
00733               *(ptr++) = (char) number;
00734            } else {
00735               switch (c) {
00736               case 'E':
00737               case 'e':
00738                   *(ptr++) = '\033';
00739                   break;
00740 
00741               case 'a':
00742                   *(ptr++) = '\007';
00743                   break;
00744 
00745               case 'l':
00746               case 'n':
00747                   *(ptr++) = '\n';
00748                   break;
00749 
00750               case 'r':
00751                   *(ptr++) = '\r';
00752                   break;
00753 
00754               case 'b':
00755                   *(ptr++) = '\010';
00756                   break;
00757 
00758               case 's':
00759                   *(ptr++) = ' ';
00760                   break;
00761 
00762               case 'f':
00763                   *(ptr++) = '\014';
00764                   break;
00765 
00766               case 't':
00767                   *(ptr++) = '\t';
00768                   break;
00769 
00770               case '\\':
00771                   *(ptr++) = '\\';
00772                   break;
00773 
00774               case '^':
00775                   *(ptr++) = '^';
00776                   break;
00777 
00778               case ',':
00779                   *(ptr++) = ',';
00780                   break;
00781 
00782               case ':':
00783                   *(ptr++) = ':';
00784                   break;
00785 
00786               case '\n':
00787                   continue;
00788 
00789               default:
00790                   _nc_warning("Illegal character %s in \\ sequence",
00791                             unctrl(ch));
00792                   /* FALLTHRU */
00793               case '|':
00794                   *(ptr++) = (char) ch;
00795               }             /* endswitch (ch) */
00796            }                /* endelse (ch < '0' ||  ch > '7') */
00797        }
00798        /* end else if (ch == '\\') */
00799        else if (ch == '\n' && (_nc_syntax == SYN_TERMINFO)) {
00800            /* newlines embedded in a terminfo string are ignored */
00801            ignored = TRUE;
00802        } else {
00803            *(ptr++) = (char) ch;
00804        }
00805 
00806        if (!ignored) {
00807            last_ch = ch;
00808            count++;
00809        }
00810        ignored = FALSE;
00811 
00812        if (count > MAXCAPLEN && !long_warning) {
00813            _nc_warning("Very long string found.  Missing separator?");
00814            long_warning = TRUE;
00815        }
00816     }                       /* end while */
00817 
00818     *ptr = '\0';
00819 
00820     return (ch);
00821 }
00822 
00823 /*
00824  *     _nc_push_token()
00825  *
00826  *     Push a token of given type so that it will be reread by the next
00827  *     get_token() call.
00828  */
00829 
00830 NCURSES_EXPORT(void)
00831 _nc_push_token(int tokclass)
00832 {
00833     /*
00834      * This implementation is kind of bogus, it will fail if we ever do more
00835      * than one pushback at a time between get_token() calls.  It relies on the
00836      * fact that _nc_curr_token is static storage that nothing but
00837      * _nc_get_token() touches.
00838      */
00839     pushtype = tokclass;
00840     if (pushname == 0)
00841        pushname = typeMalloc(char, MAX_NAME_SIZE + 1);
00842     _nc_get_type(pushname);
00843 
00844     DEBUG(3, ("pushing token: `%s', class %d",
00845              _nc_curr_token.tk_name, pushtype));
00846 }
00847 
00848 /*
00849  * Panic mode error recovery - skip everything until a "ch" is found.
00850  */
00851 NCURSES_EXPORT(void)
00852 _nc_panic_mode(char ch)
00853 {
00854     int c;
00855 
00856     for (;;) {
00857        c = next_char();
00858        if (c == ch)
00859            return;
00860        if (c == EOF)
00861            return;
00862     }
00863 }