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 /tecundo.c | |
download | videoteco-fork-2ee4787d1df9784d40a7eda91e61691da3d56f74.tar.gz |
Initial revision
Diffstat (limited to 'tecundo.c')
-rw-r--r-- | tecundo.c | 504 |
1 files changed, 504 insertions, 0 deletions
diff --git a/tecundo.c b/tecundo.c new file mode 100644 index 0000000..e0f9422 --- /dev/null +++ b/tecundo.c @@ -0,0 +1,504 @@ +char *tecundo_c_version = "tecundo.c: $Revision: 1.1 $"; + +/* + * $Date: 2007/12/10 21:59:21 $ + * $Source: /cvsroot/videoteco/videoteco/tecundo.c,v $ + * $Revision: 1.1 $ + * $Locker: $ + */ + +/* tecundo.c + * Subroutines to implement the undo capabilities 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 search_buff search_string; + extern char user_message[]; + extern char exit_flag; + extern char immediate_execute_flag; + extern int last_search_pos1,last_search_pos2; + extern int last_search_status; + + extern struct buff_header *curbuf,*buffer_headers; + extern struct buff_header *qregister_push_down_list; + extern struct tags *current_tags; + void tecundo_list(struct undo_token *); + + + +/* PARSER_UNDO - Execute an UNDO command + * + * Function: + * + * This routine is called with an undo token to reverse some changes + * to the program state. + */ +int +parser_undo(ut) +register struct undo_token *ut; +{ +char tmp_message[LINE_BUFFER_SIZE]; +register struct cmd_token *ct; + + PREAMBLE(); + + switch(ut->opcode){ +/* + * CHANGEDOT is used to undo a movement of dot. iarg1 contains the buffer + * position we want to go back to. + */ + case UNDO_C_CHANGEDOT: + curbuf->dot = ut->iarg1; + break; +/* + * DELETE is used to undo the addition of characters to the buffer. iarg1 + * contains the buffer position to begin deleting at, iarg2 contains the + * number of characters that should be deleted. + */ + case UNDO_C_DELETE: + if(ut->iarg2 > 0){ + buff_delete((struct buff_header *)ut->carg1,ut->iarg1, + ut->iarg2); + }/* End IF */ + break; +/* + * INSERT is used to undo the deletion of characters from the buffer. + * iarg1 contains the position in the buffer of the deletion. iarg2 + * contains a count of the number of bytes which were deleted. carg1 + * is a pointer to a tec_alloc'ed buffer which holds the deleted bytes. + */ + case UNDO_C_INSERT: + buff_insert(curbuf,ut->iarg1,ut->carg1,ut->iarg2); + break; +/* + * UQREGISTER is used to undo the loading of an integer value into a + * Q register. iarg1 is the Q register name, iarg2 is the old value. + */ + case UNDO_C_UQREGISTER: + {/* Local Block */ + register struct buff_header *hbp; + + hbp = buff_qfind(ut->iarg1,0); + if(hbp == NULL){ + sprintf(tmp_message,"?Cannot find Q-register <%c>", + ut->iarg1); + error_message(tmp_message); + return(FAIL); + }/* End IF */ + + hbp->ivalue = ut->iarg2; + break; + }/* End Local Block */ +/* + * MEMFREE allows us to free up memory allocated to a command token or an + * undo token. + */ + case UNDO_C_MEMFREE: + tec_release(TYPE_C_CBUFF,ut->carg1); + ut->carg1 = NULL; + return(SUCCESS); +/* + * SHORTEN_STRING allows us to handle rubouts etc while a string was being + * built. + */ + case UNDO_C_SHORTEN_STRING: + {/* Local Block */ + register int i; + register char *cp; +/* + * IARG1 holds the length we want to shorten the string to. If the string is + * already shorter than that, we leave it alone of course. Note that we use + * IARG2 to hold the address of the string. + */ + i = ut->iarg1; + cp = ut->carg1; + while(i--){ + if(*cp) cp++; + }/* End While */ + *cp = '\0'; + return(SUCCESS); + }/* End Local Block */ +/* + * SET_SEARCH_STRING sets the default search string + */ + case UNDO_C_SET_SEARCH_STRING: + return(SUCCESS); + +/* + * CHANGEBUFF changes the current buffer. We pass a flag to buff_openbuffnum + * so that if we return to buffer zero, it doesn't build a new map. + */ + case UNDO_C_CHANGEBUFF: + + buff_openbuffnum(ut->iarg1,0); + return(SUCCESS); + +/* + * MACRO undoes all the changes a macro made + */ + case UNDO_C_MACRO: + ct = (struct cmd_token *)ut->carg1; + while(ct->next_token) ct = ct->next_token; + while(ct){ +/* + * If this command token has an undo list associated with it, call the + * routine which will undo the entire undo list under this token. + */ + if(ct->undo_list){ + tecundo_list(ct->undo_list); + ct->undo_list = NULL; + }/* End IF */ +/* + * If the command token is not at the head of the list, back up one so + * as to keep it's address while we free up this command token. + */ + if(ct->prev_token){ + ct = ct->prev_token; + free_cmd_token(ct->next_token); + ct->next_token = NULL; + }/* End IF */ +/* + * Else, it IS the head of the list and we can simply free it up and break + * out of the loop. + */ + else { + free_cmd_token(ct); + ut->carg1 = NULL; + break; + }/* End Else */ + }/* End While */ + + return(SUCCESS); + +/* + * SHORTEN_MESSAGE handles rubouts in ^A messages + */ + case UNDO_C_SHORTEN_MESSAGE: + {/* Local Block */ + register int i; + i = strlen(user_message); + if(i > 0) user_message[i-1] = '\0'; + return(SUCCESS); + }/* End Local Block */ + +/* + * BULK_INSERT is used to undo a deleted region + */ + case UNDO_C_BULK_INSERT: + buff_bulk_insert(curbuf, + ut->iarg1,ut->iarg2,(struct buff_line *)ut->carg1); + return(SUCCESS); +/* + * SET_IMMEDIATE_MODE resets the immediate execute state + */ + case UNDO_C_SET_IMMEDIATE_MODE: + immediate_execute_flag = ut->iarg1; + return(SUCCESS); + +/* + * PUSH is used to re-push a Q register onto the Q register push down + * list (stack). + */ + case UNDO_C_PUSH: + push_qregister(ut->iarg1); + return(SUCCESS); +/* + * POP is used to undo a Q register push. It just takes an entry off of + * the Q register pushdown list and destroys it. + */ + case UNDO_C_POP: + {/* Local Block */ + register struct buff_header *hbp; + + hbp = qregister_push_down_list; + if(hbp){ + qregister_push_down_list = hbp->next_header; +/* + * Place it on the main buffer list so that buff_destroy can find it + */ + hbp->next_header = buffer_headers; + buffer_headers = hbp; + buff_destroy(hbp); + }/* End IF */ + + return(SUCCESS); + + }/* End Local Block */ + +/* + * MODIFIED is used to flag a change in the state of the current edit buffers + * modified status. We undo it by clearing the modified flag and clearing the + * indication in the buffer status line display. + */ + case UNDO_C_MODIFIED: + ((struct buff_header *)(ut->carg1))->ismodified = NO; + if(screen_label_line((struct buff_header *)ut->carg1, + "",LABEL_C_MODIFIED) == FAIL){ + return(FAIL); + }/* End IF */ + return(SUCCESS); +/* + * This function undoes the creation of a buffer by the EB command + */ + case UNDO_C_CLOSEBUFF: + buff_destroy((struct buff_header *)ut->carg1); + break; +/* + * This function undoes a window switch + */ + case UNDO_C_WINDOW_SWITCH: + window_switch(ut->iarg1); + break; +/* + * This function undoes a window split + */ + case UNDO_C_WINDOW_SPLIT: + window_switch(ut->iarg1); + screen_delete_window((struct window *)ut->carg1); + break; +/* + * This function reopens a buffer which was closed with EF + */ + case UNDO_C_REOPENBUFF: + buff_reopenbuff((struct buff_header *)ut->carg1); + break; +/* + * This function replaces the buffer name which was changed by a rename + * operation. + */ + case UNDO_C_RENAME_BUFFER: + tec_release(TYPE_C_CBUFF,curbuf->name); + curbuf->name = ut->carg1; + break; + +/* + * This function replaces arguments which may have been overwritten during + * a loop. + */ + case UNDO_C_PRESERVEARGS: + ct = (struct cmd_token *)ut->carg1; + ct->ctx.iarg1 = ut->iarg1; + ct->ctx.iarg2 = ut->iarg2; + break; + +/* + * This function replaces runtime options changed by the EJ command + */ + case UNDO_C_SETOPTIONS: + cmd_setoptions(ut->iarg1,ut->iarg2,NULL); + break; +/* + * This function restores some globals used by the searching system + */ + case UNDO_C_SET_SEARCH_GLOBALS: + last_search_pos1 = ut->iarg1; + last_search_pos2 = ut->iarg2; + last_search_status = (int)ut->carg1; + break; +/* + * This function puts the previous tags file back + */ + case UNDO_C_LOAD_TAGS: + tag_free_struct(current_tags); + current_tags = (struct tags *)ut->carg1; + break; + +/* + * This function puts the previous tag entry selection back + */ + case UNDO_C_SELECT_TAGS: + current_tags->current_entry = (struct tagent *)ut->carg1; + break; + + case UNDO_C_SET_EXIT_FLAG: + exit_flag = 0; + break; + +/* + * Here when we get an undo code we don't know about. This is an internal + * error to teco! + */ + default: + sprintf(tmp_message,"?Unknown undo opcode %d",ut->opcode); + error_message(tmp_message); + return(FAIL); + }/* End Switch */ + + return(SUCCESS); + +}/* End Routine */ + + + +/* ALLOCATE_UNDO_TOKEN - Allocate an undo token structure + * + * Function: + * + * This routine is called to allocate an undo token structure. If there + * is one on the free list, it is used, otherwise we allocate one. UNDO + * tokens are used so that we can back out of operations which change + * some state other than that of the parser. The normal case is that we + * make some change to the edit buffer, and want to be able to back out + * of it if we want. + */ +struct undo_token * +allocate_undo_token(ct) +register struct cmd_token *ct; +{ +register struct undo_token *ut; + + PREAMBLE(); + + ut = (struct undo_token *)tec_alloc(TYPE_C_UNDO,sizeof(struct undo_token)); + if(ut == NULL) return(NULL); + + ut->opcode = UNDO_C_UNUSED; + ut->iarg1 = 0; + ut->iarg2 = 0; + ut->carg1 = NULL; + ut->next_token = NULL; + + if(ct != NULL){ + ut->next_token = ct->undo_list; + ct->undo_list = ut; + }/* End IF */ + + return(ut); + +}/* End Routine */ + + + +/* FREE_UNDO_TOKEN - Routine to place an undo token on the free list + * + * Function: + * + * This routine is called with the address of the undo token + * to be placed on the free list. + */ +void +free_undo_token(ut) +register struct undo_token *ut; +{ + + PREAMBLE(); + + tec_release(TYPE_C_UNDO,(char *)ut); + +}/* End Routine */ + + + +/* TECUNDO_LIST - Cause a list of undo structures to be backed out + * + * Function: + * + * This routine is called with the head of a list of undo tokens that + * need to be undone. They are placed on the list such that the head + * of the list is the first that needs to be undone. + */ +void +tecundo_list(nut) +register struct undo_token *nut; +{ +register struct undo_token *ut; + + PREAMBLE(); + + while((ut = nut)){ + +/* + * Remember what the next token address is and unchain it from the current + * undo token. + */ + nut = ut->next_token; + ut->next_token = NULL; +/* + * Now call the undo routine to back out the changes to the edit buffer that + * this token calls for. Then place the token back on the free list. + */ + parser_undo(ut); + free_undo_token(ut); + + }/* End While */ + +}/* End Routine */ + + + +/* TECUNDO_CLEANUP - Place the list of undo tokens back on the free list + * + * Function: + * + * This routine is called with the head of a list of undo tokens. It + * places them back on the undo free list while releasing any resources + * they may have allocated. For example, the MEMFREE token has to free + * the memory the block points to. + */ +void +tecundo_cleanup(tut) +register struct undo_token *tut; +{ +register struct undo_token *ut; + + PREAMBLE(); + + while((ut = tut)){ + tut = tut->next_token; + switch(ut->opcode){ + case UNDO_C_MEMFREE: + if(ut->carg1) tec_release(TYPE_C_CBUFF,ut->carg1); + ut->carg1 = NULL; + free_undo_token(ut); + break; + case UNDO_C_MACRO: + if(ut->carg1){ + parser_cleanup_ctlist((struct cmd_token *)ut->carg1); + }/* End IF */ + ut->carg1 = NULL; + free_undo_token(ut); + break; + case UNDO_C_BULK_INSERT: + buff_free_line_buffer_list((struct buff_line *)ut->carg1); + ut->carg1 = NULL; + free_undo_token(ut); + break; + case UNDO_C_REOPENBUFF: + {/* Local Block */ + register struct buff_header *hbp; + hbp = (struct buff_header *)ut->carg1; + hbp->next_header = buffer_headers; + buffer_headers = hbp; + buff_destroy(hbp); + }/* End Local Block */ + free_undo_token(ut); + break; + case UNDO_C_RENAME_BUFFER: + tec_release(TYPE_C_CBUFF,ut->carg1); + free_undo_token(ut); + break; + case UNDO_C_LOAD_TAGS: + tag_free_struct((struct tags *)ut->carg1); + break; + default: + free_undo_token(ut); + }/* End Switch */ + }/* End While */ +}/* End Routine */ |