X-Git-Url: https://ncurses.scripts.mit.edu/?p=ncurses.git;a=blobdiff_plain;f=ncurses%2Ftinfo%2Fcomp_scan.c;h=b2072577a49989c50d5922e2dbf51659a6e85d3a;hp=e937f7eb5adac719db9787a2b771260d098d5838;hb=86b16a498d6d545c03dceff7636d269eb7eb1e8f;hpb=027ae42953e3186daed8f3882da73de48291b606 diff --git a/ncurses/tinfo/comp_scan.c b/ncurses/tinfo/comp_scan.c index e937f7eb..b2072577 100644 --- a/ncurses/tinfo/comp_scan.c +++ b/ncurses/tinfo/comp_scan.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 1998-2005,2006 Free Software Foundation, Inc. * + * Copyright (c) 1998-2016,2017 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * @@ -48,10 +48,9 @@ #include #include -#include #include -MODULE_ID("$Id: comp_scan.c,v 1.78 2006/12/16 19:17:01 tom Exp $") +MODULE_ID("$Id: comp_scan.c,v 1.108 2017/08/25 22:57:21 tom Exp $") /* * Maximum length of string capability we'll accept before raising an error. @@ -61,19 +60,14 @@ MODULE_ID("$Id: comp_scan.c,v 1.78 2006/12/16 19:17:01 tom Exp $") #define iswhite(ch) (ch == ' ' || ch == '\t') -NCURSES_EXPORT_VAR(int) -_nc_syntax = 0; /* termcap or terminfo? */ -NCURSES_EXPORT_VAR(long) -_nc_curr_file_pos = 0; /* file offset of current line */ -NCURSES_EXPORT_VAR(long) -_nc_comment_start = 0; /* start of comment range before name */ -NCURSES_EXPORT_VAR(long) -_nc_comment_end = 0; /* end of comment range before name */ -NCURSES_EXPORT_VAR(long) -_nc_start_line = 0; /* start line of current entry */ - -NCURSES_EXPORT_VAR(struct token) -_nc_curr_token = +NCURSES_EXPORT_VAR (int) _nc_syntax = 0; /* termcap or terminfo? */ +NCURSES_EXPORT_VAR (int) _nc_strict_bsd = 1; /* ncurses extended termcap? */ +NCURSES_EXPORT_VAR (long) _nc_curr_file_pos = 0; /* file offset of current line */ +NCURSES_EXPORT_VAR (long) _nc_comment_start = 0; /* start of comment range before name */ +NCURSES_EXPORT_VAR (long) _nc_comment_end = 0; /* end of comment range before name */ +NCURSES_EXPORT_VAR (long) _nc_start_line = 0; /* start line of current entry */ + +NCURSES_EXPORT_VAR (struct token) _nc_curr_token = { 0, 0, 0 }; @@ -91,8 +85,7 @@ static int pushtype; /* type of pushback token */ static char *pushname; #if NCURSES_EXT_FUNCS -NCURSES_EXPORT_VAR(bool) -_nc_disable_period = FALSE; /* used by tic -a option */ +NCURSES_EXPORT_VAR (bool) _nc_disable_period = FALSE; /* used by tic -a option */ #endif /***************************************************************************** @@ -135,14 +128,19 @@ _nc_reset_input(FILE *fp, char *buf) * Returns the final nonblank character on the current input buffer */ static int -last_char(void) +last_char(int from_end) { size_t len = strlen(bufptr); + int result = 0; + while (len--) { - if (!isspace(UChar(bufptr[len]))) - return bufptr[len]; + if (!isspace(UChar(bufptr[len]))) { + if (from_end < (int) len) + result = bufptr[(int) len - from_end]; + break; + } } - return 0; + return result; } /* @@ -170,6 +168,8 @@ next_char(void) if (result != 0) { FreeAndNull(result); FreeAndNull(pushname); + bufptr = 0; + bufstart = 0; allocated = 0; } /* @@ -191,18 +191,19 @@ next_char(void) * 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 { + size_t used = 0; bufstart = 0; - used = 0; do { if (used + (LEXBUFSIZ / 4) >= allocated) { allocated += (allocated + LEXBUFSIZ); result = typeRealloc(char, allocated, result); if (result == 0) return (EOF); + if (bufstart) + bufstart = result; } if (used == 0) _nc_curr_file_pos = ftell(yyin); @@ -210,15 +211,21 @@ next_char(void) if (fgets(result + used, (int) (allocated - used), yyin) != 0) { bufstart = result; if (used == 0) { + if (_nc_curr_line == 0 + && IS_TIC_MAGIC(result)) { + _nc_err_abort("This is a compiled terminal description, not a source"); + } _nc_curr_line++; _nc_curr_col = 0; } } else { if (used != 0) - strcat(result, "\n"); + _nc_STRCAT(result, "\n", allocated); } if ((bufptr = bufstart) != 0) { used = strlen(bufptr); + if (used == 0) + return (EOF); while (iswhite(*bufptr)) { if (*bufptr == '\t') { _nc_curr_col = (_nc_curr_col | 7) + 1; @@ -259,12 +266,12 @@ next_char(void) } static void -push_back(char c) +push_back(int c) /* push a character back onto the input stream */ { if (bufptr == bufstart) _nc_syserr_abort("Can't backspace off beginning of line"); - *--bufptr = c; + *--bufptr = (char) c; _nc_curr_col--; } @@ -293,6 +300,17 @@ eat_escaped_newline(int ch) return ch; } +#define TOK_BUF_SIZE MAX_ENTRY_SIZE + +#define OkToAdd() \ + ((tok_ptr - tok_buf) < (TOK_BUF_SIZE - 2)) + +#define AddCh(ch) \ + *tok_ptr++ = (char) ch; \ + *tok_ptr = '\0' + +static char *tok_buf; + /* * int * get_token() @@ -330,15 +348,14 @@ NCURSES_EXPORT(int) _nc_get_token(bool silent) { static const char terminfo_punct[] = "@%&*!#"; - static char *buffer; - char *after_list; - char *after_name; + char *after_name; /* after primary name */ + char *after_list; /* after primary and alias list */ char *numchk; - char *ptr; + char *tok_ptr; char *s; char numbuf[80]; - int ch; + int ch, c0, c1; int dot_flag = FALSE; int type; long number; @@ -366,11 +383,10 @@ _nc_get_token(bool silent) if (end_of_stream()) { yyin = 0; - next_char(); /* frees its allocated memory */ - if (buffer != 0) { - if (_nc_curr_token.tk_name == buffer) + (void) next_char(); /* frees its allocated memory */ + if (tok_buf != 0) { + if (_nc_curr_token.tk_name == tok_buf) _nc_curr_token.tk_name = 0; - FreeAndNull(buffer); } return (EOF); } @@ -384,6 +400,7 @@ _nc_get_token(bool silent) } ch = eat_escaped_newline(ch); + _nc_curr_token.tk_valstring = 0; #ifdef TRACE old_line = _nc_curr_line; @@ -418,23 +435,23 @@ _nc_get_token(bool silent) #if NCURSES_EXT_FUNCS && !(ch == '.' && _nc_disable_period) #endif - && !strchr(terminfo_punct, (char) ch)) { + && ((strchr) (terminfo_punct, (char) ch) == 0)) { if (!silent) _nc_warning("Illegal character (expected alphanumeric or %s) - '%s'", - terminfo_punct, unctrl((chtype) ch)); + terminfo_punct, unctrl(UChar(ch))); _nc_panic_mode(separator); goto start_token; } - if (buffer == 0) - buffer = typeMalloc(char, MAX_ENTRY_SIZE); + if (tok_buf == 0) + tok_buf = typeMalloc(char, TOK_BUF_SIZE); #ifdef TRACE old_line = _nc_curr_line; old_col = _nc_curr_col; #endif - ptr = buffer; - *(ptr++) = ch; + tok_ptr = tok_buf; + AddCh(ch); if (first_column) { _nc_comment_start = token_start; @@ -448,10 +465,10 @@ _nc_get_token(bool silent) if (ch == EOF) { _nc_err_abort(MSG_NO_INPUTS); } else if (ch == '|') { - after_list = ptr; + after_list = tok_ptr; if (after_name == 0) - after_name = ptr; - } else if (ch == ':' && last_char() != ',') { + after_name = tok_ptr; + } else if (ch == ':' && last_char(0) != ',') { _nc_syntax = SYN_TERMCAP; separator = ':'; break; @@ -465,18 +482,74 @@ _nc_get_token(bool silent) 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. + * We saw a comma, but are not entirely sure this is + * terminfo format, since we can still be parsing the + * description field (for either syntax). + * + * A properly formatted termcap line ends with either a + * colon, or a backslash after a colon. It is possible + * to have a backslash in the middle of a capability, but + * then there would be no leading whitespace on the next + * line - something we want to discourage. */ + c0 = last_char(0); + c1 = last_char(1); + if (c1 != ':' && c0 != '\\' && c0 != ':') { + bool capability = FALSE; + + /* + * Since it is not termcap, assume the line is terminfo + * format. However, the comma can be embedded in a + * description field. It also can be a separator + * between a description field and a capability. + * + * Improve the guess by checking if the next word after + * the comma does not look like a capability. In that + * case, extend the description past the comma. + */ + for (s = bufptr; isspace(UChar(*s)); ++s) { + ; + } + if (islower(UChar(*s))) { + char *name = s; + while (isalnum(UChar(*s))) { + ++s; + } + if (*s == '#' || *s == '=' || *s == '@') { + /* + * Checking solely with syntax allows us to + * support extended capabilities with string + * values. + */ + capability = TRUE; + } else if (*s == ',') { + c0 = *s; + *s = '\0'; + /* + * Otherwise, we can handle predefined boolean + * capabilities, still aided by syntax. + */ + if (_nc_find_entry(name, + _nc_get_hash_table(FALSE))) { + capability = TRUE; + } + *s = (char) c0; + } + } + if (capability) { + break; + } + } } else ch = eat_escaped_newline(ch); - *ptr++ = ch; + if (OkToAdd()) { + AddCh(ch); + } else { + break; + } } - ptr[0] = '\0'; + *tok_ptr = '\0'; if (_nc_syntax == ERR) { /* * Grrr...what we ought to do here is barf, complaining that @@ -488,9 +561,11 @@ _nc_get_token(bool silent) separator = ':'; } else if (_nc_syntax == SYN_TERMINFO) { /* throw away trailing /, *$/ */ - for (--ptr; iswhite(*ptr) || *ptr == ','; ptr--) + for (--tok_ptr; + iswhite(*tok_ptr) || *tok_ptr == ','; + tok_ptr--) continue; - ptr[1] = '\0'; + tok_ptr[1] = '\0'; } /* @@ -501,8 +576,8 @@ _nc_get_token(bool silent) if (after_name != 0) { ch = *after_name; *after_name = '\0'; - _nc_set_type(buffer); - *after_name = ch; + _nc_set_type(tok_buf); + *after_name = (char) ch; } /* @@ -517,7 +592,7 @@ _nc_get_token(bool silent) _nc_warning("older tic versions may treat the description field as an alias"); } } else { - after_list = buffer + strlen(buffer); + after_list = tok_buf + strlen(tok_buf); DEBUG(1, ("missing description")); } @@ -526,7 +601,7 @@ _nc_get_token(bool silent) * 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) { + for (s = tok_buf; s < after_list; ++s) { if (isspace(UChar(*s))) { if (!silent) _nc_warning("whitespace in name or alias field"); @@ -542,7 +617,7 @@ _nc_get_token(bool silent) } } - _nc_curr_token.tk_name = buffer; + _nc_curr_token.tk_name = tok_buf; type = NAMES; } else { if (had_newline && _nc_syntax == SYN_TERMCAP) { @@ -559,30 +634,35 @@ _nc_get_token(bool silent) break; } } - *(ptr++) = ch; + if (OkToAdd()) { + AddCh(ch); + } else { + ch = EOF; + break; + } } - *ptr++ = '\0'; + *tok_ptr++ = '\0'; /* separate name/value in buffer */ switch (ch) { case ',': case ':': if (ch != separator) _nc_err_abort("Separator inconsistent with syntax"); - _nc_curr_token.tk_name = buffer; + _nc_curr_token.tk_name = tok_buf; 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; + tok_buf, unctrl(UChar(ch))); + _nc_curr_token.tk_name = tok_buf; type = CANCEL; break; case '#': found = 0; while (isalnum(ch = next_char())) { - numbuf[found++] = ch; + numbuf[found++] = (char) ch; if (found >= sizeof(numbuf) - 1) break; } @@ -590,21 +670,29 @@ _nc_get_token(bool silent) number = strtol(numbuf, &numchk, 0); if (!silent) { if (numchk == numbuf) - _nc_warning("no value given for `%s'", buffer); + _nc_warning("no value given for `%s'", tok_buf); if ((*numchk != '\0') || (ch != separator)) - _nc_warning("Missing separator"); + _nc_warning("Missing separator for `%s'", tok_buf); + if (number < 0) + _nc_warning("value of `%s' cannot be negative", tok_buf); + if (number > MAX_OF_TYPE(NCURSES_INT2)) { + _nc_warning("limiting value of `%s' from %#lx to %#x", + tok_buf, + number, MAX_OF_TYPE(NCURSES_INT2)); + number = MAX_OF_TYPE(NCURSES_INT2); + } } - _nc_curr_token.tk_name = buffer; - _nc_curr_token.tk_valnumber = number; + _nc_curr_token.tk_name = tok_buf; + _nc_curr_token.tk_valnumber = (int) number; type = NUMBER; break; case '=': - ch = _nc_trans_string(ptr, buffer + MAX_ENTRY_SIZE); + ch = _nc_trans_string(tok_ptr, tok_buf + TOK_BUF_SIZE); if (!silent && ch != separator) _nc_warning("Missing separator"); - _nc_curr_token.tk_name = buffer; - _nc_curr_token.tk_valstring = ptr; + _nc_curr_token.tk_name = tok_buf; + _nc_curr_token.tk_valstring = tok_ptr; type = STRING; break; @@ -615,7 +703,7 @@ _nc_get_token(bool silent) /* just to get rid of the compiler warning */ type = UNDEF; if (!silent) - _nc_warning("Illegal character - '%s'", unctrl((chtype) ch)); + _nc_warning("Illegal character - '%s'", unctrl(UChar(ch))); } } /* end else (first_column == FALSE) */ } /* end else (ch != EOF) */ @@ -708,50 +796,58 @@ _nc_trans_string(char *ptr, char *last) int count = 0; int number = 0; int i, c; - chtype ch, last_ch = '\0'; + int last_ch = '\0'; bool ignored = FALSE; bool long_warning = FALSE; - while ((ch = c = next_char()) != (chtype) separator && c != EOF) { - if (ptr == (last - 1)) + while ((c = next_char()) != separator && c != EOF) { + if (ptr >= (last - 1)) { + if (c != EOF) { + while ((c = next_char()) != separator && c != EOF) { + ; + } + } break; + } if ((_nc_syntax == SYN_TERMCAP) && c == '\n') break; - if (ch == '^' && last_ch != '%') { - ch = c = next_char(); + if (c == '^' && last_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 (!(is7bits(c) && isprint(c))) { + _nc_warning("Illegal ^ character - '%s'", unctrl(UChar(c))); } - if (ch == '?') { + if (c == '?' && (_nc_syntax != SYN_TERMCAP)) { *(ptr++) = '\177'; - if (_nc_tracing) - _nc_warning("Allow ^? as synonym for \\177"); } else { - if ((ch &= 037) == 0) - ch = 128; - *(ptr++) = (char) (ch); + if ((c &= 037) == 0) + c = 128; + *(ptr++) = (char) (c); } - } else if (ch == '\\') { - ch = c = next_char(); + } else if (c == '\\') { + bool strict_bsd = ((_nc_syntax == SYN_TERMCAP) && _nc_strict_bsd); + + c = next_char(); if (c == EOF) _nc_err_abort(MSG_NO_INPUTS); - if (ch >= '0' && ch <= '7') { - number = ch - '0'; + if (isoctal(c) || (strict_bsd && isdigit(c))) { + number = c - '0'; for (i = 0; i < 2; i++) { - ch = c = next_char(); + c = next_char(); if (c == EOF) _nc_err_abort(MSG_NO_INPUTS); - if (c < '0' || c > '7') { + if (!isoctal(c)) { if (isdigit(c)) { - _nc_warning("Non-octal digit `%c' in \\ sequence", c); - /* allow the digit; it'll do less harm */ + if (!strict_bsd) { + _nc_warning("Non-octal digit `%c' in \\ sequence", c); + /* allow the digit; it'll do less harm */ + } } else { - push_back((char) c); + push_back(c); break; } } @@ -759,21 +855,16 @@ _nc_trans_string(char *ptr, char *last) number = number * 8 + c - '0'; } - if (number == 0) + number = UChar(number); + if (number == 0 && !strict_bsd) 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; @@ -786,10 +877,6 @@ _nc_trans_string(char *ptr, char *last) *(ptr++) = '\010'; break; - case 's': - *(ptr++) = ' '; - break; - case 'f': *(ptr++) = '\014'; break; @@ -810,40 +897,57 @@ _nc_trans_string(char *ptr, char *last) *(ptr++) = ','; break; - case ':': - *(ptr++) = ':'; - break; - case '\n': continue; default: - _nc_warning("Illegal character '%s' in \\ sequence", - unctrl(ch)); + if ((_nc_syntax == SYN_TERMINFO) || !_nc_strict_bsd) { + switch (c) { + case 'a': + c = '\007'; + break; + case 'e': + c = '\033'; + break; + case 'l': + c = '\n'; + break; + case 's': + c = ' '; + break; + case ':': + c = ':'; + break; + default: + _nc_warning("Illegal character '%s' in \\ sequence", + unctrl(UChar(c))); + break; + } + } /* FALLTHRU */ case '|': - *(ptr++) = (char) ch; - } /* endswitch (ch) */ - } /* endelse (ch < '0' || ch > '7') */ + *(ptr++) = (char) c; + } /* endswitch (c) */ + } /* endelse (c < '0' || c > '7') */ } - /* end else if (ch == '\\') */ - else if (ch == '\n' && (_nc_syntax == SYN_TERMINFO)) { + /* end else if (c == '\\') */ + else if (c == '\n' && (_nc_syntax == SYN_TERMINFO)) { /* * Newlines embedded in a terminfo string are ignored, provided * that the next line begins with whitespace. */ ignored = TRUE; } else { - *(ptr++) = (char) ch; + *(ptr++) = (char) c; } if (!ignored) { if (_nc_curr_col <= 1) { - push_back(ch); - ch = '\n'; + push_back(c); + c = '\n'; break; } - last_ch = ch; + last_ch = c; count++; } ignored = FALSE; @@ -856,7 +960,7 @@ _nc_trans_string(char *ptr, char *last) *ptr = '\0'; - return (ch); + return (c); } /* @@ -893,10 +997,8 @@ _nc_push_token(int tokclass) NCURSES_EXPORT(void) _nc_panic_mode(char ch) { - int c; - for (;;) { - c = next_char(); + int c = next_char(); if (c == ch) return; if (c == EOF) @@ -911,5 +1013,8 @@ _nc_comp_scan_leaks(void) if (pushname != 0) { FreeAndNull(pushname); } + if (tok_buf != 0) { + FreeAndNull(tok_buf); + } } #endif