/* * InsertLines - insert a set of lines after specified number in current file */ vi_rc InsertLines( linenum s, fcb_list *fcblist, undo_stack *us ) { fcb *sfcb, *cfcb; linenum l, e; vi_rc rc; rc = ModificationTest(); if( rc != ERR_NO_ERR ) { return( rc ); } if( s < 0 ) { return( ERR_NO_SUCH_LINE ); } /* * find the number of lines inserted */ e = 0; for( cfcb = fcblist->head; cfcb != NULL; cfcb = cfcb->next ) { e += cfcb->end_line - cfcb->start_line + 1; } e += s; /* * see if there is a null fcb at the head; if so, ditch * the null fcb and then reset line ranges */ if( CurrentFile->fcbs.head->nullfcb ) { FreeEntireFcb( CurrentFile->fcbs.head ); CurrentFile->fcbs = *fcblist; e = e - s; s = 0; /* * if we are to insert after line 0, then make this block of * fcbs the first set in the text */ } else if( s == 0 ) { fcblist->tail->next = CurrentFile->fcbs.head; CurrentFile->fcbs.head->prev = fcblist->tail; CurrentFile->fcbs.head = fcblist->head; } else { /* * if we are inserting after the last fcb in the file, * make this block of fcbs the last set in the text */ rc = FindFcbWithLine( s + 1, CurrentFile, &sfcb ); if( rc != ERR_NO_ERR ) { if( rc != ERR_NO_SUCH_LINE ) { return( rc ); } fcblist->head->prev = CurrentFile->fcbs.tail; CurrentFile->fcbs.tail->next = fcblist->head; CurrentFile->fcbs.tail = fcblist->tail; /* * put the lines after the line to be have text inserted * into a new fcb, then insert the block of fcb's after * the fcb containing the line to have text inserted */ } else { rc = SplitFcbAtLine( s + 1, CurrentFile, sfcb ); if( rc > ERR_NO_ERR ) { return( rc ); } /* * line we want to split at is already the first line * in the fcb, so chain the new fcb block before * the fcb containg the line we want to split at */ if( rc == NO_SPLIT_CREATED_AT_START_LINE ) { if( sfcb->prev != NULL ) { sfcb->prev->next = fcblist->head; } fcblist->head->prev = sfcb->prev; sfcb->prev = fcblist->tail; fcblist->tail->next = sfcb; /* * chain the new fcb block after the fcb that used * to containing the line we wanted to split at, and * before the new fcb containing the line we want * to split at */ } else { if( rc == NO_SPLIT_CREATED_AT_END_LINE ) { // Die( "Impossible, can't be past last line"); } if( sfcb->next != NULL ) { sfcb->next->prev = fcblist->tail; } fcblist->tail->next = sfcb->next; sfcb->next = fcblist->head; fcblist->head->prev = sfcb; } } } /* * now, resequence line numbers and set proper file ptr */ for( cfcb = fcblist->head; cfcb != NULL; cfcb = cfcb->next ) { cfcb->f = CurrentFile; l = cfcb->end_line - cfcb->start_line; if( cfcb->prev != NULL ) { cfcb->start_line = cfcb->prev->end_line + 1; } else { cfcb->start_line = 1; } cfcb->end_line = cfcb->start_line + l; } /* * finish up: collect fcbs, point to corrent line, and * build undo for operation */ rc = MergeAllFcbs( &CurrentFile->fcbs ); if( rc != ERR_NO_ERR ) { return( rc ); } StartUndoGroup( us ); rc = ValidateCurrentLine(); if( rc != ERR_NO_ERR ) { return( rc ); } Modified( true ); UndoInsert( s + 1, e, us ); EndUndoGroup( us ); return( ERR_NO_ERR ); } /* InsertLines */
/* * PatchDeleteUndo - go and patch together undo deletes */ void PatchDeleteUndo( undo_stack *stack ) { undo *top, *next, *del, *topdel, *after, *tmp; bool merge; /* * see if we can merge this with the last undo record * (provided we are in an open undo group) * * we need the following undo sequence, after the first one: * END_UNDO_GROUP * UNDO_DELETE_FCBS * - must have same start line as the first one * START_UNDO_GROUP */ if( stack == NULL || stack->OpenUndo <= 0 || stack->current < 0 || !EditFlags.Undo ) { return; } top = stack->stack[stack->current]; topdel = top->next; next = top->next->next->next; /* go past first delete group */ if( next == NULL || next->type != END_UNDO_GROUP ) { return; } next = next->next; if( next == NULL || next->type != UNDO_DELETE_FCBS ) { return; } del = next; next = next->next; if( next == NULL || next->type != START_UNDO_GROUP ) { return; } after = next->next; /* * if two starts are the same, then these are back-to-back deletes * and we can merge them. */ merge = FALSE; if( del->data.fcbs.head->start_line == topdel->data.fcbs.head->start_line ) { merge = TRUE; } /* * merge data two records together */ if( merge ) { /* * join fcbs from the two undo records: the fcbs * from the 2nd record become the head fcbs, and * the fcbs from the 2nd record follow them. */ del->data.fcbs.tail->next = topdel->data.fcbs.head; topdel->data.fcbs.head->prev = del->data.fcbs.tail; topdel->data.fcbs.head = del->data.fcbs.head; numberLines( topdel->data.fcbs.head, topdel->data.fcbs.head->start_line ); /* * join the top undo sequence with the third one */ next = top->next->next->next; /* go past first delete group */ top->next->next->next = after; /* join first undo group to third */ /* * delete the END_UNDO_GROUP, UNDO_DELETE_FCBS, * and START_UNDO_GROUP records for the 2nd entry */ tmp = next->next; MemFree( next ); next = tmp; tmp = next->next; MemFree( next ); MemFree( tmp ); /* * merge the line data from the fcbs together */ MergeAllFcbs( &topdel->data.fcbs ); } } /* PatchDeleteUndo */