/* * 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 */
/* * FindRegularExpressionBackwards - do a reverse search for a regular expression */ vi_rc FindRegularExpressionBackwards( char *pat, i_mark *pos1, char **linedata, linenum termline, find_type flags ) { vi_rc rc; char *data; bool wrapped = false; bool found; linenum ilineno = 0; line *cline; fcb *cfcb; regexp rcpy; int scol; linenum sline; /* * initialize for search */ if( wrapMsgPrinted ) { wrapMsgPrinted = false; ClearWindow( message_window_id ); } sline = pos1->line; rc = CGimmeLinePtr( sline, &cfcb, &cline ); if( rc != ERR_NO_ERR ) { return( rc ); } if( flags & FINDFL_WRAP ) { ilineno = sline; } scol = pos1->column; if( pat != NULL ) { rc = CurrentRegComp( pat ); if( rc != ERR_NO_ERR ) { return( rc ); } } memset( &rcpy, 0, sizeof( rcpy ) ); /* * loop until string found */ for( ;; ) { data = cline->data; found = false; /* * run through all possible matches on the line, accepting * only the last one */ if( scol >= 0 ) { while( *data != '\0' && RegExec( CurrentRegularExpression, data, (data == cline->data) ) ) { int col, len; if( RegExpError != ERR_NO_ERR ) { return( RegExpError ); } col = GetCurrRegExpColumn( cline->data ); len = GetCurrRegExpLength(); if( col + len > scol ) { break; } found = true; memcpy( &rcpy, CurrentRegularExpression, sizeof( regexp ) ); data = &(cline->data[col + 1]); } if( found ) { break; } } /* * get next line */ rc = GimmePrevLinePtr( &cfcb, &cline ); if( rc == ERR_NO_ERR ) { --sline; } else if( rc == ERR_NO_MORE_LINES ) { if( (flags & FINDFL_WRAP) == 0 ) { return( ERR_FIND_TOP_OF_FILE ); } else { Message1( wrapMsg, "top" ); MyBeep(); wrapMsgPrinted = true; } if( wrapped ) { return( ERR_FIND_NOT_FOUND ); } rc = CFindLastLine( &sline ); if( rc != ERR_NO_ERR ) { return( rc ); } rc = CGimmeLinePtr( sline, &cfcb, &cline ); if( rc != ERR_NO_ERR ) { return( rc ); } wrapped = true; } else { return( rc ); } if( sline < termline ) { return( ERR_FIND_PAST_TERM_LINE ); } if( wrapped ) { if( sline < ilineno ) { return( ERR_FIND_NOT_FOUND ); } } scol = cline->len; } *linedata = cline->data; memcpy( CurrentRegularExpression, &rcpy, sizeof( regexp ) ); pos1->column = GetCurrRegExpColumn( cline->data ); pos1->line = sline; return( ERR_NO_ERR ); } /* FindRegularExpressionBackwards */
/* * FindRegularExpression - do a forward search for a regular expression */ vi_rc FindRegularExpression( char *pat, i_mark *pos1, char **linedata, linenum termline, find_type flags ) { vi_rc rc; int found; linenum ilineno = 0; bool wrapped = false; char *data; line *cline; fcb *cfcb; int scol; linenum sline; /* * initialize for search */ if( wrapMsgPrinted ) { wrapMsgPrinted = false; ClearWindow( message_window_id ); } sline = pos1->line; if( flags & FINDFL_WRAP ) { ilineno = sline; } rc = CGimmeLinePtr( sline, &cfcb, &cline ); if( rc != ERR_NO_ERR ) { return( rc ); } scol = pos1->column; if( pat != NULL ) { rc = CurrentRegComp( pat ); if( rc != ERR_NO_ERR ) { return( rc ); } } /* * loop until string found */ data = &cline->data[scol]; while( (found = RegExec( CurrentRegularExpression, data, (data == cline->data) )) == 0 ) { if( RegExpError != ERR_NO_ERR ) { return( RegExpError ); } /* * get next line */ rc = CGimmeNextLinePtr( &cfcb, &cline ); if( rc == ERR_NO_ERR ) { ++sline; } else if( rc == ERR_NO_MORE_LINES ) { if( (flags & FINDFL_WRAP) == 0 ) { return( ERR_FIND_END_OF_FILE ); } else { Message1( wrapMsg, "bottom" ); MyBeep(); wrapMsgPrinted = true; } if( wrapped ) { return( ERR_FIND_NOT_FOUND ); } sline = 1; rc = CGimmeLinePtr( sline, &cfcb, &cline ); if( rc != ERR_NO_ERR ) { return( rc ); } wrapped = true; } else { return( rc ); } if( sline > termline ) { return( ERR_FIND_PAST_TERM_LINE ); } if( wrapped ) { if( sline > ilineno ) { return( ERR_FIND_NOT_FOUND ); } } scol = 0; data = cline->data; } *linedata = cline->data; pos1->column = GetCurrRegExpColumn( cline->data ); pos1->line = sline; return( ERR_NO_ERR ); } /* FindRegularExpression */
/* * 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 */