Exemplo n.º 1
0
_nc_set_writedir(char *dir)
/* set the write directory for compiled entries */
{
    const char *destination;
    char actual[PATH_MAX];

    if (dir == 0
	&& use_terminfo_vars())
	dir = getenv("TERMINFO");

    if (dir != 0)
	(void) _nc_tic_dir(dir);

    destination = _nc_tic_dir(0);
    if (make_directory(destination) < 0) {
	char *home = _nc_home_terminfo();

	if (home != 0) {
	    destination = home;
	    if (make_directory(destination) < 0)
		_nc_err_abort("%s: permission denied (errno %d)",
			      destination, errno);
	}
    }

    /*
     * Note: because of this code, this logic should be exercised
     * *once only* per run.
     */
    if (chdir(_nc_tic_dir(destination)) < 0
	|| getcwd(actual, sizeof(actual)) == 0)
	_nc_err_abort("%s: not a directory", destination);
    _nc_keep_tic_dir(strdup(actual));
}
Exemplo n.º 2
0
_nc_read_entry_source(FILE *fp, char *buf,
		      int literal, bool silent,
		      bool(*hook) (ENTRY *))
/* slurp all entries in the given file into core */
{
    ENTRY thisentry;
    bool oldsuppress = _nc_suppress_warnings;
    int immediate = 0;

    if (silent)
	_nc_suppress_warnings = TRUE;	/* shut the lexer up, too */

    _nc_reset_input(fp, buf);
    for (;;) {
	memset(&thisentry, 0, sizeof(thisentry));
	if (_nc_parse_entry(&thisentry, literal, silent) == ERR)
	    break;
	if (!isalnum(UChar(thisentry.tterm.term_names[0])))
	    _nc_err_abort("terminal names must start with letter or digit");

	/*
	 * This can be used for immediate compilation of entries with no "use="
	 * references to disk.  That avoids consuming a lot of memory when the
	 * resolution code could fetch entries off disk.
	 */
	if (hook != NULLHOOK && (*hook) (&thisentry)) {
	    immediate++;
	} else {
	    enqueue(&thisentry);
	    /*
	     * The enqueued entry is copied with _nc_copy_termtype(), so we can
	     * free some of the data from thisentry, i.e., the arrays.
	     */
	    FreeIfNeeded(thisentry.tterm.Booleans);
	    FreeIfNeeded(thisentry.tterm.Numbers);
	    FreeIfNeeded(thisentry.tterm.Strings);
#if NCURSES_XNAMES
	    FreeIfNeeded(thisentry.tterm.ext_Names);
#endif
	}
    }

    if (_nc_tail) {
	/* set up the head pointer */
	for (_nc_head = _nc_tail; _nc_head->last; _nc_head = _nc_head->last)
	    continue;

	DEBUG(1, ("head = %s", _nc_head->tterm.term_names));
	DEBUG(1, ("tail = %s", _nc_tail->tterm.term_names));
    }
#ifdef TRACE
    else if (!immediate)
	DEBUG(1, ("no entries parsed"));
#endif

    _nc_suppress_warnings = oldsuppress;
}
Exemplo n.º 3
0
static inline void
get_space(size_t need)
{
    need += out_used;
    if (need > out_size) {
	out_size = need * 2;
	out_buff = typeRealloc(char, out_size, out_buff);
	if (out_buff == 0)
	    _nc_err_abort(MSG_NO_MEMORY);
    }
Exemplo n.º 4
0
static char *
init_string(void)
/* initialize 'my_string', 'my_length' */
{
    if (my_string == 0)
	my_string = typeMalloc(char, my_length = 256);
    if (my_string == 0)
	_nc_err_abort(MSG_NO_MEMORY);

    *my_string = '\0';
    return my_string;
}
Exemplo n.º 5
0
_nc_set_writedir(char *dir)
{
    const char *destination;
    char actual[PATH_MAX];

    if (dir == 0
#ifndef USE_ROOT_ENVIRON
	&& use_terminfo_vars()
#endif
	)
	dir = getenv("TERMINFO");

    if (dir != 0)
	(void) _nc_tic_dir(dir);

    destination = _nc_tic_dir(0);
    if (make_db_root(destination) < 0) {
	char *home = _nc_home_terminfo();

	if (home != 0) {
	    destination = home;
	    if (make_db_root(destination) < 0)
		_nc_err_abort("%s: permission denied (errno %d)",
			      destination, errno);
	}
    }

    /*
     * Note: because of this code, this logic should be exercised
     * *once only* per run.
     */
#if USE_HASHED_DB
    make_db_path(actual, destination, sizeof(actual));
#else
    if (chdir(_nc_tic_dir(destination)) < 0
	|| getcwd(actual, sizeof(actual)) == 0)
	_nc_err_abort("%s: not a directory", destination);
#endif
    _nc_keep_tic_dir(strdup(actual));
}
Exemplo n.º 6
0
/*
 * Check for access rights to destination directories
 * Create any directories which don't exist.
 *
 * Note:  there's no reason to return the result of make_db_root(), since
 * this function is called only in instances where that has to succeed.
 */
static void
check_writeable(int code)
{
    static const char dirnames[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    static bool verified[sizeof(dirnames)];

    char dir[sizeof(LEAF_FMT)];
    char *s = 0;

    if (code == 0 || (s = strchr(dirnames, code)) == 0)
	_nc_err_abort("Illegal terminfo subdirectory \"" LEAF_FMT "\"", code);

    if (verified[s - dirnames])
	return;

    snprintf(dir, sizeof(dir), LEAF_FMT, code);
    if (make_db_root(dir) < 0) {
	_nc_err_abort("%s/%s: permission denied", _nc_tic_dir(0), dir);
    }

    verified[s - dirnames] = TRUE;
}
Exemplo n.º 7
0
void  _nc_set_writedir(char *dir)
/* set the write directory for compiled entries */
{
    const char *destination;

    if (dir != 0)
	(void) _nc_tic_dir(dir);
    else if (getenv("TERMINFO") != NULL)
	(void) _nc_tic_dir(getenv("TERMINFO"));

    destination = _nc_tic_dir(0);
    if (make_directory(destination) < 0)
    {
	char	*home;

	/* ncurses extension...fall back on user's private directory */
	if ((home = getenv("HOME")) != (char *)NULL &&
	    strlen(home) + sizeof(PRIVATE_INFO) <= PATH_MAX)
	{
	    char *temp = malloc(sizeof(PRIVATE_INFO) + strlen(home));
	    if (temp == NULL)
		_nc_err_abort("Out of memory");
	    (void) sprintf(temp, PRIVATE_INFO, home);
	    destination = temp;

	    if (make_directory(destination) < 0)
		_nc_err_abort("%s: permission denied (errno %d)",
			destination, errno);
	}
    }

    /*
     * Note: because of this code, this logic should be exercised
     * *once only* per run.
     */
    if (chdir(_nc_tic_dir(destination)) < 0)
	_nc_err_abort("%s: not a directory", destination);
}
Exemplo n.º 8
0
static char *
save_string(char *d, const char *const s)
{
    size_t have = (size_t) (d - my_string);
    size_t need = have + strlen(s) + 2;
    if (need > my_length) {
	my_string = (char *) _nc_doalloc(my_string, my_length = (need + need));
	if (my_string == 0)
	    _nc_err_abort(MSG_NO_MEMORY);
	d = my_string + have;
    }
    _nc_STRCPY(d, s, my_length - have);
    return d + strlen(d);
}
Exemplo n.º 9
0
static char *
save_string(char *d, const char *const s)
{
    size_t have = (d - my_string);
    size_t need = have + strlen(s) + 2;
    if (need > my_length) {
	my_string = (char *) realloc(my_string, my_length = (need + need));
	if (my_string == 0)
	    _nc_err_abort(MSG_NO_MEMORY);
	d = my_string + have;
    }
    (void) strcpy(d, s);
    return d + strlen(d);
}
Exemplo n.º 10
0
static void
enqueue(ENTRY * ep)
/* add an entry to the in-core list */
{
    ENTRY *newp = _nc_copy_entry(ep);

    if (newp == 0)
	_nc_err_abort(MSG_NO_MEMORY);

    newp->last = _nc_tail;
    _nc_tail = newp;

    newp->next = 0;
    if (newp->last)
	newp->last->next = newp;
}
Exemplo n.º 11
0
static void file_comparison(int argc, char *argv[])
{
#define MAXCOMPARE	2
    /* someday we may allow comparisons on more files */
    int	filecount = 0;
    ENTRY	*heads[MAXCOMPARE];
    ENTRY	*tails[MAXCOMPARE];
    ENTRY	*qp, *rp;
    int		i, n;

    dump_init((char *)NULL, F_LITERAL, S_TERMINFO, 0, itrace, FALSE);

    for (n = 0; n < argc && n < MAXCOMPARE; n++)
    {
	if (freopen(argv[n], "r", stdin) == NULL)
	    _nc_err_abort("Can't open %s", argv[n]);

	_nc_head = _nc_tail = (ENTRY *)NULL;

	/* parse entries out of the source file */
	_nc_set_source(argv[n]);
	_nc_read_entry_source(stdin, NULL, TRUE, FALSE, NULLHOOK);

	if (itrace)
	    (void) fprintf(stderr, "Resolving file %d...\n", n-0);

	/* do use resolution */
	if (!_nc_resolve_uses())
	{
	    (void) fprintf(stderr,
			   "There are unresolved use entries in %s:\n",
			   argv[n]);
	    for_entry_list(qp)
		if (qp->nuses)
		{
		    (void) fputs(qp->tterm.term_names, stderr);
		    (void) fputc('\n', stderr);
		}
	    exit(EXIT_FAILURE);
	}

	heads[filecount] = _nc_head;
	tails[filecount] = _nc_tail;
	filecount++;
    }
Exemplo n.º 12
0
_nc_home_terminfo(void)
{
    char *result = 0;
#if USE_HOME_TERMINFO
    char *home;

    if (use_terminfo_vars()) {
	if (MyBuffer == 0) {
	    if ((home = getenv("HOME")) != 0) {
		unsigned want = (strlen(home) + sizeof(PRIVATE_INFO));
		MyBuffer = typeMalloc(char, want);
		if (MyBuffer == 0)
		    _nc_err_abort(MSG_NO_MEMORY);
		(void) sprintf(MyBuffer, PRIVATE_INFO, home);
	    }
	}
	result = MyBuffer;
    }
Exemplo n.º 13
0
char *
_nc_home_terminfo(void)
{
    char *home;
    static char *temp = 0;

    if (use_terminfo_vars()) {
	if (temp == 0) {
	    if ((home = getenv("HOME")) != 0
		&& my_length <= PATH_MAX) {
		temp = typeMalloc(char, my_length);
		if (temp == 0)
		    _nc_err_abort("Out of memory");
		(void) sprintf(temp, PRIVATE_INFO, home);
	    }
	}
	return temp;
    }
Exemplo n.º 14
0
_nc_parse_entry(struct entry *entryp, int literal, bool silent)
{
    int token_type;
    struct name_table_entry const *entry_ptr;
    char *ptr, *base;
    bool bad_tc_usage = FALSE;

    token_type = _nc_get_token(silent);

    if (token_type == EOF)
	return (EOF);
    if (token_type != NAMES)
	_nc_err_abort("Entry does not start with terminal names in column one");

    _nc_init_entry(&entryp->tterm);

    entryp->cstart = _nc_comment_start;
    entryp->cend = _nc_comment_end;
    entryp->startline = _nc_start_line;
    DEBUG(2, ("Comment range is %ld to %ld", entryp->cstart, entryp->cend));

    /*
     * Strip off the 2-character termcap name, if present.  Originally termcap
     * used that as an indexing aid.  We can retain 2-character terminfo names,
     * but note that they would be lost if we translate to/from termcap.  This
     * feature is supposedly obsolete since "newer" BSD implementations do not
     * use it; however our reference for this feature is SunOS 4.x, which
     * implemented it.  Note that the resulting terminal type was never the
     * 2-character name, but was instead the first alias after that.
     */
    ptr = _nc_curr_token.tk_name;
    if (_nc_syntax == SYN_TERMCAP
#if NCURSES_XNAMES
	&& !_nc_user_definable
#endif
	) {
	if (ptr[2] == '|') {
	    ptr += 3;
	    _nc_curr_token.tk_name[2] = '\0';
	}
    }

    entryp->tterm.str_table = entryp->tterm.term_names = _nc_save_str(ptr);

    DEBUG(1, ("Starting '%s'", ptr));

    /*
     * We do this because the one-token lookahead in the parse loop
     * results in the terminal type getting prematurely set to correspond
     * to that of the next entry.
     */
    _nc_set_type(_nc_first_name(entryp->tterm.term_names));

    /* check for overly-long names and aliases */
    for (base = entryp->tterm.term_names; (ptr = strchr(base, '|')) != 0;
	 base = ptr + 1) {
	if (ptr - base > MAX_ALIAS) {
	    _nc_warning("%s `%.*s' may be too long",
			(base == entryp->tterm.term_names)
			? "primary name"
			: "alias",
			(int) (ptr - base), base);
	}
    }

    entryp->nuses = 0;

    for (token_type = _nc_get_token(silent);
	 token_type != EOF && token_type != NAMES;
	 token_type = _nc_get_token(silent)) {
	bool is_use = (strcmp(_nc_curr_token.tk_name, "use") == 0);
	bool is_tc = !is_use && (strcmp(_nc_curr_token.tk_name, "tc") == 0);
	if (is_use || is_tc) {
	    entryp->uses[entryp->nuses].name = _nc_save_str(_nc_curr_token.tk_valstring);
	    entryp->uses[entryp->nuses].line = _nc_curr_line;
	    entryp->nuses++;
	    if (entryp->nuses > 1 && is_tc) {
		BAD_TC_USAGE
	    }
	} else {
Exemplo n.º 15
0
_nc_resolve_uses2(bool fullresolve, bool literal)
/* try to resolve all use capabilities */
{
    ENTRY *qp, *rp, *lastread = 0;
    bool keepgoing;
    unsigned i;
    int unresolved, total_unresolved, multiples;

    DEBUG(2, ("RESOLUTION BEGINNING"));

    /*
     * Check for multiple occurrences of the same name.
     */
    multiples = 0;
    for_entry_list(qp) {
	int matchcount = 0;

	for_entry_list(rp) {
	    if (qp > rp
		&& _nc_entry_match(qp->tterm.term_names, rp->tterm.term_names)) {
		matchcount++;
		if (matchcount == 1) {
		    (void) fprintf(stderr, "Name collision between %s",
				   _nc_first_name(qp->tterm.term_names));
		    multiples++;
		}
		if (matchcount >= 1)
		    (void) fprintf(stderr, " %s", _nc_first_name(rp->tterm.term_names));
	    }
	}
	if (matchcount >= 1)
	    (void) putc('\n', stderr);
    }
    if (multiples > 0)
	return (FALSE);

    DEBUG(2, ("NO MULTIPLE NAME OCCURRENCES"));

    /*
     * First resolution stage: compute link pointers corresponding to names.
     */
    total_unresolved = 0;
    _nc_curr_col = -1;
    for_entry_list(qp) {
	unresolved = 0;
	for (i = 0; i < qp->nuses; i++) {
	    bool foundit;
	    char *child = _nc_first_name(qp->tterm.term_names);
	    char *lookfor = qp->uses[i].name;
	    long lookline = qp->uses[i].line;

	    foundit = FALSE;

	    _nc_set_type(child);

	    /* first, try to resolve from in-core records */
	    for_entry_list(rp) {
		if (rp != qp
		    && _nc_name_match(rp->tterm.term_names, lookfor, "|")) {
		    DEBUG(2, ("%s: resolving use=%s (in core)",
			      child, lookfor));

		    qp->uses[i].link = rp;
		    foundit = TRUE;
		}
	    }

	    /* if that didn't work, try to merge in a compiled entry */
	    if (!foundit) {
		TERMTYPE thisterm;
		char filename[PATH_MAX];

		memset(&thisterm, 0, sizeof(thisterm));
		if (_nc_read_entry(lookfor, filename, &thisterm) == 1) {
		    DEBUG(2, ("%s: resolving use=%s (compiled)",
			      child, lookfor));

		    rp = typeMalloc(ENTRY, 1);
		    if (rp == 0)
			_nc_err_abort(MSG_NO_MEMORY);
		    rp->tterm = thisterm;
		    rp->nuses = 0;
		    rp->next = lastread;
		    lastread = rp;

		    qp->uses[i].link = rp;
		    foundit = TRUE;
		}
	    }

	    /* no good, mark this one unresolvable and complain */
	    if (!foundit) {
		unresolved++;
		total_unresolved++;

		_nc_curr_line = lookline;
		_nc_warning("resolution of use=%s failed", lookfor);
		qp->uses[i].link = 0;
	    }
	}
    }
    if (total_unresolved) {
	/* free entries read in off disk */
	_nc_free_entries(lastread);
	return (FALSE);
    }

    DEBUG(2, ("NAME RESOLUTION COMPLETED OK"));

    /*
     * OK, at this point all (char *) references in `name' members
     * have been successfully converted to (ENTRY *) pointers in
     * `link' members.  Time to do the actual merges.
     */
    if (fullresolve) {
	do {
	    TERMTYPE merged;

	    keepgoing = FALSE;

	    for_entry_list(qp) {
		if (qp->nuses > 0) {
		    DEBUG(2, ("%s: attempting merge",
			      _nc_first_name(qp->tterm.term_names)));
		    /*
		     * If any of the use entries we're looking for is
		     * incomplete, punt.  We'll catch this entry on a
		     * subsequent pass.
		     */
		    for (i = 0; i < qp->nuses; i++)
			if (qp->uses[i].link->nuses) {
			    DEBUG(2, ("%s: use entry %d unresolved",
				      _nc_first_name(qp->tterm.term_names), i));
			    goto incomplete;
			}

		    /*
		     * First, make sure there is no garbage in the
		     * merge block.  As a side effect, copy into
		     * the merged entry the name field and string
		     * table pointer.
		     */
		    _nc_copy_termtype(&merged, &(qp->tterm));

		    /*
		     * Now merge in each use entry in the proper
		     * (reverse) order.
		     */
		    for (; qp->nuses; qp->nuses--)
			_nc_merge_entry(&merged,
					&qp->uses[qp->nuses - 1].link->tterm);

		    /*
		     * Now merge in the original entry.
		     */
		    _nc_merge_entry(&merged, &qp->tterm);

		    /*
		     * Replace the original entry with the merged one.
		     */
		    FreeIfNeeded(qp->tterm.Booleans);
		    FreeIfNeeded(qp->tterm.Numbers);
		    FreeIfNeeded(qp->tterm.Strings);
#if NCURSES_XNAMES
		    FreeIfNeeded(qp->tterm.ext_Names);
#endif
		    qp->tterm = merged;
		    _nc_wrap_entry(qp, TRUE);

		    /*
		     * We know every entry is resolvable because name resolution
		     * didn't bomb.  So go back for another pass.
		     */
		    /* FALLTHRU */
		  incomplete:
		    keepgoing = TRUE;
		}
	    }
	} while
	    (keepgoing);

	DEBUG(2, ("MERGES COMPLETED OK"));
    }

    /*
     * We'd like to free entries read in off disk at this point, but can't.
     * The merge_entry() code doesn't copy the strings in the use entries,
     * it just aliases them.  If this ever changes, do a
     * free_entries(lastread) here.
     */

    DEBUG(2, ("RESOLUTION FINISHED"));

    if (fullresolve)
	if (_nc_check_termtype != 0) {
	    _nc_curr_col = -1;
	    for_entry_list(qp) {
		_nc_curr_line = qp->startline;
		_nc_set_type(_nc_first_name(qp->tterm.term_names));
		_nc_check_termtype2(&qp->tterm, literal);
	    }
	    DEBUG(2, ("SANITY CHECK FINISHED"));
	}
Exemplo n.º 16
0
_nc_get_token(bool silent)
{
    static const char terminfo_punct[] = "@%&*!#";
    long number;
    int type;
    int ch;
    char *numchk;
    char numbuf[80];
    unsigned found;
    static char buffer[MAX_ENTRY_SIZE];
    char *ptr;
    int dot_flag = FALSE;
    long token_start;

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

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

	pushtype = NO_PUSHBACK;
	pushname[0] = '\0';

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

    if (end_of_stream())
	return (EOF);

  start_token:
    token_start = stream_pos();
    while ((ch = next_char()) == '\n' || iswhite(ch))
	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(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;
	}

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

	if (first_column) {
	    char *desc;

	    _nc_comment_start = token_start;
	    _nc_comment_end = _nc_curr_file_pos;
	    _nc_start_line = _nc_curr_line;

	    _nc_syntax = ERR;
	    while ((ch = next_char()) != '\n') {
		if (ch == EOF)
		    _nc_err_abort("premature EOF");
		else if (ch == ':' && last_char() != ',') {
		    _nc_syntax = SYN_TERMCAP;
		    separator = ':';
		    break;
		} else if (ch == ',') {
		    _nc_syntax = SYN_TERMINFO;
		    separator = ',';
		    /*
		     * Fall-through here is not an accident.  The idea is that
		     * if we see a comma, we figure this is terminfo unless we
		     * subsequently run into a colon -- but we don't stop
		     * looking for that colon until hitting a newline.  This
		     * allows commas to be embedded in description fields of
		     * either syntax.
		     */
		    /* FALLTHRU */
		} 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.
	     */
	    ptr = strchr(buffer, '|');
	    if (ptr == (char *) NULL)
		ptr = buffer + strlen(buffer);
	    ch = *ptr;
	    *ptr = '\0';
	    _nc_set_type(buffer);
	    *ptr = ch;

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

	    /*
	     * 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 (ptr = buffer; ptr < desc; ptr++) {
		if (isspace(CharOf(*ptr))) {
		    if (!silent)
			_nc_warning("whitespace in name or alias field");
		    break;
		} else if (*ptr == '/') {
		    if (!silent)
			_nc_warning("slashes aren't allowed in names or aliases");
		    break;
		} else if (strchr("$[]!*?", *ptr)) {
		    if (!silent)
			_nc_warning("dubious character `%c' in name or alias field", *ptr);
		    break;
		}
	    }

	    ptr = buffer;

	    _nc_curr_token.tk_name = buffer;
	    type = NAMES;
	} else {
	    while ((ch = next_char()) != EOF) {
		if (!isalnum(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 + sizeof(buffer));
		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);
}
Exemplo n.º 17
0
static void
postprocess_termcap(TERMTYPE * tp, bool has_base)
{
    char buf[MAX_LINE * 2 + 2];
    string_desc result;

    /*
     * TERMCAP DEFAULTS AND OBSOLETE-CAPABILITY TRANSLATIONS
     *
     * This first part of the code is the functional inverse of the
     * fragment in capdefaults.c.
     * ----------------------------------------------------------------------
     */

    /* if there was a tc entry, assume we picked up defaults via that */
    if (!has_base) {
	if (WANTED(init_3string) && termcap_init2)
	    init_3string = _nc_save_str(termcap_init2);

	if (WANTED(reset_2string) && termcap_reset)
	    reset_2string = _nc_save_str(termcap_reset);

	if (WANTED(carriage_return)) {
	    if (carriage_return_delay > 0) {
		sprintf(buf, "%s$<%d>", C_CR, carriage_return_delay);
		carriage_return = _nc_save_str(buf);
	    } else
		carriage_return = _nc_save_str(C_CR);
	}
	if (WANTED(cursor_left)) {
	    if (backspace_delay > 0) {
		sprintf(buf, "%s$<%d>", C_BS, backspace_delay);
		cursor_left = _nc_save_str(buf);
	    } else if (backspaces_with_bs == 1)
		cursor_left = _nc_save_str(C_BS);
	    else if (PRESENT(backspace_if_not_bs))
		cursor_left = backspace_if_not_bs;
	}
	/* vi doesn't use "do", but it does seems to use nl (or '\n') instead */
	if (WANTED(cursor_down)) {
	    if (PRESENT(linefeed_if_not_lf))
		cursor_down = linefeed_if_not_lf;
	    else if (linefeed_is_newline != 1) {
		if (new_line_delay > 0) {
		    sprintf(buf, "%s$<%d>", C_LF, new_line_delay);
		    cursor_down = _nc_save_str(buf);
		} else
		    cursor_down = _nc_save_str(C_LF);
	    }
	}
	if (WANTED(scroll_forward) && crt_no_scrolling != 1) {
	    if (PRESENT(linefeed_if_not_lf))
		cursor_down = linefeed_if_not_lf;
	    else if (linefeed_is_newline != 1) {
		if (new_line_delay > 0) {
		    sprintf(buf, "%s$<%d>", C_LF, new_line_delay);
		    scroll_forward = _nc_save_str(buf);
		} else
		    scroll_forward = _nc_save_str(C_LF);
	    }
	}
	if (WANTED(newline)) {
	    if (linefeed_is_newline == 1) {
		if (new_line_delay > 0) {
		    sprintf(buf, "%s$<%d>", C_LF, new_line_delay);
		    newline = _nc_save_str(buf);
		} else
		    newline = _nc_save_str(C_LF);
	    } else if (PRESENT(carriage_return) && PRESENT(scroll_forward)) {
		_nc_str_init(&result, buf, sizeof(buf));
		if (_nc_safe_strcat(&result, carriage_return)
		 && _nc_safe_strcat(&result, scroll_forward))
		    newline = _nc_save_str(buf);
	    } else if (PRESENT(carriage_return) && PRESENT(cursor_down)) {
		_nc_str_init(&result, buf, sizeof(buf));
		if (_nc_safe_strcat(&result, carriage_return)
		 && _nc_safe_strcat(&result, cursor_down))
		    newline = _nc_save_str(buf);
	    }
	}
    }

    /*
     * Inverse of capdefaults.c code ends here.
     * ----------------------------------------------------------------------
     *
     * TERMCAP-TO TERMINFO MAPPINGS FOR SOURCE TRANSLATION
     *
     * These translations will *not* be inverted by tgetent().
     */

    if (!has_base) {
	/*
	 * We wait until now to decide if we've got a working cr because even
	 * one that doesn't work can be used for newline. Unfortunately the
	 * space allocated for it is wasted.
	 */
	if (return_does_clr_eol == 1 || no_correctly_working_cr == 1)
	    carriage_return = ABSENT_STRING;

	/*
	 * Supposedly most termcap entries have ta now and '\t' is no longer a
	 * default, but it doesn't seem to be true...
	 */
	if (WANTED(tab)) {
	    if (horizontal_tab_delay > 0) {
		sprintf(buf, "%s$<%d>", C_HT, horizontal_tab_delay);
		tab = _nc_save_str(buf);
	    } else
		tab = _nc_save_str(C_HT);
	}
	if (init_tabs == ABSENT_NUMERIC && has_hardware_tabs == TRUE)
	    init_tabs = 8;

	/*
	 * Assume we can beep with ^G unless we're given bl@.
	 */
	if (WANTED(bell))
	    bell = _nc_save_str("\007");
    }

    /*
     * Translate the old termcap :pt: capability to it#8 + ht=\t
     */
    if (has_hardware_tabs == TRUE) {
	if (init_tabs != 8 && init_tabs != ABSENT_NUMERIC)
	    _nc_warning("hardware tabs with a width other than 8: %d", init_tabs);
	else {
	    if (tab && _nc_capcmp(tab, C_HT))
		_nc_warning("hardware tabs with a non-^I tab string %s",
			    _nc_visbuf(tab));
	    else {
		if (WANTED(tab))
		    tab = _nc_save_str(C_HT);
		init_tabs = 8;
	    }
	}
    }
    /*
     * Now translate the ko capability, if there is one.  This
     * isn't from mytinfo...
     */
    if (PRESENT(other_non_function_keys)) {
	char *base = other_non_function_keys;
	char *bp, *cp, *dp;
	struct name_table_entry const *from_ptr;
	struct name_table_entry const *to_ptr;
	assoc const *ap;
	char buf2[MAX_TERMINFO_LENGTH];
	bool foundim;

	/* we're going to use this for a special case later */
	dp = strchr(other_non_function_keys, 'i');
	foundim = (dp != 0) && (dp[1] == 'm');

	/* look at each comma-separated capability in the ko string... */
	for (base = other_non_function_keys;
	     (cp = strchr(base, ',')) != 0;
	     base = cp + 1) {
	    size_t len = cp - base;

	    for (ap = ko_xlate; ap->from; ap++)
		if (len == strlen(ap->from)
		    && strncmp(ap->from, base, len) == 0)
		    break;
	    if (!ap->to) {
		_nc_warning("unknown capability `%.*s' in ko string",
			    (int) len, base);
		continue;
	    } else if (ap->to == CANCELLED_STRING)	/* ignore it */
		continue;

	    /* now we know we found a match in ko_table, so... */

	    from_ptr = _nc_find_entry(ap->from, _nc_cap_hash_table);
	    to_ptr = _nc_find_entry(ap->to, _nc_info_hash_table);

	    if (!from_ptr || !to_ptr)	/* should never happen! */
		_nc_err_abort("ko translation table is invalid, I give up");

	    if (WANTED(tp->Strings[from_ptr->nte_index])) {
		_nc_warning("no value for ko capability %s", ap->from);
		continue;
	    }

	    if (tp->Strings[to_ptr->nte_index]) {
		/* There's no point in warning about it if it's the same
		 * string; that's just an inefficiency.
		 */
		if (strcmp(
			      tp->Strings[from_ptr->nte_index],
			      tp->Strings[to_ptr->nte_index]) != 0)
		    _nc_warning("%s (%s) already has an explicit value %s, ignoring ko",
				ap->to, ap->from,
				_nc_visbuf(tp->Strings[to_ptr->nte_index]));
		continue;
	    }

	    /*
	     * The magic moment -- copy the mapped key string over,
	     * stripping out padding.
	     */
	    for (dp = buf2, bp = tp->Strings[from_ptr->nte_index]; *bp; bp++) {
		if (bp[0] == '$' && bp[1] == '<') {
		    while (*bp && *bp != '>') {
			++bp;
		    }
		} else
		    *dp++ = *bp;
	    }
	    *dp++ = '\0';

	    tp->Strings[to_ptr->nte_index] = _nc_save_str(buf2);
	}

	/*
	 * Note: ko=im and ko=ic both want to grab the `Insert'
	 * keycap.  There's a kich1 but no ksmir, so the ic capability
	 * got mapped to kich1 and im to kIC to avoid a collision.
	 * If the description has im but not ic, hack kIC back to kich1.
	 */
	if (foundim && WANTED(key_ic) && key_sic) {
	    key_ic = key_sic;
	    key_sic = ABSENT_STRING;
	}
    }

    if (!hard_copy) {
	if (WANTED(key_backspace))
	    key_backspace = _nc_save_str(C_BS);
	if (WANTED(key_left))
	    key_left = _nc_save_str(C_BS);
	if (WANTED(key_down))
	    key_down = _nc_save_str(C_LF);
    }

    /*
     * Translate XENIX forms characters.
     */
    if (PRESENT(acs_ulcorner) ||
	PRESENT(acs_llcorner) ||
	PRESENT(acs_urcorner) ||
	PRESENT(acs_lrcorner) ||
	PRESENT(acs_ltee) ||
	PRESENT(acs_rtee) ||
	PRESENT(acs_btee) ||
	PRESENT(acs_ttee) ||
	PRESENT(acs_hline) ||
	PRESENT(acs_vline) ||
	PRESENT(acs_plus)) {
	char buf2[MAX_TERMCAP_LENGTH];

	_nc_str_init(&result, buf2, sizeof(buf2));
	_nc_safe_strcat(&result, acs_chars);

	append_acs (&result, 'j', acs_lrcorner);
	append_acs (&result, 'k', acs_urcorner);
	append_acs (&result, 'l', acs_ulcorner);
	append_acs (&result, 'm', acs_llcorner);
	append_acs (&result, 'n', acs_plus);
	append_acs (&result, 'q', acs_hline);
	append_acs (&result, 't', acs_ltee);
	append_acs (&result, 'u', acs_rtee);
	append_acs (&result, 'v', acs_btee);
	append_acs (&result, 'w', acs_ttee);
	append_acs (&result, 'x', acs_vline);

	if (buf2[0]) {
	    acs_chars = _nc_save_str(buf2);
	    _nc_warning("acsc string synthesized from XENIX capabilities");
	}
    } else if (acs_chars == 0
	       && enter_alt_charset_mode != 0
	       && exit_alt_charset_mode != 0) {
	acs_chars =
	    _nc_save_str("``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~");
    }
}
Exemplo n.º 18
0
int
_nc_parse_entry(struct entry *entryp, int literal, bool silent)
{
    int token_type;
    struct name_table_entry const *entry_ptr;
    char *ptr, *base;

    token_type = _nc_get_token();

    if (token_type == EOF)
	return (EOF);
    if (token_type != NAMES)
	_nc_err_abort("Entry does not start with terminal names in column one");

    _nc_init_entry(&entryp->tterm);

    entryp->cstart = _nc_comment_start;
    entryp->cend = _nc_comment_end;
    entryp->startline = _nc_start_line;
    DEBUG(2, ("Comment range is %ld to %ld", entryp->cstart, entryp->cend));

    /* junk the 2-character termcap name, if present */
    ptr = _nc_curr_token.tk_name;
    if (ptr[2] == '|') {
	ptr = _nc_curr_token.tk_name + 3;
	_nc_curr_token.tk_name[2] = '\0';
    }

    entryp->tterm.str_table = entryp->tterm.term_names = _nc_save_str(ptr);

    DEBUG(1, ("Starting '%s'", ptr));

    /*
     * We do this because the one-token lookahead in the parse loop
     * results in the terminal type getting prematurely set to correspond
     * to that of the next entry.
     */
    _nc_set_type(_nc_first_name(entryp->tterm.term_names));

    /* check for overly-long names and aliases */
    for (base = entryp->tterm.term_names; (ptr = strchr(base, '|')) != 0;
	 base = ptr + 1) {
	if (ptr - base > MAX_ALIAS) {
	    _nc_warning("%s `%.*s' may be too long",
			(base == entryp->tterm.term_names)
			? "primary name"
			: "alias",
			ptr - base, base);
	}
    }

    entryp->nuses = 0;

    for (token_type = _nc_get_token();
	 token_type != EOF && token_type != NAMES;
	 token_type = _nc_get_token()) {
	if (strcmp(_nc_curr_token.tk_name, "use") == 0
	    || strcmp(_nc_curr_token.tk_name, "tc") == 0) {
	    entryp->uses[entryp->nuses].name = _nc_save_str(_nc_curr_token.tk_valstring);
	    entryp->uses[entryp->nuses].line = _nc_curr_line;
	    entryp->nuses++;
	} else {
	    /* normal token lookup */
	    entry_ptr = _nc_find_entry(_nc_curr_token.tk_name,
				       _nc_syntax ? _nc_cap_hash_table : _nc_info_hash_table);

	    /*
	     * Our kluge to handle aliasing.  The reason it's done
	     * this ugly way, with a linear search, is so the hashing
	     * machinery doesn't have to be made really complicated
	     * (also we get better warnings this way).  No point in
	     * making this case fast, aliased caps aren't common now
	     * and will get rarer.
	     */
	    if (entry_ptr == NOTFOUND) {
		const struct alias *ap;

		if (_nc_syntax == SYN_TERMCAP) {
		    for (ap = _nc_capalias_table; ap->from; ap++)
			if (strcmp(ap->from, _nc_curr_token.tk_name) == 0) {
			    if (ap->to == (char *) 0) {
				_nc_warning("%s (%s termcap extension) ignored",
					    ap->from, ap->source);
				goto nexttok;
			    }

			    entry_ptr = _nc_find_entry(ap->to, _nc_cap_hash_table);
			    if (entry_ptr && !silent)
				_nc_warning("%s (%s termcap extension) aliased to %s",
					    ap->from, ap->source, ap->to);
			    break;
			}
		} else {	/* if (_nc_syntax == SYN_TERMINFO) */
		    for (ap = _nc_infoalias_table; ap->from; ap++)
			if (strcmp(ap->from, _nc_curr_token.tk_name) == 0) {
			    if (ap->to == (char *) 0) {
				_nc_warning("%s (%s terminfo extension) ignored",
					    ap->from, ap->source);
				goto nexttok;
			    }

			    entry_ptr = _nc_find_entry(ap->to, _nc_info_hash_table);
			    if (entry_ptr && !silent)
				_nc_warning("%s (%s terminfo extension) aliased to %s",
					    ap->from, ap->source, ap->to);
			    break;
			}

		    if (entry_ptr == NOTFOUND) {
			entry_ptr = lookup_fullname(_nc_curr_token.tk_name);
		    }
		}
	    }
#if NCURSES_XNAMES
	    /*
	     * If we have extended-names active, we will automatically
	     * define a name based on its context.
	     */
	    if (entry_ptr == NOTFOUND
		&& _nc_user_definable
		&& (entry_ptr = _nc_extend_names(entryp,
						 _nc_curr_token.tk_name,
						 token_type)) != 0) {
		if (_nc_tracing >= DEBUG_LEVEL(1))
		    _nc_warning("extended capability '%s'", _nc_curr_token.tk_name);
	    }
#endif /* NCURSES_XNAMES */

	    /* can't find this cap name, not even as an alias */
	    if (entry_ptr == NOTFOUND) {
		if (!silent)
		    _nc_warning("unknown capability '%s'",
				_nc_curr_token.tk_name);
		continue;
	    }

	    /* deal with bad type/value combinations. */
	    if (token_type != CANCEL && entry_ptr->nte_type != token_type) {
		/*
		 * Nasty special cases here handle situations in which type
		 * information can resolve name clashes.  Normal lookup
		 * finds the last instance in the capability table of a
		 * given name, regardless of type.  find_type_entry looks
		 * for a first matching instance with given type.  So as
		 * long as all ambiguous names occur in pairs of distinct
		 * type, this will do the job.
		 */

		/* tell max_attributes from arrow_key_map */
		if (token_type == NUMBER && !strcmp("ma", _nc_curr_token.tk_name))
		    entry_ptr = _nc_find_type_entry("ma", NUMBER,
						    _nc_get_table(_nc_syntax
								  != 0));

		/* map terminfo's string MT to MT */
		else if (token_type == STRING && !strcmp("MT", _nc_curr_token.tk_name))
		    entry_ptr = _nc_find_type_entry("MT", STRING,
						    _nc_get_table(_nc_syntax
								  != 0));

		/* treat strings without following "=" as empty strings */
		else if (token_type == BOOLEAN && entry_ptr->nte_type == STRING)
		    token_type = STRING;
		/* we couldn't recover; skip this token */
		else {
		    if (!silent) {
			const char *type_name;
			switch (entry_ptr->nte_type) {
			case BOOLEAN:
			    type_name = "boolean";
			    break;
			case STRING:
			    type_name = "string";
			    break;
			case NUMBER:
			    type_name = "numeric";
			    break;
			default:
			    type_name = "unknown";
			    break;
			}
			_nc_warning("wrong type used for %s capability '%s'",
				    type_name, _nc_curr_token.tk_name);
		    }
		    continue;
		}
	    }

	    /* now we know that the type/value combination is OK */
	    switch (token_type) {
	    case CANCEL:
		switch (entry_ptr->nte_type) {
		case BOOLEAN:
		    entryp->tterm.Booleans[entry_ptr->nte_index] = CANCELLED_BOOLEAN;
		    break;

		case NUMBER:
		    entryp->tterm.Numbers[entry_ptr->nte_index] = CANCELLED_NUMERIC;
		    break;

		case STRING:
		    entryp->tterm.Strings[entry_ptr->nte_index] = CANCELLED_STRING;
		    break;
		}
		break;

	    case BOOLEAN:
		entryp->tterm.Booleans[entry_ptr->nte_index] = TRUE;
		break;

	    case NUMBER:
		entryp->tterm.Numbers[entry_ptr->nte_index] =
		    _nc_curr_token.tk_valnumber;
		break;

	    case STRING:
		ptr = _nc_curr_token.tk_valstring;
		if (_nc_syntax == SYN_TERMCAP)
		    ptr = _nc_captoinfo(_nc_curr_token.tk_name,
					ptr,
					parametrized[entry_ptr->nte_index]);
		entryp->tterm.Strings[entry_ptr->nte_index] = _nc_save_str(ptr);
		break;

	    default:
		if (!silent)
		    _nc_warning("unknown token type");
		_nc_panic_mode((_nc_syntax == SYN_TERMCAP) ? ':' : ',');
		continue;
	    }
	}			/* end else cur_token.name != "use" */
      nexttok:
	continue;		/* cannot have a label w/o statement */
    }				/* endwhile (not EOF and not NAMES) */

    _nc_push_token(token_type);
    _nc_set_type(_nc_first_name(entryp->tterm.term_names));

    /*
     * Try to deduce as much as possible from extension capabilities
     * (this includes obsolete BSD capabilities).  Sigh...it would be more
     * space-efficient to call this after use resolution, but it has
     * to be done before entry allocation is wrapped up.
     */
    if (!literal) {
	if (_nc_syntax == SYN_TERMCAP) {
	    bool has_base_entry = FALSE;
	    int i;

	    /*
	     * Don't insert defaults if this is a `+' entry meant only
	     * for inclusion in other entries (not sure termcap ever
	     * had these, actually).
	     */
	    if (strchr(entryp->tterm.term_names, '+'))
		has_base_entry = TRUE;
	    else
		/*
		 * Otherwise, look for a base entry that will already
		 * have picked up defaults via translation.
		 */
		for (i = 0; i < entryp->nuses; i++)
		    if (!strchr((char *) entryp->uses[i].name, '+'))
			has_base_entry = TRUE;

	    postprocess_termcap(&entryp->tterm, has_base_entry);
	} else
	    postprocess_terminfo(&entryp->tterm);
    }
    _nc_wrap_entry(entryp);

    return (OK);
}
Exemplo n.º 19
0
_nc_trans_string(char *ptr, char *last)
{
    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("Premature EOF");

	    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("Premature EOF");

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

		    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));
		    *(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);
}
Exemplo n.º 20
0
static int
next_char(void)
{
    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 == '\t') {
	    _nc_curr_col = (_nc_curr_col | 7);
	}
    } 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);
		    bufstart = result;
		}
		if (used == 0)
		    _nc_curr_file_pos = ftell(yyin);

		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");
		}
		if ((bufptr = bufstart) != 0) {
		    used = strlen(bufptr);
		    while (iswhite(*bufptr)) {
			if (*bufptr == '\t') {
			    _nc_curr_col = (_nc_curr_col | 7) + 1;
			} else {
			    _nc_curr_col++;
			}
			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 */