/* * EnterHexKey - enter a hexidecimal key stroke and insert it into the text */ vi_rc EnterHexKey( void ) { int i; char st[MAX_STR], val; vi_rc rc; const char *ptr; rc = ModificationTest(); if( rc != ERR_NO_ERR ) { return( rc ); } if( CurrentLine->len >= EditVars.MaxLine - 1 ) { return( ERR_LINE_FULL ); } rc = PromptForString( "Enter the number of char to insert:", st, sizeof( st ) - 1, NULL ); if( rc != ERR_NO_ERR ) { if( rc == NO_VALUE_ENTERED ) { return( ERR_NO_ERR ); } return( rc ); } /* * get value */ ptr = SkipLeadingSpaces( st ); val = (char)strtol( ptr, NULL, 0 ); if( val == '\0' ) { return( ERR_INVALID_VALUE ); } /* * build undo record */ StartUndoGroup( UndoStack ); CurrentLineReplaceUndoStart(); CurrentLineReplaceUndoEnd( true ); EndUndoGroup( UndoStack ); /* * add the char */ GetCurrentLine(); for( i = WorkLine->len; i >= CurrentPos.column - 1; i-- ) { WorkLine->data[i + 1] = WorkLine->data[i]; } WorkLine->data[CurrentPos.column - 1] = val; WorkLine->len++; DisplayWorkLine( true ); if( CurrentPos.column < WorkLine->len ) { GoToColumn( CurrentPos.column + 1, WorkLine->len + 1 ); } ReplaceCurrentLine(); EditFlags.Dotable = true; return( ERR_NO_ERR ); } /* EnterHexKey */
/* * IMBackSpace - process the backspace key in insert mode */ vi_rc IMBackSpace( void ) { char killedChar, overChar; bool mv_right; bool stay_at_end; int i; if( CurrentFile == NULL ) { return( ERR_NO_FILE ); } startNewLineUndo(); if( abbrevCnt > 0 ) { abbrevCnt--; } if( CurrentPos.column == 1 ) { if( !EditFlags.WrapBackSpace ) { return( ERR_NO_ERR ); } if( CurrentPos.line ==1 ) { return( ERR_NO_ERR ); } stay_at_end = FALSE; if( WorkLine->len == 0 ) { stay_at_end = TRUE; } doneWithCurrentLine(); abbrevCnt = 0; GoToLineRelCurs( CurrentPos.line - 1 ); GoToColumnOnCurrentLine( CurrentLine->len ); mv_right = TRUE; if( CurrentLine->len == 0 ) { mv_right = FALSE; } GenericJoinCurrentLineToNext( FALSE ); if( mv_right && !stay_at_end ) { GoToColumnOnCurrentLine( CurrentPos.column + 1 ); } if( stay_at_end ) { GoToColumnOK( CurrentLine->len + 1 ); } CurrentLineReplaceUndoStart(); currLineRepUndo = TRUE; GetCurrentLine(); return( ERR_NO_ERR ); } killedChar = WorkLine->data[CurrentPos.column - 2]; overChar = WorkLine->data[CurrentPos.column - 1]; for( i = CurrentPos.column - 1; i <= WorkLine->len + 1; i++ ) { WorkLine->data[i - 1] = WorkLine->data[i]; } WorkLine->len--; GoToColumn( CurrentPos.column - 1, WorkLine->len + 1 ); DisplayWorkLine( SSKillsFlags( killedChar ) || SSKillsFlags( overChar ) ); return( ERR_NO_ERR ); } /* IMBackSpace */
/* * startNewLineUndo - start current line undo stuff */ static void startNewLineUndo( void ) { if( needNewUndoForLine ) { CurrentLineReplaceUndoStart(); currLineRepUndo = TRUE; GetCurrentLine(); needNewUndoForLine = FALSE; } } /* startNewLineUndo */
/* * stdInsert - standard insert on a line */ static vi_rc stdInsert( int col, bool overstrike ) { vi_rc rc; rc = ModificationTest(); if( rc == ERR_NO_ERR ) { StartUndoGroup( UndoStack ); CurrentLineReplaceUndoStart(); currLineRepUndo = TRUE; continueInsertText( col, overstrike ); } return( rc ); } /* stdInsert */
/* * DeleteRangeOnCurrentLine - perform the deletion */ vi_rc DeleteRangeOnCurrentLine( int scol, int ecol, int savebuf_flag ) { int i; vi_rc rc; /* * verify range */ if( scol > ecol ) { i = scol; scol = ecol; ecol = i; } /* * go delete block and set up undo */ CurrentLineReplaceUndoStart(); rc = DeleteBlockFromCurrentLine( scol, ecol, savebuf_flag ); if( rc != ERR_NO_ERR ) { CurrentLineReplaceUndoCancel(); return( rc ); } DisplayWorkLine( TRUE ); ReplaceCurrentLine(); CurrentLineReplaceUndoEnd( TRUE ); EditFlags.Dotable = TRUE; if( savebuf_flag ) { #ifdef __WIN__ if( LastSavebuf == 0 ) { Message1( "%d characters deleted into the clipboard", ecol - scol + 1 ); } else { #endif Message1( "%d %s%s%c", ecol - scol + 1, MSG_CHARACTERS, MSG_DELETEDINTOBUFFER, LastSavebuf ); #ifdef __WIN__ } #endif } return( ERR_NO_ERR ); } /* DeleteRangeOnCurrentLine */
/* * DeleteAndInsertText - delete text range, then insert at beginning */ vi_rc DeleteAndInsertText( int scol, int ecol ) { int startcol; vi_rc rc; StartUndoGroup( UndoStack ); CurrentLineReplaceUndoStart(); currLineRepUndo = TRUE; if( ecol >= 0 ) { if( CurrentLine->len > 0 ) { rc = DeleteBlockFromCurrentLine( scol, ecol, FALSE ); if( rc == ERR_NO_ERR ) { startcol = CurrentPos.column; if( scol > ecol ) { startcol = ecol + 1; } if( startcol > WorkLine->len ) { startcol = WorkLine->len + 1; } DisplayWorkLine( TRUE ); ReplaceCurrentLine(); rc = GoToColumnOK( startcol ); } if( rc != ERR_NO_ERR ) { CurrentLineReplaceUndoCancel(); EndUndoGroup( UndoStack ); return( rc ); } } else { ReplaceCurrentLine(); } } continueInsertText( CurrentPos.column, FALSE ); return( ERR_NO_ERR ); } /* DeleteAndInsertText */
/* * insertGenericSavebuf - insert contents of a savebuf before/after current pos */ static vi_rc insertGenericSavebuf( int buf, bool afterflag ) { #ifdef __WIN__ savebuf clip; #endif savebuf *tmp; fcb_list fcblist; fcb *end; int i, scol, len; int maxCursor; vi_rc rc; rc = ModificationTest(); if( rc != ERR_NO_ERR ) { return( rc ); } if( EditFlags.Modeless ) { DeleteSelectedRegion(); SelRgn.selected = false; } #ifdef __WIN__ if( buf == CLIPBOARD_SAVEBUF ) { rc = GetClipboardSavebuf( &clip ); if( rc != ERR_NO_ERR ) { return( rc ); } tmp = &clip; } else #endif if( buf >= MAX_SAVEBUFS ) { tmp = &SpecialSavebufs[buf - MAX_SAVEBUFS]; } else { tmp = &Savebufs[buf]; } switch( tmp->type ) { case SAVEBUF_NOP: rc = ERR_EMPTY_SAVEBUF; break; case SAVEBUF_LINE: /* * get starting data */ len = strlen( tmp->u.data ); if( len + CurrentLine->len >= EditVars.MaxLine ) { rc = ERR_LINE_FULL; break; } if( afterflag ) { scol = CurrentPos.column; } else { scol = CurrentPos.column - 1; } CurrentLineReplaceUndoStart(); GetCurrentLine(); /* * open up line and copy in data */ if( WorkLine->len == 0 ) { scol = 0; } for( i = WorkLine->len; i >= scol; i-- ) { WorkLine->data[i + len] = WorkLine->data[i]; } for( i = 0; i < len; i++ ) { WorkLine->data[i + scol] = tmp->u.data[i]; } WorkLine->len += len; DisplayWorkLine( true ); ReplaceCurrentLine(); CurrentLineReplaceUndoEnd( true ); scol += len + 1; maxCursor = CurrentLine->len; if( EditFlags.Modeless ) { maxCursor++; } if( scol > maxCursor ) { scol = maxCursor; } rc = GoToColumn( scol, maxCursor ); break; case SAVEBUF_FCBS: fcblist.head = NULL; fcblist.tail = NULL; end = tmp->u.fcbs.tail->next; tmp->u.fcbs.tail->next = NULL; CreateDuplicateFcbList( tmp->u.fcbs.head, &fcblist ); tmp->u.fcbs.tail->next = end; if( !EditFlags.LineBased ) { rc = InsertLinesAtCursor( &fcblist, UndoStack ); } else { if( afterflag) { rc = InsertLines( CurrentPos.line, &fcblist, UndoStack ); } else { rc = InsertLines( CurrentPos.line - 1, &fcblist, UndoStack ); } } break; } #ifdef __WIN__ if( tmp == &clip ) { freeSavebuf( &clip ); } #endif EditFlags.Dotable = true; return( rc ); } /* insertGenericSavebuf */
/* * GenericJoinCurrentLineToNext */ vi_rc GenericJoinCurrentLineToNext( bool remsp ) { line *nline = CurrentLine; fcb *nfcb = CurrentFcb; int i, j, k; vi_rc rc; /* * get next line data */ rc = CGimmeNextLinePtr( &nfcb, &nline ); if( rc != ERR_NO_ERR ) { return( rc ); } if( CurrentLine->len + nline->len + 1 >= EditVars.MaxLine ) { return( ERR_LINE_FULL ); } /* * now, copy in the data */ StartUndoGroup( UndoStack ); CurrentLineReplaceUndoStart(); CurrentLineReplaceUndoEnd( true ); GetCurrentLine(); if( remsp ) { while( WorkLine->len > 0 && WorkLine->data[WorkLine->len - 1] == ' ' ) { WorkLine->data[WorkLine->len - 1] = 0; WorkLine->len--; } j = FindStartOfALine( nline ) - 1; k = 0; if( !(j == 0 && nline->data[0] == ' ') ) { if( WorkLine->len != 0 ) { WorkLine->data[WorkLine->len] = ' '; k = WorkLine->len + 1; } for( i = j; i <= nline->len; i++ ) { WorkLine->data[k + i - j] = nline->data[i]; } } } else { k = WorkLine->len; for( i = 0; i <= nline->len; i++ ) { WorkLine->data[k + i] = nline->data[i]; } } WorkLine->len = strlen( WorkLine->data ); ReplaceCurrentLine(); /* * delete next line */ rc = DeleteLineRange( CurrentPos.line + 1, CurrentPos.line + 1, 0 ); if( rc != ERR_NO_ERR ) { return( rc ); } EndUndoGroup( UndoStack ); if( remsp ) { if( k < 2 ) { k = 2; } rc = GoToColumn( k - 1, CurrentLine->len ); if( rc != ERR_NO_ERR ) { return( rc ); } } DCDisplayAllLines(); return( ERR_NO_ERR ); } /* GenericJoinCurrentLineToNext */
/* * Substitute - perform substitution */ vi_rc Substitute( linenum n1, linenum n2, char *data ) { char *sstr, *rstr, *newr; char flag[20], *linedata; bool iflag = false; bool gflag = false; bool undoflag = false; bool restline = false; bool splitpending = false; bool undoline = false; int i, rlen, slen; bool splitme; long changecnt = 0, linecnt = 0; linenum llineno, ll, lastline = 0, extra; i_mark pos; vi_rc rc; LastSubstituteCancelled = 0; LastChangeCount = 0; LastLineCount = 0; sstr = alloca( MAX_INPUT_LINE ); if( sstr == NULL ) { return( ERR_NO_STACK ); } strcpy( sstr, data ); rc = ModificationTest(); if( rc != ERR_NO_ERR ) { return( rc ); } strcpy( data, sstr ); rstr = alloca( MAX_INPUT_LINE ); if( rstr == NULL ) { return( ERR_NO_STACK ); } if( NextWordSlash( data, sstr ) < 0 ) { return( ERR_INVALID_SUBS_CMD ); } if( NextWordSlash( data, rstr ) < 0 ) { return( ERR_INVALID_SUBS_CMD ); } slen = NextWord1( data, flag ); for( i = 0; i < slen; i++ ) { switch( flag[i] ) { case 'g': gflag = true; break; case 'i': case 'c': iflag = true; break; } } rc = CurrentRegComp( sstr ); if( rc != ERR_NO_ERR ) { return( rc ); } /* * verify last line */ if( n2 > CurrentFile->fcbs.tail->end_line ) { rc = CFindLastLine( &ll ); if( rc != ERR_NO_ERR ) { return( rc ); } if( n2 > ll ) { return( ERR_INVALID_LINE_RANGE ); } } /* * set for start of search */ if( EditFlags.Verbose && EditFlags.EchoOn ) { ClearWindow( MessageWindow ); } SaveCurrentFilePos(); llineno = n1 - 1; EditFlags.AllowRegSubNewline = true; newr = StaticAlloc(); for( pos.column = 0, pos.line = n1; pos.line <= n2; nextSearchStartPos( &pos, gflag, rlen ) ) { /* * get regular expression, and build replacement string */ rc = FindRegularExpression( NULL, &pos, &linedata, n2, 0 ); if( rc != ERR_NO_ERR || pos.line > n2 ) { break; } slen = GetCurrRegExpLength(); splitme = RegSub( CurrentRegularExpression, rstr, newr, pos.line ); rlen = strlen( newr ); ProcessingMessage( pos.line ); /* * if in global mode, see if we already have an undo for * this line */ if( gflag ) { if( lastline != pos.line ) { undoline = false; } } /* * interactive mode? yes, then display text and ask to change */ if( iflag ) { change_resp rsp; if( !restline ) { ClearWindow( MessageWindow ); } restline = true; GoToLineNoRelCurs( pos.line ); if( EditFlags.GlobalInProgress ) { EditFlags.DisplayHold = false; DCDisplayAllLines(); EditFlags.DisplayHold = true; } HilightSearchString( &pos, slen ); rsp = ChangePrompt(); if( rsp == CHANGE_NO ) { ResetDisplayLine(); rlen = 1; continue; } else if( rsp == CHANGE_CANCEL ) { ResetDisplayLine(); LastSubstituteCancelled = 1; break; } else if( rsp == CHANGE_ALL ) { ResetDisplayLine(); iflag = false; } } /* * set up for global undo if we haven't already */ if( !undoflag ) { StartUndoGroup( UndoStack ); undoflag = true; } /* * bump change counts */ changecnt++; if( llineno != pos.line ) { if( splitpending ) { splitpending = false; extra = SplitUpLine( llineno ); n2 += extra; pos.line += extra; } linecnt++; llineno = pos.line; } /* * get copy of line, and verify that new stuff fits */ CurrentPos.line = pos.line; rc = CGimmeLinePtr( pos.line, &CurrentFcb, &CurrentLine ); if( rc != ERR_NO_ERR ) { break; } if( CurrentLine->len + rlen - slen >= EditVars.MaxLine ) { rc = ERR_LINE_FULL; break; } /* * now build the individual undo */ CurrentFcb->non_swappable = true; if( !undoline ) { CurrentLineReplaceUndoStart(); CurrentLineReplaceUndoEnd( true ); if( gflag ) { undoline = true; lastline = pos.line; } } /* * remove the old string */ GetCurrentLine(); WorkLine->len = ReplaceSubString( WorkLine->data, WorkLine->len, pos.column, pos.column + slen - 1, newr, rlen ); if( iflag ) { DisplayWorkLine( true ); } ReplaceCurrentLine(); /* * if not global, only do this change on this line */ if( splitme ) { splitpending = true; } CurrentFcb->non_swappable = false; } StaticFree( newr ); EditFlags.AllowRegSubNewline = false; /* * is there still a split line pending? */ if( splitpending ) { SplitUpLine( llineno ); } RestoreCurrentFilePos(); if( restline ) { SetCurrentLine( CurrentPos.line ); GoToColumnOK( CurrentPos.column ); } if( undoflag ) { EndUndoGroup( UndoStack ); } switch( rc ) { case ERR_NO_ERR: case ERR_LINE_FULL: case ERR_FIND_PAST_TERM_LINE: case ERR_FIND_NOT_FOUND: case ERR_FIND_END_OF_FILE: /* * display results */ if( rc == ERR_LINE_FULL ) { Message1( "Stopped at line %l - line full", pos.line ); } else { Message1( "%l changes on %l lines", changecnt, linecnt ); LastLineCount = linecnt; LastChangeCount = changecnt; } DCDisplayAllLines(); rc = ERR_NO_ERR; break; default: break; } return( rc ); } /* Substitute */
/* * InsertLinesAtCursor - insert a set of lines at current pos. in file */ vi_rc InsertLinesAtCursor( fcb_list *fcblist, undo_stack *us ) { fcb *cfcb; linenum e; int lastLineLen; char *source; line *tLine; vi_rc rc; rc = ModificationTest(); if( rc != ERR_NO_ERR ) { return( rc ); } /* * 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); } // add chars from right of cursor to end of last line of buffer source = CurrentLine->data + CurrentPos.column - 1; lastLineLen = fcblist->tail->lines.tail->len; fcblist->tail->lines.tail->len += CurrentLine->len - CurrentPos.column + 1; fcblist->tail->byte_cnt += CurrentLine->len - CurrentPos.column + 1; tLine = fcblist->tail->lines.tail->prev; fcblist->tail->lines.tail = MemReAlloc( fcblist->tail->lines.tail, sizeof( line ) + fcblist->tail->lines.tail->len + 1 ); if( tLine ) { tLine->next = fcblist->tail->lines.tail; } strcpy( fcblist->tail->lines.tail->data + lastLineLen, source ); StartUndoGroup( us ); // create new current line in work line CurrentLineReplaceUndoStart(); GetCurrentLine(); WorkLine->len = CurrentPos.column + fcblist->head->lines.head->len - 1; strcpy( WorkLine->data + CurrentPos.column - 1, fcblist->head->lines.head->data ); // replace current line ReplaceCurrentLine(); CurrentLineReplaceUndoEnd( true ); // remove first line of buffer FetchFcb( fcblist->head ); fcblist->head->non_swappable = true; fcblist->head->start_line++; fcblist->head->byte_cnt -= fcblist->head->lines.head->len + 1; tLine = fcblist->head->lines.head; fcblist->head->lines.head = fcblist->head->lines.head->next; fcblist->head->lines.head->prev = NULL; MemFree( tLine ); fcblist->head->non_swappable = false; // add rest of lines of buffer & done if( fcblist->head->lines.head) { InsertLines( CurrentPos.line, fcblist, us ); } EndUndoGroup( us ); // if are indeed linebased, move cursor as well if( !EditFlags.LineBased ) { GoToLineNoRelCurs( CurrentPos.line + e - 1 ); GoToColumnOnCurrentLine( lastLineLen + 1 ); } return( ERR_NO_ERR ); } /* InsertLinesAtCursor */