char *tecparse_c_version = "tecparse.c: $Revision: 1.3 $";
/*
* $Date: 2007/12/26 13:28:30 $
* $Source: /cvsroot/videoteco/videoteco/tecparse.c,v $
* $Revision: 1.3 $
* $Locker: $
*/
/**
* \file tecparse.c
* \brief Subroutines to implement the finite state parser
*/
/*
* Copyright (C) 1985-2007 BY Paul Cantrell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "teco.h"
#include "tecparse.h"
struct cmd_token *cmd_list = NULL;
struct cmd_token *last_cmd_list = NULL;
struct cmd_token *jump_to_token;
struct cmd_token *resume_execute_ct;
struct cmd_token *last_token_executed;
struct search_buff search_string;
char user_message[PARSER_STRING_MAX];
unsigned long remembered_dot;
char immediate_execute_flag = YES;
char trace_mode_flag = NO;
extern int tty_input_chan;
extern int errno;
extern char exit_flag;
extern char intr_flag;
extern char susp_flag;
extern char input_pending_flag;
extern char alternate_escape_character;
extern char main_delete_character;
extern char alternate_delete_character;
extern char checkpoint_flag;
extern char checkpoint_enabled;
extern char waiting_for_input_flag;
extern char resize_flag;
extern char ring_audible_bell;
extern char suspend_is_okay_flag;
extern struct buff_header *curbuf,*buffer_headers;
extern int term_speed;
/*
* Forward declarations
*/
struct cmd_token *parse_rubout_character(struct cmd_token *,int);
struct cmd_token *parse_rubout_cmd_token(struct cmd_token *);
void preserve_rubout_char(char);
void parser_clean_preserve_list(void);
int parser_getc(void);
int unpreserve_rubout_char(struct cmd_token *);
char * trace_convert_opcode_to_name( int opcode );
char * trace_convert_state_to_name( int state );
char * trace_convert_exec_state_to_name( int state );
/**
* \brief Main entry point of the parser
*
* This routine reads input characters and builds the token
* list. It also calls the execute states as long as the go
* flag is set. When it hits the final parse state, it then
* executes any states which were not immediately executed.
*/
void
tecparse()
{
register struct cmd_token *ct;
int status;
int c;
static char no_mem = 0;
PREAMBLE();
/*
* We start our command token list with a special token that simply means that
* this is the begining of the list. We also set the current state to be the
* initial state of the parser.
*/
resume_execute_ct = NULL;
ct = allocate_cmd_token((struct cmd_token *)NULL);
if(ct != NULL){
no_mem = 0;
ct->opcode = TOK_C_FIRSTTOKEN;
ct->ctx.state = STATE_C_INITIALSTATE;
ct->ctx.go_flag = YES;
if(immediate_execute_flag == NO) ct->ctx.go_flag = NO;
cmd_list = ct;
screen_reset_echo(cmd_list);
/*
* Now we loop until we reach a final state, or something horrible happens.
*/
while(1){
c = parser_getc();
status = tecparse_syntax(c);
if(status == FAIL) break;
}/* End While */
screen_format_windows();
}/* End IF */
else {
if(no_mem){
tec_panic("no memory available");
}/* End IF */
no_mem = 1;
error_message("");
}/* End Else */
screen_refresh();
/*
* Here to clean up old parse lists. Note that we always clean up the list
* on last_cmd_list, and then move the current command list over there. This
* is so that we always remember one command string back incase the user uses
* the '*' command to save it all to a q-register. Besides unchaining command
* blocks, the cleanup routine follows down undo lists and macro lists to
* reclaim all the memory they are using.
*/
parser_cleanup_ctlist(last_cmd_list);
last_cmd_list = cmd_list;
cmd_list = NULL;
/*
* Also clean up the rubout Q-register.
*/
parser_clean_preserve_list();
/*
* Also, clean up any lookaside lists
*/
tec_gc_lists();
}/* End Routine */
/**
* \brief Here to manipulate the tree according to new input
*
* This routine is called with an input byte to manipulate the
* parser tree and execute any associated code.
*/
int
tecparse_syntax( int c )
{
register struct cmd_token *ct;
struct cmd_token trace_ct;
register struct cmd_token *final_token,*last_token;
int status;
char token_used,token_marked;
char old_modified_state;
struct buff_header *old_curbuf;
struct undo_token *ut;
PREAMBLE();
/*
* Find the end of the current command list.
*/
ct = cmd_list;
while(ct->next_token){
ct = ct->next_token;
}/* End While */
/*
* parse_special_character tests whether this character is an immediate
* typing control character which should not be sent to the state machine but
* handled locally. This is how we handle things like rubout, rubout word,
* and Control-U.
*/
if(parse_special_character(ct,c)){
return(1);
}/* End IF */
/*
* We only echo the character if is is not a special character
*/
screen_echo(c);
if(input_pending_flag == NO){
screen_format_windows();
screen_refresh();
}/* End IF */
/*
* We set the token_used flag to indicate that we have not used the input
* byte yet.
*/
token_used = token_marked = NO;
/*
* Now we loop until we use the input byte, or reach a terminating state
*/
while(1){
/*
* If the last state transition used the input byte, we return to our
* caller.
*/
if(token_used == YES){
return(1);
}/* End IF */
/*
* Allocate a command token to hold the next state transition in. The routine
* will automatically link it onto the end of the list.
*/
ct = allocate_cmd_token(ct);
if(ct == NULL){
error_message("");
return(1);
}/* End IF */
/*
* Here we check for the special RETURN state. Although all this could be done
* in the state machine itself, this was a good place to consolidate things.
* We pop the state machine stack a level so as to return to the calling state.
* Note that iarg1 and iarg2 are copied from the calling state, so that they
* are preserved. This means that the substate must return it's value through
* tmpval which is not preserved.
*/
if(ct->ctx.state == STATE_C_RETURN){
ct->ctx.state = ct->ctx.return_state;
ct->ctx.return_state = ct->ctx.caller_token->ctx.return_state;
ct->ctx.iarg1_flag = ct->ctx.caller_token->ctx.iarg1_flag;
ct->ctx.iarg2_flag = ct->ctx.caller_token->ctx.iarg2_flag;
ct->ctx.iarg1 = ct->ctx.caller_token->ctx.iarg1;
ct->ctx.iarg2 = ct->ctx.caller_token->ctx.iarg2;
ct->ctx.caller_token = ct->ctx.caller_token->ctx.caller_token;
}/* End IF */
/*
* Set up the initial state of the command token. The COPYTOKEN opcode doesn't
* really mean anything except that the opcode hasn't really been set, so it's
* more for debugging purposes than anything else. Notice that since we are
* actually placing an input byte in input_byte, we set the default that the
* state will indeed eat the byte. If this is not the case, it is up to the
* state to clear the flag.
*/
ct->opcode = TOK_C_COPYTOKEN;
ct->flags |= TOK_M_EAT_TOKEN;
ct->input_byte = c;
/*
* If this is the first time through here for this input character,
* mark this is the input character token so that rubout works correctly.
*/
if(token_marked == NO){
ct->opcode = TOK_C_INPUTCHAR;
token_marked = YES;
}/* End IF */
/*
* Call the state machine to process this character. Although more command
* tokens may be added onto the list by the state machine, we leave ct where
* it is for the moment so that we can work forward through all the generated
* states.
*/
parse_input_character(ct,ct);
/*
* If the state machine indicates that the input character was eaten, remember
* this fact.
*/
if(ct->flags & TOK_M_EAT_TOKEN) token_used = YES;
/*
* If this character would cause us to transition into an error state, we
* simply don't allow it. We generate a rubout sequence to remove the offending
* character and allow the user to make a decision about what to do next.
*/
if(ct->ctx.state == STATE_C_ERRORSTATE){
token_used = YES;
while(ct->next_token) ct = ct->next_token;
ct = parse_rubout_character(ct,0);
screen_reset_echo(cmd_list);
return(1);
}/* End IF*/
/*
* If ? debug mode is on, record new syntax tokens in the ? buffer
*/
if(trace_mode_flag == YES){
last_token = ct;
while(last_token){
trace_mode(TRACE_C_PARSE,last_token,0);
last_token = last_token->next_token;
}/* End While */
}/* End IF */
/*
* Ok, the state transition seems to have gone smoothly, if the go flag is set
* we are in immediate execute mode and can perform the execution phase of the
* state transition.
*/
if(resume_execute_ct != NULL){
ct = resume_execute_ct;
ct->ctx.go_flag = YES;
resume_execute_ct = NULL;
}
/*
* We need a place to chain off undo tokens. If we use the current token,
* loops will distribute undo tokens all over the parse tree, with no way
* to tell which order they were created in. So we find the last token, and
* chain everything off of that. That way, if a rubout is hit, all the undo
* tokens will be undone in order back to the last keystroke token. As the
* user types more keystrokes, we keep finding the new end of the command
* chain, and chaining undo tokens off of that. Thus order will be preserved.
*/
final_token = ct;
while (final_token->next_token) final_token = final_token->next_token;
last_token = ct->prev_token;
while(ct){
/*
* We still want to copy tmpvals forward from state to state unless the
* parse stage is attempting a store.
*/
if(last_token){
/*
* Carry the argument values forward to this state. If the last state was a
* RETURN state, then only copy out the tmpval, and fetch the callers iargs.
*/
if((ct->flags & TOK_M_PARSELOAD_IARG1) == 0){
ct->ctx.iarg1 = last_token->ctx.iarg1;
}/* End IF */
if((ct->flags & TOK_M_PARSELOAD_IARG2) == 0){
ct->ctx.iarg2 = last_token->ctx.iarg2;
}/* End IF */
if(ct->ctx.state == STATE_C_RETURN){
if((ct->flags & TOK_M_PARSELOAD_IARG1) == 0){
ct->ctx.iarg1 = ct->ctx.caller_token->ctx.iarg1;
}/* End IF */
if((ct->flags & TOK_M_PARSELOAD_IARG2) == 0){
ct->ctx.iarg2 = ct->ctx.caller_token->ctx.iarg2;
}/* End IF */
}/* End IF */
/*
* If the next state is STOREVAL, the syntax stage is setting storeval. The
* typical example of this is when the syntax stage sees a constant like '1'.
* It uses this state to set the temporary value to 1.
*/
if(
ct->execute_state != EXEC_C_STOREVAL &&
((ct->flags & TOK_M_PARSELOAD_TMPVAL) == 0)
){
ct->ctx.tmpval = last_token->ctx.tmpval;
}/* End IF */
}/* End IF */
if(ct->execute_state){
/*
* This is sort of a kludge, but it's an easy place to see if this
* state transition causes the buffer to become modified. If so, we
* link on an undo token to that if this gets undone, the modified
* status gets put back. If we didn't do it here, we would have to
* either do it in every command, and that would get tedious.
*/
old_modified_state = curbuf->ismodified;
old_curbuf = curbuf;
if(trace_mode_flag == YES){
trace_ct = *ct;
}/* End IF */
status = execute_a_state(ct,final_token);
if(status == BLOCKED){
resume_execute_ct = ct;
}
/*
* An INVALIDATE status occurs when the execute engine changes the
* command token list in such a way that we may no longer be pointing
* at something valid. So we back out, and re-enter..
*/
if(status == INVALIDATE){
return(SUCCESS);
}
if(trace_mode_flag == YES){
trace_mode(TRACE_C_EXEC,&trace_ct,ct);
}/* End IF */
/*
* If the modified state went from unmodified to modified, link on an
* undo token incase this gets undone - then the modified status will
* get put back to its original state.
*/
if(old_modified_state == NO && old_curbuf->ismodified == YES){
if(ct->undo_list){
ut = ct->undo_list;
while(ut->next_token) ut = ut->next_token;
ut->next_token = allocate_undo_token(NULL);
ut = ut->next_token;
}/* End IF */
else ct->undo_list = ut = allocate_undo_token(NULL);
if(ut != NULL){
ut->opcode = UNDO_C_MODIFIED;
ut->carg1 = (char *)old_curbuf;
}/* End IF */
}/* End IF */
if(susp_flag) cmd_pause();
/*
* Since we are in immediate execute mode, if we get an error during the
* execution phase, we know it was generated by the most recently input
* character. Therefore, we can handle it the same way we do during the syntax
* parsing, by pretending a rubout character was input.
*/
if(status == BLOCKED) break;
if(intr_flag) break;
if(status != SUCCESS){
token_used = YES;
while(ct->next_token) ct = ct->next_token;
ct = parse_rubout_character(ct,0);
screen_reset_echo(cmd_list);
break;
}/* End IF */
}/* End IF */
last_token = ct;
if(jump_to_token){
ct = jump_to_token;
jump_to_token = NULL;
continue;
}
if(ct->next_token) ct = ct->next_token;
else break;
}/* End While */
/*
* Now regardless of whether go_flag is set, chain ct forward to the end of
* the token list.
*/
while(ct->next_token) ct = ct->next_token;
/*
* If we hit FINALSTATE, this is the way the state machine has of telling us
* to reset to the begining parser state. We remember the final token address
* so that all additional undo tokens can be chained off of it.
*/
if(ct->ctx.state == STATE_C_FINALSTATE){
return(0);
}/* End IF */
}/* End While */
}/* End Routine */
/**
* \brief Here to execute a Q register as a macro
*
* This routine executes the specified q register as a macro. It returns
* SUCCESS or FAILURE depending on what happens within the macro. Note
* that it is very similar to the main parse routine. There are two major
* differences: First, the characters are gotton from the q-register
* rather than the input stream, and second, the entire parse is done
* to completion before any execution takes place. This means that the
* macro can modify the contents of the q-register without changing the
* way the macro will execute.
*/
int
tecmacro(
struct buff_header *qbp,
struct cmd_token *input_ct,
struct cmd_token **macro_cmd_list )
{
register struct cmd_token *ct;
struct cmd_token trace_ct;
register struct cmd_token *last_token;
int c = 0;
int status;
char token_used;
unsigned long i;
char old_modified_state;
struct buff_header *old_curbuf;
struct undo_token *ut;
PREAMBLE();
/*
* We start our command token list with a special token that simply means that
* this is the begining of the list. We also set the current state to be the
* initial state of the parser.
*/
ct = allocate_cmd_token((struct cmd_token *)NULL);
if(ct == NULL) return(FAIL);
ct->opcode = TOK_C_FIRSTTOKEN;
ct->ctx.state = STATE_C_INITIALSTATE;
ct->ctx.go_flag = NO;
/*
* By setting STATUS_PASSED, we insure that the first command in the macro will
* get any arguments we have been passed.
*/
ct->ctx.flags |= CTOK_M_STATUS_PASSED;
ct->ctx.iarg1_flag = input_ct->ctx.iarg1_flag;
ct->ctx.iarg2_flag = input_ct->ctx.iarg2_flag;
ct->ctx.iarg1 = input_ct->ctx.iarg1;
ct->ctx.iarg2 = input_ct->ctx.iarg2;
*macro_cmd_list = ct;
/*
* We set the token_used flag so that we will call the getc routine. This flag
* in general lets us remember whether or not a state transistion ate an input
* character or not.
*/
token_used = YES;
/*
* Now we loop until we reach a final state, or something horrible happens.
*/
i = 0;
while(i <= qbp->zee){
/*
* Allocate a command token to hold the next state transition in. The routine
* will automatically link it onto the end of the list.
*/
ct = allocate_cmd_token(ct);
if(ct == NULL) return(FAIL);
/*
* Here we check for the special RETURN state. Although all this could be done
* in the state machine itself, this was a good place to consolidate things.
* We pop the state machine stack a level so as to return to the calling state.
* Note that iarg1 and iarg2 are copied from the calling state, so that they
* are preserved. This means that the substate must return it's value through
* tmpval which is not preserved.
*/
if(ct->ctx.state == STATE_C_RETURN){
ct->ctx.state = ct->ctx.return_state;
ct->ctx.return_state = ct->ctx.caller_token->ctx.return_state;
ct->ctx.iarg1_flag = ct->ctx.caller_token->ctx.iarg1_flag;
ct->ctx.iarg2_flag = ct->ctx.caller_token->ctx.iarg2_flag;
ct->ctx.iarg1 = ct->ctx.caller_token->ctx.iarg1;
ct->ctx.iarg2 = ct->ctx.caller_token->ctx.iarg2;
ct->ctx.caller_token = ct->ctx.caller_token->ctx.caller_token;
}/* End IF */
/*
* Set up the comand token a little
*/
ct->opcode = TOK_C_COPYTOKEN;
ct->flags |= TOK_M_EAT_TOKEN;
ct->input_byte = c;
/*
* If the last state ate the input character, we need to fetch another from the
* command source.
*/
if(token_used == YES){
if(i == qbp->zee) c = ESCAPE;
else c = buff_contents(qbp,i++);
#ifdef NEEDED_WHICH_I_DONT_THINK_IT_IS
if(parse_special_character(ct,c)){
ct = *macro_cmd_list;
while(ct->next_token) ct = ct->next_token;
continue;
}/* End IF */
#endif
ct->opcode = TOK_C_INPUTCHAR;
ct->input_byte = c;
}/* End IF */
token_used = NO;
/*
* Call the state machine to process this character. Although more command
* tokens may be added onto the list by the state machine, we leave ct where
* it is for the moment so that we can work forward through all the generated
* states.
*/
parse_input_character(ct,*macro_cmd_list);
/*
* If the state machine indicates that the input character was eaten, remember
* this fact.
*/
if(ct->flags & TOK_M_EAT_TOKEN) token_used = YES;
/*
* If this character would cause us to transition into an error state, we
* terminate the macro and indicate where the error was.
*/
if(ct->ctx.state == STATE_C_ERRORSTATE){
token_used = YES;
while(ct->next_token) ct = ct->next_token;
while(ct->opcode != TOK_C_FIRSTTOKEN){
ct = parse_rubout_character(ct,0);
}/* End While */
return(FAIL);
}/* End IF*/
/*
* Always chain ct forward over any generated tokens
*/
while(ct->next_token) ct = ct->next_token;
/*
* If we hit FINALSTATE, this is the way the state machine has of telling us
* to reset to the begining parser state.
*/
if(ct->ctx.state == STATE_C_FINALSTATE) break;
}/* End While */
/*
* Now that the syntax parsing has been completed, we start execution of the
* macro.
*/
ct = last_token = *macro_cmd_list;
while(ct){
/*
* If we hit the final state, we don't need to go any further.
*/
if(ct->ctx.state == STATE_C_FINALSTATE) break;
/*
* Carry the argument values forward to this state. If the last state was a
* RETURN state, then only copy out the tmpval, and fetch the callers iargs.
*/
if((ct->flags & TOK_M_PARSELOAD_IARG1) == 0){
ct->ctx.iarg1 = last_token->ctx.iarg1;
}/* End IF */
if((ct->flags & TOK_M_PARSELOAD_IARG2) == 0){
ct->ctx.iarg2 = last_token->ctx.iarg2;
}/* End IF */
if(ct->ctx.state == STATE_C_RETURN){
if((ct->flags & TOK_M_PARSELOAD_IARG1) == 0){
ct->ctx.iarg1 = ct->ctx.caller_token->ctx.iarg1;
}/* End IF */
if((ct->flags & TOK_M_PARSELOAD_IARG2) == 0){
ct->ctx.iarg2 = ct->ctx.caller_token->ctx.iarg2;
}/* End IF */
}/* End IF */
/*
* If the next state is STOREVAL, the syntax stage is setting storeval. The
* typical example of this is when the syntax stage sees a constant like '1'.
* It uses this state to set the temporary value to 1.
*/
if(
ct->execute_state != EXEC_C_STOREVAL &&
((ct->flags & TOK_M_PARSELOAD_TMPVAL) == 0)
){
ct->ctx.tmpval = last_token->ctx.tmpval;
}/* End IF */
/*
* If this token has an execute state, call the execute phase to implement it.
*/
if(trace_mode_flag == YES){
trace_mode(TRACE_C_MACRO,ct,0);
}/* End IF */
if(ct->execute_state){
old_modified_state = curbuf->ismodified;
old_curbuf = curbuf;
if(trace_mode_flag == YES){
trace_ct = *ct;
}/* End IF */
status = execute_a_state(ct,*macro_cmd_list);
if(trace_mode_flag == YES){
trace_mode(TRACE_C_EXEC,&trace_ct,ct);
}/* End IF */
if(old_modified_state == NO && old_curbuf->ismodified == YES){
if(ct->undo_list){
ut = ct->undo_list;
while(ut->next_token) ut = ut->next_token;
ut->next_token = allocate_undo_token(NULL);
ut = ut->next_token;
}/* End IF */
else ct->undo_list = ut = allocate_undo_token(NULL);
if(ut != NULL){
ut->opcode = UNDO_C_MODIFIED;
ut->carg1 = (char *)old_curbuf;
}/* End IF */
}/* End IF */
if(status != SUCCESS) goto cleanup;
if(exit_flag == YES) goto cleanup;
if(intr_flag) goto cleanup;
if(susp_flag) cmd_pause();
}/* End IF */
/*
* Ok, now chain to the next token, or quit if done
*/
last_token = ct;
ct = ct->next_token;
if(jump_to_token){
ct = jump_to_token;
last_token = ct;
jump_to_token = NULL;
}/* End IF */
}/* End While */
cleanup:
if(input_ct->ctx.flags & CTOK_M_STATUS_PASSED){
input_ct->ctx.iarg1_flag = last_token->ctx.iarg1_flag;
input_ct->ctx.iarg1 = last_token->ctx.iarg1;
}/* End IF */
return(SUCCESS);
}/* End Routine */
/**
* \brief Test for and handle special characters
*
* This routine is called on each input character to determine whether
* it requires special handling. It catches characters such as rubout,
* ^W, ^U.
*/
int
parse_special_character( struct cmd_token *ct, int c )
{
char state_seen;
int tmp;
PREAMBLE();
switch(c){
case RUBOUT:
ct = parse_rubout_character(ct,1);
break;
case CNTRL_U:
/*
* Get rid of any right at the deletion point
*/
if(ct->opcode == TOK_C_INPUTCHAR){
ct = parse_rubout_character(ct,1);
}/* End IF */
while(ct != cmd_list){
if(ct->opcode == TOK_C_INPUTCHAR && ct->input_byte == '\n'){
break;
}/* End IF */
ct = parse_rubout_character(ct,1);
}/* End While */
break;
case CNTRL_W:
state_seen = 0;
tmp = 0;
while(ct != cmd_list){
if(ct->flags & TOK_M_WORDBOUNDARY){
state_seen = 1;
break;
}/* End IF */
if(ct->opcode == TOK_C_INPUTCHAR){
tmp += 1;
if(tmp == 1 && ct->input_byte == '\n'){
preserve_rubout_char(ct->input_byte);
ct = parse_rubout_cmd_token(ct);
break;
}/* End IF */
if(ct->input_byte != ' ' && ct->input_byte != '\t') break;
preserve_rubout_char(ct->input_byte);
}/* End IF */
ct = parse_rubout_cmd_token(ct);
}/* End While */
while(ct != cmd_list){
if(ct->flags & TOK_M_WORDBOUNDARY) state_seen = 1;
if(ct->opcode == TOK_C_INPUTCHAR){
if(state_seen){
preserve_rubout_char(ct->input_byte);
ct = parse_rubout_cmd_token(ct);
break;
}/* End IF */
if(isspace((int)ct->input_byte)) break;
preserve_rubout_char(ct->input_byte);
}/* End IF */
ct = parse_rubout_cmd_token(ct);
}/* End While */
break;
case CNTRL_R:
if(!unpreserve_rubout_char(ct)){
error_message("^R no input tokens available");
}/* End IF */
return(1);
default:
return(0);
}/* End Switch */
screen_reset_echo(cmd_list);
return(1);
}/* End Routine */
/**
* \brief Rubout the most recent character
*
* This routine is called when a rubout character is typed. We have to
* back the parser up to the state it was in before the original char
* was typed, as well as performing any undo functions to make sure
* that the edit buffer also gets backed up.
*/
struct cmd_token *
parse_rubout_character( struct cmd_token *ct, int preserve_flag )
{
register struct cmd_token *oct;
struct undo_token *ut;
char saved_opcode;
PREAMBLE();
while(1){
/*
* If the preserve flag is on, we want to save any deleted bytes in the
* q-register that is used for this purpose. That way, the user can
* correct for mistakenly typing the wrong rubout code.
*/
if(preserve_flag && ct->opcode == TOK_C_INPUTCHAR){
preserve_rubout_char(ct->input_byte);
}/* End IF */
/*
* For each of the command tokens, we need to undo all the chained undo
* tokens.
*/
while( (ut = ct->undo_list) != NULL ){
/*
* Take the top undo token off of the list and change the listhead to point
* to it's child.
*/
ct->undo_list = ut->next_token;
ut->next_token = NULL;
/*
* Now call the undo routine to back out the changes to the edit buffer that
* this token calls for. Then place the token back on the free list.
*/
parser_undo(ut);
free_undo_token(ut);
}/* End While */
/*
* If this is TOK_C_FIRSTTOKEN, it means he is trying to rubout the head of the
* list. This is probably not such a hot idea...
*/
if(ct->opcode == TOK_C_FIRSTTOKEN) break;
/*
* We save the opcode so that after cleaning up the token, we will know whether
* it was an input character or not.
*/
saved_opcode = ct->opcode;
oct = ct->prev_token;
if(oct == NULL) break;
oct->next_token = NULL;
ct->prev_token = NULL;
free_cmd_token(ct);
ct = oct;
/*
* If this was an input character, then we have backed up enough.
*/
if(saved_opcode == TOK_C_INPUTCHAR) break;
}/* End While */
return(ct);
}/* End Routine */
/**
* \brief Rubout the most recent command token
*
* This routine is called to remove the last token on the command
* list. It gets used in rubout / ^U / ^W processing.
*/
struct cmd_token *
parse_rubout_cmd_token( struct cmd_token *ct )
{
register struct cmd_token *oct;
struct undo_token *ut;
PREAMBLE();
/*
* We need to undo all the undo tokens chained off of this command token.
*/
while( (ut = ct->undo_list) != NULL ){
/*
* Take the top undo token off of the list and change the listhead to point
* to it's child.
*/
ct->undo_list = ut->next_token;
ut->next_token = NULL;
/*
* Now call the undo routine to back out the changes to the edit buffer that
* this token calls for. Then place the token back on the free list.
*/
parser_undo(ut);
free_undo_token(ut);
}/* End While */
oct = ct->prev_token;
if(oct) oct->next_token = NULL;
ct->prev_token = NULL;
free_cmd_token(ct);
return(oct);
}/* End Routine */
/**
* \brief Return next input character
*
* This routine is called by the parser when another input byte is needed.
*/
int
parser_getc()
{
register int i;
char inbuf[4];
#ifdef VMS
short qio_iosb[4];
#endif /* VMS */
PREAMBLE();
/*
* If there are no unclaimed bytes in the buffer, we need to read one
* from the command channel.
*/
input_pending_flag = tty_input_pending();
if(input_pending_flag == NO){
if(ring_audible_bell){
term_putc(BELL);
ring_audible_bell = 0;
}/* End IF */
screen_echo('\0');
screen_format_windows();
screen_refresh();
}/* End IF */
#ifdef CHECKPOINT
if(checkpoint_enabled == YES && checkpoint_flag == YES){
cmd_checkpoint();
checkpoint_flag = NO;
}/* End IF */
#endif /* CHECKPOINT */
while(1){
#ifdef UNIX
if(susp_flag){
pause_while_in_input_wait();
continue;
}/* End IF */
if(resize_flag){
screen_resize();
}/* End IF */
waiting_for_input_flag = YES;
i = read(tty_input_chan,inbuf,1);
waiting_for_input_flag = NO;
intr_flag = 0;
if(i >= 0) break;
if(errno == EINTR) continue;
#endif
#ifdef MSDOS
waiting_for_input_flag = YES;
/* does not echo */
i = getch();
waiting_for_input_flag = NO;
intr_flag = 0;
if(i != EOF){
inbuf[0] = i == '\r' ? '\n' : i;
break;
}
#endif
#ifdef VMS
waiting_for_input_flag = YES;
i = sys$qiow(0,tty_input_chan,IO$_READVBLK|IO$M_NOECHO|IO$M_NOFILTR,
qio_iosb,0,0,inbuf,1,0,0,0,0);
waiting_for_input_flag = NO;
if(!(i & STS$M_SUCCESS)) exit(i);
if(qio_iosb[0] != 1)
printf("!!! iosb[0] is %d\n",qio_iosb[0]);
if(inbuf[0] == '\r') inbuf[0] = '\n';
else if(inbuf[0] == '\n') inbuf[0] = '\r';
if(inbuf[0] == '`') inbuf[0] = ESCAPE;
if(inbuf[0] == CNTRL_Z && suspend_is_okay_flag == YES){
pause_while_in_input_wait();
continue;
}/* End IF */
break;
#endif
perror("error reading command input");
punt(errno);
}/* End While */
screen_reset_message();
input_pending_flag = tty_input_pending();
if(inbuf[0] == alternate_escape_character){
return(ESCAPE);
}/* End IF */
if(inbuf[0] == main_delete_character){
return(RUBOUT);
}/* End IF */
if(inbuf[0] == alternate_delete_character){
return(RUBOUT);
}/* End IF */
return(inbuf[0]);
}/* End Routine */
/**
* \brief Save rubbed out characters
*
* This routine is called in response to the user rubbing out input
* characters with rubout, ^U, or ^W. Sometimes he does this by
* mistake, and can delete large amounts of typing unintentially.
* This routine saves these characters in a special Q-register so
* that he can get them back if he wants.
*/
void
preserve_rubout_char( char the_byte )
{
register struct buff_header *qbp;
PREAMBLE();
/*
* Get a pointer to the special Q-register which holds the characters which
* have been rubbed out.
*/
qbp = buff_qfind('@',1);
if(qbp == NULL){
return;
}/* End IF */
/*
* Put the deleted byte into the Q-register where it can be retrieved by
* the user if so desired.
*/
buff_insert_char(qbp,0,the_byte);
}/* End Routine */
/**
* \brief Poke a rubbed out char back into the parse
*
* This routine is called on behalf of a ^R command which causes the
* most recent rubbed out character to be restored to the parse tree.
* The return code determines whether this was done okay or not.
*/
int
unpreserve_rubout_char( struct cmd_token *ct )
{
register struct buff_header *qbp;
int c;
PREAMBLE();
/*
* Get a pointer to the special Q-register which holds the characters which
* have been rubbed out.
*/
qbp = buff_qfind('@',1);
if(qbp == NULL){
return(FAIL);
}/* End IF */
/*
* Make sure thre are some bytes in it
*/
if(!qbp->zee) return(FAIL);
/*
* Get the first byte saved in the Q-register
*/
c = buff_contents(qbp,0);
buff_delete(qbp,0,1);
tecparse_syntax(c);
return(SUCCESS);
}/* End Routine */
/**
* \brief Zero the rubout preserve Q-register
*
* This routine is called at double-escape time to clean up the
* special Q-register so that it doesn't grow without bounds.
*/
void
parser_clean_preserve_list( void )
{
register struct buff_header *qbp;
PREAMBLE();
/*
* Get a pointer to the special Q-register which holds the characters which
* have been rubbed out.
*/
qbp = buff_qfind('@',1);
if(qbp == NULL){
return;
}/* End IF */
/*
* Delete all the bytes in the Q-register
*/
buff_delete(qbp,0,qbp->zee);
}/* End Routine */
/**
* \brief Copy the current parse tree into a Q-register
*
* This routine copies the input bytes from the current command string
* into the specified Q-register.
*/
void
parser_dump_command_line( struct buff_header *qbp )
{
register struct cmd_token *ct;
PREAMBLE();
ct = cmd_list;
while(ct){
if(ct->opcode == TOK_C_INPUTCHAR){
buff_insert_char(qbp,qbp->zee,ct->input_byte);
}/* End IF */
ct = ct->next_token;
}/* End While */
}/* End Routine */
/**
* \brief Replace current parse tree
*
* This routine replaces the current command string with the contents
* the specified Q-register.
*/
int
parser_replace_command_line( struct buff_header *qbp )
{
register struct cmd_token *ct;
register struct cmd_token *first_different_ct;
register unsigned long c;
char temp;
register char *command_buffer;
register unsigned long cb_zee;
PREAMBLE();
cb_zee = 0;
command_buffer = tec_alloc(TYPE_C_CBUFF,qbp->zee);
if(command_buffer == NULL) return(FAIL);
/*
* Walk the parse list to find the first place there is a difference
* between the current parse list, and the one to be installed. When
* we find the first difference, remember it, and then start copying
* the changed bytes into our temporary Q-register.
*/
first_different_ct = NULL;
ct = cmd_list;
for(c = 0; c < qbp->zee - 1; c++){
temp = buff_contents(qbp,c);
if(first_different_ct == NULL){
while(ct && ct->opcode != TOK_C_INPUTCHAR){
ct = ct->next_token;
}/* End While */
if(ct && ct->input_byte != temp) first_different_ct = ct;
if(ct && ct->next_token) ct = ct->next_token;
}/* End IF */
if(first_different_ct){
command_buffer[cb_zee++] = temp;
}/* End IF */
}/* End FOR */
if(ct != NULL && first_different_ct == NULL){
while(ct->next_token){
if(ct->opcode == TOK_C_INPUTCHAR) break;
ct = ct->next_token;
}
first_different_ct = ct;
}
/*
* We only have to do the following if there were any changed bytes at
* all. If he changed his mind and didn't modify the command list at all,
* nothing really has to happen at all.
*/
if(first_different_ct){
while(first_different_ct->next_token != NULL &&
first_different_ct->next_token->opcode != TOK_C_INPUTCHAR){
first_different_ct = first_different_ct->next_token;
}
ct = cmd_list;
while(ct->next_token) ct = ct->next_token;
/*
* Remove from the tail of the parse list all the bytes up to and including
* the first different character. This leaves us with a parse list which is
* just the part that has not changed.
*/
temp = 1;
while(ct != cmd_list && temp != 0){
if(ct == first_different_ct) temp = 0;
ct = parse_rubout_character(ct,0);
}/* End While */
/*
* Now we walk through the Q-register, adding these bytes to the end of the
* parse list. These are the bytes which are different from the original
* parse list.
*/
qbp->pos_cache.lbp = NULL;
input_pending_flag = YES;
for(c = 0; c < cb_zee; c++){
temp = command_buffer[c];
tecparse_syntax(temp);
}/* End While */
}/* End IF */
tec_release(TYPE_C_CBUFF,command_buffer);
parser_reset_echo();
return(SUCCESS);
}/* End Routine */
/**
* \brief Allocate a command token structure
*
* This routine is called to allocate a command token structure. If there
* is one on the free list, it is used, otherwise we allocate one. If
* an old_token was specified, the context area is copied into the new
* token, which has the effect of rippling the context forward through
* the parse.
*/
struct cmd_token *
allocate_cmd_token( struct cmd_token *old_token )
{
register struct cmd_token *ct;
PREAMBLE();
/*
* Call the memory allocator for a command token block
*/
ct = (struct cmd_token *)tec_alloc(TYPE_C_CMD,sizeof(struct cmd_token));
if(ct == NULL) return(NULL);
/*
* We set up the initial state to be that of an empty token, with fields
* which are not set up yet set to their proper defaults.
*/
memset(ct,0,sizeof(*ct));
/*
* If there was an old token specified, two things must happen. First, we
* have to link the new token onto the old token list. Second, we have to
* copy the context area from the old token into the new one.
*/
if(old_token){
old_token->next_token = ct;
ct->prev_token = old_token;
ct->ctx = old_token->ctx;
}/* End IF */
return(ct);
}/* End Routine */
/**
* \brief Routine to place a cmd token on the free list
*
* This routine is called with the address of the command token
* to be placed on the free list.
*/
void
free_cmd_token( struct cmd_token *ct )
{
PREAMBLE();
tec_release(TYPE_C_CMD,(char *)ct);
}/* End Routine */
/**
* \brief Pauses with the terminal in a good state
*
* This routine is called to pause the editor while we have been in
* an input wait state. The big deal here is that we want to remove
* the reverse video box that may be on the echo line before we pause
* back to the system command processor.
*/
void
pause_while_in_input_wait()
{
PREAMBLE();
screen_reset_echo(cmd_list);
screen_refresh();
cmd_pause();
screen_echo('\0');
screen_refresh();
}/* End Routine */
/**
* \brief Routine to deallocate all the blocks on a ct list
*
* This function deallocates all the blocks on a command token list,
* including cmd_tokens and undo_tokens.
*/
void
parser_cleanup_ctlist( struct cmd_token *ct )
{
register struct cmd_token *oct;
PREAMBLE();
/*
* For each command token, if it has a list of undo tokens connected we
* call the routine which knows how to clean them up.
*/
while(ct){
if(ct->undo_list){
tecundo_cleanup(ct->undo_list);
}/* End IF */
ct->undo_list = NULL;
/*
* Now we remember what the next token in the list is, and then call the
* routine to free the current one.
*/
oct = ct;
ct = ct->next_token;
free_cmd_token(oct);
}/* End While */
}/* End Routine */
/**
* \brief Called by routines that don't want any arguments
*
* This function is called by states which don't want to accept any
* arguments. If there are any present, it will generate an error message
* and set the error state.
*/
int
parse_any_arguments( struct cmd_token *ct, char *cmd_name )
{
char tmp_message[LINE_BUFFER_SIZE];
PREAMBLE();
/*
* If either of the iarg flags is set, that means we received an argument.
*/
if(ct->ctx.iarg1_flag == YES || ct->ctx.iarg2_flag == YES){
(void) strcpy(tmp_message,"?The ");
(void) strcat(tmp_message,cmd_name);
(void) strcat(tmp_message," command accepts no arguments");
error_message(tmp_message);
ct->ctx.state = STATE_C_ERRORSTATE;
return(1);
}/* End IF */
return(0);
}/* End Routine */
/**
* \brief Called by routines that only want one arg
*
* This function is called by states which only want to accept one
* argument. If there are two present, it will generate an error message
* and set the error state.
*/
int
parse_more_than_one_arg( struct cmd_token *ct, char *cmd_name )
{
char tmp_message[LINE_BUFFER_SIZE];
PREAMBLE();
/*
* If the iarg2 flag is set, that means that we received two arguments when
* we really only want one.
*/
if(ct->ctx.iarg2_flag == YES){
(void) strcpy(tmp_message,"?Two Arguments to ");
(void) strcat(tmp_message,cmd_name);
(void) strcat(tmp_message," not allowed");
error_message(tmp_message);
ct->ctx.state = STATE_C_ERRORSTATE;
return(1);
}/* End IF */
return(0);
}/* End Routine */
/**
* \brief Check for illegal buffer positions
*
* This routine is called to verify that buffer positions specified are
* legal. If they are not, it generates an error message.
*/
int
parse_illegal_buffer_position( long pos1, long pos2, char *cmd_name )
{
char illegal_position;
char tmp_message[LINE_BUFFER_SIZE];
PREAMBLE();
illegal_position = 0;
if(pos1 < 0) illegal_position = 1;
else if(pos2 < 0) illegal_position = 1;
else if((unsigned long)pos1 > curbuf->zee) illegal_position = 1;
else if((unsigned long)pos2 > curbuf->zee) illegal_position = 1;
if(illegal_position == 0) return(0);
(void) strcpy(tmp_message,"?Attempt to Move Pointer Off Page with ");
(void) strcat(tmp_message,cmd_name);
error_message(tmp_message);
return(1);
}/* End Routine */
/**
* \brief Re-echo the input line
*
* This is just an entry point to restore the echo line from a module
* that doesn't want to know about the cmd_list structure.
*/
void
parser_reset_echo()
{
PREAMBLE();
screen_reset_echo(cmd_list);
}/* End Routine */
/**
* \brief Trace execution of commands
*
* This routine is called at parse and execute time if tracing has been
* enabled by the ? command. It causes q-register ? to be filled with
* execution trace information.
*/
void
trace_mode( int phase, struct cmd_token *ct0, struct cmd_token *ct1 )
{
register struct buff_header *qbp;
char tmp_message[LINE_BUFFER_SIZE];
register char *cp;
register char *state_name;
PREAMBLE();
qbp = buff_qfind('?',1);
if(qbp == NULL) return;
switch(phase){
case TRACE_C_PARSE:
state_name = trace_convert_opcode_to_name(ct0->opcode);
if(state_name == NULL) state_name = "UNKNOWN";
sprintf(tmp_message, "PARSE: %p Opcode %s %c",
ct0, state_name,
/* ct0->opcode == TOK_C_INPUTCHAR ? ct0->input_byte : ' '); */
ct0->flags & TOK_M_EAT_TOKEN ? ct0->input_byte : ' ');
if(ct0->flags & TOK_M_EAT_TOKEN){
strcat(tmp_message," TOK_M_EAT_TOKEN");
}/* End IF */
if(ct0->flags & TOK_M_WORDBOUNDARY){
strcat(tmp_message," TOK_M_WORDBOUNDARY");
}/* End IF */
if(ct0->flags & TOK_M_PARSELOAD_IARG1){
strcat(tmp_message," TOK_M_PARSELOAD_IARG1");
}/* End IF */
if(ct0->flags & TOK_M_PARSELOAD_IARG2){
strcat(tmp_message," TOK_M_PARSELOAD_IARG2");
}/* End IF */
if(ct0->flags & TOK_M_PARSELOAD_TMPVAL){
strcat(tmp_message," TOK_M_PARSELOAD_TMPVAL");
}/* End IF */
strcat(tmp_message,"\n");
buff_insert(qbp,qbp->zee,tmp_message,strlen(tmp_message));
/* int execute_state; */
state_name = trace_convert_state_to_name(ct0->ctx.state);
if(state_name == NULL) state_name = "UNKNOWN";
sprintf(tmp_message," Parser State: %s '%c'",
state_name,isprint((int)ct0->q_register) ?
ct0->q_register : ' ');
if(ct0->ctx.flags & CTOK_M_COLON_SEEN){
strcat(tmp_message," CTOK_M_COLON_SEEN");
}/* End IF */
if(ct0->ctx.flags & CTOK_M_ATSIGN_SEEN){
strcat(tmp_message," CTOK_M_ATSIGN_SEEN");
}/* End IF */
if(ct0->ctx.flags & CTOK_M_STATUS_PASSED){
strcat(tmp_message," CTOK_M_STATUS_PASSED");
}/* End IF */
strcat(tmp_message,"\n");
buff_insert(qbp,qbp->zee,tmp_message,strlen(tmp_message));
if(ct0->ctx.go_flag == 0){
sprintf(tmp_message," Go flag clear\n");
buff_insert(qbp,qbp->zee,tmp_message,strlen(tmp_message));
}/* End IF */
if(ct0->ctx.pnest || ct0->ctx.inest || ct0->ctx.cnest){
sprintf(tmp_message," PNEST: %d INEST %d CNEST %d\n",
ct0->ctx.pnest,ct0->ctx.inest,ct0->ctx.cnest);
buff_insert(qbp,qbp->zee,tmp_message,strlen(tmp_message));
}/* End IF */
sprintf(tmp_message," iarg1_flag %d iarg1 %ld (0x%lx)\n",
ct0->ctx.iarg1_flag,ct0->ctx.iarg1,ct0->ctx.iarg1);
buff_insert(qbp,qbp->zee,tmp_message,strlen(tmp_message));
sprintf(tmp_message," iarg2_flag %d iarg2 %ld (0x%lx)\n",
ct0->ctx.iarg2_flag,ct0->ctx.iarg2,ct0->ctx.iarg2);
buff_insert(qbp,qbp->zee,tmp_message,strlen(tmp_message));
sprintf(tmp_message," carg %p\n",ct0->ctx.carg);
buff_insert(qbp,qbp->zee,tmp_message,strlen(tmp_message));
sprintf(tmp_message," tmpval %ld (0x%lx)\n",
ct0->ctx.tmpval,ct0->ctx.tmpval);
buff_insert(qbp,qbp->zee,tmp_message,strlen(tmp_message));
if(ct0->ctx.return_state || ct0->ctx.caller_token){
state_name = "";
if(ct0->ctx.return_state){
state_name =
trace_convert_state_to_name(ct0->ctx.return_state);
if(state_name == NULL) state_name = "UNKNOWN";
}/* End IF */
sprintf(tmp_message, " return_state %s caller_token %p\n",
state_name, ct0->ctx.caller_token);
buff_insert(qbp,qbp->zee,tmp_message,strlen(tmp_message));
}/* End IF */
break;
case TRACE_C_EXEC:
state_name = trace_convert_exec_state_to_name(ct0->execute_state);
if(state_name == NULL) state_name = "UNKNOWN";
sprintf(tmp_message, "EXEC: %p Exec State: %s\n",
ct1, state_name);
buff_insert(qbp,qbp->zee,tmp_message,strlen(tmp_message));
sprintf(tmp_message," iarg1_flag %d iarg1 %ld (0x%lx)",
ct0->ctx.iarg1_flag,ct0->ctx.iarg1,ct0->ctx.iarg1);
while(strlen(tmp_message) < 39) strcat(tmp_message," ");
strcat(tmp_message," ");
cp = &tmp_message[strlen(tmp_message)];
sprintf(cp," iarg1_flag %d iarg1 %ld (0x%lx)\n",
ct1->ctx.iarg1_flag,ct1->ctx.iarg1,ct1->ctx.iarg1);
buff_insert(qbp,qbp->zee,tmp_message,strlen(tmp_message));
sprintf(tmp_message," iarg2_flag %d iarg2 %ld (0x%lx)",
ct0->ctx.iarg2_flag,ct0->ctx.iarg2,ct0->ctx.iarg2);
while(strlen(tmp_message) < 39) strcat(tmp_message," ");
strcat(tmp_message," ");
cp = &tmp_message[strlen(tmp_message)];
sprintf(cp," iarg2_flag %d iarg2 %ld (0x%lx)\n",
ct1->ctx.iarg2_flag,ct1->ctx.iarg2,ct1->ctx.iarg2);
buff_insert(qbp,qbp->zee,tmp_message,strlen(tmp_message));
sprintf(tmp_message," carg %p",ct0->ctx.carg);
while(strlen(tmp_message) < 39) strcat(tmp_message," ");
strcat(tmp_message," ");
cp = &tmp_message[strlen(tmp_message)];
sprintf(cp," carg %p\n",ct1->ctx.carg);
buff_insert(qbp,qbp->zee,tmp_message,strlen(tmp_message));
sprintf(tmp_message," tmpval %ld (0x%lx)",
ct0->ctx.tmpval,ct0->ctx.tmpval);
while(strlen(tmp_message) < 39) strcat(tmp_message," ");
strcat(tmp_message," ");
cp = &tmp_message[strlen(tmp_message)];
sprintf(cp," tmpval %ld (0x%lx)\n",
ct1->ctx.tmpval,ct1->ctx.tmpval);
buff_insert(qbp,qbp->zee,tmp_message,strlen(tmp_message));
break;
case TRACE_C_MACRO:
state_name = trace_convert_opcode_to_name(ct0->opcode);
if(state_name == NULL) state_name = "UNKNOWN";
sprintf(tmp_message, "MACRO PLACEHOLDER: %p Opcode %s %c",
ct0, state_name,
/* ct0->opcode == TOK_C_INPUTCHAR ? ct0->input_byte : ' '); */
ct0->flags & TOK_M_EAT_TOKEN ? ct0->input_byte : ' ');
if(ct0->flags & TOK_M_EAT_TOKEN){
strcat(tmp_message," TOK_M_EAT_TOKEN");
}/* End IF */
if(ct0->flags & TOK_M_WORDBOUNDARY){
strcat(tmp_message," TOK_M_WORDBOUNDARY");
}/* End IF */
if(ct0->flags & TOK_M_PARSELOAD_IARG1){
strcat(tmp_message," TOK_M_PARSELOAD_IARG1");
}/* End IF */
if(ct0->flags & TOK_M_PARSELOAD_IARG2){
strcat(tmp_message," TOK_M_PARSELOAD_IARG2");
}/* End IF */
if(ct0->flags & TOK_M_PARSELOAD_TMPVAL){
strcat(tmp_message," TOK_M_PARSELOAD_TMPVAL");
}/* End IF */
strcat(tmp_message,"\n");
buff_insert(qbp,qbp->zee,tmp_message,strlen(tmp_message));
/* int execute_state; */
state_name = trace_convert_state_to_name(ct0->ctx.state);
if(state_name == NULL) state_name = "UNKNOWN";
sprintf(tmp_message," Parser State: %s '%c'",
state_name,
isprint((int)ct0->q_register) ? ct0->q_register : ' ');
if(ct0->ctx.flags & CTOK_M_COLON_SEEN){
strcat(tmp_message," CTOK_M_COLON_SEEN");
}/* End IF */
if(ct0->ctx.flags & CTOK_M_ATSIGN_SEEN){
strcat(tmp_message," CTOK_M_ATSIGN_SEEN");
}/* End IF */
if(ct0->ctx.flags & CTOK_M_STATUS_PASSED){
strcat(tmp_message," CTOK_M_STATUS_PASSED");
}/* End IF */
strcat(tmp_message,"\n");
buff_insert(qbp,qbp->zee,tmp_message,strlen(tmp_message));
if(ct0->ctx.go_flag == 0){
sprintf(tmp_message," Go flag clear\n");
buff_insert(qbp,qbp->zee,tmp_message,strlen(tmp_message));
}/* End IF */
if(ct0->ctx.pnest || ct0->ctx.inest || ct0->ctx.cnest){
sprintf(tmp_message," PNEST: %d INEST %d CNEST %d\n",
ct0->ctx.pnest,ct0->ctx.inest,ct0->ctx.cnest);
buff_insert(qbp,qbp->zee,tmp_message,strlen(tmp_message));
}/* End IF */
sprintf(tmp_message," iarg1_flag %d iarg1 %ld (0x%lx)\n",
ct0->ctx.iarg1_flag,ct0->ctx.iarg1,ct0->ctx.iarg1);
buff_insert(qbp,qbp->zee,tmp_message,strlen(tmp_message));
sprintf(tmp_message," iarg2_flag %d iarg2 %ld (0x%lx)\n",
ct0->ctx.iarg2_flag,ct0->ctx.iarg2,ct0->ctx.iarg2);
buff_insert(qbp,qbp->zee,tmp_message,strlen(tmp_message));
sprintf(tmp_message," carg %p\n",ct0->ctx.carg);
buff_insert(qbp,qbp->zee,tmp_message,strlen(tmp_message));
sprintf(tmp_message," tmpval %ld (0x%lx)\n",
ct0->ctx.tmpval,ct0->ctx.tmpval);
buff_insert(qbp,qbp->zee,tmp_message,strlen(tmp_message));
if(ct0->ctx.return_state || ct0->ctx.caller_token){
state_name = "";
if(ct0->ctx.return_state){
state_name =
trace_convert_state_to_name(ct0->ctx.return_state);
if(state_name == NULL) state_name = "UNKNOWN";
}/* End IF */
sprintf(tmp_message, " return_state %s caller_token %p\n",
state_name, ct0->ctx.caller_token);
buff_insert(qbp,qbp->zee,tmp_message,strlen(tmp_message));
}/* End IF */
break;
}/* End Switch */
}
char *
trace_convert_opcode_to_name( int opcode )
{
PREAMBLE();
switch(opcode){
case TOK_C_UNUSED:
return("TOK_C_UNUSED");
case TOK_C_FIRSTTOKEN:
return("TOK_C_FIRSTTOKEN");
case TOK_C_INPUTCHAR:
return("TOK_C_INPUTCHAR");
case TOK_C_COPYTOKEN:
return("TOK_C_COPYTOKEN");
case TOK_C_ITERATION_BEGIN:
return("TOK_C_ITERATION_BEGIN");
case TOK_C_ITERATION_END:
return("TOK_C_ITERATION_END");
case TOK_C_CONDITIONAL_END:
return("TOK_C_CONDITIONAL_END");
case TOK_C_LABEL_BEGIN:
return("TOK_C_LABEL_BEGIN");
case TOK_C_LABEL_END:
return("TOK_C_LABEL_END");
case TOK_C_GOTO_BEGIN:
return("TOK_C_GOTO_BEGIN");
case TOK_C_GOTO_END:
return("TOK_C_GOTO_END");
case TOK_C_FINALTOKEN:
return("TOK_C_FINALTOKEN");
case TOK_C_INITIALSTATE:
return("TOK_C_INITIALSTATE");
case TOK_C_CONDITIONAL_ELSE:
return("TOK_C_CONDITIONAL_ELSE");
default:
return(NULL);
}/* End Switch */
}/* End Routine */
char *
trace_convert_state_to_name( int state )
{
PREAMBLE();
switch(state){
case STATE_C_INITIALSTATE:
return("STATE_C_INITIALSTATE");
case STATE_C_MAINCOMMANDS:
return("STATE_C_MAINCOMMANDS");
case STATE_C_ESCAPESEEN:
return("STATE_C_ESCAPESEEN");
case STATE_C_ECOMMAND:
return("STATE_C_ECOMMAND");
case STATE_C_ARG1:
return("STATE_C_ARG1");
case STATE_C_ARG2:
return("STATE_C_ARG2");
case STATE_C_EXPRESSION:
return("STATE_C_EXPRESSION");
case STATE_C_OPERATOR:
return("STATE_C_OPERATOR");
case STATE_C_PLUS:
return("STATE_C_PLUS");
case STATE_C_MINUS:
return("STATE_C_MINUS");
case STATE_C_TIMES:
return("STATE_C_TIMES");
case STATE_C_DIVIDE:
return("STATE_C_DIVIDE");
case STATE_C_MINUSSEEN:
return("STATE_C_MINUSSEEN");
case STATE_C_SUBEXPRESSION:
return("STATE_C_SUBEXPRESSION");
case STATE_C_OPERAND:
return("STATE_C_OPERAND");
case STATE_C_NUMBER_SUBSTATE:
return("STATE_C_NUMBER_SUBSTATE");
case STATE_C_QOPERAND:
return("STATE_C_QOPERAND");
case STATE_C_INSERT:
return("STATE_C_INSERT");
case STATE_C_QUOTED_INSERT:
return("STATE_C_QUOTED_INSERT");
case STATE_C_UMINUS:
return("STATE_C_UMINUS");
case STATE_C_LABEL:
return("STATE_C_LABEL");
case STATE_C_UQREGISTER:
return("STATE_C_UQREGISTER");
case STATE_C_WRITEFILE:
return("STATE_C_WRITEFILE");
case STATE_C_STRING:
return("STATE_C_STRING");
case STATE_C_SEARCH:
return("STATE_C_SEARCH");
case STATE_C_FCOMMAND:
return("STATE_C_FCOMMAND");
case STATE_C_FSPART1:
return("STATE_C_FSPART1");
case STATE_C_FSPART2:
return("STATE_C_FSPART2");
case STATE_C_EDITBUF:
return("STATE_C_EDITBUF");
case STATE_C_READFILE:
return("STATE_C_READFILE");
case STATE_C_XQREGISTER:
return("STATE_C_XQREGISTER");
case STATE_C_GQREGISTER:
return("STATE_C_GQREGISTER");
case STATE_C_MQREGISTER:
return("STATE_C_MQREGISTER");
case STATE_C_VIEWBUF:
return("STATE_C_VIEWBUF");
case STATE_C_FDCOMMAND:
return("STATE_C_FDCOMMAND");
case STATE_C_CONDITIONALS:
return("STATE_C_CONDITIONALS");
case STATE_C_GOTO:
return("STATE_C_GOTO");
case STATE_C_FRPART1:
return("STATE_C_FRPART1");
case STATE_C_FRPART2:
return("STATE_C_FRPART2");
case STATE_C_MESSAGE:
return("STATE_C_MESSAGE");
case STATE_C_FKCOMMAND:
return("STATE_C_FKCOMMAND");
case STATE_C_ECCOMMAND:
return("STATE_C_ECCOMMAND");
case STATE_C_SAVECOMMAND:
return("STATE_C_SAVECOMMAND");
case STATE_C_PERCENT_OPERAND:
return("STATE_C_PERCENT_OPERAND");
case STATE_C_ATINSERT:
return("STATE_C_ATINSERT");
case STATE_C_ATINSERT_PART2:
return("STATE_C_ATINSERT_PART2");
case STATE_C_ONE_EQUALS:
return("STATE_C_ONE_EQUALS");
case STATE_C_TWO_EQUALS:
return("STATE_C_TWO_EQUALS");
case STATE_C_SKIP_ELSE:
return("STATE_C_SKIP_ELSE");
case STATE_C_PUSH_QREGISTER:
return("STATE_C_PUSH_QREGISTER");
case STATE_C_POP_QREGISTER:
return("STATE_C_POP_QREGISTER");
case STATE_C_NSEARCH:
return("STATE_C_NSEARCH");
case STATE_C_ACCEPT_ARGS:
return("STATE_C_ACCEPT_ARGS");
case STATE_C_EQQREGISTER1:
return("STATE_C_EQQREGISTER1");
case STATE_C_EQQREGISTER2:
return("STATE_C_EQQREGISTER2");
case STATE_C_RADIX:
return("STATE_C_RADIX");
case STATE_C_HEX_NUMBER:
return("STATE_C_HEX_NUMBER");
case STATE_C_OCTAL_NUMBER:
return("STATE_C_OCTAL_NUMBER");
case STATE_C_HEX_NUMBER_SUBSTATE:
return("STATE_C_HEX_NUMBER_SUBSTATE");
case STATE_C_OCTAL_NUMBER_SUBSTATE:
return("STATE_C_OCTAL_NUMBER_SUBSTATE");
case STATE_C_BACKSLASH:
return("STATE_C_BACKSLASH");
case STATE_C_DELAYED_MINUS:
return("STATE_C_DELAYED_MINUS");
case STATE_C_DELAYED_PLUS:
return("STATE_C_DELAYED_PLUS");
case STATE_C_FSPART3:
return("STATE_C_FSPART3");
case STATE_C_RETURN:
return("STATE_C_RETURN");
case STATE_C_FINALSTATE:
return("STATE_C_FINALSTATE");
case STATE_C_ERRORSTATE:
return("STATE_C_ERRORSTATE");
default:
return(NULL);
}/* End Switch */
}/* End Routine */
char *
trace_convert_exec_state_to_name( int state )
{
PREAMBLE();
switch(state){
case EXEC_C_NULLSTATE:
return("EXEC_C_NULLSTATE");
case EXEC_C_DOTARG1:
return("EXEC_C_DOTARG1");
case EXEC_C_ZEEARG1:
return("EXEC_C_ZEEARG1");
case EXEC_C_HARGUMENT:
return("EXEC_C_HARGUMENT");
case EXEC_C_EXITCOMMAND:
return("EXEC_C_EXITCOMMAND");
case EXEC_C_UQREGISTER:
return("EXEC_C_UQREGISTER");
case EXEC_C_JUMP:
return("EXEC_C_JUMP");
case EXEC_C_INSERT:
return("EXEC_C_INSERT");
case EXEC_C_LINE:
return("EXEC_C_LINE");
case EXEC_C_CHAR:
return("EXEC_C_CHAR");
case EXEC_C_RCHAR:
return("EXEC_C_RCHAR");
case EXEC_C_DELETE:
return("EXEC_C_DELETE");
case EXEC_C_HVALUE:
return("EXEC_C_HVALUE");
case EXEC_C_DOTVALUE:
return("EXEC_C_DOTVALUE");
case EXEC_C_ZEEVALUE:
return("EXEC_C_ZEEVALUE");
case EXEC_C_QVALUE:
return("EXEC_C_QVALUE");
case EXEC_C_EQUALS:
return("EXEC_C_EQUALS");
case EXEC_C_REDRAW_SCREEN:
return("EXEC_C_REDRAW_SCREEN");
case EXEC_C_STOREVAL:
return("EXEC_C_STOREVAL");
case EXEC_C_STORE1:
return("EXEC_C_STORE1");
case EXEC_C_STORE2:
return("EXEC_C_STORE2");
case EXEC_C_UMINUS:
return("EXEC_C_UMINUS");
case EXEC_C_PLUS:
return("EXEC_C_PLUS");
case EXEC_C_MINUS:
return("EXEC_C_MINUS");
case EXEC_C_TIMES:
return("EXEC_C_TIMES");
case EXEC_C_DIVIDE:
return("EXEC_C_DIVIDE");
case EXEC_C_KILL:
return("EXEC_C_KILL");
case EXEC_C_WRITEFILE:
return("EXEC_C_WRITEFILE");
case EXEC_C_SEARCH:
return("EXEC_C_SEARCH");
case EXEC_C_SETSEARCH:
return("EXEC_C_SETSEARCH");
case EXEC_C_FSREPLACE1:
return("EXEC_C_FSREPLACE1");
case EXEC_C_ITERATION_BEGIN:
return("EXEC_C_ITERATION_BEGIN");
case EXEC_C_ITERATION_END:
return("EXEC_C_ITERATION_END");
case EXEC_C_READFILE:
return("EXEC_C_READFILE");
case EXEC_C_EDITBUF:
return("EXEC_C_EDITBUF");
case EXEC_C_XQREGISTER:
return("EXEC_C_XQREGISTER");
case EXEC_C_GQREGISTER:
return("EXEC_C_GQREGISTER");
case EXEC_C_SEMICOLON:
return("EXEC_C_SEMICOLON");
case EXEC_C_MQREGISTER:
return("EXEC_C_MQREGISTER");
case EXEC_C_CLOSEBUF:
return("EXEC_C_CLOSEBUF");
case EXEC_C_VIEWBUF:
return("EXEC_C_VIEWBUF");
case EXEC_C_FDCOMMAND:
return("EXEC_C_FDCOMMAND");
case EXEC_C_ACOMMAND:
return("EXEC_C_ACOMMAND");
case EXEC_C_BACKSLASH:
return("EXEC_C_BACKSLASH");
case EXEC_C_BACKSLASHARG:
return("EXEC_C_BACKSLASHARG");
case EXEC_C_COND_GT:
return("EXEC_C_COND_GT");
case EXEC_C_COND_LT:
return("EXEC_C_COND_LT");
case EXEC_C_COND_EQ:
return("EXEC_C_COND_EQ");
case EXEC_C_COND_NE:
return("EXEC_C_COND_NE");
case EXEC_C_COND_DIGIT:
return("EXEC_C_COND_DIGIT");
case EXEC_C_COND_ALPHA:
return("EXEC_C_COND_ALPHA");
case EXEC_C_COND_LOWER:
return("EXEC_C_COND_LOWER");
case EXEC_C_COND_UPPER:
return("EXEC_C_COND_UPPER");
case EXEC_C_COND_SYMBOL:
return("EXEC_C_COND_SYMBOL");
case EXEC_C_GOTO:
return("EXEC_C_GOTO");
case EXEC_C_FRREPLACE:
return("EXEC_C_FRREPLACE");
case EXEC_C_MESSAGE:
return("EXEC_C_MESSAGE");
case EXEC_C_RESET_MESSAGE:
return("EXEC_C_RESET_MESSAGE");
case EXEC_C_OUTPUT_MESSAGE:
return("EXEC_C_OUTPUT_MESSAGE");
case EXEC_C_FKCOMMAND:
return("EXEC_C_FKCOMMAND");
case EXEC_C_REMEMBER_DOT:
return("EXEC_C_REMEMBER_DOT");
case EXEC_C_ECCOMMAND:
return("EXEC_C_ECCOMMAND");
case EXEC_C_SAVECOMMAND:
return("EXEC_C_SAVECOMMAND");
case EXEC_C_SCROLL:
return("EXEC_C_SCROLL");
case EXEC_C_UPDATE_SCREEN:
return("EXEC_C_UPDATE_SCREEN");
case EXEC_C_SET_IMMEDIATE_MODE:
return("EXEC_C_SET_IMMEDIATE_MODE");
case EXEC_C_PERCENT_VALUE:
return("EXEC_C_PERCENT_VALUE");
case EXEC_C_WORD:
return("EXEC_C_WORD");
case EXEC_C_TWO_EQUALS:
return("EXEC_C_TWO_EQUALS");
case EXEC_C_THREE_EQUALS:
return("EXEC_C_THREE_EQUALS");
case EXEC_C_SKIP_ELSE:
return("EXEC_C_SKIP_ELSE");
case EXEC_C_PUSH_QREGISTER:
return("EXEC_C_PUSH_QREGISTER");
case EXEC_C_POP_QREGISTER:
return("EXEC_C_POP_QREGISTER");
case EXEC_C_NSEARCH:
return("EXEC_C_NSEARCH");
case EXEC_C_EQQREGISTER:
return("EXEC_C_EQQREGISTER");
case EXEC_C_WINDOW_CONTROL:
return("EXEC_C_WINDOW_CONTROL");
case EXEC_C_NEXT_WINDOW:
return("EXEC_C_NEXT_WINDOW");
case EXEC_C_RLINE:
return("EXEC_C_RLINE");
case EXEC_C_DELWORD:
return("EXEC_C_DELWORD");
case EXEC_C_RDELWORD:
return("EXEC_C_RDELWORD");
case EXEC_C_OPENBRACE:
return("EXEC_C_OPENBRACE");
case EXEC_C_CLOSEBRACE:
return("EXEC_C_CLOSEBRACE");
case EXEC_C_SKIPLABEL:
return("EXEC_C_SKIPLABEL");
case EXEC_C_SETOPTIONS:
return("EXEC_C_SETOPTIONS");
case EXEC_C_FSREPLACE2:
return("EXEC_C_FSREPLACE2");
case EXEC_C_FSREPLACE3:
return("EXEC_C_FSREPLACE3");
default:
return(NULL);
}/* End Switch */
}/* End Routine */