/* * insertTextOnOtherLine - open up a different line */ static vi_rc insertTextOnOtherLine( insert_dir type ) { char *buffx; int i, j; linenum a, b; bool above_line = FALSE; vi_rc rc; rc = ModificationTest(); if( rc != ERR_NO_ERR ) { return( rc ); } /* * special case: no data in file */ if( CurrentFcb->nullfcb ) { return( InsertTextAfterCursor() ); } /* * get line deletion and undo crap */ a = b = CurrentPos.line + 1; if( type == INSERT_BEFORE ) { a--; b--; above_line = TRUE; } /* * set up for undo */ StartUndoGroup( UndoStack ); Modified( TRUE ); StartUndoGroup( UndoStack ); UndoInsert( a, a, UndoStack ); currLineRepUndo = FALSE; /* * add extra line, and spaces if needed. */ if( EditFlags.AutoIndent ) { buffx = StaticAlloc(); i = GetAutoIndentAmount( buffx, 0, above_line ); AddNewLineAroundCurrent( buffx, i, type ); StaticFree( buffx ); j = i + 1; } else { AddNewLineAroundCurrent( NULL, 0, type ); j = 1; } GoToLineRelCurs( b ); GoToColumn( j, CurrentLine->len + 1 ); DCDisplayAllLines(); continueInsertText( CurrentPos.column, FALSE ); return( ERR_NO_ERR ); } /* insertTextOnOtherLine */
/* TwoPartSubstitute - goes from current line to current line minus 1 * doing substitute in 2 parts if it has to, that * appear as 1 */ vi_rc TwoPartSubstitute( char *find, char *replace, int prompt, int wrap ) { vi_rc rc; long changecnt, linecnt; linenum end_line; char *cmd = MemAlloc( MAX_INPUT_LINE ); StartUndoGroup( UndoStack ); // search from current position forward to end of doc sprintf( cmd, "/%s/%s/g%c", find, replace, ( prompt ) ? 'i' : '\0' ); end_line = CurrentFile->fcbs.tail->end_line; rc = Substitute( CurrentPos.line, end_line, cmd ); changecnt = LastChangeCount; linecnt = LastLineCount; if( wrap && !LastSubstituteCancelled && CurrentPos.line != 1 && rc == ERR_NO_ERR ) { // search from beginning of do to here sprintf( cmd, "/%s/%s/g%c", find, replace, ( prompt ) ? 'i' : '\0' ); rc = Substitute( 1, CurrentPos.line - 1, cmd ); linecnt += LastLineCount; changecnt += LastChangeCount; } if( rc == ERR_NO_ERR ) { Message1( "%l changes on %l lines", changecnt, linecnt ); } EndUndoGroup( UndoStack ); MemFree( cmd ); return( rc ); } /* TwoPartSubstitute */
/* * 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 */
/* * doRunKeyMap - execute a key map a specified number of times */ static vi_rc doRunKeyMap( key_map *scr, long total ) { int max; vi_rc rc = ERR_NO_ERR; undo_stack *cstack; if( EditFlags.InputKeyMapMode ) { return( ERR_INPUT_KEYMAP_RUNNING ); } cstack = UndoStack; StartUndoGroup( cstack ); while( total > 0 ) { /* * set up key map to run */ CurrentKeyMap = scr->data; if( scr->no_input_window ) { EditFlags.NoInputWindow = TRUE; } // max = strlen( CurrentKeyMap ); for( max = 0; CurrentKeyMap[max] != 0; max++ ); EditFlags.KeyMapInProgress = TRUE; EditFlags.KeyMapMode = TRUE; LastError = ERR_NO_ERR; /* * run until done */ for( CurrentKeyMapCount = 0; CurrentKeyMapCount < max; ) { LastEvent = GetNextEvent( FALSE ); rc = DoLastEvent(); if( rc > ERR_NO_ERR || LastError != ERR_NO_ERR ) { break; } DoneLastEvent( rc, TRUE ); } EditFlags.KeyMapMode = FALSE; EditFlags.NoInputWindow = FALSE; EditFlags.KeyMapInProgress = FALSE; if( rc > ERR_NO_ERR || LastError != ERR_NO_ERR ) { break; } total--; } TryEndUndoGroup( cstack ); EditFlags.Dotable = FALSE; return( rc ); } /* doRunKeyMap */
/* * 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 */
/* * StartInputKeyMap - start up input key map */ vi_rc StartInputKeyMap( vi_key key ) { if( EditFlags.InputKeyMapMode || EditFlags.KeyMapMode ) { return( ERR_INPUT_KEYMAP_RUNNING ); } CurrentKeyMap = InputKeyMaps[key].data; CurrentKeyMapCount = 0; EditFlags.InputKeyMapMode = TRUE; currUndoStack = UndoStack; StartUndoGroup( currUndoStack ); if( InputKeyMaps[key].no_input_window ) { EditFlags.NoInputWindow = TRUE; } return( ERR_NO_ERR ); } /* StartInputKeyMap */
/* * UndoReplaceLines - undo the replacement of a group of lines */ vi_rc UndoReplaceLines( linenum sline, linenum eline ) { vi_rc rc; fcb_list fcblist; if( !EditFlags.Undo || UndoStack == NULL ) { return( ERR_NO_ERR ); } rc = GetCopyOfLineRange( sline, eline, &fcblist ); if( rc != ERR_NO_ERR ) { return( rc ); } StartUndoGroup( UndoStack ); UndoDeleteFcbs( sline - 1, &fcblist, UndoStack ); UndoInsert( sline, eline, UndoStack ); EndUndoGroup( UndoStack ); return( ERR_NO_ERR ); } /* UndoReplaceLines */
/* * JoinCurrentLineToNext */ vi_rc JoinCurrentLineToNext( void ) { int i, j; vi_rc rc; rc = ModificationTest(); if( rc != ERR_NO_ERR ) { return( rc ); } i = (int) GetRepeatCount(); StartUndoGroup( UndoStack ); for( j = 0; j < i; j++ ) { rc = GenericJoinCurrentLineToNext( true ); if( rc != ERR_NO_ERR ) { break; } } EndUndoGroup( UndoStack ); return( rc ); } /* JoinCurrentLineToNext */
/* * 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 */
/* * InsertTextForSpecialKey - insert text for ^O, ALT_O */ void InsertTextForSpecialKey( vi_key event, char *buff ) { linenum line; int type; if( CurrentFile == NULL ) { return; } line = CurrentPos.line; type = INSERT_BEFORE; if( event == VI_KEY( CTRL_O ) ) { type = INSERT_AFTER; line += 1; } Modified( true ); StartUndoGroup( UndoStack ); UndoInsert( line, line, UndoStack ); AddNewLineAroundCurrent( buff, strlen( buff ), type ); EndUndoGroup( UndoStack ); DCDisplayAllLines(); DCUpdate(); } /* InsertTextForSpecialKey */
/* * 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 */
/* * 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 */
/* * Source - main driver */ vi_rc Source( char *fn, char *data, int *ln ) { undo_stack *atomic = NULL; labels *lab, lb; vlist vl; files fi; sfile *sf, *curr; char tmp[MAX_SRC_LINE]; char sname[FILENAME_MAX]; vi_rc rc; bool sicmp, wfb, ssa, exm; resident *res; int cTokenID; /* * startup */ LastRC = LastRetCode; memset( &fi, 0, sizeof( fi ) ); vl.head = vl.tail = NULL; res = residentScript( fn ); if( res != NULL && EditFlags.LoadResidentScript ) { return( ERR_SCRIPT_ALREADY_RESIDENT ); } if( EditFlags.CompileScript || res == NULL ) { lab = &lb; memset( lab, 0, sizeof( labels ) ); sf = NULL; } else { lab = &res->lab; sf = res->sf; } if( EditFlags.CompileScript ) { sname[0] = 0; NextWord1( data, sname ); } /* * initialize variables */ memset( &fi, 0, sizeof( fi ) ); rc = initSource( &vl, data ); if( rc != ERR_NO_ERR ) { return( rc ); } /* * pre-process */ sicmp = EditFlags.ScriptIsCompiled; SourceErrCount = 0; if( EditFlags.CompileScript || res == NULL ) { EditFlags.ScriptIsCompiled = FALSE; rc = PreProcess( fn, &sf, lab ); finiSourceErrFile( fn ); if( rc != ERR_NO_ERR || SourceErrCount > 0 ) { EditFlags.ScriptIsCompiled = sicmp; return( rc ); } } else { EditFlags.ScriptIsCompiled = res->scriptcomp; } /* * if we were loading a resident script, then add it */ if( EditFlags.LoadResidentScript ) { finiSource( NULL, &vl, NULL, NULL ); if( SourceErrCount == 0 ) { addResidentScript( fn, sf, lab ); } EditFlags.ScriptIsCompiled = sicmp; return( ERR_NO_ERR ); } /* * if we were compiling, dump results and go back */ if( EditFlags.CompileScript ) { rc = barfScript( fn, sf, &vl, ln, sname ); finiSource( lab, &vl, sf, NULL ); return( rc ); } /* * process each source line */ exm = EditFlags.ExMode; wfb = EditFlags.WatchForBreak; ssa = EditFlags.SourceScriptActive; EditFlags.SourceScriptActive = TRUE; EditFlags.WatchForBreak = TRUE; EditFlags.ExMode = TRUE; curr = sf->next; while( curr != NULL ) { cTokenID = curr->token - SRC_T_NULL - 1; if( !EditFlags.Starting ) { if( EditFlags.BreakPressed ) { ClearBreak(); break; } } rc = LastError = ERR_NO_ERR; if( curr->data != NULL ) { strcpy( tmp, curr->data ); } else { tmp[0] = 0; } if( EditFlags.Appending ) { if( curr->hasvar) { Expand( tmp, &vl ); } rc = AppendAnother( tmp ); goto evil_continue; } if( cTokenID == PCL_T_ENDFILETYPESOURCE ) { rc = FTSEnd(); goto evil_continue; } if( EditFlags.FileTypeSource ) { rc = FTSAddCmd( tmp, curr->token ); goto evil_continue; } if( curr->token > SRC_T_NULL ) { if( curr->hasvar) { Expand( tmp, &vl ); } rc = TryCompileableToken( cTokenID, tmp, FALSE, 0 ); if( rc == NOT_COMPILEABLE_TOKEN ) { rc = ProcessWindow( cTokenID, tmp ); } if( rc < ERR_NO_ERR ) { rc = ERR_NO_ERR; } } else switch( curr->token ) { case SRC_T_ATOMIC: if( atomic == NULL ) { atomic = UndoStack; StartUndoGroup( atomic ); } break; case SRC_T_IF: rc = SrcIf( &curr, &vl ); break; case SRC_T_GOTO: rc = SrcGoTo( &curr, tmp, lab ); break; case SRC_T_LABEL: break; case SRC_T_RETURN: if( curr->data != NULL ) { int ret; GetErrorTokenValue( &ret, curr->data ); rc = ret; } else { rc = ERR_NO_ERR; } goto evil_exit; case SRC_T_GET: SrcGet( tmp, &vl ); rc = ERR_NO_ERR; break; case SRC_T_INPUT: LastRC = SrcInput( tmp, &vl ); if( LastRC != NO_VALUE_ENTERED && LastRC != ERR_NO_ERR ) { rc = LastRC; } break; case SRC_T_NEXTWORD: rc = SrcNextWord( tmp, &vl ); break; case SRC_T_ASSIGN: rc = SrcAssign( tmp, &vl ); break; case SRC_T_EXPR: rc = SrcExpr( curr, &vl ); break; case SRC_T_OPEN: LastRC = SrcOpen( curr, &vl, &fi, tmp ); if( LastRC != ERR_FILE_NOT_FOUND && LastRC != ERR_NO_ERR ) { rc = LastRC; } break; case SRC_T_READ: LastRC = SrcRead( curr, &fi, tmp, &vl ); if( LastRC != END_OF_FILE && LastRC != ERR_NO_ERR ) { rc = LastRC; } break; case SRC_T_WRITE: rc = SrcWrite( curr, &fi, tmp, &vl ); break; case SRC_T_CLOSE: rc = SrcClose( curr, &vl, &fi, tmp ); break; default: #ifdef __WIN__ { if( RunWindowsCommand( tmp, &LastRC, &vl ) ) { rc = LastRC; break; } } #endif if( curr->hasvar ) { Expand( tmp, &vl ); } LastRC = RunCommandLine( tmp ); if( LastRC == DO_NOT_CLEAR_MESSAGE_WINDOW ) { LastRC = LastError; } break; } evil_continue: if( rc != ERR_NO_ERR ) { break; } curr = curr->next; } evil_exit: if( EditFlags.Appending ) { AppendAnother( "." ); } if( curr != NULL ) { *ln = curr->line; } else { *ln = CurrentSrcLine; rc = ERR_NO_ERR; } EditFlags.WatchForBreak = wfb; EditFlags.SourceScriptActive = ssa; EditFlags.ScriptIsCompiled = sicmp; EditFlags.ExMode = exm; if( res != NULL && !EditFlags.CompileScript ) { sf = NULL; lab = NULL; } finiSource( lab, &vl, sf, atomic ); return( rc ); } /* Source */
/* * 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 */
/* * 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 */
/* * DoGenericFilter - filter some crap */ vi_rc DoGenericFilter( linenum s, linenum e, const char *cmd ) { fcb *cfcb, *tfcb; line *cline; vi_rc rc; char filtin[_MAX_PATH], filtout[_MAX_PATH]; fcb_list fcblist; int fh; rc = ModificationTest(); if( rc != ERR_NO_ERR ) { return( rc ); } /* * filter on a line */ rc = GetCopyOfLineRange( s, e, &fcblist ); if( rc != ERR_NO_ERR ) { return( rc ); } /* * get file */ MakeTmpPath( filtin, FILTER_FILE_NAME ); fh = mkstemp( filtin ); if( fh == -1 ) return( ERR_FILE_OPEN ); /* * now, dump this crap to a tmp file */ for( cfcb = fcblist.head; cfcb != NULL; cfcb = tfcb ) { FetchFcb( cfcb ); for( cline = cfcb->lines.head; cline != NULL; cline = cline->next ) { write( fh, cline->data, strlen( cline->data ) ); #if defined( __UNIX__ ) write( fh, "\n", 1 ); #else write( fh, "\r\n", 2 ); #endif } tfcb = cfcb->next; FcbFree( cfcb ); } close( fh ); MakeTmpPath( filtout, FILTER_FILE_NAME ); fh = mkstemp( filtout ); if( fh == -1 ) { remove( filtin ); return( ERR_FILE_OPEN ); } close( fh ); /* * shell out to the given command */ ExecCmd( filtin, filtout, cmd ); StartUndoGroup( UndoStack ); rc = DeleteLineRange( s, e, 0 ); if( rc == ERR_NO_ERR ) { ReadAFile( s - 1, filtout ); Message1( "%l lines filtered through %s", e - s + 1, cmd ); } EndUndoGroup( UndoStack ); /* * cleanup */ if( rc == ERR_NO_ERR ) { rc = DO_NOT_CLEAR_MESSAGE_WINDOW; } remove( filtin ); remove( filtout ); return( rc ); } /* DoGenericFilter */
/* * Global - perform global command */ vi_rc Global( linenum n1, linenum n2, const char *data, int dmt ) { char *sstr, *linedata; bool match; vi_rc rc; vi_rc rc1; long changecnt = 0; linenum ll; fcb *cfcb; line *cline; regexp crx; i_mark pos; /* * get search string and command */ rc = ModificationTest(); if( rc != ERR_NO_ERR ) { return( rc ); } sstr = alloca( MAX_INPUT_LINE ); if( sstr == NULL ) { return( ERR_NO_STACK ); } data = SkipLeadingSpaces( data ); data = GetNextWord( data, sstr, SingleSlash ); if( *sstr == '\0' ) { return( ERR_INVALID_GLOBAL_CMD ); } if( *data == '/' ) ++data; // skip one slash character data = SkipLeadingSpaces( data ); /* * 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 ); } rc = CurrentRegComp( sstr ); if( rc != ERR_NO_ERR ) { return( rc ); } SaveCurrentFilePos(); StartUndoGroup( UndoStack ); EditFlags.DisplayHold = true; /* * pass one - find all matches */ for( pos.line = n1; pos.line <= n2; pos.line++ ) { /* * go thorugh file, marking global lines */ pos.column = 0; rc = FindRegularExpression( NULL, &pos, &linedata, n2, 0 ); if( rc != ERR_NO_ERR ) { if( rc == ERR_FIND_PAST_TERM_LINE || rc == ERR_FIND_NOT_FOUND || rc == ERR_FIND_END_OF_FILE ) { break; } RestoreCurrentFilePos(); EditFlags.DisplayHold = false; return( rc ); } if( pos.line > n2 ) { break; } /* * go to appropriate spot in file */ rc = GoToLineNoRelCurs( pos.line ); if( rc != ERR_NO_ERR ) { RestoreCurrentFilePos(); EditFlags.DisplayHold = false; return( rc ); } /* * mark fcb and line for a match */ CurrentFcb->globalmatch = true; CurrentLine->u.ld.globmatch = true; if( EditFlags.Verbose && EditFlags.EchoOn ) { // WPrintfLine( MessageWindow,1,"Match on line %l",clineno ); Message1( "Match on line %l", pos.line ); } } /* * negate range, if needed */ if( dmt ) { /* * run through each line, flipping globmatch flag on lines */ CGimmeLinePtr( n1, &CurrentFcb, &CurrentLine ); match = false; for( CurrentPos.line = n1; CurrentPos.line <= n2; CurrentPos.line++ ) { if( CurrentLine->u.ld.globmatch ) { CurrentLine->u.ld.globmatch = false; } else { match = true; CurrentLine->u.ld.globmatch = true; } CurrentLine = CurrentLine->next; if( CurrentLine == NULL ) { CurrentFcb->globalmatch = match; CurrentFcb = CurrentFcb->next; FetchFcb( CurrentFcb ); CurrentLine = CurrentFcb->lines.head; match = false; } } } /* * Pass 2: do all changes */ rc = ERR_NO_ERR; EditFlags.GlobalInProgress = true; memcpy( &crx, CurrentRegularExpression, sizeof( crx ) ); for( CurrentFcb = CurrentFile->fcbs.head; CurrentFcb != NULL; CurrentFcb = CurrentFcb->next ) { if( !CurrentFcb->globalmatch ) continue; FetchFcb( CurrentFcb ); CurrentPos.line = CurrentFcb->start_line; for( CurrentLine = CurrentFcb->lines.head; CurrentLine != NULL; CurrentLine = CurrentLine->next, CurrentPos.line++ ) { if( !CurrentLine->u.ld.globmatch ) continue; CurrentLine->u.ld.globmatch = false; changecnt++; CurrentPos.column = 1; ProcessingMessage( CurrentPos.line ); /* * build command line */ rc = RunCommandLine( data ); if( rc > ERR_NO_ERR ) { break; } } if( rc > ERR_NO_ERR ) { break; } CurrentFcb->globalmatch = false; } /* * we have an error, so fix up fcbs */ if( rc > ERR_NO_ERR ) { for( cfcb = CurrentFile->fcbs.head; cfcb != NULL; cfcb = cfcb->next ) { if( cfcb->globalmatch ) { cfcb->globalmatch = false; cfcb->non_swappable = false; for( cline = cfcb->lines.head; cline != NULL; cline = cline->next ) { cline->u.ld.globmatch = false; } } } } /* * display results */ EditFlags.GlobalInProgress = false; EditFlags.DisplayHold = false; EndUndoGroup( UndoStack ); RestoreCurrentFilePos(); rc1 = SetCurrentLine( CurrentPos.line ); if( rc1 != ERR_NO_ERR ) { if( rc1 == ERR_NO_SUCH_LINE ) { SetCurrentLine( 1 ); } else { return( rc1 ); } } Message1( "%l matches found",changecnt ); DCDisplayAllLines(); return( rc ); } /* Global */
/* * ProcessEx - process an ex command */ vi_rc ProcessEx( linenum n1, linenum n2, bool n2f, int tkn, const char *data ) { vi_rc rc = ERR_INVALID_COMMAND, i; char word[MAX_STR]; linenum addr, tlines; fcb *cfcb; line *cline; fcb_list fcblist; GetNextWord1( data, word ); data = word; if( GetAddress( &data, &addr ) != ERR_NO_ERR ) { addr = -1; } tlines = n2 - n1 + 1; switch( tkn ) { case EX_T_APPEND: if( !EditFlags.ExMode ) { return( ERR_ONLY_VALID_IN_EX_MODE ); } if( !n2f ) { rc = Append( n1, true ); } break; case EX_T_CHANGE: if( !EditFlags.ExMode ) { return( ERR_ONLY_VALID_IN_EX_MODE ); } StartUndoGroup( UndoStack ); rc = DeleteLineRange( n1, n2, 0 ); if( rc != ERR_NO_ERR ) { EndUndoGroup( UndoStack ); break; } rc = Append( n1 - 1, false ); if( rc != ERR_NO_ERR ) { EndUndoGroup( UndoStack ); break; } break; case EX_T_COPY: if( addr < 0 || IsPastLastLine( addr ) ) { return( ERR_INVALID_ADDRESS ); } i = GetCopyOfLineRange( n1, n2, &fcblist ); if( i ) { break; } rc = InsertLines( addr, &fcblist, UndoStack ); GoToLineNoRelCurs( addr ); if( rc == ERR_NO_ERR ) { Message1( strCmmsg, tlines, "copied", addr ); } break; case EX_T_INSERT: if( !EditFlags.ExMode ) { return( ERR_ONLY_VALID_IN_EX_MODE ); } if( !n2f ) { rc = Append( n1 - 1, true ); } break; case EX_T_JOIN: if( SaveAndResetFilePos( n1 ) != ERR_NO_ERR ) { rc = ERR_NO_SUCH_LINE; break; } if( tlines == 1 ) { n2 = n1 + 1; tlines = 2; } SetRepeatCount( tlines - 1 ); rc = JoinCurrentLineToNext(); RestoreCurrentFilePos(); GoToLineNoRelCurs( n1 ); if( rc == ERR_NO_ERR ) { Message1( "lines %l to %l joined", n1, n2 ); } break; case EX_T_LIST: if( !EditFlags.ExMode ) { return( ERR_ONLY_VALID_IN_EX_MODE ); } for( rc = CGimmeLinePtr( n1, &cfcb, &cline ); rc == ERR_NO_ERR; rc = CGimmeNextLinePtr( &cfcb, &cline ) ) { if( EditFlags.LineNumbers ) { MyPrintf( "%M %s\n", n1, cline->data ); } else { MyPrintf( "%s\n", cline->data ); } if( n1 >= n2 ) { break; } n1++; } break; case EX_T_MARK: rc = SetGenericMark( n1, 1, C2VIKEY( word[0] ) ); break; case EX_T_MOVE: if( addr < 0 || IsPastLastLine( addr ) ) { return( ERR_INVALID_ADDRESS ); } SavebufNumber = WORK_SAVEBUF; StartUndoGroup( UndoStack ); rc = DeleteLineRange( n1, n2, SAVEBUF_FLAG ); if( SavebufNumber != WORK_SAVEBUF ) { /* if this changes, the command will fail * this could be caused by checking out a read-only file * so fix the deleted text and give an error message */ DoUndo(); return( ERR_INVALID_COMMAND ); } if( rc != ERR_NO_ERR ) { EndUndoGroup( UndoStack ); break; } if( addr > n2 ) { addr -= tlines; } else if( addr >= n1 && addr <= n2 ) { addr = n1; } rc = InsertLines( addr, &WorkSavebuf->u.fcbs, UndoStack ); EndUndoGroup( UndoStack ); GoToLineNoRelCurs( addr ); if( rc == ERR_NO_ERR ) { Message1( strCmmsg, tlines, "moved", addr ); } break; case EX_T_UNDO: rc = DoUndo(); break; case EX_T_UNDO_DMT: rc = DoUndoUndo(); break; case EX_T_EQUALS: Message1( "%l", n1 ); rc = ERR_NO_ERR; break; case EX_T_VERSION: rc = DoVersion(); break; case EX_T_VISUAL: case EX_T_VISUAL_DMT: if( EditFlags.LineDisplay ) { ScreenPage( -1 ); EditFlags.ExMode = false; EditFlags.LineDisplay = false; EditFlags.ClockActive = true; ReDisplayScreen(); DoVersion(); } if( word[0] != '\0' ) { rc = EditFile( word, ( tkn == EX_T_VISUAL_DMT ) ); } else { rc = ERR_NO_ERR; } break; } return( rc ); } /* ProcessEx */
vi_rc Change( range *r ) { int scol, ecol; int tmp; vi_rc rc; vi_key key; #ifndef __WIN__ int vecol; #endif /* * change line ranges */ if( r->start.line != r->end.line ) { StartUndoGroup( UndoStack ); if( !r->line_based ) { rc = Cut( r->start.line, r->start.column, r->end.line, r->end.column, true ); r->end.column = -1; scol = -1; ecol = -1; } else { if( r->start.line == CurrentPos.line ) { r->start.line++; } else { r->end.line--; } if( r->start.line <= r->end.line ) { rc = DeleteLineRange( r->start.line, r->end.line, 0 ); if( rc != ERR_NO_ERR ) { EndUndoGroup( UndoStack ); return( rc ); } } scol = FindStartOfCurrentLine() - 1; ecol = CurrentLine->len - 1; } DCDisplayAllLines(); rc = DeleteAndInsertText( scol, ecol ); EndUndoGroup( UndoStack ); return( rc ); } /* * change text on current line */ rc = ERR_NO_ERR; GoToLineNoRelCurs( r->start.line ); ecol = r->end.column; scol = r->start.column; #ifdef __WIN__ // GetCurrentLine(); strcpy( WorkLine->data, CurrentLine->data ); tmp = WorkLine->data[ecol]; WorkLine->data[ecol] = '$'; #else vecol = VirtualColumnOnCurrentLine( ecol + 1 ); vecol--; ExpandTabsInABuffer( CurrentLine->data, CurrentLine->len, WorkLine->data, EditVars.MaxLine + 1 ); WorkLine->len = strlen( WorkLine->data ); tmp = WorkLine->data[vecol]; WorkLine->data[vecol] = '$'; #endif if( WorkLine->len == 0 ) { WorkLine->data[1] = '\0'; } EditFlags.InsertModeActive = true; GoToColumn( scol + 1, CurrentLine->len ); EditFlags.InsertModeActive = false; DisplayWorkLine( true ); UnselectRegion(); DCUpdate(); #ifndef __WIN__ HiliteAColumnRange( CurrentPos.line, scol, ecol ); #endif /* * now, get ready to do change */ key = GetNextEvent( false ); #ifdef __WIN__ WorkLine->data[ecol] = tmp; #else WorkLine->data[vecol] = tmp; #endif DisplayWorkLine( true ); if( key == VI_KEY( ESC ) && !EditFlags.ChangeLikeVI ) { WorkLine->len = -1; GoToColumn( scol + 1, CurrentLine->len ); } else { KeyAdd( key ); rc = DeleteAndInsertText( scol, ecol ); } return( rc ); } /* Change */