diff options
author | paulcantrell <paulcantrell> | 2007-12-10 21:59:20 +0000 |
---|---|---|
committer | paulcantrell <paulcantrell> | 2007-12-10 21:59:20 +0000 |
commit | 2ee4787d1df9784d40a7eda91e61691da3d56f74 (patch) | |
tree | 0947afb6c37ffeb4ae193401a187255cf27b0ed3 /tecexec.c | |
download | videoteco-fork-2ee4787d1df9784d40a7eda91e61691da3d56f74.tar.gz |
Initial revision
Diffstat (limited to 'tecexec.c')
-rw-r--r-- | tecexec.c | 2801 |
1 files changed, 2801 insertions, 0 deletions
diff --git a/tecexec.c b/tecexec.c new file mode 100644 index 0000000..6d94fd5 --- /dev/null +++ b/tecexec.c @@ -0,0 +1,2801 @@ +char *tecexec_c_version = "tecexec.c: $Revision: 1.1 $"; + +/* + * $Date: 2007/12/10 21:59:20 $ + * $Source: /cvsroot/videoteco/videoteco/tecexec.c,v $ + * $Revision: 1.1 $ + * $Locker: $ + */ + +/* tecexec.c + * The SWITCH/CASE statements which implement execution stage of the parser + * + * COPYRIGHT (c) 1985-2003 BY + * PAUL CANTRELL & J. M. NISHINAGA + * SUDBURY, MA 01776 + * ALL RIGHTS RESERVED + * + * This software is furnished in it's current state free of charge. + * The authors reserve all rights to the software. Further + * distribution of the software is not authorized. Modifications to + * the software may be made locally, but shall not be distributed + * without the consent of the authors. This software or any other + * copies thereof, may not be provided or otherwise made available + * to anyone without express permission of the authors. Title to and + * ownership of this software remains with the authors. + * + */ + +#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 int last_search_pos1,last_search_pos2; + extern int last_search_status; + extern int 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 *); + + + +/* EXECUTE_A_STATE - Do the runtime execution part of a command + * + * Function: + * + * 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(ct,uct) +register 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; + struct wildcard_expansion *expand_filename(); + + 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 int i,j; + int 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 = %d",ct->ctx.iarg1); + screen_message(tmp_buffer); + return(SUCCESS); + + case EXEC_C_TWO_EQUALS: + sprintf(tmp_buffer,"value = 0%o",ct->ctx.iarg1); + screen_message(tmp_buffer); + return(SUCCESS); + + case EXEC_C_THREE_EQUALS: + sprintf(tmp_buffer,"value = 0x%X",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 int 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 int 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 int 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 int 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 int 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 int count; + int original_position; + int 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 int count; + int original_position; + int 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 int i,j; + int 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 */ + int 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 || arg1 > curbuf->zee){ + sprintf(tmp_message, + "?Illegal buffer position %d in search command",arg1); + error_message(tmp_message); + return(FAIL); + }/* End IF */ + if(arg2 < 0 || arg2 > curbuf->zee){ + sprintf(tmp_message, + "?Illegal buffer position %d 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 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); + + 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 int 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(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(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<string>$ 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) sprintf(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; + struct wildcard_expansion *expand_filename(); + 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; + struct wildcard_expansion *expand_filename(); + + 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; + struct wildcard_expansion *expand_filename(); + +/* + * 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; + struct wildcard_expansion *expand_filename(); + +/* + * 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 */ + int status; + + 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 = 0; + + status = cmd_oscmd(ct); + ut->iarg2 = curbuf->dot - ut->iarg1; + 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 */ + + + +/* PUSH_QREGISTER - Push a Q register onto the stack + * + * Function: + * + * This routine is called to make a copy of a Q register and place it + * on the Q register stack. + */ +int +push_qregister(letter) +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 */ + + +/* EXTRACT_LABEL - Build a string with the contents of the label in it + * + * Function: + * + * This routine is called to build a string with the label name + * in it. The current use is for error messages. + */ +void +extract_label(label_ptr,string1) +register 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 */ + +/* COMPARE_LABEL - Test if this is our label + * + * Function: + * + * This routine is called by the GOTO function to compare labels + * to see if they match. + */ +int +compare_label(goto_ptr,label_ptr) +register struct cmd_token *goto_ptr; +register 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 */ + + + +/* FIND_CONDITIONAL_ELSE - Routine to find the else of a conditional + * + * Function: + * + * 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(ct) +register 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 */ + +/* FIND_CONDITIONAL_END - Routine to find the close of a conditional + * + * Function: + * + * This routine is called to skip over the else clause and find the + * end of the conditional. + */ +int +find_conditional_end(ct) +register 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 */ + + + +/* EXEC_DOQ0 - Execute Q register zero as a macro + * + * Function: + * + * 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 */ |