char *tecexec_c_version = "tecexec.c: $Revision: 1.3 $";
/*
* $Date: 2007/12/26 13:28:30 $
* $Source: /cvsroot/videoteco/videoteco/tecexec.c,v $
* $Revision: 1.3 $
* $Locker: $
*/
/**
* \file tecexec.c
* \brief The SWITCH/CASE statements which implement execution stage of the 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"
extern struct cmd_token *jump_to_token;
extern struct cmd_token *last_token_executed;
extern struct cmd_token *last_cmd_list;
extern struct search_buff search_string;
extern char user_message[PARSER_STRING_MAX];
extern char exit_flag;
extern struct window *window_list;
extern struct buff_header *curbuf,*buffer_headers;
extern struct buff_header *qregister_push_down_list;
extern unsigned long last_search_pos1,last_search_pos2;
extern int last_search_status;
extern unsigned long remembered_dot;
extern char intr_flag;
extern char immediate_execute_flag;
extern struct window *curwin;
int find_conditional_else(struct cmd_token *);
int find_conditional_end(struct cmd_token *);
int compare_label(struct cmd_token *,struct cmd_token *);
void extract_label(struct cmd_token *,char *);
/**
* \brief Do the runtime execution part of a command
*
* This routine is called to execute the runtime part of a command token.
* This could be during immediate execution mode, directly after a token
* gets parsed, or it could be during final stages when we are either
* running commands which cannot be undone (like ex), or simply complex
* things like an iteration. The execute_state which we dispatch on was
* set by the parse state during syntax analysis.
*/
int
execute_a_state( struct cmd_token *ct, struct cmd_token *uct )
{
register struct undo_token *ut;
char tmp_buffer[LINE_BUFFER_SIZE],tmp_message[LINE_BUFFER_SIZE];
PREAMBLE();
last_token_executed = ct;
switch(ct->execute_state){
/*
* Here to return the numeric value of a q-register. This has to be done
* at run time because the value of the q-register might be modified during
* the course of the command. Note that we return an error if the q-register
* has never been loaded. Otherwise, we return the value in tmpval so that
* it can be the input to further arithmetic expressions.
*/
case EXEC_C_QVALUE:
{/* Local Block */
register struct buff_header *hbp;
if(ct->q_register == '*'){
ct->ctx.tmpval = curbuf->buffer_number;
return(SUCCESS);
}/* End IF */
hbp = buff_qfind(ct->q_register,0);
if(hbp == NULL){
sprintf(tmp_message,"?Q-register %c empty",ct->q_register);
error_message(tmp_message);
return(FAIL);
}/* End IF */
ct->ctx.tmpval = hbp->ivalue;
return(SUCCESS);
}/* End Local Block */
/*
* Here to return the numeric value of a q-register and also increment it's
* value. Other than the incrementing, this is exactly like the QVALUE state.
*/
case EXEC_C_PERCENT_VALUE:
{/* Local Block */
register struct buff_header *hbp;
hbp = buff_qfind(ct->q_register,0);
if(hbp == NULL){
sprintf(tmp_message,"?Q-register %c empty",ct->q_register);
error_message(tmp_message);
return(FAIL);
}/* End IF */
/*
* Set up an undo block so that we can put the previous value back into
* the q-register if this command gets undone.
*/
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_UQREGISTER;
ut->iarg1 = ct->q_register;
ut->iarg2 = hbp->ivalue;
hbp->ivalue += ct->ctx.tmpval;
ct->ctx.tmpval = hbp->ivalue;
return(SUCCESS);
}/* End Local Block */
/*
* Here to read a file into a q-register. We also set up undo tokens to
* restore the previous contents of the q-register if he undoes this.
*/
case EXEC_C_EQQREGISTER:
{/* Local Block */
register struct buff_header *qbp;
struct wildcard_expansion *name_list,*np;
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEBUFF;
ut->iarg1 = curbuf->buffer_number;
qbp = buff_qfind(ct->ctx.tmpval,1);
if(ct->ctx.tmpval == '*'){
if(ct->ctx.carg){
rename_edit_buffer(curbuf,ct->ctx.carg,uct);
}/* End IF */
else {
load_qname_register();
buff_switch(qbp,1);
}/* End Else */
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = SUCCESS;
}/* End IF */
return(SUCCESS);
}/* End IF */
if(ct->ctx.carg == NULL || ct->ctx.carg[0] == '\0'){
buff_switch(qbp,1);
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = SUCCESS;
}/* End IF */
return(SUCCESS);
}/* End IF */
/*
* Delete the previous contents of the q-register, but allow it to be
* reconstructed if this gets undone. Note that we don't have to do
* this if there was nothing there. Also, if the colon modifier was
* specified, then we append to the buffer instead of replacing it.
*/
if((ct->ctx.flags & CTOK_M_COLON_SEEN) == 0 && qbp->zee){
buff_delete_with_undo(uct,qbp,0,qbp->zee);
}/* End IF */
/*
* Set up an undo argument to delete any characters which get inserted as
* part of the buff_read we do to load the q-register.
*/
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_DELETE;
ut->carg1 = (char *)qbp;
ut->iarg1 = qbp->dot;
ut->iarg2 = qbp->zee;
np = expand_filename(ct->ctx.carg);
if(np == NULL){
sprintf(tmp_message,"EQ No such file <%s>",ct->ctx.carg);
error_message(tmp_message);
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = FAIL;
return(SUCCESS);
}/* End IF */
return(FAIL);
}/* End IF */
while(np){
buff_read(qbp,np->we_name);
name_list = np;
np = np->we_next;
tec_release(TYPE_C_WILD,(char *)name_list);
}/* End While */
ut->iarg2 = qbp->zee - ut->iarg2;
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = SUCCESS;
}/* End IF */
return(SUCCESS);
}/* End Local Block */
/*
* Here to load a q-register with a numeric value. Note that not only do we
* have to put the new number into it, we also have to set up the undo token
* so that if this command is backed out of we can restore the previous value
* to the q-register.
*/
case EXEC_C_UQREGISTER:
{/* Local Block */
register struct buff_header *hbp;
/*
* Find the q-register. If it does not exist yet, create it.
*/
hbp = buff_qfind(ct->q_register,1);
if(hbp == NULL){
return(FAIL);
}/* End IF */
/*
* Insure that we have an argument to store
*/
if(ct->ctx.iarg1_flag == NO){
error_message("?Argument required for U command");
return(FAIL);
}/* End IF */
/*
* Set up an undo block so that we can put the previous value back into
* the q-register if this command gets undone.
*/
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_UQREGISTER;
ut->iarg1 = ct->q_register;
ut->iarg2 = hbp->ivalue;
hbp->ivalue = ct->ctx.iarg1;
return(SUCCESS);
}/* End Local Block */
/*
* Here to load the text contents of the specified q-register into the
* edit buffer at the current location.
*/
case EXEC_C_GQREGISTER:
{/* Local Block */
register struct buff_header *hbp;
register struct buff_header *qbp;
hbp = curbuf;
/*
* If this is the buffer name q-register, we have to do some special
* stuff.
*/
if(ct->q_register == '*') load_qname_register();
/*
* Get a pointer to the q-register buffer structure. If it doesn't
* exist, declare an error.
*/
qbp = buff_qfind(ct->q_register,0);
if(qbp == NULL){
sprintf(tmp_message,"?Q-register <%c> does not exist",
ct->q_register);
error_message(tmp_message);
return(FAIL);
}/* End IF */
/*
* Test if the q-register is empty, and declare an error if it is
*/
if(qbp->zee == 0){
sprintf(tmp_message,"?Q-register <%c> is empty",
ct->q_register);
error_message(tmp_message);
return(FAIL);
}/* End IF */
/*
* Make sure the Q register and the edit buffer are not the same buffer
*/
if(qbp == hbp){
strcpy(tmp_message,
"?Cannot use G to copy from a Q-register to itself");
error_message(tmp_message);
return(FAIL);
}/* End IF */
/*
* Now copy the text out of the q-register and insert it into the edit buffer
*/
buff_insert_from_buffer_with_undo(uct,hbp,hbp->dot,qbp,0,qbp->zee);
return(SUCCESS);
}/* End Local Block */
/*
* Here to execute the macro in the specified Q register
*/
case EXEC_C_MQREGISTER:
{/* Local Block */
register struct buff_header *qbp;
/*
* Get a pointer to the q-register buffer structure. If it doesn't
* exist, declare an error.
*/
qbp = buff_qfind(ct->q_register,0);
if(qbp == NULL){
sprintf(tmp_message,"?Q-register <%c> does not exist",
ct->q_register);
error_message(tmp_message);
return(FAIL);
}/* End IF */
/*
* It's an error if the q-register is empty
*/
if(qbp->zee == 0){
sprintf(tmp_message,"?Q-register <%c> is empty",
ct->q_register);
error_message(tmp_message);
return(FAIL);
}/* End IF */
/*
* Set up the undo block, and pass its address to the tecmacro routine so
* that the tecmacro can chain the command list off of it.
*/
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_MACRO;
ut->carg1 = NULL;
return(tecmacro(qbp,ct,(struct cmd_token **)&ut->carg1));
}/* End Local Block */
/*
* Here to load text into a q-register in response to the X command.
* This clears any existing text from the q-register, and then copies
* the specified text into it.
*/
case EXEC_C_XQREGISTER:
{/* Local Block */
register struct buff_header *hbp;
register struct buff_header *qbp;
register struct buff_line *lbp;
register long i,j;
long pos1,pos2;
hbp = curbuf;
/*
* Get a pointer to the q-register buffer structure. If it doesn't
* exist, create it.
*/
qbp = buff_qfind(ct->q_register,1);
if(qbp == NULL){
return(FAIL);
}/* End IF */
/*
* Make sure the Q register and the edit buffer are not the same buffer
*/
if(qbp == hbp){
strcpy(tmp_message,
"?Cannot use X to copy from a Q-register to itself");
error_message(tmp_message);
return(FAIL);
}/* End IF */
/*
* If two arguments were specified, then he has specified an a,b range to
* be copied.
*/
if(ct->ctx.iarg1_flag == YES && ct->ctx.iarg2_flag == YES){
pos1 = ct->ctx.iarg1;
pos2 = ct->ctx.iarg2;
if(parse_illegal_buffer_position(pos1,pos2,"X")){
return(FAIL);
}/* End IF */
if(pos2 < pos1){
pos2 = ct->ctx.iarg1;
pos1 = ct->ctx.iarg2;
}/* End IF */
}/* End IF */
/*
* Else, if it was a single command, it is a relative copy which affects a
* portion of the buffer in a similar way as if it was an L command. Our job
* now is to turn it into a a,b range.
*/
else {
lbp = buff_find_line(hbp,hbp->dot);
if(lbp == NULL) return(FAIL);
/*
* Start by pretending it was a 0L command, and get to the begining of
* the line. That allows us to not worry about offset onto current line.
*/
j = 0 - buff_find_offset(hbp,lbp,hbp->dot);
i = ct->ctx.iarg1;
if(ct->ctx.iarg1_flag == NO) i = 1;
/*
* If argument is positive, movement is forward
*/
if(i > 0){
while(i-- && lbp){
j += lbp->byte_count;
lbp = lbp->next_line;
}/* End WHILE */
if(lbp == NULL){
error_message("?Attempt to Move Pointer Off Page with X");
return(FAIL);
}/* End IF */
pos1 = hbp->dot;
pos2 = hbp->dot + j;
}/* End IF */
/*
* Else, it is backwards
*/
else {
while(i++ && lbp){
lbp = lbp->prev_line;
if(lbp == NULL){
error_message("?Attempt to Move Pointer Off Page with X");
return(FAIL);
}/* End IF */
j -= lbp->byte_count;
}/* End WHILE */
pos1 = hbp->dot + j;
pos2 = hbp->dot;
}/* End Else */
}/* End Else */
/*
* Now that we have calculated the buffer positions to be used by the command,
* we can actually do the work.
*/
j = pos2 - pos1;
/*
* Delete the previous contents of the q-register, but allow it to be
* reconstructed if this gets undone. Note that we don't have to do
* this if there was nothing there. Also, if the colon modifier was
* specified, then we append to the buffer instead of replacing it.
*/
if((ct->ctx.flags & CTOK_M_COLON_SEEN) == 0 && qbp->zee){
buff_delete_with_undo(uct,qbp,0,qbp->zee);
}/* End IF */
/*
* Now copy the new text from the edit buffer into the q-register
*/
buff_insert_from_buffer_with_undo(uct,qbp,qbp->zee,hbp,pos1,j);
/*
* If the q-register specified is '*', then the actual result is to rename
* the current buffer.
*/
if(ct->q_register == '*'){
rename_edit_buffer(hbp,qbp->name,uct);
}/* End IF */
return(SUCCESS);
}/* End Local Block */
/*
* Here to load text into a q-register in response to the * command.
* This clears any existing text from the q-register, and then copies
* the previous command string into it.
*/
case EXEC_C_SAVECOMMAND:
{/* Local Block */
register struct buff_header *qbp;
register struct cmd_token *oct;
register int i;
/*
* Get a pointer to the q-register buffer structure. If it doesn't
* exist, create it.
*/
qbp = buff_qfind(ct->q_register,1);
if(qbp == NULL){
return(FAIL);
}/* End IF */
/*
* Delete the previous contents of the q-register, but allow it to be
* reconstructed if this gets undone. Note that we don't have to do
* this if there was nothing there.
*/
if(qbp->zee) buff_delete_with_undo(uct,qbp,0,qbp->zee);
/*
* Set up an undo token to delete the contents of the q-register that we
* are about to load.
*/
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_DELETE;
ut->carg1 = (char *)qbp;
ut->iarg1 = 0;
ut->iarg2 = 0;
/*
* Now we go through the last command list and anytime we see an input
* byte, we copy it into the q-register.
*/
oct = last_cmd_list;
i = 0;
while(oct){
if(oct->flags & TOK_M_EAT_TOKEN){
buff_insert_char(qbp,i++,oct->input_byte);
ut->iarg2 += 1;
}/* End IF */
oct = oct->next_token;
}/* End While */
return(SUCCESS);
}/* End Local Block */
/*
* Here to push the specified q-register onto the q-register stack
*/
case EXEC_C_PUSH_QREGISTER:
if(ct->q_register == '*') load_qname_register();
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
if(push_qregister(ct->q_register) != SUCCESS) return(FAIL);
ut->opcode = UNDO_C_POP;
return(SUCCESS);
/*
* Here to pop a Q register off of the stack and replace a Q register
* with it. Since this destroys the Q register we pop onto, we first
* must save the entire Q register.
*/
case EXEC_C_POP_QREGISTER:
{/* Local Block */
register struct buff_header *pbp;
register struct buff_header *qbp;
/*
* Get a pointer to the pushed buffer structure. If there are none on
* the stack, then he has tried to pop too many, and this is an error.
*/
pbp = qregister_push_down_list;
if(pbp == NULL){
error_message("?Q-register push down list is empty");
return(FAIL);
}/* End IF */
/*
* Get a pointer to the q-register buffer structure. If it doesn't
* exist, create it.
*/
qbp = buff_qfind(ct->q_register,1);
if(qbp == NULL){
return(FAIL);
}/* End IF */
/*
* Arrange to restore the numeric contents of the Q register if this
* should be undone.
*/
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_UQREGISTER;
ut->iarg1 = ct->q_register;
ut->iarg2 = qbp->ivalue;
qbp->ivalue = pbp->ivalue;
/*
* Delete the previous contents of the q-register, but allow it to be
* reconstructed if this gets undone. Note that we don't have to do
* this if there was nothing there.
*/
if(qbp->zee){
if(buff_delete_with_undo(uct,qbp,0,qbp->zee) == FAIL){
return(FAIL);
}/* End IF */
}/* End IF */
/*
* Arrange for it to be deleted if this gets undone.
*/
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_DELETE;
ut->carg1 = (char *)qbp;
ut->iarg1 = 0;
ut->iarg2 = pbp->zee;
/*
* Transfer the contents of the pushed register into the actual Q register
*/
buff_bulk_insert(qbp,0,pbp->zee,pbp->first_line);
pbp->first_line = NULL;
qbp->pos_cache.lbp = NULL;
qbp->pos_cache.base = 0;
/*
* Arrange that the push be re-done if the pop is undone.
*/
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_PUSH;
ut->iarg1 = ct->q_register;
/*
* Place it on the main buffer list so that buff_destroy can find it
*/
qregister_push_down_list = pbp->next_header;
pbp->next_header = buffer_headers;
buffer_headers = pbp;
buff_destroy(pbp);
/*
* If the q-register specified is '*', then the actual result is to rename
* the current buffer.
*/
if(ct->q_register == '*'){
rename_edit_buffer(curbuf,qbp->name,uct);
}/* End IF */
return(SUCCESS);
}/* End Local Block */
/*
* Here to return the current position of 'dot'
*/
case EXEC_C_DOTVALUE:
ct->ctx.tmpval = curbuf->dot;
return(SUCCESS);
/*
* Here to return the number of bytes in the edit buffer
*/
case EXEC_C_ZEEVALUE:
ct->ctx.tmpval = curbuf->zee;
return(SUCCESS);
/*
* Here to return the value 0,Z which H is shorthand for
*/
case EXEC_C_HVALUE:
ct->ctx.iarg1 = 0;
ct->ctx.iarg2 = curbuf->zee;
return(SUCCESS);
/*
* Print out the numeric value of an expression
*/
case EXEC_C_EQUALS:
if(ct->ctx.iarg1_flag == NO){
error_message("?Argument required for = command");
return(FAIL);
}/* End IF */
sprintf(tmp_buffer,"value = %ld",ct->ctx.iarg1);
screen_message(tmp_buffer);
return(SUCCESS);
case EXEC_C_TWO_EQUALS:
sprintf(tmp_buffer,"value = 0%lo",ct->ctx.iarg1);
screen_message(tmp_buffer);
return(SUCCESS);
case EXEC_C_THREE_EQUALS:
sprintf(tmp_buffer,"value = 0x%lX",ct->ctx.iarg1);
screen_message(tmp_buffer);
return(SUCCESS);
/*
* Here to insert the value of the expression into the edit buffer as a
* decimal representation.
*/
case EXEC_C_BACKSLASH:
{/* Local Block */
register long i,j;
char *cp;
int length = 0;
if(ct->ctx.iarg2 < 2 || ct->ctx.iarg2 > 36) ct->ctx.iarg2 = 10;
j = ct->ctx.iarg1;
cp = tmp_buffer + sizeof(tmp_buffer);
do {
i = j % ct->ctx.iarg2;
j = (j - i) / ct->ctx.iarg2;
if(i > 9) i += ('A' - 10);
else i += '0';
*(--cp) = i;
length += 1;
} while(j);
buff_insert_with_undo(uct,curbuf,curbuf->dot,cp,length);
return(SUCCESS);
}/* End Local Block */
/*
* Here to interpret the ascii digits following 'dot' in the edit buffer
* as a decimal number, and return this number as the value of this expression,
* leaving 'dot' positioned after the digits.
*/
case EXEC_C_BACKSLASHARG:
{/* Local Block */
register int i;
register int radix;
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEDOT;
ut->iarg1 = curbuf->dot;
radix = ct->ctx.tmpval;
ct->ctx.tmpval = 0;
for(;;){
i = buff_contents(curbuf,curbuf->dot);
if(i >= '0' && i <= '9') i -= '0';
else if(i >= 'a' && i <= 'z') i -= ('a' - 10);
else if(i >= 'A' && i <= 'Z') i -= ('A' - 10);
else break;
if(i < 0 || i >= radix) break;
ct->ctx.tmpval = ct->ctx.tmpval * radix + i;
if(curbuf->dot == curbuf->zee) break;
curbuf->dot++;
}/* End FOR */
return(SUCCESS);
}/* End Local Block */
/*
* The poor bastard wants to leave...
*/
case EXEC_C_EXITCOMMAND:
{/* Local Block */
register struct buff_header *hbp;
if(ct->ctx.iarg1_flag == NO || ct->ctx.iarg1 != -1){
for(hbp = buffer_headers; hbp != NULL; hbp = hbp->next_header){
if(hbp->buffer_number <= 0) continue;
if(hbp->ismodified != 0 && hbp->isreadonly == 0){
error_message("?Modified buffers exist");
return(FAIL);
}/* End IF */
}/* End FOR */
}/* End IF */
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_SET_EXIT_FLAG;
exit_flag = YES;
return(SUCCESS);
}/* End Local Block */
/*
* Here to jump to an absolute position in the buffer
*/
case EXEC_C_JUMP:
if(ct->ctx.iarg1_flag == YES && ct->ctx.iarg1 < 0){
error_message("?Negative Argument to J");
return(FAIL);
}/* End IF */
if(ct->ctx.iarg1_flag == NO) ct->ctx.iarg1 = 0;
if(parse_illegal_buffer_position(ct->ctx.iarg1,0,"J")){
return(FAIL);
}/* End IF */
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEDOT;
ut->iarg1 = curbuf->dot;
if(ct->ctx.iarg1_flag == NO) curbuf->dot = 0;
else curbuf->dot = ct->ctx.iarg1;
return(SUCCESS);
/*
* Here to move dot by a relative number of buffer positions
*/
case EXEC_C_CHAR:
{/* Local Block */
register long i;
i = curbuf->dot + 1;
if(ct->ctx.iarg1_flag == YES){
i = curbuf->dot + ct->ctx.iarg1;
}/* End IF */
if(parse_illegal_buffer_position(i,0,"C")) return(FAIL);
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEDOT;
ut->iarg1 = curbuf->dot;
curbuf->dot = i;
return(SUCCESS);
}/* End Local Block */
/*
* Here to move dot by a relative number of buffer positions, just like
* the "C" command, except that the direction is by default backwards.
*/
case EXEC_C_RCHAR:
{/* Local Block */
register long i;
i = curbuf->dot - 1;
if(ct->ctx.iarg1_flag == YES){
i = curbuf->dot - ct->ctx.iarg1;
}/* End IF */
if(parse_illegal_buffer_position(i,0,"R")) return(FAIL);
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEDOT;
ut->iarg1 = curbuf->dot;
curbuf->dot = i;
return(SUCCESS);
}/* End Local Block */
/*
* Here to delete the specified number of characters following 'dot'.
* A negative value indicates we should delete characters BEFORE 'dot'.
*/
case EXEC_C_DELETE:
{/* Local Block */
register long i;
i = 1;
if(ct->ctx.iarg1_flag == YES) i = ct->ctx.iarg1;
if(parse_illegal_buffer_position(curbuf->dot+i,0,"D")){
return(FAIL);
}/* End IF */
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEDOT;
ut->iarg1 = curbuf->dot;
if(i < 0){
i = 0 - i;
curbuf->dot -= i;
}/* End IF */
/*
* Call the standard routine which deletes the specified buffer positions
* and constructs the undo list so that it can be rebuilt if necessary.
*/
if(i) buff_delete_with_undo(uct,curbuf,curbuf->dot,i);
return(SUCCESS);
}/* End Local Block */
/*
* Here to move 'dot' by the specified number of words. Note that words
* can have a pretty nebulous definition, depending on what you are doing.
* This should probably have a q-register which contains all of the delimeters.
*/
case EXEC_C_WORD:
{/* Local Block */
register long count;
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEDOT;
ut->iarg1 = curbuf->dot;
count = ct->ctx.iarg1;
if(ct->ctx.iarg1_flag == NO) count = 1;
cmd_wordmove(count);
return(SUCCESS);
}/* End Local Block */
/*
* Here to delete the specified number of words. Note that words
* can have a pretty nebulous definition, depending on what you are doing.
* This should probably have a q-register which contains all of the delimeters.
*/
case EXEC_C_DELWORD:
{/* Local Block */
register long count;
unsigned long original_position;
unsigned long pos;
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEDOT;
ut->iarg1 = original_position = curbuf->dot;
count = ct->ctx.iarg1;
if(ct->ctx.iarg1_flag == NO) count = 1;
cmd_wordmove(count);
pos = original_position;
count = curbuf->dot - original_position;
if(count < 0){
count = 0 - count;
pos = curbuf->dot;
}/* End IF */
if(count) buff_delete_with_undo(uct,curbuf,pos,count);
return(SUCCESS);
}/* End Local Block */
/*
* Here to delete backward the specified number of words. Note that
* words can have a pretty nebulous definition, depending on what you are
* doing. This should probably have a q-register which contains all of the
* delimeters.
*/
case EXEC_C_RDELWORD:
{/* Local Block */
register long count;
unsigned long original_position;
unsigned long pos;
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEDOT;
ut->iarg1 = original_position = curbuf->dot;
count = 0 - ct->ctx.iarg1;
if(ct->ctx.iarg1_flag == NO) count = -1;
cmd_wordmove(count);
pos = original_position;
count = curbuf->dot - original_position;
if(count < 0){
count = 0 - count;
pos = curbuf->dot;
}/* End IF */
if(count) buff_delete_with_undo(uct,curbuf,pos,count);
return(SUCCESS);
}/* End Local Block */
/*
* Here to move the 'dot' by the specified number of lines.
*/
case EXEC_C_LINE:
{/* Local Block */
register struct buff_header *hbp;
register struct buff_line *lbp;
register int i,j;
hbp = curbuf;
lbp = buff_find_line(hbp,hbp->dot);
/*
* Start by pretending it was a 0L command, and get to the begining of
* the line. That allows us to not worry about offset onto current line.
*/
j = 0 - buff_find_offset(hbp,lbp,hbp->dot);
i = ct->ctx.iarg1;
if(ct->ctx.iarg1_flag == NO) i = 1;
/*
* If argument is positive, movement is forward
*/
if(i > 0){
while(i-- && lbp){
j += lbp->byte_count;
lbp = lbp->next_line;
}/* End WHILE */
if(lbp == NULL){
error_message("?Attempt to Move Pointer Off Page with L");
return(FAIL);
}/* End IF */
}/* End IF */
else {
while(i++ && lbp){
lbp = lbp->prev_line;
if(lbp == NULL){
error_message("?Attempt to Move Pointer Off Page with L");
return(FAIL);
}/* End IF */
j -= lbp->byte_count;
}/* End WHILE */
}/* End Else */
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEDOT;
ut->iarg1 = hbp->dot;
hbp->dot += j;
return(SUCCESS);
}/* End Local Block */
/*
* Here to move the 'dot' backward by the specified number of lines.
*/
case EXEC_C_RLINE:
{/* Local Block */
register struct buff_header *hbp;
register struct buff_line *lbp;
register int i,j;
hbp = curbuf;
lbp = buff_find_line(hbp,hbp->dot);
/*
* Start by pretending it was a 0L command, and get to the begining of
* the line. That allows us to not worry about offset onto current line.
*/
j = 0 - buff_find_offset(hbp,lbp,hbp->dot);
i = 0 - ct->ctx.iarg1;
if(ct->ctx.iarg1_flag == NO) i = -1;
/*
* If argument is positive, movement is forward
*/
if(i > 0){
while(i-- && lbp){
j += lbp->byte_count;
lbp = lbp->next_line;
}/* End WHILE */
if(lbp == NULL){
error_message("?Attempt to Move Pointer Off Page with B");
return(FAIL);
}/* End IF */
}/* End IF */
else {
while(i++ && lbp){
lbp = lbp->prev_line;
if(lbp == NULL){
error_message("?Attempt to Move Pointer Off Page with B");
return(FAIL);
}/* End IF */
j -= lbp->byte_count;
}/* End WHILE */
}/* End Else */
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEDOT;
ut->iarg1 = hbp->dot;
hbp->dot += j;
return(SUCCESS);
}/* End Local Block */
/*
* Here to kill the specified number of lines.
*/
case EXEC_C_KILL:
{/* Local Block */
register struct buff_header *hbp;
register struct buff_line *lbp;
register long i,j;
long pos1,pos2;
hbp = curbuf;
/*
* If two arguments were specified, then he has specified an a,b range to
* be killed.
*/
if(ct->ctx.iarg1_flag == YES && ct->ctx.iarg2_flag == YES){
pos1 = ct->ctx.iarg1;
pos2 = ct->ctx.iarg2;
if(parse_illegal_buffer_position(pos1,pos2,"K")){
return(FAIL);
}/* End IF */
if(pos2 < pos1){
pos2 = ct->ctx.iarg1;
pos1 = ct->ctx.iarg2;
}/* End IF */
}/* End IF */
/*
* Else, if it was a single command, it is a relative kill which affects a
* portion of the buffer in a similar way as if it was an L command. Our job
* now is to turn it into a a,b range.
*/
else {
lbp = buff_find_line(hbp,hbp->dot);
/*
* Start by pretending it was a 0L command, and get to the begining of
* the line. That allows us to not worry about offset onto current line.
*/
j = 0 - buff_find_offset(hbp,lbp,hbp->dot);
i = ct->ctx.iarg1;
if(ct->ctx.iarg1_flag == NO) i = 1;
/*
* If argument is positive, movement is forward
*/
if(i > 0){
while(i-- && lbp){
j += lbp->byte_count;
lbp = lbp->next_line;
}/* End WHILE */
if(lbp == NULL){
error_message("?Attempt to Move Pointer Off Page with K");
return(FAIL);
}/* End IF */
pos1 = hbp->dot;
pos2 = hbp->dot + j;
}/* End IF */
else {
while(i++ && lbp){
lbp = lbp->prev_line;
if(lbp == NULL){
error_message("?Attempt to Move Pointer Off Page with K");
return(FAIL);
}/* End IF */
j -= lbp->byte_count;
}/* End WHILE */
pos1 = hbp->dot + j;
pos2 = hbp->dot;
}/* End Else */
}/* End Else */
j = pos2 - pos1;
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEDOT;
ut->iarg1 = hbp->dot;
/*
* Call the standard routine which deletes the specified buffer positions
* and constructs the undo list so that it can be rebuilt if necessary.
*/
if(j) buff_delete_with_undo(uct,hbp,pos1,j);
return(SUCCESS);
}/* End Local Block */
/*
* Here to insert a character as part of an insert command
*/
case EXEC_C_INSERT:
buff_insert_char_with_undo(
uct,
curbuf,
curbuf->dot,
ct->ctx.iarg1_flag ? ct->ctx.iarg1 : ct->input_byte
);
return(SUCCESS);
/*
* This state is used when a subroutine state is trying to return a
* value to the calling state. It gets specially noticed by the parser,
* so it really doesn't do much except act as a flag.
*/
case EXEC_C_STOREVAL:
return(SUCCESS);
/*
* Store the current expression value as the first argument to a command
*/
case EXEC_C_STORE1:
ct->ctx.iarg1 = ct->ctx.tmpval;
return(SUCCESS);
/*
* Store the current expression value as the second argument to a command
*/
case EXEC_C_STORE2:
ct->ctx.iarg2 = ct->ctx.tmpval;
return(SUCCESS);
/*
* Here when we have a leading minus sign in an expression such as -3+4
*/
case EXEC_C_UMINUS:
ct->ctx.tmpval = 0 - ct->ctx.tmpval;
return(SUCCESS);
/*
* Here to add the two parts of the expression to produce a new temporary
* value.
*/
case EXEC_C_PLUS:
ct->ctx.tmpval = ct->ctx.iarg2 + ct->ctx.tmpval;
return(SUCCESS);
/*
* Here to subtract the two parts of the expression to produce a new temporary
* value.
*/
case EXEC_C_MINUS:
ct->ctx.tmpval = ct->ctx.iarg2 - ct->ctx.tmpval;
return(SUCCESS);
/*
* Here to multiply the two parts of the expression to produce a new temporary
* value.
*/
case EXEC_C_TIMES:
ct->ctx.tmpval = ct->ctx.iarg1 * ct->ctx.tmpval;
return(SUCCESS);
/*
* Here to divide the two parts of the expression to produce a new temporary
* value.
*/
case EXEC_C_DIVIDE:
if(ct->ctx.tmpval == 0){
error_message("?Attempt to Divide by Zero");
return(FAIL);
}/* End IF */
ct->ctx.tmpval = ct->ctx.iarg1 / ct->ctx.tmpval;
return(SUCCESS);
/*
* Here in response to the "A" command which returns as a value the ASCII
* value of the character at 'dot' + offset.
*/
case EXEC_C_ACOMMAND:
{/* Local Block */
register int i;
i = curbuf->dot + ct->ctx.tmpval;
if(parse_illegal_buffer_position(i,i+1,"A")){
return(FAIL);
}/* End IF */
ct->ctx.tmpval = buff_contents(curbuf,i);
return(SUCCESS);
}/* End Local Block */
/*
* Here to cause a repaint of the screen incase it got messed up by
* something
*/
case EXEC_C_REDRAW_SCREEN:
screen_redraw();
return(SUCCESS);
/*
* Here to search for a given string. This gets used not only in the
* "S" command, but as a substate in any command which requires searching
* for a string (such as FD, FK, FS, FR, etc.)
*/
case EXEC_C_SEARCH:
{/* Local Block */
long arg1,arg2;
#if 0
struct buff_header *qbp;
#endif
if(set_search_string_with_undo(ct->ctx.carg,uct) == FAIL){
return(FAIL);
}/* End IF */
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEDOT;
ut->iarg1 = curbuf->dot;
arg1 = 1;
arg2 = -1;
if(ct->ctx.iarg1_flag) arg1 = ct->ctx.iarg1;
if(ct->ctx.iarg2_flag) arg2 = ct->ctx.iarg2;
/*
* If there are two arguments, then it is a constrained search and we must
* insure that the two positions specified are valid buffer positions.
*/
if(ct->ctx.iarg1_flag && ct->ctx.iarg2_flag){
if(arg1 < 0 || (unsigned long)arg1 > curbuf->zee){
sprintf(tmp_message,
"?Illegal buffer position %ld in search command",arg1);
error_message(tmp_message);
return(FAIL);
}/* End IF */
if(arg2 < 0 || (unsigned long)arg2 > curbuf->zee){
sprintf(tmp_message,
"?Illegal buffer position %ld in search command",arg2);
error_message(tmp_message);
return(FAIL);
}/* End IF */
}/* End IF */
/*
* That done, we call the search command to perform the search
*/
if(cmd_search(arg1,arg2,&search_string) == FAIL){
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = FAIL;
return(SUCCESS);
}/* End IF */
if(!ct->ctx.inest && search_string.error_message_given == NO){
sprintf(tmp_message,
"?Cannot find '%.40s'",search_string.input);
error_message(tmp_message);
}/* End IF */
return(SUCCESS);
}/* End IF */
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = -1;
}/* End IF */
return(SUCCESS);
}/* End Local Block */
/*
* Here to implement the FR command. The FR command is similar to the FS
* command (Find-Substitute), except that if the second string argument is
* null, rather than simply deleting the first string argument, it is replaced
* by the default replace string.
*/
case EXEC_C_FRREPLACE:
{/* Local Block */
register struct buff_header *qbp;
register unsigned long j;
if(last_search_status == 0){
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = FAIL;
return(SUCCESS);
}/* End IF */
if(ct->ctx.inest != 0) return(SUCCESS);
return(FAIL);
}/* End IF */
j = last_search_pos2 - last_search_pos1;
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEDOT;
ut->iarg1 = curbuf->dot;
/*
* Call the standard routine which deletes the specified buffer positions
* and constructs the undo list so that it can be rebuilt if necessary.
*/
if(j) buff_delete_with_undo(uct,curbuf,last_search_pos1,j);
qbp = buff_qfind('-',1);
if(qbp == NULL){
return(FAIL);
}/* End IF */
buff_insert_from_buffer_with_undo(
uct,
curbuf, /* destination is current edit buf */
last_search_pos1, /* at the search position */
qbp, /* source is replacement q-register*/
0, /* from position 0 to the end */
qbp->zee
);
if(ct->ctx.iarg1_flag == YES){
if( ct->ctx.iarg1 < 0){
curbuf->dot = last_search_pos1;
}/* End IF */
else if(ct->ctx.iarg2_flag == YES){
if(ct->ctx.iarg2 < ct->ctx.iarg1){
curbuf->dot = last_search_pos1;
}/* End IF */
}/* End Else */
}/* End IF */
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = -1;
}/* End IF */
return(SUCCESS);
}/* End Local Block */
/*
* Here to implement the FS (Find-Substitute) command which searches for
* the first string argument and replaces it with the second.
*/
case EXEC_C_FSREPLACE1:
{/* Local Block */
register unsigned long j;
register struct buff_header *qbp;
ct->ctx.tmpval = 0;
if(last_search_status == 0){
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = FAIL;
return(SUCCESS);
}/* End IF */
if(ct->ctx.inest != 0) return(SUCCESS);
return(FAIL);
}/* End IF */
#ifdef INTERACTIVE_FS
j = last_search_pos2 - last_search_pos1;
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEDOT;
ut->iarg1 = curbuf->dot;
if(j) buff_delete_with_undo(uct,curbuf,last_search_pos1,j);
#endif /* INTERACTIVE_FS */
return(SUCCESS);
case EXEC_C_FSREPLACE2:
if(last_search_status == 0){
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = FAIL;
return(SUCCESS);
}/* End IF */
if(ct->ctx.inest != 0) return(SUCCESS);
return(FAIL);
}/* End IF */
qbp = buff_qfind('-',1);
if(qbp == NULL){
return(FAIL);
}/* End IF */
#ifdef INTERACTIVE_FS
buff_insert_char_with_undo(uct,curbuf,curbuf->dot,ct->input_byte);
#endif /* INTERACTIVE_FS */
/*
* What this does is hope that the replacement string is the same as the
* previous one. Only if we get a miscompare do we delete the contents of
* the replacement q-register, and insert the new string.
*/
if((long)qbp->zee > ct->ctx.tmpval){
if(ct->input_byte == buff_contents(qbp,ct->ctx.tmpval)){
ct->ctx.tmpval += 1;
return(SUCCESS);
}
buff_delete_with_undo(uct,qbp,ct->ctx.tmpval,
qbp->zee-ct->ctx.tmpval);
}
buff_insert_char_with_undo(uct,qbp,ct->ctx.tmpval,ct->input_byte);
ct->ctx.tmpval += 1;
return(SUCCESS);
case EXEC_C_FSREPLACE3:
qbp = buff_qfind('-',1);
if(qbp == NULL){
return(FAIL);
}/* End IF */
if((long)qbp->zee > ct->ctx.tmpval){
buff_delete_with_undo(uct,qbp,ct->ctx.tmpval,
qbp->zee-ct->ctx.tmpval);
}
#ifndef INTERACTIVE_FS
j = last_search_pos2 - last_search_pos1;
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEDOT;
ut->iarg1 = curbuf->dot;
if(j) buff_delete_with_undo(uct,curbuf,last_search_pos1,j);
buff_insert_from_buffer_with_undo(uct,
curbuf,
curbuf->dot,
qbp,
0,
qbp->zee
);
#endif /* !INTERACTIVE_FS */
if(ct->ctx.iarg1_flag == YES){
if( ct->ctx.iarg1 < 0){
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEDOT;
ut->iarg1 = curbuf->dot;
curbuf->dot = last_search_pos1;
}/* End IF */
else if(ct->ctx.iarg2_flag == YES){
if(ct->ctx.iarg2 < ct->ctx.iarg1){
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEDOT;
ut->iarg1 = curbuf->dot;
curbuf->dot = last_search_pos1;
}/* End IF */
}/* End Else */
}/* End IF */
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = last_search_status;
}/* End IF */
return(SUCCESS);
}/* End Local Block */
/*
* Here to execute the FT (tags) command. Since this is a fairly complicated
* command, we call a subroutine to perform the actions.
*/
case EXEC_C_FTAGS:
{/* Local Block */
register int arg_count = 0;
register int status;
if(ct->ctx.iarg1_flag == YES) arg_count = 1;
if(ct->ctx.iarg2_flag == YES) arg_count = 2;
status = cmd_tags(
uct,
arg_count,
ct->ctx.iarg1,
ct->ctx.iarg2,
ct->ctx.carg
);
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = status;
return(SUCCESS);
}/* End IF */
return(status);
}/* End Local Block */
/*
* Here to execute the FD command which searches for a string and deletes
* it. It is like FS but saves you from typing the second escape.
*/
case EXEC_C_FDCOMMAND:
{/* Local Block */
register int j;
if(last_search_status == 0){
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = FAIL;
return(SUCCESS);
}/* End IF */
if(ct->ctx.inest != 0) return(SUCCESS);
return(FAIL);
}/* End IF */
j = last_search_pos2 - last_search_pos1;
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEDOT;
ut->iarg1 = curbuf->dot;
/*
* Call the standard routine which deletes the specified buffer positions
* and constructs the undo list so that it can be rebuilt if necessary.
*/
if(j) buff_delete_with_undo(uct,curbuf,last_search_pos1,j);
curbuf->dot = last_search_pos1;
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = -1;
}/* End IF */
return(SUCCESS);
}/* End Local Block */
/*
* Here to implement the FK command. The FK command remembers the current
* position in the buffer and searches for the specified string. It then
* deletes the characters from the old current position up to but not
* including the search string.
*/
case EXEC_C_FKCOMMAND:
{/* Local Block */
register int j;
if(last_search_status == 0){
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = FAIL;
return(SUCCESS);
}/* End IF */
if(ct->ctx.inest != 0) return(SUCCESS);
return(FAIL);
}/* End IF */
if(remembered_dot <= last_search_pos1){
last_search_pos2 = last_search_pos1;
last_search_pos1 = remembered_dot;
}/* End IF */
else {
last_search_pos1 = last_search_pos2;
last_search_pos2 = remembered_dot;
curbuf->dot = last_search_pos1;
}/* End IF */
j = last_search_pos2 - last_search_pos1;
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEDOT;
ut->iarg1 = curbuf->dot;
/*
* Call the standard routine which deletes the specified buffer positions
* and constructs the undo list so that it can be rebuilt if necessary.
*/
if(j) buff_delete_with_undo(uct,curbuf,last_search_pos1,j);
curbuf->dot = last_search_pos1;
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = -1;
}/* End IF */
return(SUCCESS);
}/* End Local Block */
/*
* This state is used by the FK command to remember the current dot
* position before it is changed by the search command.
*/
case EXEC_C_REMEMBER_DOT:
remembered_dot = curbuf->dot;
return(SUCCESS);
/*
* Here to implement the N search which searches across edit buffers for
* the given string.
*/
case EXEC_C_NSEARCH:
{/* Local Block */
int count;
struct buff_header *original_buffer;
int original_dot;
int saved_dot,saved_top,saved_bottom;
int first_buffer;
int last_buffer = 0;
char back_in_original_buffer;
/*
* We set the search string, just like all the other search commands
*/
if(set_search_string_with_undo(ct->ctx.carg,uct) == FAIL){
return(FAIL);
}/* End IF */
/*
* Remember the buffer that we started in, and be ready to change back to
* it if we undo.
*/
original_buffer = curbuf;
original_dot = curbuf->dot;
count = 1;
if(ct->ctx.iarg1_flag) count = ct->ctx.iarg1;
/*
* If he says 1,5n$ then we search for the string in buffers 1
* through 5. We check that both buffers exist before we begin the search.
*/
if(ct->ctx.iarg2_flag){
count = 1;
first_buffer = ct->ctx.iarg1;
last_buffer = ct->ctx.iarg2;
if(first_buffer != curbuf->buffer_number){
if(buff_openbuffer(NULL,last_buffer,0) != SUCCESS){
return(FAIL);
}/* End IF */
if(buff_openbuffer(NULL,first_buffer,0) != SUCCESS){
return(FAIL);
}/* End IF */
curbuf->dot = 0;
}/* End IF */
}/* End IF */
/*
* In the starting buffer, we want to search from 'dot' to the end. Then
* we would search all the other buffers, and then the original one again,
* but from the top to 'dot'. The saved_dot stuff is necessary because
* the cmd_search routine has the side effect of changing 'dot' in the
* buffer being searched. However, we only want to affect 'dot' in the
* final buffer that the final occurance of the search string is found in.
*/
saved_dot = curbuf->dot;
saved_top = curbuf->dot;
saved_bottom = curbuf->zee;
back_in_original_buffer = 0;
while(count > 0){
if(cmd_search(saved_top,saved_bottom,&search_string) != FAIL){
saved_top = curbuf->dot;
count -= 1;
continue;
}/* End IF */
/*
* Here if the search failed. We want to switch over to the next buffer and
* try again, until we exhaust all the buffers. If we reach the final buffer
* without finding the string, we return an error to the user, leaving him
* back in his original buffer.
*/
if(ct->ctx.iarg2_flag && curbuf->buffer_number == last_buffer){
if(buff_openbuffer(NULL,original_buffer->buffer_number,0) != SUCCESS){
error_message("Boom! lost original buffer");
return(FAIL);
}/* End IF */
back_in_original_buffer = 1;
}/* End IF */
if(back_in_original_buffer){
curbuf->dot = saved_dot;
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = FAIL;
return(SUCCESS);
}/* End IF */
sprintf(tmp_message,
"?Cannot find '%.40s'",search_string.input);
if(!ct->ctx.inest && !intr_flag &&
search_string.error_message_given == NO){
error_message(tmp_message);
}/* End IF */
return(SUCCESS);
}/* End IF */
/*
* We havn't tried all the buffers yet, switch to the next one.
*/
curbuf->dot = saved_dot;
while(1){
curbuf = curbuf->next_header;
if(curbuf == NULL) curbuf = buffer_headers;
if(curbuf->buffer_number == -1) break;
if(curbuf->buffer_number > 0) break;
if(ct->ctx.iarg2_flag) continue;
if(curbuf == original_buffer) break;
}/* End While */
saved_dot = curbuf->dot;
saved_top = 0;
saved_bottom = curbuf->zee;
if(ct->ctx.iarg2_flag == NO){
if(curbuf->buffer_number == original_buffer->buffer_number){
back_in_original_buffer = 1;
saved_bottom = original_dot;
}/* End IF */
}/* End IF */
}/* End While */
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEBUFF;
ut->iarg1 = original_buffer->buffer_number;
buff_switch(curbuf,1);
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEDOT;
ut->iarg1 = saved_dot;
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = -1;
}/* End IF */
return(SUCCESS);
}/* End Local Block */
/*
* Here to begin an iteration < ... >
*/
case EXEC_C_ITERATION_BEGIN:
{/* Local Block */
register struct cmd_token *oct;
if(ct->ctx.iarg1_flag == YES){
if(ct->ctx.iarg1 <= 0){
oct = ct;
while((oct = oct->next_token)){
if(oct->opcode != TOK_C_ITERATION_END) continue;
if(oct->ctx.inest != (ct->ctx.inest-1)) continue;
jump_to_token = oct;
return(SUCCESS);
}/* End While */
ct->ctx.go_flag = NO;
return(SUCCESS);
}/* End IF */
ct->ctx.iarg1 -= 1;
}/* End IF */
return(SUCCESS);
}/* End Local Block */
/*
* Here to provide the execution code for the end of an iteration.
* This must search backwards in the parse tokens to find the begining
* of the iteration, and set up to jump to that token
*/
case EXEC_C_ITERATION_END:
{/* Local Block */
register struct cmd_token *oct;
/*
* The parser left us a pointer to the begining of the iteration so we can
* find it without having to search.
*/
oct = ct->ctx.caller_token;
if(oct->ctx.iarg1_flag == YES){
if(oct->ctx.iarg1 <= 0){
return(SUCCESS);
}/* End IF */
}/* End IF */
/*
* The following line grabs the old iteration value so that when the
* begining of iteration code grabs the "previous" iarg1, this will
* be it. Think of it this way: the code has to do something different
* the first time into the iteration (it has to load the results of the
* STORE1, then the subsequent times it has to decrement what's already
* there. That's why this seems a little kludgy.
*/
ct->ctx.iarg1 = oct->ctx.iarg1;
jump_to_token = oct;
return(SUCCESS);
}/* End Local Block */
/*
* Here to implement the semicolon command which is used to jump out
* of an iteration if the argument is >= 0.
*/
case EXEC_C_SEMICOLON:
{/* Local Block */
register struct cmd_token *oct;
int value;
value = last_search_status;
if(ct->ctx.iarg1_flag == YES) value = ct->ctx.iarg1;
if(value < 0) return(SUCCESS);
oct = ct;
while((oct = oct->next_token)){
if(oct->opcode != TOK_C_ITERATION_END) continue;
if(oct->ctx.inest != (ct->ctx.inest-1)) continue;
if(oct->next_token){
jump_to_token = oct->next_token;
return(SUCCESS);
}/* End IF */
}/* End While */
ct->ctx.go_flag = NO;
return(BLOCKED);
}/* End Local Block */
/*
* Here to implement the various conditional operators
*/
case EXEC_C_COND_GT:
if(ct->ctx.iarg1 <= 0){
return(find_conditional_else(ct));
}/* End IF */
return(SUCCESS);
case EXEC_C_COND_LT:
if(ct->ctx.iarg1 >= 0){
return(find_conditional_else(ct));
}/* End IF */
return(SUCCESS);
case EXEC_C_COND_EQ:
if(ct->ctx.iarg1 != 0){
return(find_conditional_else(ct));
}/* End IF */
return(SUCCESS);
case EXEC_C_COND_NE:
if(ct->ctx.iarg1 == 0){
return(find_conditional_else(ct));
}/* End IF */
return(SUCCESS);
case EXEC_C_COND_DIGIT:
if(!isdigit(ct->ctx.iarg1)){
return(find_conditional_else(ct));
}/* End IF */
return(SUCCESS);
case EXEC_C_COND_ALPHA:
if(!isalpha(ct->ctx.iarg1)){
return(find_conditional_else(ct));
}/* End IF */
return(SUCCESS);
case EXEC_C_COND_LOWER:
if(!islower(ct->ctx.iarg1)){
return(find_conditional_else(ct));
}/* End IF */
return(SUCCESS);
case EXEC_C_COND_UPPER:
if(!isupper(ct->ctx.iarg1)){
return(find_conditional_else(ct));
}/* End IF */
return(SUCCESS);
case EXEC_C_COND_SYMBOL:
if(!isalnum(ct->ctx.iarg1) && ct->ctx.iarg1 != '_'){
return(find_conditional_else(ct));
}/* End IF */
return(SUCCESS);
case EXEC_C_SKIP_ELSE:
return(find_conditional_end(ct));
/*
* Here to implement the GOTO command OLABEL$
*/
case EXEC_C_GOTO:
{/* Local Block */
struct cmd_token *goto_ptr;
struct cmd_token *test_ptr;
/*
* First step is to find the begining of this goto string
*/
goto_ptr = ct;
while((goto_ptr = goto_ptr->prev_token)){
if(goto_ptr->opcode != TOK_C_GOTO_BEGIN) continue;
break;
}/* End While */
/*
* Now try to find the label. First search backwards for it
*/
test_ptr = goto_ptr;
while((test_ptr = test_ptr->prev_token)){
if(test_ptr->opcode != TOK_C_LABEL_BEGIN) continue;
if(compare_label(goto_ptr,test_ptr) == YES){
ct->ctx.go_flag = NO;
jump_to_token = test_ptr;
return(SUCCESS);
}/* End IF */
}/* End While */
/*
* The label is not in front of us, look for it afterwards
*/
test_ptr = goto_ptr;
while((test_ptr = test_ptr->next_token)){
if(test_ptr->opcode == TOK_C_FINALTOKEN){
char string1[PARSER_STRING_MAX];
extract_label(goto_ptr,string1);
(void) snprintf(tmp_message,sizeof(tmp_message),"?Can't find label <%s>",
string1);
error_message(tmp_message);
return(FAIL);
}/* End IF */
if(test_ptr->opcode != TOK_C_LABEL_BEGIN) continue;
if(compare_label(goto_ptr,test_ptr) == YES){
jump_to_token = test_ptr;
return(SUCCESS);
}/* End IF */
}/* End While */
ct->ctx.go_flag = NO;
return(BLOCKED);
}/* End Local Block */
/*
* Here to write out the buffer. If the filename is specified, write it
* to that name, otherwise write it to the default name of the buffer.
*/
case EXEC_C_WRITEFILE:
{/* Local Block */
int status;
struct wildcard_expansion *name_list,*np;
char *filename;
if(curbuf->isreadonly){
error_message("?File is Readonly");
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = FAIL;
return(SUCCESS);
}/* End IF */
return(FAIL);
}/* End IF */
if(ct->ctx.carg) filename = ct->ctx.carg;
else filename = curbuf->name;
np = expand_filename(filename);
if(np == NULL){
sprintf(tmp_message,"EW No such file <%s>",filename);
error_message(tmp_message);
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = FAIL;
return(SUCCESS);
}/* End IF */
return(FAIL);
}/* End IF */
if(np->we_next){
sprintf(tmp_message,"EW: Non-unique filename <%s>",filename);
error_message(tmp_message);
while(np){
name_list = np;
np = np->we_next;
tec_release(TYPE_C_WILD,(char *)name_list);
}/* End While */
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = FAIL;
return(SUCCESS);
}/* End IF */
return(FAIL);
}/* End IF */
status = cmd_write(curbuf,np->we_name);
tec_release(TYPE_C_WILD,(char *)np);
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = status;
return(SUCCESS);
}/* End IF */
return(status);
}/* End Local Block */
/*
* Read in the named file to the current position in the edit buffer
*/
case EXEC_C_READFILE:
{/* Local Block */
struct wildcard_expansion *name_list,*np;
if(ct->ctx.carg == NULL || ct->ctx.carg[0] == '\0'){
error_message("?ER Requires a filename");
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = FAIL;
return(SUCCESS);
}/* End IF */
return(FAIL);
}/* End IF */
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_DELETE;
ut->carg1 = (char *)curbuf;
ut->iarg1 = curbuf->dot;
ut->iarg2 = curbuf->zee;
np = expand_filename(ct->ctx.carg);
if(np == NULL){
sprintf(tmp_message,"ER No such file <%s>",ct->ctx.carg);
error_message(tmp_message);
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = FAIL;
return(SUCCESS);
}/* End IF */
return(FAIL);
}/* End IF */
while(np){
buff_read(curbuf,np->we_name);
name_list = np;
np = np->we_next;
tec_release(TYPE_C_WILD,(char *)name_list);
}/* End While */
ut->iarg2 = curbuf->zee - ut->iarg2;
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = SUCCESS;
return(SUCCESS);
}/* End IF */
return(SUCCESS);
}/* End Local Block */
/*
* Here to change the current edit buffer. If a numeric argument is
* supplied, change to that buffer, otherwise a string should have been
* specified, and this is the name of the file/buffer to be loaded.
*/
case EXEC_C_EDITBUF:
{/* Local Block */
struct buff_header *hbp,*old_buffer,*first_buffer;
struct wildcard_expansion *name_list,*np;
/*
* Here if there is no string argument. It better be a numeric buffer
* number argument. If so, switch to that buffer, and set the undo to
* switch back to the old one if this gets undone.
*/
if(ct->ctx.carg == NULL || ct->ctx.carg[0] == '\0'){
if(ct->ctx.iarg1_flag == NO){
error_message("?EB Requires a filename or argument");
return(FAIL);
}/* End IF */
old_buffer = curbuf;
if(buff_openbuffer(0,ct->ctx.iarg1,0) == FAIL){
return(FAIL);
}/* End IF */
if(curbuf->buffer_number != ct->ctx.iarg1){
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = FAIL;
return(SUCCESS);
}
return(FAIL);
}/* End IF */
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEBUFF;
ut->iarg1 = old_buffer->buffer_number;
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = SUCCESS;
}
return(SUCCESS);
}/* End IF */
old_buffer = curbuf;
first_buffer = NULL;
np = expand_filename(ct->ctx.carg);
if(np == NULL){
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = FAIL;
return(SUCCESS);
}
sprintf(tmp_message,"EB No such file <%s>",ct->ctx.carg);
error_message(tmp_message);
return(FAIL);
}/* End IF */
while(np){
/*
* The following hack detects whether a new buffer was created so that
* we know whether or not to set up an undo to un-create it.
*/
hbp = buff_find(np->we_name);
if(buff_openbuffer(np->we_name,0,0) == SUCCESS){
if(hbp == NULL){
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CLOSEBUFF;
ut->carg1 = (char *)curbuf;
}/* End IF */
if(first_buffer == NULL) first_buffer = curbuf;
}/* End IF */
name_list = np;
np = np->we_next;
tec_release(TYPE_C_WILD,(char *)name_list);
}/* End While */
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEBUFF;
ut->iarg1 = old_buffer->buffer_number;
buff_openbuffer(0,first_buffer->buffer_number,0);
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = SUCCESS;
return(SUCCESS);
}
return(SUCCESS);
}/* End Local Block */
/*
* Here to implement the EF command which removes an edit buffer.
*/
case EXEC_C_CLOSEBUF:
{/* Local Block */
register struct buff_header *hbp,*bp;
register int i;
hbp = curbuf;
if(curbuf->buffer_number == 0){
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = FAIL;
return(SUCCESS);
}/* End IF */
error_message("?EF Not allowed on special buffers");
return(FAIL);
}/* End IF */
if(hbp->ismodified && !hbp->isreadonly){
if(ct->ctx.iarg1_flag == NO ||
ct->ctx.iarg1 != -1){
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = FAIL;
return(SUCCESS);
}/* End IF */
sprintf(tmp_message,"?EF Buffer %s is modified",
curbuf->name);
error_message(tmp_message);
return(FAIL);
}/* End IF */
}/* End IF */
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEBUFF;
ut->iarg1 = hbp->buffer_number;
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_REOPENBUFF;
ut->iarg1 = hbp->buffer_number;
ut->carg1 = (char *)hbp;
/*
* Unlink this buffer header from the header list. Check to see if it is
* at the head of the list. If not at the head of the list, we have to
* search the list till we find it's father. Then we make it's father's
* child be it's child.
*/
i = 0;
bp = buffer_headers;
if(bp == hbp) buffer_headers = bp->next_header;
else {
while(bp){
if(bp->next_header == hbp) break;
bp = bp->next_header;
}/* End While */
bp->next_header = hbp->next_header;
curbuf = NULL;
if(bp->buffer_number > 0 && hbp->buffer_number > 0){
i = bp->buffer_number;
}/* End IF */
else if(bp->buffer_number < 0 && hbp->buffer_number < 0){
i = bp->buffer_number;
}/* End Else */
else if(hbp->buffer_number > 0 && hbp->next_header){
i = hbp->next_header->buffer_number;
}/* End Else */
else i = -1;
}/* End Else */
/*
* Pick a different buffer to be the current buffer
*/
if(i){
if(buff_openbuffer(NULL,i,0) == FAIL) i = 0;
}/* End IF */
if(!i){
if(buff_openbuffer(NULL,-1,0) == FAIL){
buff_openbuffer(NULL,0,0);
}/* End IF */
}/* End IF */
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = SUCCESS;
}/* End IF */
return(SUCCESS);
}/* End Local Block */
/*
* Here to implement the EV command which is identical to the EB command
* except that if the buffer does not exist, when it is created it is created
* as a read only buffer.
*/
case EXEC_C_VIEWBUF:
{/* Local Block */
struct buff_header *hbp,*old_buffer,*first_buffer;
struct wildcard_expansion *name_list,*np;
/*
* Here if there is no string argument. It better be a numeric buffer
* number argument. If so, switch to that buffer, and set the undo to
* switch back to the old one if this gets undone.
*/
if(ct->ctx.carg == NULL || ct->ctx.carg[0] == '\0'){
if(ct->ctx.iarg1_flag == NO){
error_message("?EV Requires a filename or argument");
return(FAIL);
}/* End IF */
old_buffer = curbuf;
buff_openbuffer(0,ct->ctx.iarg1,1);
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEBUFF;
ut->iarg1 = old_buffer->buffer_number;
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = SUCCESS;
}
return(SUCCESS);
}/* End IF */
old_buffer = curbuf;
first_buffer = NULL;
np = expand_filename(ct->ctx.carg);
if(np == NULL){
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = FAIL;
return(SUCCESS);
}
sprintf(tmp_message,"EV No such file <%s>",ct->ctx.carg);
error_message(tmp_message);
return(FAIL);
}/* End IF */
while(np){
/*
* The following hack detects whether a new buffer was created so that
* we know whether or not to set up an undo to un-create it.
*/
hbp = buff_find(np->we_name);
if(buff_openbuffer(np->we_name,0,1) == SUCCESS){
if(hbp == NULL){
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CLOSEBUFF;
ut->carg1 = (char *)curbuf;
}/* End IF */
if(first_buffer == NULL) first_buffer = curbuf;
}/* End IF */
name_list = np;
np = np->we_next;
tec_release(TYPE_C_WILD,(char *)name_list);
}/* End While */
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEBUFF;
ut->iarg1 = old_buffer->buffer_number;
buff_openbuffer(0,first_buffer->buffer_number,1);
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = SUCCESS;
return(SUCCESS);
}
return(SUCCESS);
}/* End Local Block */
/*
* Here to scroll the screen the specified number of lines
*/
case EXEC_C_SCROLL:
if(ct->ctx.iarg1_flag == NO) ct->ctx.iarg1 = 1;
screen_scroll(ct->ctx.iarg1);
return(SUCCESS);
/*
* Here to cause the screen to update
*/
case EXEC_C_UPDATE_SCREEN:
screen_format_windows();
screen_refresh();
return(SUCCESS);
/*
* Here to either split or combine windows
*/
case EXEC_C_WINDOW_CONTROL:
{/* Local Block */
struct window *old_wptr;
struct window *new_wptr;
if(ct->ctx.iarg1_flag == NO) screen_delete_window(curwin);
if(ct->ctx.iarg1_flag == YES && ct->ctx.iarg2_flag == YES){
old_wptr = curwin;
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
new_wptr =
screen_split_window(
curwin,
ct->ctx.iarg1,
ct->ctx.iarg2
);
if(new_wptr == NULL) return(FAIL);
ut->opcode = UNDO_C_WINDOW_SPLIT;
ut->iarg1 = old_wptr->win_window_number;
ut->carg1 = (char *)new_wptr;
}/* End Else */
return(SUCCESS);
}/* End Local Block */
/*
* Here to select the next window as active
*/
case EXEC_C_NEXT_WINDOW:
{/* Local Block */
int status;
int new_window;
new_window = ct->ctx.iarg1_flag == YES ? ct->ctx.iarg1 : 0;
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_WINDOW_SWITCH;
ut->iarg1 = curwin->win_window_number;
status = window_switch(new_window);
return(status);
}/* End Local Block */
/*
* Here to reset a ^A message to NULL
*/
case EXEC_C_RESET_MESSAGE:
user_message[0] = '\0';
return(SUCCESS);
/*
* Here to add a byte to the length of the current user message string
*/
case EXEC_C_MESSAGE:
{/* Local Block */
register int i;
if(strlen(user_message) > (sizeof(user_message) - 1)){
error_message("?^A message length exceeded");
return(FAIL);
}/* End IF */
i = strlen(user_message);
user_message[i] = ct->input_byte;
user_message[i+1] = '\0';
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_SHORTEN_MESSAGE;
return(SUCCESS);
}/* End Local Block */
/*
* Here to print the current user message to the status line of the screen
*/
case EXEC_C_OUTPUT_MESSAGE:
screen_message(user_message);
screen_refresh();
return(SUCCESS);
/*
* Here to execute the specified operating system command, and insert the
* generated output into the edit buffer.
*/
case EXEC_C_ECCOMMAND:
{/* Local Block */
register int arg_count = 0;
register struct buff_header *hbp;
register struct buff_line *lbp;
register int i,j;
register int status;
int pos1 = 0, pos2 = 0;
if(ct->ctx.iarg1_flag == YES) arg_count = 1;
if(ct->ctx.iarg2_flag == YES) arg_count = 2;
hbp = curbuf;
/*
* If two arguments were specified, then he has specified an a,b range to
* be piped into the process.
*/
if(arg_count == 2){
pos1 = ct->ctx.iarg1;
pos2 = ct->ctx.iarg2;
if(parse_illegal_buffer_position(pos1,pos2,"EC")){
return(FAIL);
}/* End IF */
if(pos2 < pos1){
pos2 = ct->ctx.iarg1;
pos1 = ct->ctx.iarg2;
}/* End IF */
}/* End IF */
/*
* Else, if it was a single command, it is a relative EC which affects a
* portion of the buffer in a similar way as if it was an L command. Our job
* now is to turn it into a a,b range.
*/
else if(arg_count == 1){
lbp = buff_find_line(hbp,hbp->dot);
/*
* Start by pretending it was a 0L command, and get to the begining of
* the line. That allows us to not worry about offset onto current line.
*/
j = 0 - buff_find_offset(hbp,lbp,hbp->dot);
i = ct->ctx.iarg1;
/*
* If argument is positive, movement is forward
*/
if(i > 0){
while(i-- && lbp){
j += lbp->byte_count;
lbp = lbp->next_line;
}/* End WHILE */
if(lbp == NULL){
error_message("?Attempt to Move Pointer Off Page with EC");
return(FAIL);
}/* End IF */
pos1 = hbp->dot;
pos2 = hbp->dot + j;
}/* End IF */
else {
while(i++ && lbp){
lbp = lbp->prev_line;
if(lbp == NULL){
error_message("?Attempt to Move Pointer Off Page with EC");
return(FAIL);
}/* End IF */
j -= lbp->byte_count;
}/* End WHILE */
pos1 = hbp->dot + j;
pos2 = hbp->dot;
}/* End Else */
}/* End Else */
status = cmd_oscmd(uct,arg_count,pos1,pos2,ct->ctx.carg);
if(ct->ctx.flags & CTOK_M_COLON_SEEN){
ct->ctx.tmpval = status;
return(SUCCESS);
}/* End IF */
return(status);
}/* End Local Block */
case EXEC_C_SET_IMMEDIATE_MODE:
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_SET_IMMEDIATE_MODE;
ut->iarg1 = immediate_execute_flag;
immediate_execute_flag = YES;
if(ct->ctx.iarg1 == 0){
ct->ctx.go_flag = NO;
immediate_execute_flag = NO;
}/* End IF */
return(SUCCESS);
case EXEC_C_OPENBRACE:
{/* Local Block */
register struct buff_header *qbp;
/*
* Get a pointer to the q-register buffer structure. If it doesn't
* exist, create it.
*/
qbp = buff_qfind('$',1);
if(qbp == NULL){
return(FAIL);
}/* End IF */
/*
* Set up the undo token to remember the current edit buffer, and then switch
* to the Q-register.
*/
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_CHANGEBUFF;
ut->iarg1 = curbuf->buffer_number;
buff_switch(qbp,1);
/*
* Delete the previous contents of the q-register, but allow it to be
* reconstructed if this gets undone. Note that we don't have to do
* this if there was nothing there.
*/
if(qbp->zee) buff_delete_with_undo(uct,qbp,0,qbp->zee);
/*
* Arrange for it to be deleted if this gets undone.
*/
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
/*
* Copy the parser command line into the Q-register
*/
parser_dump_command_line(qbp);
ut->opcode = UNDO_C_DELETE;
ut->carg1 = (char *)qbp;
ut->iarg1 = 0;
ut->iarg2 = qbp->zee;
return(SUCCESS);
}/* End Local Block */
case EXEC_C_CLOSEBRACE:
{/* Local Block */
register struct buff_header *qbp;
/*
* Get a pointer to the q-register buffer structure. If it doesn't
* exist, that is an error
*/
qbp = buff_qfind('$',0);
if(qbp == NULL){
return(FAIL);
}/* End IF */
/*
* Replace the command line with the contents of the Q-register
*/
parser_replace_command_line(qbp);
return(INVALIDATE);
}/* End Local Block */
/*
* Here to skip a label (this occurs when we run into a label)
*/
case EXEC_C_SKIPLABEL:
while(ct){
if(ct->opcode == TOK_C_LABEL_END){
jump_to_token = ct;
return(SUCCESS);
}/* End IF */
ct = ct->next_token;
}/* End While */
return(SUCCESS);
/*
* Here if he wants to set some options up
*/
case EXEC_C_SETOPTIONS:
ut = allocate_undo_token(uct);
if(ut == NULL) return(FAIL);
ut->opcode = UNDO_C_SETOPTIONS;
return(cmd_setoptions(ct->ctx.iarg1,ct->ctx.iarg2,ut));
default:
sprintf(tmp_message,"?TECEXEC: unknown state %d dispatched",
ct->execute_state);
error_message(tmp_message);
return(FAIL);
}/* End Switch */
}/* End Routine */
/**
* \brief Push a Q register onto the stack
*
* This routine is called to make a copy of a Q register and place it
* on the Q register stack.
*/
int
push_qregister( char letter )
{
register struct buff_header *hbp;
register struct buff_header *qbp;
PREAMBLE();
/*
* Get a pointer to the q-register buffer structure. If it doesn't
* exist, create it.
*/
qbp = buff_qfind(letter,1);
if(qbp == NULL){
return(FAIL);
}/* End IF */
hbp = buff_duplicate(qbp);
hbp->next_header = qregister_push_down_list;
qregister_push_down_list = hbp;
return(SUCCESS);
}/* End Routine */
/**
* \brief Build a string with the contents of the label in it
*
* This routine is called to build a string with the label name
* in it. The current use is for error messages.
*/
void
extract_label( struct cmd_token *label_ptr, char *string1 )
{
register char *cp1;
cp1 = string1;
*cp1 = '\0';
while(label_ptr){
if(cp1 >= &string1[PARSER_STRING_MAX-1]) break;
if(label_ptr->opcode == TOK_C_INPUTCHAR){
if(label_ptr->input_byte == '!') break;
*cp1++ = label_ptr->input_byte;
*cp1 = '\0';
}/* End IF */
if(label_ptr->opcode == TOK_C_LABEL_END) break;
label_ptr = label_ptr->next_token;
}/* End While */
}/* End Routine */
/**
* \brief Test if this is our label
*
* This routine is called by the GOTO function to compare labels
* to see if they match.
*/
int
compare_label( struct cmd_token *goto_ptr, struct cmd_token *label_ptr )
{
char string1[PARSER_STRING_MAX],string2[PARSER_STRING_MAX];
char *cp1;
PREAMBLE();
cp1 = string1;
*cp1 = '\0';
while(goto_ptr){
if(cp1 >= &string1[PARSER_STRING_MAX-1]) break;
if(goto_ptr->opcode == TOK_C_INPUTCHAR){
if(goto_ptr->input_byte == ESCAPE) break;
*cp1++ = goto_ptr->input_byte;
*cp1 = '\0';
}/* End IF */
if(goto_ptr->opcode == TOK_C_GOTO_END) break;
goto_ptr = goto_ptr->next_token;
}/* End While */
cp1 = string2;
*cp1 = '\0';
while(label_ptr){
if(cp1 >= &string2[PARSER_STRING_MAX-1]) break;
if(label_ptr->opcode == TOK_C_INPUTCHAR){
if(label_ptr->input_byte == '!') break;
*cp1++ = label_ptr->input_byte;
*cp1 = '\0';
}/* End IF */
if(label_ptr->opcode == TOK_C_LABEL_END) break;
label_ptr = label_ptr->next_token;
}/* End While */
if(strcmp(string1,string2) == 0) return(YES);
return(NO);
}/* End Routine */
/**
* \brief Routine to find the else of a conditional
*
* This routine is called by the conditional expressions when the
* specified condition has not been met and we want to execute the
* else clause of the conditional. The routine searches until it
* finds either the else, or the end of the conditional.
*/
int
find_conditional_else( struct cmd_token *ct )
{
register struct cmd_token *oct;
PREAMBLE();
oct = ct;
while((oct = oct->next_token)){
if(oct->opcode == TOK_C_CONDITIONAL_ELSE){
if(oct->ctx.cnest == ct->ctx.cnest){
jump_to_token = oct;
return(SUCCESS);
}/* End IF */
}/* End IF */
if(oct->opcode == TOK_C_CONDITIONAL_END){
if(oct->ctx.cnest == (ct->ctx.cnest-1)){
jump_to_token = oct;
return(SUCCESS);
}/* End IF */
}/* End IF */
}/* End While */
ct->ctx.go_flag = NO;
return(BLOCKED);
}/* End Routine */
/**
* \brief Routine to find the close of a conditional
*
* This routine is called to skip over the else clause and find the
* end of the conditional.
*/
int
find_conditional_end( struct cmd_token *ct )
{
register struct cmd_token *oct;
PREAMBLE();
oct = ct;
while((oct = oct->next_token)){
if(oct->opcode != TOK_C_CONDITIONAL_END) continue;
if(oct->ctx.cnest != (ct->ctx.cnest-1)) continue;
jump_to_token = oct;
return(SUCCESS);
}/* End While */
ct->ctx.go_flag = NO;
return(BLOCKED);
}/* End Routine */
/**
* \brief Execute Q register zero as a macro
*
* This routine is called to execute Q register zero as a macro on
* startup. This allows the user to initialize things from his teco.ini
* before teco reaches command level.
*/
int
exec_doq0()
{
register struct buff_header *qbp;
register struct undo_token *ut;
struct cmd_token *ct;
PREAMBLE();
/*
* Get a pointer to the q-register buffer structure. If it doesn't
* exist, declare an error.
*/
qbp = buff_qfind('0',0);
if(qbp == NULL){
error_message("?Internal Error! Q register 0 disappeared during init");
return(FAIL);
}/* End IF */
/*
* If the Q register is empty, just return with no error.
*/
if(qbp->zee == 0){
return(SUCCESS);
}/* End IF */
/*
* Set up a fake command token and undo token structure for the parser to
* chain undo blocks off of. We don't ever undo this stuff, but the routine
* expects it to be there.
*/
ct = allocate_cmd_token((struct cmd_token *)NULL);
if(ct == NULL) return(FAIL);
ut = allocate_undo_token(ct);
if(ut == NULL){
free_cmd_token(ct);
return(FAIL);
}/* End IF */
ut->opcode = UNDO_C_MACRO;
ut->carg1 = NULL;
tecmacro(qbp,ct,(struct cmd_token **)&ut->carg1);
parser_cleanup_ctlist(ct);
return(SUCCESS);
}/* End Routine */