clsubs.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 435 行
C
435 行
/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: Text substitution.
*
****************************************************************************/
#include <stdio.h>
#include <string.h>
#include "walloca.h"
#include "vi.h"
#include "rxsupp.h"
#include "win.h"
#ifdef __WIN__
#include "winvi.h"
#endif
// LastSubstituteCancelled is a global used to perform an interactive
// search and replace in 2 parts
int LastSubstituteCancelled;
int LastChangeCount;
int LastLineCount;
/* TwoPartSubstitute - goes from current line to current line minus 1
* doing substitute in 2 parts if it has to, that
* appear as 1
*/
int TwoPartSubstitute( char *find, char *replace, int prompt, int wrap ){
int 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 == TRUE ) ? 'i' : '\0' );
end_line = CurrentFile->fcb_tail->end_line;
rc = Substitute( CurrentLineNumber, end_line, cmd );
changecnt = LastChangeCount;
linecnt = LastLineCount;
if( wrap && !LastSubstituteCancelled && CurrentLineNumber != 1 && rc == ERR_NO_ERR ) {
// search from beginning of do to here
sprintf( cmd, "/%s/%s/g%c", find, replace, ( prompt == TRUE ) ? 'i' : '\0' );
rc = Substitute( 1,CurrentLineNumber-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 */
/*
* Substitute - perform substitution
*/
int Substitute( linenum n1, linenum n2, char *data )
{
char *sstr,*rstr,*newr;
char flag[20],*linedata;
bool iflag=FALSE,gflag=FALSE,undoflag=FALSE,restline=FALSE;
bool splitpending=FALSE,undoline=FALSE;
int i,rlen,slen,key;
int ccol,rc,splitme,k;
long changecnt=0,linecnt=0;
linenum clineno,llineno,ll,lastline=0,extra;
LastSubstituteCancelled = 0;
LastChangeCount = 0;
LastLineCount = 0;
sstr = alloca( MAX_INPUT_LINE );
if( sstr == NULL ) {
return( ERR_NO_STACK );
}
strcpy( sstr, data );
if( rc = ModificationTest() ) {
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 );
}
if( (k=NextWord1( data, flag ) ) >= 0 ) {
for( i=0;i<k;i++ ) {
switch( flag[i] ) {
case 'g':
gflag = TRUE;
break;
case 'i':
case 'c':
iflag = TRUE;
break;
}
}
}
i = CurrentRegComp( sstr );
if( i ) {
return( i );
}
/*
* verify last line
*/
if( n2 > CurrentFile->fcb_tail->end_line ) {
i = CFindLastLine( &ll );
if( i ) {
return( i );
}
if( n2 > ll ) {
return( ERR_INVALID_LINE_RANGE );
}
}
/*
* set for start of search
*/
if( EditFlags.Verbose && EditFlags.EchoOn ) {
ClearWindow( MessageWindow );
}
SaveCurrentFilePos();
llineno = n1-1;
clineno = n1;
ccol = 0;
EditFlags.AllowRegSubNewline = TRUE;
newr = StaticAlloc();
while( TRUE ) {
/*
* get regular expression, and build replacement string
*/
i = FindRegularExpression( NULL, &clineno, ccol, &linedata, n2, FALSE );
if( !i ) {
ccol = GetCurrRegExpColumn( linedata );
slen = GetCurrRegExpLength();
} else {
if( i == ERR_FIND_PAST_TERM_LINE || i == ERR_FIND_NOT_FOUND || i == ERR_FIND_END_OF_FILE ) {
break;
}
RestoreCurrentFilePos();
EditFlags.AllowRegSubNewline = FALSE;
return( i );
}
if( clineno > n2 ) {
break;
}
splitme = RegSub( CurrentRegularExpression, rstr, newr, clineno );
rlen = strlen( newr );
ProcessingMessage( clineno );
/*
* if in global mode, see if we already have an undo for
* this line
*/
if( gflag ) {
if( lastline != clineno ) {
undoline = FALSE;
}
}
/*
* interactive mode? yes, then display text and ask to change
*/
if( iflag ) {
if( !restline ) {
ClearWindow( MessageWindow );
}
restline = TRUE;
GoToLineNoRelCurs( clineno );
if( EditFlags.GlobalInProgress ) {
EditFlags.DisplayHold = FALSE;
DCDisplayAllLines();
EditFlags.DisplayHold = TRUE;
}
HilightSearchString( clineno, ccol, slen );
#ifdef __WIN__
key = MessageBox( Root, "Change this occurence?", "Replace Text",
MB_ICONQUESTION | MB_YESNOCANCEL );
switch( key ) {
case IDNO:
ResetDisplayLine();
rlen = 1;
goto TRYNEXTMATCH;
case IDCANCEL:
ResetDisplayLine();
LastSubstituteCancelled = 1;
goto DONEALLREPLACEMENTS;
}
if( key == 0 ) {
#endif
Message1( "Change? (y)es/(n)o/(a)ll/(q)uit" );
key = 0;
while( key != 'y' ) {
key = GetNextEvent( FALSE );
switch( key ) {
case 'a':
ResetDisplayLine();
iflag = FALSE;
key='y';
break;
case 'q':
ResetDisplayLine();
goto DONEALLREPLACEMENTS;
case 'n':
ResetDisplayLine();
rlen = 1;
goto TRYNEXTMATCH;
}
}
#ifdef __WIN__
}
#endif
}
/*
* set up for global undo if we haven't already
*/
if( !undoflag ) {
StartUndoGroup( UndoStack );
undoflag = TRUE;
}
/*
* bump change counts
*/
changecnt++;
if( llineno != clineno ) {
if( splitpending ) {
splitpending = FALSE;
extra = SplitUpLine( llineno );
n2 += extra;
clineno += extra;
}
linecnt++;
llineno = clineno;
}
/*
* get copy of line, and verify that new stuff fits
*/
CurrentLineNumber = clineno;
i = CGimmeLinePtr( clineno, &CurrentFcb, &CurrentLine );
if( i ) {
RestoreCurrentFilePos();
EditFlags.AllowRegSubNewline = FALSE;
StaticFree( newr );
return( i );
}
if( CurrentLine->len + rlen - slen >= 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 = clineno;
}
}
/*
* remove the old string
*/
GetCurrentLine();
WorkLine->len = ReplaceSubString( WorkLine->data, WorkLine->len,
ccol, ccol+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;
TRYNEXTMATCH:
if( gflag ) {
ccol += rlen;
if( (slen == 0 && rlen == 0) || CurrentLine->data[ ccol ] == 0 ) {
clineno++;
if( clineno > n2 ) {
break;
}
ccol = 0;
}
} else {
clineno++;
if( clineno > n2 ) {
break;
}
ccol = 0;
}
}
/*
* is there still a split line pending?
*/
DONEALLREPLACEMENTS:
if( splitpending ) {
SplitUpLine( llineno );
}
/*
* display results
*/
RestoreCurrentFilePos();
EditFlags.AllowRegSubNewline = FALSE;
if( restline ) {
SetCurrentLine( CurrentLineNumber );
GoToColumnOK( CurrentColumn );
}
if( undoflag ) {
EndUndoGroup( UndoStack );
}
if( rc == ERR_LINE_FULL ) {
Message1( "Stopped at line %l - line full", clineno );
} else {
Message1( "%l changes on %l lines",changecnt,linecnt );
LastLineCount = linecnt;
LastChangeCount = changecnt;
}
DCDisplayAllLines();
StaticFree( newr );
return( ERR_NO_ERR );
} /* Substitute */
/*
* SplitUpLine - split up a line with SPLIT_CHAR's in them
*/
linenum SplitUpLine( linenum cl )
{
linenum extra = 0;
int j,i,k;
char *buff;
/*
* run through, and for every 0x01, make a new line
*/
while( 1 ) {
/*
* get current line
*/
CurrentLineNumber = cl+extra;
CGimmeLinePtr( CurrentLineNumber, &CurrentFcb, &CurrentLine );
GetCurrentLine();
for( i=0;i<=WorkLine->len;i++ ) {
/*
* found a place to split. make this line shorter,
* and create a new line with the rest of the data
* for this line
*/
if( WorkLine->data[i] == SPLIT_CHAR ) {
buff = StaticAlloc();
k = 0;
for( j=i+1;j<=WorkLine->len;j++ ) {
buff[k++] = WorkLine->data[j];
}
WorkLine->data[i] = 0;
WorkLine->len = i;
ReplaceCurrentLine();
AddNewLineAroundCurrent( buff,k-1, INSERT_AFTER );
extra++;
StaticFree( buff );
break;
}
/*
* at the very end, undo what we did and go back
*/
if( WorkLine->data[i] == 0 ) {
ReplaceCurrentLine();
UndoInsert( cl+1, cl+extra, UndoStack );
return( extra );
}
}
}
} /* SplitUpLine */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?