int _nc_get_token(void)
_nc_get_token(void)
int _nc_get_token(void){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 == '.') {			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) && !strchr(terminfo_punct, (char)ch)) {		 _nc_warning("Illegal character (expected alphanumeric or %s) - %s",			terminfo_punct, _tracechar((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 (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(*ptr))			    {				_nc_warning("whitespace in name or alias field");				break;			    }			    else if (*ptr == '/')			    {				_nc_warning("slashes aren't allowed in names or aliases");				break;			    }			    else if (strchr("$[]!*?", *ptr))			    {				_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)					_nc_warning("Missing separator after `%s', have %s",						buffer, _tracechar((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 (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);				if (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;				_nc_warning("Illegal character - %s",					_tracechar((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 & TRACE_IEVENT)	{	    fprintf(stderr, "Token: ");	    switch (type)	    {		case BOOLEAN:		    fprintf(stderr, "Boolean; name='%s'\n",			    _nc_curr_token.tk_name);		    break;		case NUMBER:		    fprintf(stderr, "Number;  name='%s', value=%d\n",			    _nc_curr_token.tk_name,			    _nc_curr_token.tk_valnumber);		    break;		case STRING:		    fprintf(stderr, "String;  name='%s', value=%s\n",			    _nc_curr_token.tk_name,			    _nc_visbuf(_nc_curr_token.tk_valstring));		    break;		case CANCEL:		    fprintf(stderr, "Cancel; name='%s'\n",			    _nc_curr_token.tk_name);		    break;		case NAMES:		    fprintf(stderr, "Names; value='%s'\n",			    _nc_curr_token.tk_name);		    break;		case EOF:		    fprintf(stderr, "End of file\n");		    break;		default:		    _nc_warning("Bad token type");	    }	}#endif	if (dot_flag == TRUE)		/* if commented out, use the next one */	    type = _nc_get_token();	DEBUG(3, ("token: `%s', class %d", _nc_curr_token.tk_name, type));	return(type);}