blob: fe6e8e7631cee4c30aa09bb79c2dc08438ca7c15 [file] [log] [blame]
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301/****************************************************************************
Steve Kondikae271bc2015-11-15 02:50:53 +01002 * Copyright (c) 1998-2012,2013 Free Software Foundation, Inc. *
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303 * *
4 * Permission is hereby granted, free of charge, to any person obtaining a *
5 * copy of this software and associated documentation files (the *
6 * "Software"), to deal in the Software without restriction, including *
7 * without limitation the rights to use, copy, modify, merge, publish, *
8 * distribute, distribute with modifications, sublicense, and/or sell *
9 * copies of the Software, and to permit persons to whom the Software is *
10 * furnished to do so, subject to the following conditions: *
11 * *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
14 * *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
22 * *
23 * Except as contained in this notice, the name(s) of the above copyright *
24 * holders shall not be used in advertising or otherwise to promote the *
25 * sale, use or other dealings in this Software without prior written *
26 * authorization. *
27 ****************************************************************************/
28
29/****************************************************************************
30 * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
31 * and: Eric S. Raymond <esr@snark.thyrsus.com> *
32 * and: Thomas E. Dickey 1996 on *
33 ****************************************************************************/
34
35/*
36 * comp_scan.c --- Lexical scanner for terminfo compiler.
37 *
38 * _nc_reset_input()
39 * _nc_get_token()
40 * _nc_panic_mode()
41 * int _nc_syntax;
42 * int _nc_curr_line;
43 * long _nc_curr_file_pos;
44 * long _nc_comment_start;
45 * long _nc_comment_end;
46 */
47
48#include <curses.priv.h>
49
50#include <ctype.h>
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +053051#include <tic.h>
52
Steve Kondikae271bc2015-11-15 02:50:53 +010053MODULE_ID("$Id: comp_scan.c,v 1.102 2013/11/16 19:57:50 tom Exp $")
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +053054
55/*
56 * Maximum length of string capability we'll accept before raising an error.
57 * Yes, there is a real capability in /etc/termcap this long, an "is".
58 */
59#define MAXCAPLEN 600
60
61#define iswhite(ch) (ch == ' ' || ch == '\t')
62
Steve Kondikae271bc2015-11-15 02:50:53 +010063NCURSES_EXPORT_VAR (int) _nc_syntax = 0; /* termcap or terminfo? */
64NCURSES_EXPORT_VAR (int) _nc_strict_bsd = 1; /* ncurses extended termcap? */
65NCURSES_EXPORT_VAR (long) _nc_curr_file_pos = 0; /* file offset of current line */
66NCURSES_EXPORT_VAR (long) _nc_comment_start = 0; /* start of comment range before name */
67NCURSES_EXPORT_VAR (long) _nc_comment_end = 0; /* end of comment range before name */
68NCURSES_EXPORT_VAR (long) _nc_start_line = 0; /* start line of current entry */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +053069
Steve Kondikae271bc2015-11-15 02:50:53 +010070NCURSES_EXPORT_VAR (struct token) _nc_curr_token =
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +053071{
72 0, 0, 0
73};
74
75/*****************************************************************************
76 *
77 * Token-grabbing machinery
78 *
79 *****************************************************************************/
80
81static bool first_column; /* See 'next_char()' below */
82static bool had_newline;
83static char separator; /* capability separator */
84static int pushtype; /* type of pushback token */
85static char *pushname;
86
87#if NCURSES_EXT_FUNCS
Steve Kondikae271bc2015-11-15 02:50:53 +010088NCURSES_EXPORT_VAR (bool) _nc_disable_period = FALSE; /* used by tic -a option */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +053089#endif
90
91/*****************************************************************************
92 *
93 * Character-stream handling
94 *
95 *****************************************************************************/
96
97#define LEXBUFSIZ 1024
98
99static char *bufptr; /* otherwise, the input buffer pointer */
100static char *bufstart; /* start of buffer so we can compute offsets */
101static FILE *yyin; /* scanner's input file descriptor */
102
103/*
104 * _nc_reset_input()
105 *
106 * Resets the input-reading routines. Used on initialization,
107 * or after a seek has been done. Exactly one argument must be
108 * non-null.
109 */
110
111NCURSES_EXPORT(void)
112_nc_reset_input(FILE *fp, char *buf)
113{
114 pushtype = NO_PUSHBACK;
115 if (pushname != 0)
116 pushname[0] = '\0';
117 yyin = fp;
118 bufstart = bufptr = buf;
119 _nc_curr_file_pos = 0L;
120 if (fp != 0)
121 _nc_curr_line = 0;
122 _nc_curr_col = 0;
123}
124
125/*
126 * int last_char()
127 *
128 * Returns the final nonblank character on the current input buffer
129 */
130static int
Steve Kondikae271bc2015-11-15 02:50:53 +0100131last_char(int from_end)
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530132{
133 size_t len = strlen(bufptr);
Steve Kondikae271bc2015-11-15 02:50:53 +0100134 int result = 0;
135
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530136 while (len--) {
Steve Kondikae271bc2015-11-15 02:50:53 +0100137 if (!isspace(UChar(bufptr[len]))) {
138 if (from_end < (int) len)
139 result = bufptr[(int) len - from_end];
140 break;
141 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530142 }
Steve Kondikae271bc2015-11-15 02:50:53 +0100143 return result;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530144}
145
146/*
147 * int next_char()
148 *
149 * Returns the next character in the input stream. Comments and leading
150 * white space are stripped.
151 *
152 * The global state variable 'firstcolumn' is set TRUE if the character
153 * returned is from the first column of the input line.
154 *
155 * The global variable _nc_curr_line is incremented for each new line.
156 * The global variable _nc_curr_file_pos is set to the file offset of the
157 * beginning of each line.
158 */
159
160static int
161next_char(void)
162{
163 static char *result;
164 static size_t allocated;
165 int the_char;
166
167 if (!yyin) {
168 if (result != 0) {
169 FreeAndNull(result);
170 FreeAndNull(pushname);
171 allocated = 0;
172 }
173 /*
174 * An string with an embedded null will truncate the input. This is
175 * intentional (we don't read binary files here).
176 */
177 if (bufptr == 0 || *bufptr == '\0')
178 return (EOF);
179 if (*bufptr == '\n') {
180 _nc_curr_line++;
181 _nc_curr_col = 0;
182 } else if (*bufptr == '\t') {
183 _nc_curr_col = (_nc_curr_col | 7);
184 }
185 } else if (!bufptr || !*bufptr) {
186 /*
187 * In theory this could be recoded to do its I/O one character at a
188 * time, saving the buffer space. In practice, this turns out to be
189 * quite hard to get completely right. Try it and see. If you
190 * succeed, don't forget to hack push_back() correspondingly.
191 */
192 size_t used;
193 size_t len;
194
195 do {
196 bufstart = 0;
197 used = 0;
198 do {
199 if (used + (LEXBUFSIZ / 4) >= allocated) {
200 allocated += (allocated + LEXBUFSIZ);
201 result = typeRealloc(char, allocated, result);
202 if (result == 0)
203 return (EOF);
Steve Kondikae271bc2015-11-15 02:50:53 +0100204 if (bufstart)
205 bufstart = result;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530206 }
207 if (used == 0)
208 _nc_curr_file_pos = ftell(yyin);
209
210 if (fgets(result + used, (int) (allocated - used), yyin) != 0) {
211 bufstart = result;
212 if (used == 0) {
Steve Kondikae271bc2015-11-15 02:50:53 +0100213 if (_nc_curr_line == 0
214 && IS_TIC_MAGIC(result)) {
215 _nc_err_abort("This is a compiled terminal description, not a source");
216 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530217 _nc_curr_line++;
218 _nc_curr_col = 0;
219 }
220 } else {
221 if (used != 0)
Steve Kondikae271bc2015-11-15 02:50:53 +0100222 _nc_STRCAT(result, "\n", allocated);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530223 }
224 if ((bufptr = bufstart) != 0) {
225 used = strlen(bufptr);
226 while (iswhite(*bufptr)) {
227 if (*bufptr == '\t') {
228 _nc_curr_col = (_nc_curr_col | 7) + 1;
229 } else {
230 _nc_curr_col++;
231 }
232 bufptr++;
233 }
234
235 /*
236 * Treat a trailing <cr><lf> the same as a <newline> so we
237 * can read files on OS/2, etc.
238 */
239 if ((len = strlen(bufptr)) > 1) {
240 if (bufptr[len - 1] == '\n'
241 && bufptr[len - 2] == '\r') {
242 len--;
243 bufptr[len - 1] = '\n';
244 bufptr[len] = '\0';
245 }
246 }
247 } else {
248 return (EOF);
249 }
250 } while (bufptr[len - 1] != '\n'); /* complete a line */
251 } while (result[0] == '#'); /* ignore comments */
252 } else if (*bufptr == '\t') {
253 _nc_curr_col = (_nc_curr_col | 7);
254 }
255
256 first_column = (bufptr == bufstart);
257 if (first_column)
258 had_newline = FALSE;
259
260 _nc_curr_col++;
261 the_char = *bufptr++;
262 return UChar(the_char);
263}
264
265static void
Steve Kondikae271bc2015-11-15 02:50:53 +0100266push_back(int c)
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530267/* push a character back onto the input stream */
268{
269 if (bufptr == bufstart)
270 _nc_syserr_abort("Can't backspace off beginning of line");
Steve Kondikae271bc2015-11-15 02:50:53 +0100271 *--bufptr = (char) c;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530272 _nc_curr_col--;
273}
274
275static long
276stream_pos(void)
277/* return our current character position in the input stream */
278{
279 return (yyin ? ftell(yyin) : (bufptr ? bufptr - bufstart : 0));
280}
281
282static bool
283end_of_stream(void)
284/* are we at end of input? */
285{
286 return ((yyin ? feof(yyin) : (bufptr && *bufptr == '\0'))
287 ? TRUE : FALSE);
288}
289
290/* Assume we may be looking at a termcap-style continuation */
291static NCURSES_INLINE int
292eat_escaped_newline(int ch)
293{
294 if (ch == '\\')
295 while ((ch = next_char()) == '\n' || iswhite(ch))
296 continue;
297 return ch;
298}
299
300#define TOK_BUF_SIZE MAX_ENTRY_SIZE
301
302#define OkToAdd() \
303 ((tok_ptr - tok_buf) < (TOK_BUF_SIZE - 2))
304
305#define AddCh(ch) \
306 *tok_ptr++ = (char) ch; \
307 *tok_ptr = '\0'
308
Steve Kondikae271bc2015-11-15 02:50:53 +0100309static char *tok_buf;
310
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530311/*
312 * int
313 * get_token()
314 *
315 * Scans the input for the next token, storing the specifics in the
316 * global structure 'curr_token' and returning one of the following:
317 *
318 * NAMES A line beginning in column 1. 'name'
319 * will be set to point to everything up to but
320 * not including the first separator on the line.
321 * BOOLEAN An entry consisting of a name followed by
322 * a separator. 'name' will be set to point to
323 * the name of the capability.
324 * NUMBER An entry of the form
325 * name#digits,
326 * 'name' will be set to point to the capability
327 * name and 'valnumber' to the number given.
328 * STRING An entry of the form
329 * name=characters,
330 * 'name' is set to the capability name and
331 * 'valstring' to the string of characters, with
332 * input translations done.
333 * CANCEL An entry of the form
334 * name@,
335 * 'name' is set to the capability name and
336 * 'valnumber' to -1.
337 * EOF The end of the file has been reached.
338 *
339 * A `separator' is either a comma or a semicolon, depending on whether
340 * we are in termcap or terminfo mode.
341 *
342 */
343
344NCURSES_EXPORT(int)
345_nc_get_token(bool silent)
346{
347 static const char terminfo_punct[] = "@%&*!#";
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530348
Steve Kondikae271bc2015-11-15 02:50:53 +0100349 char *after_name; /* after primary name */
350 char *after_list; /* after primary and alias list */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530351 char *numchk;
352 char *tok_ptr;
353 char *s;
354 char numbuf[80];
Steve Kondikae271bc2015-11-15 02:50:53 +0100355 int ch, c0, c1;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530356 int dot_flag = FALSE;
357 int type;
358 long number;
359 long token_start;
360 unsigned found;
361#ifdef TRACE
362 int old_line;
363 int old_col;
364#endif
365
366 if (pushtype != NO_PUSHBACK) {
367 int retval = pushtype;
368
369 _nc_set_type(pushname != 0 ? pushname : "");
370 DEBUG(3, ("pushed-back token: `%s', class %d",
371 _nc_curr_token.tk_name, pushtype));
372
373 pushtype = NO_PUSHBACK;
374 if (pushname != 0)
375 pushname[0] = '\0';
376
377 /* currtok wasn't altered by _nc_push_token() */
378 return (retval);
379 }
380
381 if (end_of_stream()) {
382 yyin = 0;
Steve Kondikae271bc2015-11-15 02:50:53 +0100383 (void) next_char(); /* frees its allocated memory */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530384 if (tok_buf != 0) {
385 if (_nc_curr_token.tk_name == tok_buf)
386 _nc_curr_token.tk_name = 0;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530387 }
388 return (EOF);
389 }
390
391 start_token:
392 token_start = stream_pos();
393 while ((ch = next_char()) == '\n' || iswhite(ch)) {
394 if (ch == '\n')
395 had_newline = TRUE;
396 continue;
397 }
398
399 ch = eat_escaped_newline(ch);
Steve Kondikae271bc2015-11-15 02:50:53 +0100400 _nc_curr_token.tk_valstring = 0;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530401
402#ifdef TRACE
403 old_line = _nc_curr_line;
404 old_col = _nc_curr_col;
405#endif
406 if (ch == EOF)
407 type = EOF;
408 else {
409 /* if this is a termcap entry, skip a leading separator */
410 if (separator == ':' && ch == ':')
411 ch = next_char();
412
413 if (ch == '.'
414#if NCURSES_EXT_FUNCS
415 && !_nc_disable_period
416#endif
417 ) {
418 dot_flag = TRUE;
419 DEBUG(8, ("dot-flag set"));
420
421 while ((ch = next_char()) == '.' || iswhite(ch))
422 continue;
423 }
424
425 if (ch == EOF) {
426 type = EOF;
427 goto end_of_token;
428 }
429
430 /* have to make some punctuation chars legal for terminfo */
431 if (!isalnum(UChar(ch))
432#if NCURSES_EXT_FUNCS
433 && !(ch == '.' && _nc_disable_period)
434#endif
Steve Kondikae271bc2015-11-15 02:50:53 +0100435 && ((strchr) (terminfo_punct, (char) ch) == 0)) {
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530436 if (!silent)
437 _nc_warning("Illegal character (expected alphanumeric or %s) - '%s'",
Steve Kondikae271bc2015-11-15 02:50:53 +0100438 terminfo_punct, unctrl(UChar(ch)));
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530439 _nc_panic_mode(separator);
440 goto start_token;
441 }
442
443 if (tok_buf == 0)
444 tok_buf = typeMalloc(char, TOK_BUF_SIZE);
445
446#ifdef TRACE
447 old_line = _nc_curr_line;
448 old_col = _nc_curr_col;
449#endif
450 tok_ptr = tok_buf;
451 AddCh(ch);
452
453 if (first_column) {
454 _nc_comment_start = token_start;
455 _nc_comment_end = _nc_curr_file_pos;
456 _nc_start_line = _nc_curr_line;
457
458 _nc_syntax = ERR;
459 after_name = 0;
460 after_list = 0;
461 while ((ch = next_char()) != '\n') {
462 if (ch == EOF) {
463 _nc_err_abort(MSG_NO_INPUTS);
464 } else if (ch == '|') {
465 after_list = tok_ptr;
466 if (after_name == 0)
467 after_name = tok_ptr;
Steve Kondikae271bc2015-11-15 02:50:53 +0100468 } else if (ch == ':' && last_char(0) != ',') {
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530469 _nc_syntax = SYN_TERMCAP;
470 separator = ':';
471 break;
472 } else if (ch == ',') {
473 _nc_syntax = SYN_TERMINFO;
474 separator = ',';
475 /*
476 * If we did not see a '|', then we found a name with no
477 * aliases or description.
478 */
479 if (after_name == 0)
480 break;
481 /*
Steve Kondikae271bc2015-11-15 02:50:53 +0100482 * We saw a comma, but are not entirely sure this is
483 * terminfo format, since we can still be parsing the
484 * description field (for either syntax).
485 *
486 * A properly formatted termcap line ends with either a
487 * colon, or a backslash after a colon. It is possible
488 * to have a backslash in the middle of a capability, but
489 * then there would be no leading whitespace on the next
490 * line - something we want to discourage.
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530491 */
Steve Kondikae271bc2015-11-15 02:50:53 +0100492 c0 = last_char(0);
493 c1 = last_char(1);
494 if (c1 != ':' && c0 != '\\' && c0 != ':') {
495 bool capability = FALSE;
496
497 /*
498 * Since it is not termcap, assume the line is terminfo
499 * format. However, the comma can be embedded in a
500 * description field. It also can be a separator
501 * between a description field and a capability.
502 *
503 * Improve the guess by checking if the next word after
504 * the comma does not look like a capability. In that
505 * case, extend the description past the comma.
506 */
507 for (s = bufptr; isspace(UChar(*s)); ++s) {
508 ;
509 }
510 if (islower(UChar(*s))) {
511 char *name = s;
512 while (isalnum(UChar(*s))) {
513 ++s;
514 }
515 if (*s == '#' || *s == '=' || *s == '@') {
516 /*
517 * Checking solely with syntax allows us to
518 * support extended capabilities with string
519 * values.
520 */
521 capability = TRUE;
522 } else if (*s == ',') {
523 c0 = *s;
524 *s = '\0';
525 /*
526 * Otherwise, we can handle predefined boolean
527 * capabilities, still aided by syntax.
528 */
529 if (_nc_find_entry(name,
530 _nc_get_hash_table(FALSE))) {
531 capability = TRUE;
532 }
533 *s = (char) c0;
534 }
535 }
536 if (capability) {
537 break;
538 }
539 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530540 } else
541 ch = eat_escaped_newline(ch);
542
543 if (OkToAdd()) {
544 AddCh(ch);
545 } else {
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530546 break;
547 }
548 }
549 *tok_ptr = '\0';
550 if (_nc_syntax == ERR) {
551 /*
552 * Grrr...what we ought to do here is barf, complaining that
553 * the entry is malformed. But because a couple of name fields
554 * in the 8.2 termcap file end with |\, we just have to assume
555 * it's termcap syntax.
556 */
557 _nc_syntax = SYN_TERMCAP;
558 separator = ':';
559 } else if (_nc_syntax == SYN_TERMINFO) {
560 /* throw away trailing /, *$/ */
561 for (--tok_ptr;
562 iswhite(*tok_ptr) || *tok_ptr == ',';
563 tok_ptr--)
564 continue;
565 tok_ptr[1] = '\0';
566 }
567
568 /*
569 * This is the soonest we have the terminal name fetched. Set up
570 * for following warning messages. If there's no '|', then there
571 * is no description.
572 */
573 if (after_name != 0) {
574 ch = *after_name;
575 *after_name = '\0';
576 _nc_set_type(tok_buf);
577 *after_name = (char) ch;
578 }
579
580 /*
581 * Compute the boundary between the aliases and the description
582 * field for syntax-checking purposes.
583 */
584 if (after_list != 0) {
585 if (!silent) {
586 if (*after_list == '\0')
587 _nc_warning("empty longname field");
588 else if (strchr(after_list, ' ') == 0)
589 _nc_warning("older tic versions may treat the description field as an alias");
590 }
591 } else {
592 after_list = tok_buf + strlen(tok_buf);
593 DEBUG(1, ("missing description"));
594 }
595
596 /*
597 * Whitespace in a name field other than the long name can confuse
598 * rdist and some termcap tools. Slashes are a no-no. Other
599 * special characters can be dangerous due to shell expansion.
600 */
601 for (s = tok_buf; s < after_list; ++s) {
602 if (isspace(UChar(*s))) {
603 if (!silent)
604 _nc_warning("whitespace in name or alias field");
605 break;
606 } else if (*s == '/') {
607 if (!silent)
608 _nc_warning("slashes aren't allowed in names or aliases");
609 break;
610 } else if (strchr("$[]!*?", *s)) {
611 if (!silent)
612 _nc_warning("dubious character `%c' in name or alias field", *s);
613 break;
614 }
615 }
616
617 _nc_curr_token.tk_name = tok_buf;
618 type = NAMES;
619 } else {
620 if (had_newline && _nc_syntax == SYN_TERMCAP) {
621 _nc_warning("Missing backslash before newline");
622 had_newline = FALSE;
623 }
624 while ((ch = next_char()) != EOF) {
625 if (!isalnum(UChar(ch))) {
626 if (_nc_syntax == SYN_TERMINFO) {
627 if (ch != '_')
628 break;
629 } else { /* allow ';' for "k;" */
630 if (ch != ';')
631 break;
632 }
633 }
634 if (OkToAdd()) {
635 AddCh(ch);
636 } else {
637 ch = EOF;
638 break;
639 }
640 }
641
642 *tok_ptr++ = '\0'; /* separate name/value in buffer */
643 switch (ch) {
644 case ',':
645 case ':':
646 if (ch != separator)
647 _nc_err_abort("Separator inconsistent with syntax");
648 _nc_curr_token.tk_name = tok_buf;
649 type = BOOLEAN;
650 break;
651 case '@':
652 if ((ch = next_char()) != separator && !silent)
653 _nc_warning("Missing separator after `%s', have %s",
Steve Kondikae271bc2015-11-15 02:50:53 +0100654 tok_buf, unctrl(UChar(ch)));
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530655 _nc_curr_token.tk_name = tok_buf;
656 type = CANCEL;
657 break;
658
659 case '#':
660 found = 0;
661 while (isalnum(ch = next_char())) {
662 numbuf[found++] = (char) ch;
663 if (found >= sizeof(numbuf) - 1)
664 break;
665 }
666 numbuf[found] = '\0';
667 number = strtol(numbuf, &numchk, 0);
668 if (!silent) {
669 if (numchk == numbuf)
670 _nc_warning("no value given for `%s'", tok_buf);
671 if ((*numchk != '\0') || (ch != separator))
672 _nc_warning("Missing separator");
673 }
674 _nc_curr_token.tk_name = tok_buf;
Steve Kondikae271bc2015-11-15 02:50:53 +0100675 _nc_curr_token.tk_valnumber = (int) number;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530676 type = NUMBER;
677 break;
678
679 case '=':
680 ch = _nc_trans_string(tok_ptr, tok_buf + TOK_BUF_SIZE);
681 if (!silent && ch != separator)
682 _nc_warning("Missing separator");
683 _nc_curr_token.tk_name = tok_buf;
684 _nc_curr_token.tk_valstring = tok_ptr;
685 type = STRING;
686 break;
687
688 case EOF:
689 type = EOF;
690 break;
691 default:
692 /* just to get rid of the compiler warning */
693 type = UNDEF;
694 if (!silent)
Steve Kondikae271bc2015-11-15 02:50:53 +0100695 _nc_warning("Illegal character - '%s'", unctrl(UChar(ch)));
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530696 }
697 } /* end else (first_column == FALSE) */
698 } /* end else (ch != EOF) */
699
700 end_of_token:
701
702#ifdef TRACE
703 if (dot_flag == TRUE)
704 DEBUG(8, ("Commented out "));
705
706 if (_nc_tracing >= DEBUG_LEVEL(8)) {
707 _tracef("parsed %d.%d to %d.%d",
708 old_line, old_col,
709 _nc_curr_line, _nc_curr_col);
710 }
711 if (_nc_tracing >= DEBUG_LEVEL(7)) {
712 switch (type) {
713 case BOOLEAN:
714 _tracef("Token: Boolean; name='%s'",
715 _nc_curr_token.tk_name);
716 break;
717
718 case NUMBER:
719 _tracef("Token: Number; name='%s', value=%d",
720 _nc_curr_token.tk_name,
721 _nc_curr_token.tk_valnumber);
722 break;
723
724 case STRING:
725 _tracef("Token: String; name='%s', value=%s",
726 _nc_curr_token.tk_name,
727 _nc_visbuf(_nc_curr_token.tk_valstring));
728 break;
729
730 case CANCEL:
731 _tracef("Token: Cancel; name='%s'",
732 _nc_curr_token.tk_name);
733 break;
734
735 case NAMES:
736
737 _tracef("Token: Names; value='%s'",
738 _nc_curr_token.tk_name);
739 break;
740
741 case EOF:
742 _tracef("Token: End of file");
743 break;
744
745 default:
746 _nc_warning("Bad token type");
747 }
748 }
749#endif
750
751 if (dot_flag == TRUE) /* if commented out, use the next one */
752 type = _nc_get_token(silent);
753
754 DEBUG(3, ("token: `%s', class %d",
755 ((_nc_curr_token.tk_name != 0)
756 ? _nc_curr_token.tk_name
757 : "<null>"),
758 type));
759
760 return (type);
761}
762
763/*
764 * char
765 * trans_string(ptr)
766 *
767 * Reads characters using next_char() until encountering a separator, nl,
768 * or end-of-file. The returned value is the character which caused
769 * reading to stop. The following translations are done on the input:
770 *
771 * ^X goes to ctrl-X (i.e. X & 037)
772 * {\E,\n,\r,\b,\t,\f} go to
773 * {ESCAPE,newline,carriage-return,backspace,tab,formfeed}
774 * {\^,\\} go to {carat,backslash}
775 * \ddd (for ddd = up to three octal digits) goes to the character ddd
776 *
777 * \e == \E
778 * \0 == \200
779 *
780 */
781
782NCURSES_EXPORT(int)
783_nc_trans_string(char *ptr, char *last)
784{
785 int count = 0;
786 int number = 0;
787 int i, c;
Steve Kondikae271bc2015-11-15 02:50:53 +0100788 int last_ch = '\0';
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530789 bool ignored = FALSE;
790 bool long_warning = FALSE;
791
Steve Kondikae271bc2015-11-15 02:50:53 +0100792 while ((c = next_char()) != separator && c != EOF) {
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530793 if (ptr >= (last - 1)) {
794 if (c != EOF) {
795 while ((c = next_char()) != separator && c != EOF) {
796 ;
797 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530798 }
799 break;
800 }
801 if ((_nc_syntax == SYN_TERMCAP) && c == '\n')
802 break;
Steve Kondikae271bc2015-11-15 02:50:53 +0100803 if (c == '^' && last_ch != '%') {
804 c = next_char();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530805 if (c == EOF)
806 _nc_err_abort(MSG_NO_INPUTS);
807
Steve Kondikae271bc2015-11-15 02:50:53 +0100808 if (!(is7bits(c) && isprint(c))) {
809 _nc_warning("Illegal ^ character - '%s'", unctrl(UChar(c)));
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530810 }
Steve Kondikae271bc2015-11-15 02:50:53 +0100811 if (c == '?' && (_nc_syntax != SYN_TERMCAP)) {
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530812 *(ptr++) = '\177';
813 if (_nc_tracing)
814 _nc_warning("Allow ^? as synonym for \\177");
815 } else {
Steve Kondikae271bc2015-11-15 02:50:53 +0100816 if ((c &= 037) == 0)
817 c = 128;
818 *(ptr++) = (char) (c);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530819 }
Steve Kondikae271bc2015-11-15 02:50:53 +0100820 } else if (c == '\\') {
821 bool strict_bsd = ((_nc_syntax == SYN_TERMCAP) && _nc_strict_bsd);
822
823 c = next_char();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530824 if (c == EOF)
825 _nc_err_abort(MSG_NO_INPUTS);
826
Steve Kondikae271bc2015-11-15 02:50:53 +0100827#define isoctal(c) ((c) >= '0' && (c) <= '7')
828
829 if (isoctal(c) || (strict_bsd && isdigit(c))) {
830 number = c - '0';
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530831 for (i = 0; i < 2; i++) {
Steve Kondikae271bc2015-11-15 02:50:53 +0100832 c = next_char();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530833 if (c == EOF)
834 _nc_err_abort(MSG_NO_INPUTS);
835
Steve Kondikae271bc2015-11-15 02:50:53 +0100836 if (!isoctal(c)) {
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530837 if (isdigit(c)) {
Steve Kondikae271bc2015-11-15 02:50:53 +0100838 if (!strict_bsd) {
839 _nc_warning("Non-octal digit `%c' in \\ sequence", c);
840 /* allow the digit; it'll do less harm */
841 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530842 } else {
Steve Kondikae271bc2015-11-15 02:50:53 +0100843 push_back(c);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530844 break;
845 }
846 }
847
848 number = number * 8 + c - '0';
849 }
850
Steve Kondikae271bc2015-11-15 02:50:53 +0100851 number = UChar(number);
852 if (number == 0 && !strict_bsd)
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530853 number = 0200;
854 *(ptr++) = (char) number;
855 } else {
856 switch (c) {
857 case 'E':
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530858 *(ptr++) = '\033';
859 break;
860
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530861 case 'n':
862 *(ptr++) = '\n';
863 break;
864
865 case 'r':
866 *(ptr++) = '\r';
867 break;
868
869 case 'b':
870 *(ptr++) = '\010';
871 break;
872
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530873 case 'f':
874 *(ptr++) = '\014';
875 break;
876
877 case 't':
878 *(ptr++) = '\t';
879 break;
880
881 case '\\':
882 *(ptr++) = '\\';
883 break;
884
885 case '^':
886 *(ptr++) = '^';
887 break;
888
889 case ',':
890 *(ptr++) = ',';
891 break;
892
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530893 case '\n':
894 continue;
895
896 default:
Steve Kondikae271bc2015-11-15 02:50:53 +0100897 if ((_nc_syntax == SYN_TERMINFO) || !_nc_strict_bsd) {
898 switch (c) {
899 case 'a':
900 c = '\007';
901 break;
902 case 'e':
903 c = '\033';
904 break;
905 case 'l':
906 c = '\n';
907 break;
908 case 's':
909 c = ' ';
910 break;
911 case ':':
912 c = ':';
913 break;
914 default:
915 _nc_warning("Illegal character '%s' in \\ sequence",
916 unctrl(UChar(c)));
917 break;
918 }
919 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530920 /* FALLTHRU */
921 case '|':
Steve Kondikae271bc2015-11-15 02:50:53 +0100922 *(ptr++) = (char) c;
923 } /* endswitch (c) */
924 } /* endelse (c < '0' || c > '7') */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530925 }
Steve Kondikae271bc2015-11-15 02:50:53 +0100926 /* end else if (c == '\\') */
927 else if (c == '\n' && (_nc_syntax == SYN_TERMINFO)) {
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530928 /*
929 * Newlines embedded in a terminfo string are ignored, provided
930 * that the next line begins with whitespace.
931 */
932 ignored = TRUE;
933 } else {
Steve Kondikae271bc2015-11-15 02:50:53 +0100934 *(ptr++) = (char) c;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530935 }
936
937 if (!ignored) {
938 if (_nc_curr_col <= 1) {
Steve Kondikae271bc2015-11-15 02:50:53 +0100939 push_back(c);
940 c = '\n';
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530941 break;
942 }
Steve Kondikae271bc2015-11-15 02:50:53 +0100943 last_ch = c;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530944 count++;
945 }
946 ignored = FALSE;
947
948 if (count > MAXCAPLEN && !long_warning) {
949 _nc_warning("Very long string found. Missing separator?");
950 long_warning = TRUE;
951 }
952 } /* end while */
953
954 *ptr = '\0';
955
Steve Kondikae271bc2015-11-15 02:50:53 +0100956 return (c);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530957}
958
959/*
960 * _nc_push_token()
961 *
962 * Push a token of given type so that it will be reread by the next
963 * get_token() call.
964 */
965
966NCURSES_EXPORT(void)
967_nc_push_token(int tokclass)
968{
969 /*
970 * This implementation is kind of bogus, it will fail if we ever do more
971 * than one pushback at a time between get_token() calls. It relies on the
972 * fact that _nc_curr_token is static storage that nothing but
973 * _nc_get_token() touches.
974 */
975 pushtype = tokclass;
976 if (pushname == 0)
977 pushname = typeMalloc(char, MAX_NAME_SIZE + 1);
978 _nc_get_type(pushname);
979
980 DEBUG(3, ("pushing token: `%s', class %d",
981 ((_nc_curr_token.tk_name != 0)
982 ? _nc_curr_token.tk_name
983 : "<null>"),
984 pushtype));
985}
986
987/*
988 * Panic mode error recovery - skip everything until a "ch" is found.
989 */
990NCURSES_EXPORT(void)
991_nc_panic_mode(char ch)
992{
993 int c;
994
995 for (;;) {
996 c = next_char();
997 if (c == ch)
998 return;
999 if (c == EOF)
1000 return;
1001 }
1002}
1003
1004#if NO_LEAKS
1005NCURSES_EXPORT(void)
1006_nc_comp_scan_leaks(void)
1007{
1008 if (pushname != 0) {
1009 FreeAndNull(pushname);
1010 }
Steve Kondikae271bc2015-11-15 02:50:53 +01001011 if (tok_buf != 0) {
1012 FreeAndNull(tok_buf);
1013 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301014}
1015#endif