diff options
Diffstat (limited to 'private/utils/mep/src/search.c')
-rw-r--r-- | private/utils/mep/src/search.c | 1126 |
1 files changed, 1126 insertions, 0 deletions
diff --git a/private/utils/mep/src/search.c b/private/utils/mep/src/search.c new file mode 100644 index 000000000..a751a1eb9 --- /dev/null +++ b/private/utils/mep/src/search.c @@ -0,0 +1,1126 @@ +/*** search.c - search routines for editor +* +* Copyright <C> 1988, Microsoft Corporation +* +* Searches funnel through these routines as follows: +* +* psearch msearch searchall mgrep +* \ | / / +* \ | / / +* \_______|_______/ / +* | / +* v / +* dosearch / +* /___\_____________/ +* / \ +* / \ +* search REsearch REsearchS <=== all exported to extensions +* +* Global variables, and their meanings: +* +* User set-able switches: +* fUnixRE unixre: switch. TRUE => Use UNIX Regular Expressions +* fSrchCaseSwit case: switch. TRUE => case is significant +* fSrchWrapSwit wrap: switch. TRUE => searches wrap +* +* Previous Search Parameters: +* fSrchAllPrev TRUE => searched for all occurrances +* fSrchCasePrev TRUE => case was significant +* fSrchDirPrev TRUE => searched forward +* fSrchRePrev TRUE => used a regular expressions +* fSrchWrapPrev TRUE => wrapped around +* +* srchbuf search string +* +* Revision History: +* 26-Nov-1991 mz Strip off near/far +* +*************************************************************************/ + +#include <string.h> +#include <stdarg.h> +#include "mep.h" + + +static int cAll; /* count of ocurrances for all */ +static int cGrepped; /* count of ocurrances for mgrep*/ +static struct patType *patBuf = NULL; /* compiled pattern */ + + +/***************************************************************************\ + +MEMBER: lsearch + +SYNOPSIS: strstr based on supplied lengths rather than strlen() + +ALGORITHM: + +ARGUMENTS: + +RETURNS: + +NOTES: Supplied strings may not be zero terminated or may have embedded + NULs + This is a brute force algorithm which should be updated to + something reasonable if performance is a problem + +HISTORY: 14-Aug-90 davegi + Created + +KEYWORDS: + +SEEALSO: + +\***************************************************************************/ +char* +lsearch ( + char* pchSrc, + ULONG cbSrc, + char* pchSub, + ULONG cbSub + ) +{ + + REGISTER ULONG i; + REGISTER ULONG j; + + assert( pchSrc ); + assert( pchSub ); + + // If the sub-string is longer than the source string or, + // cbSrc > strlen( pchSrc) (hack for backwards search), return NULL + + if(( cbSub > cbSrc ) || ( cbSrc > strlen( pchSrc ) + 1)) { + return NULL; + } + + // Short Circuit... + // If first character in pchSub does not exist in pchSrc + + if( ! memchr( pchSrc, *pchSub, cbSrc )) { + return NULL; + } + + i = j = 0; + do { + if( pchSrc[ i ] == pchSub[ j ] ) { + i++; + j++; + } else { + i = i - j + 1; + j = 0; + } + } while(( j < cbSub ) && ( i < cbSrc )); + return ( j >= cbSub ) ? &( pchSrc[ i - cbSub ]) : NULL; +} + + + +static char szNullStr[] = ""; + + +/*** mgrep - multiple file search +* +* Using the internal editor search code, and optimizing for those files +* already in memory, search for a string or regular expression. +* +* Searches the file list specified by the greplist macro. +* +* no arg: search for previous search string +* Single arg: search for string. +* Double arg: search for regular expression. +* meta: toggle case from current switch setting +* +* Files to be searched which are already in the file history are simply +* searched. Files which are NOT in the file history, are read in, and if +* no occurance of the search string is found, they are then discarded as +* well. +* +* Input: +* Standard editting function +* +* Globals: +* - grep file list +* fSrchCaseSwit - users 'case' switch +* fSrchRePrev - previous RE search flag +* fUnixRE - users 'unixre' switch +* pasBuf - compiled RE pattern +* srchbuf - last searched for string. +* +* Output: +* Returns TRUE on found. +* +*************************************************************************/ +flagType +mgrep ( + CMDDATA argData, + ARG *pArg, + flagType fMeta + ) +{ + int l; /* length of matched string */ + PCMD pcmdGrepList; /* pointer to grep list */ + char *szGrepFile; /* pointer to current grep file */ + + assert (pArg); + fSrchCasePrev = fSrchCaseSwit; /* assume case switch to begin */ + + switch (pArg->argType) { + + /* + * TEXTARG: use text as search string. If RE search, also compile the regular + * expression into patBuf. (Fall into NOARG code). + */ + case TEXTARG: + strcpy ((char *) buf, pArg->arg.textarg.pText); + srchbuf[0] = 0; + if (pArg->arg.textarg.cArg == 2) { + if (patBuf != NULL) { + FREE((char *) patBuf); + } + patBuf = RECompile (buf, fSrchCaseSwit, (flagType)!fUnixRE); + if (patBuf == NULL) { + printerror ((RESize == -1) ? "Invalid pattern" : "Not enough memory for pattern"); + return FALSE; + } + fSrchRePrev = TRUE; + } else { + fSrchRePrev = FALSE; + } + strcpy (srchbuf, buf); + + + /* + * NOARG: use previous search string & parameters + */ + case NOARG: + if (srchbuf[0] == 0) { + printerror ("No search string specified"); + return FALSE; + } + break; + } + + /* + * Ee must ensure that no background compile is underway. Then get a pfile + * there. + */ + if (fBusy(pBTDComp)) { + printerror ("Cannot mgrep to <compile> during background compile"); + return FALSE; + } + + if ((PFILECOMP = FileNameToHandle (rgchComp, rgchComp)) == NULL) { + PFILECOMP = AddFile ((char *)rgchComp); + FileRead ((char *)rgchComp, PFILECOMP, FALSE); + SETFLAG (FLAGS (PFILECOMP), READONLY); + } + + /* + * Under OS/2, if it is clear that we will destroy the log file contents + * we ask the user and empty the file if he says so. + */ + if (PFILECOMP->cLines + && (confirm ("Delete current contents of compile log ? ", NULL)) + ) { + DelFile (PFILECOMP, FALSE); + } + + + BuildFence ("mgrep", rgchEmpty, buf); + AppFile (buf, PFILECOMP); + /* + * When not in a macro, indicate on the dialog line what it is we are + * searching for + */ + if (!mtest ()) { + l = sout (0, YSIZE, "mgrep for '", infColor); + l = sout (l, YSIZE, srchbuf, fgColor); + soutb (l, YSIZE, "'", infColor); + } + + if (fMeta) { + fSrchCasePrev = (flagType)!fSrchCasePrev; + } + cGrepped = 0; + + /* + * Get the list handle, and initialize to start at the head of the list. + * Attempt to process each list element. If starts with "$", use forsemi to + * process each file or pattern in each directory listed in the environment + * variable, else process the filename directly. + */ + if (pcmdGrepList = GetListHandle ("mgreplist", TRUE)) { + szGrepFile = ScanList (pcmdGrepList, TRUE); + while (szGrepFile) { + char *pathstr; + char *tmp = NULL; + + if (*szGrepFile == '$') { + char *p; + + if (*(p=strbscan (szGrepFile, ":"))) { + *p = 0; + + if ((tmp = getenvOem (szGrepFile+1)) == NULL) { + pathstr = szNullStr; + } else { + pathstr = tmp; + } + + *p++ = ':'; + szGrepFile = p; + } + } else { + pathstr = szNullStr; + } + + forsemi (pathstr, mgrep1env, szGrepFile); + + if( tmp != NULL ) { + free( tmp ); + } + + szGrepFile = ScanList (NULL, TRUE); + if (fCtrlc) { + return FALSE; + } + } + } + if (cGrepped) { + nextmsg (0, &NoArg, FALSE); + } + domessage ("%d occurrences found",cGrepped); + return (flagType)(cGrepped != 0); + + argData; +} + + + + + +/*** mgrep1env - perform grep on environment variable when found +* +* Called when an environment variable is found in the mgrep list to +* process all the files in that path. Called once per directory entry +* in the list. +* +* Input: +* pszEnv = pointer to directory name +* pFileName = pointer to filename +* +* Output: +* Returns nothing. +* +*************************************************************************/ +flagType +mgrep1env ( + char * pszEnv, + va_list pa + ) +{ + char *pszFn = (char *)va_arg( pa, char* ); + pathbuf bufFn; /* filename buffer */ + + if (fCtrlc) { + return TRUE; + } + + /* + * construct full pathname in buffer. + */ + { + pathbuf bufBuild; + + strcpy (bufBuild, pszEnv); + if (*pszEnv && (*(strend(bufBuild)-1) != '\\')) { + *(int *) strend (bufBuild) = '\\'; + } + strcat (bufBuild, pszFn); + CanonFilename (bufBuild, bufFn); + } + + forfile (bufFn, A_ALL, mgrep1file, NULL); + + return FALSE; +} + + + + +/*** mgrep1file - grep the contents of 1 file. +* +* Searches through one file for stuff. +* +* Input: +* +* Output: +* Returns ..... +* +* Exceptions: +* +* Notes: +* +*************************************************************************/ +void +mgrep1file ( + char *szGrepFile, + struct findType *pfbuf, + void * dummy + ) +{ + + flagType fDiscard; /* discard the file read? */ + fl flGrep; /* ptr to current grep loc */ + int l; /* length of matched string */ + PFILE pFileGrep; /* file to be grepped */ + + assert (szGrepFile); + + if (fCtrlc) { + return; + } + + flGrep.lin = 0; + flGrep.col = 0; + + /* + * If we can get a handle to the file, then it's alread in the list, and we + * should not discard it when done. If it is not in the list, we read it in, + * but we'll discard it, unless something is found there. + */ + if (!(pFileGrep = FileNameToHandle (szGrepFile, szGrepFile))) { + pFileGrep = AddFile (szGrepFile); + SETFLAG (FLAGS (pFileGrep), REFRESH); + fDiscard = TRUE; + } else { + fDiscard = FALSE; + } + + /* + * If the file needs to be physically read, do so. + */ + if ((FLAGS (pFileGrep) & (REFRESH | REAL)) != REAL) { + FileRead (pFileGrep->pName, pFileGrep, FALSE); + RSETFLAG (FLAGS(pFileGrep), REFRESH); + } + + /* + * Use either the normal searcher, or the regular expression searcher, based + * on the use of regular expressions. + */ + do { + if (fSrchRePrev) { + l = REsearch (pFileGrep, /* file to search */ + TRUE, /* direction: forward */ + FALSE, /* not a searchall */ + fSrchCasePrev, /* case */ + FALSE, /* wrap */ + patBuf, /* pattern */ + &flGrep); /* start/end location */ + } else { + l = search (pFileGrep, + TRUE, /* direction: forward */ + FALSE, /* not a searchall */ + fSrchCasePrev, /* case */ + FALSE, /* wrap */ + srchbuf, /* pattern */ + &flGrep); /* start/end location */ + } + + if (l >= 0) { + /* + * if the search was successfull, if adding to <compile>, do so, else + * highlight the found search string and exit. + */ + buffer linebuf; + + fDiscard = FALSE; + cGrepped++; + GetLine (flGrep.lin, linebuf, pFileGrep); + zprintf ( PFILECOMP + , PFILECOMP->cLines + , "%s %ld %d: %s" + , pFileGrep->pName + , ++flGrep.lin + , ++flGrep.col + , linebuf); + } else { + /* + * If the search was not successfull, discard the file, if needed, and move + * to the next. + */ + if (fDiscard) { + RemoveFile (pFileGrep); + } + if (UpdateIf (PFILECOMP, PFILECOMP->cLines, FALSE)) { + Display (); + } + return; + } + } while (TRUE); + + pfbuf; dummy; +} + + + + +/*** psearch - plus search function +* +* Search the current file forward for a string. +* +* Input: +* Standard Editor Editing Function +* +* Output: +* Returns TRUE on success (at least one string found). +* +*************************************************************************/ +flagType +psearch ( + CMDDATA argData, + ARG * pArg, + flagType fMeta + ) +{ + return dosearch (TRUE, pArg, fMeta, FALSE); + + argData; +} + + + + +/*** msearch - minus search function +* +* Search the current file backward for a string. +* +* Input: +* Standard Editor Editing Function +* +* Output: +* Returns TRUE on success (at least one string found). +* +*************************************************************************/ +flagType +msearch ( + CMDDATA argData, + ARG * pArg, + flagType fMeta + ) +{ + return dosearch (FALSE, pArg, fMeta, FALSE); + + argData; +} + + + + +/*** searchall +* +* Searches the entire current file for a string, and highlights all ocurrances +* +* Input: +* Standard Editor Editing Function +* +* Output: +* Returns TRUE on success (at least one string found). +* +*************************************************************************/ +flagType +searchall ( + CMDDATA argData, + ARG * pArg, + flagType fMeta + ) +{ + return dosearch (TRUE, pArg, fMeta, TRUE); + + argData; +} + + + + +/*** dosearch - perform search operation +* +* Single funnel for all file search operations. +* +* NULLARG is converted into TEXTARG +* LINEARG, STREAMARG, BOXARG are illegal +* +* Input: +* fForard = TRUE => Indicates that search is forward +* pArg = pointer to user specified args +* fMeta = TRUE => if meta on +* fAll = TRUE => highlight all ocurrances +* +* Output: +* Returns TRUE if found +* +*************************************************************************/ +flagType +dosearch ( + flagType fForward, + ARG * pArg, + flagType fMeta, + flagType fAll + ) +{ + int l; /* length of matched string */ + fl flCur; /* file loc before/after search */ + rn rnCur; /* range to be highlighted */ + + assert (pArg); + fSrchCasePrev = fSrchCaseSwit; /* assume case switch to begin */ + + switch (pArg->argType) { + + /* + * TEXTARG: use text as search string. If RE search, also compile the regular + * expression into patBuf. (Fall into NOARG code). + */ + case TEXTARG: + strcpy ((char *) buf, pArg->arg.textarg.pText); + srchbuf[0] = 0; + if (pArg->arg.textarg.cArg == 2) { + if (patBuf != NULL) { + FREE((char *) patBuf); + } + patBuf = RECompile (buf, fSrchCaseSwit, (flagType)!fUnixRE); + if (patBuf == NULL) { + printerror ((RESize == -1) ? "Invalid pattern" : "Not enough memory for pattern"); + return FALSE; + } + fSrchRePrev = TRUE; + } else { + fSrchRePrev = FALSE; + } + + fSrchWrapPrev = fSrchWrapSwit; + strcpy (srchbuf, buf); + + /* + * NOARG: use previous search string & parameters + */ + case NOARG: + if (srchbuf[0] == 0) { + printerror ("No search string specified"); + return FALSE; + } + break; + + } + + /* + * The case to be used is the use's case switch, or the opposite of that if + * meta was specified. Save rest of globals as well. + */ + fSrchAllPrev = fAll; + if (fMeta) { + fSrchCasePrev = (flagType)!fSrchCasePrev; + } + + fSrchDirPrev = fForward; + + /* + * When not in a macro, indicate on the dialog line what it is we are + * searching for + */ + if (!mtest ()) { + char c; + l = sout (0, YSIZE, fSrchDirPrev ? "+Search for '" : "-Search for '", infColor); + c = srchbuf[ XSIZE - 14]; + srchbuf[ XSIZE-14] = '\0'; + l = sout (l, YSIZE, srchbuf, fgColor); + srchbuf[ XSIZE-14] = c; + soutb (l, YSIZE, "'", infColor); + } + + /* + * If this is a search for all occurrances, we begin the search from the + * file begining. Otherwise, set the start position of the search to the + * current cursor position. + */ + if (fSrchAllPrev) { + flCur.col = 0; + flCur.lin = 0; + } else { + flCur.col = XCUR (pInsCur) + (fSrchDirPrev ? 1 : -1); + flCur.lin = YCUR (pInsCur); + } + + /* + * Use either the normal searcher, or the regular expression searcher, based + * on the use of regular expressions. + */ + if (fSrchRePrev) { + l = REsearch (pFileHead, + fSrchDirPrev, + fSrchAllPrev, + fSrchCasePrev, + fSrchWrapPrev, + patBuf, + &flCur); + } else { + l = search (pFileHead, + fSrchDirPrev, + fSrchAllPrev, + fSrchCasePrev, + fSrchWrapPrev, + srchbuf, + &flCur); + } + + /* + * if the search was successfull, output the count of items founf for search + * all, or highlight the found search string for a single ocurrance search + */ + if (l >= 0) { + if (fSrchAllPrev) { + newscreen (); + domessage ("%d occurrences found",cAll); + } else { + rnCur.flFirst = flCur; + rnCur.flLast.col = flCur.col+l-1; + rnCur.flLast.lin = flCur.lin; + ClearHiLite( pFileHead, TRUE); + SetHiLite (pFileHead,rnCur,HGCOLOR); + Display(); + } + cursorfl (flCur); + return TRUE; + } + + /* + * If the search was not successfull, indicate as such. + */ + if (!mtest ()) { + srchbuf[XSIZE-12] = 0; + domessage (fSrchDirPrev ? "+'%s' not found" : "-'%s' not found", srchbuf); + } + return FALSE; +} + + + + + +/*** search - look for a string in a file +* +* search will begin a scan of the file looking for a particular string in the +* specified file beginning at the specified location. We perform simple +* character string matching. We return the length and location of the match. +* +* Input: +* pFile = pointer to file structure to be searched +* fForward = TRUE => search forward from the specified location +* fAll = TRUE => find and highlight all ocurrances +* fCase = TRUE => case is significant in comparisons +* fWrap = TRUE => search wraps around ends of file +* pat = character pointer to the search string +* pflStart = pointers to the location of the beginning of search. Updated +* to reflect the actually found location (or the first found +* for a searchall). +* +* Output: +* Returns length of match if found, -1 if not found +* +*************************************************************************/ +int +search ( + PFILE pFile, + flagType fForward, + flagType fAll, + flagType fCase, + flagType fWrap, + char *pat, + fl *pflStart + ) +{ + int cbPhys; /* physical length of line */ + fl flCur; /* current location in file */ + LINE yMac; + linebuf sbuf; + linebuf pbuf; + int lpat = strlen (pat); + int l; + char *pFound; + char *pSearch; /* point at which to search */ + rn rnCur; /* range to be highlighted */ + + assert (pat && pflStart && pFile); + strcpy (pbuf, pat); + if (!fCase) { + _strlwr (pbuf); + } + cAll = 0; + flCur = *pflStart; + + if (fForward) { + /* + * forward search. Search every line up until the end of the file. (or up + * until the original start position, if wrap was set). Check for CTRL+C + * break, and get each lines text. + */ + yMac = pFile->cLines; + + while (flCur.lin < yMac) { + if (fCtrlc) { + break; + } + cbPhys = GetLine (flCur.lin, sbuf, pFile); + l = cbLog (sbuf); + + /* + * search the buffer for the string of interest. Convert string to lower case + * first if case insensitive search. + */ + if (!fCase) { + _strlwr (sbuf); + } + + pSearch = pLog (sbuf,flCur.col,TRUE); + if (colPhys (sbuf, pSearch) != flCur.col) { + pSearch++; + } + + while ((l > flCur.col) + && (pFound = lsearch (pSearch, cbPhys - (pSearch-sbuf), pbuf, lpat))) { + + /* + * string found. Compute starting column of match. If not already found, + * update the caller's copy. For search-all, add the highlight, else for + * search once, return the length. + */ + flCur.col = colPhys (sbuf, pFound); + if (!cAll) { + *pflStart = flCur; + } + cAll++; + if (!fAll) { + return colPhys(sbuf, pFound+lpat) - colPhys(sbuf, pFound); + } + rnCur.flFirst = flCur; + rnCur.flLast.lin = flCur.lin; + rnCur.flLast.col = flCur.col+lpat-1; + SetHiLite (pFile,rnCur,HGCOLOR); + pSearch = pLog (sbuf,flCur.col,TRUE) + 1; + flCur.col = colPhys (sbuf, pSearch); + } + noise (flCur.lin++); + + /* + * if wrap around supported, then if we're at the end of the file, wrap around + * to the begining. + */ + if (fWrap && (flCur.lin >= pFile->cLines)) { + yMac = pflStart->lin; + flCur.lin = 0; + } + flCur.col = 0; + } + } else { + /* + * backwards search. Doesn't have to be concerned about searchall, since those + * always occur forward. Otherwise, the same as above, only backwards. + */ + assert (!fAll); + yMac = 0; + while (flCur.lin >= yMac) { + if (fCtrlc) { + break; + } + GetLine (flCur.lin, sbuf, pFile) - 1; + l = cbLog (sbuf); + + /* + * search the buffer for the string of interest. Convert string to lower + * case first if case insensitive search. Terminate the buffer at the + * starting column (this is a backwards search) + */ + if (!fCase) { + _strlwr (sbuf); + } + pSearch = pLog (sbuf, flCur.col, TRUE); + *(pSearch+1) = 0; + cbPhys = pSearch - sbuf; + pSearch = sbuf; + + /* + * search the line forward once for any occurrance. Then if FOUND, search + * repeatedly for the LAST occurrance in the text, and return the info on + * that. + */ + if (pFound = lsearch (pSearch, cbPhys - (pSearch-sbuf), pbuf, lpat)) { + do { + pSearch = pFound; + } while (pFound = lsearch (pSearch+1, cbPhys - (pSearch-sbuf) , pbuf, lpat)); + flCur.col = colPhys (sbuf, pSearch); + *pflStart = flCur; + return colPhys(sbuf, pLog (sbuf,flCur.col,TRUE) + lpat) - flCur.col; + } + noise (flCur.lin--); + if (fWrap && (flCur.lin < 0)) { + yMac = pflStart->lin; + flCur.lin = pFile->cLines-1; + } + flCur.col = sizeof(linebuf)-1; + } + } + + /* + * end of search. if a search for all, and found at least one, then return the + * pattern length. Else, return -1. + */ + if (fAll && cAll) { + return lpat; + } + return -1; +} + + + + +/*** REsearch - look for a pattern in a file +* +* REsearch will begin a scan of the file looking for a particular pattern +* in the specified file beginning at the specified location. We perform +* regular expression matching. We return the length and location of the +* match. +* +* Input: +* pFile = pointer to file structure to be searched +* fForward = TRUE => search forward from the specified location +* fAll = TRUE => find and highlight all ocurrances +* fCase = TRUE => case is significant in comparisons +* fWrap = TRUE => search wraps around ends of file +* pat = pointer to compiled pattern +* pflStart = pointers to the location of the beginning of search. Updated +* to reflect the actually found location (or the first found +* for a searchall). +* +* Output: +* Returns length of (first) match if found, -1 if not found +* +*************************************************************************/ +int +REsearch ( + PFILE pFile, + flagType fForward, + flagType fAll, + flagType fCase, + flagType fWrap, + struct patType *pat, + fl *pflStart + ) +{ + fl flCur; + int l, rem; + rn rnCur; /* area to be highlighted */ + linebuf sbuf; + LINE yMac; + unsigned MaxREStack = 512; + RE_OPCODE **REStack = (RE_OPCODE **)ZEROMALLOC (MaxREStack * sizeof(*REStack)); + flagType fAgain; + + assert (pat && pflStart && pFile); + cAll = 0; + flCur = *pflStart; + + if (fForward) { + /* + * forward search. Search every line up until the end of the file. (or up + * until the original start position, if wrap was set). Check for CTRL+C + * break, and get each lines text. + */ + yMac = pFile->cLines; + while (flCur.lin < yMac) { + if (fCtrlc) { + break; + } + if (GetLine (flCur.lin, sbuf, pFile) >= flCur.col) { + fAgain = TRUE; + do { + switch (rem = REMatch (pat, sbuf, pLog (sbuf, flCur.col, TRUE), REStack, MaxREStack, TRUE)) { + + case REM_MATCH: + // + // update rnCur to reflect the logical coordinates of the string actually + // found. + // when real tabs are on, REStart returns the physical character position of + // the found string, which still needs to be mapped to the logical columns. + // + rnCur.flFirst.lin = rnCur.flLast.lin = flCur.lin; + rnCur.flFirst.col = colPhys (sbuf, REStart ((struct patType *) patBuf)); + rnCur.flLast.col = colPhys (sbuf, REStart ((struct patType *) patBuf) + RELength (pat, 0)) - 1; + + // + // If not already found, update the caller's copy. For search-all, add the + // highlight, else for search once, return the length. + // + if (!cAll++) { + *pflStart = rnCur.flFirst; + } + if (fAll) { + SetHiLite (pFile,rnCur,HGCOLOR); + } else { + FREE (REStack); + return rnCur.flLast.col - rnCur.flFirst.col + 1; + } + flCur.col = rnCur.flFirst.col + 1; + break; + + case REM_STKOVR: + // + // The RE machine stack overflowed. Increase and try again + // + MaxREStack += 128; + REStack = (RE_OPCODE **)ZEROREALLOC((PVOID)REStack, MaxREStack * sizeof (*REStack)); + break; + + // + // Either REM_INVALID (we passed in bad parameters), or REM_UNDEF (undefined + // opcode in pattern. Either way, it's an internal error + // + default: + printerror ("Internal Error: RE error %d, line %ld", rem, flCur.lin); + + case REM_NOMATCH: + fAgain = FALSE; + break; + + } + } while (fAgain); + } + noise (flCur.lin++); + + /* + * if wrap around supported, then if we're at the end of the file, wrap around + * to the begining. + */ + if (fWrap && (flCur.lin >= pFile->cLines)) { + yMac = pflStart->lin; + flCur.lin = 0; + } + flCur.col = 0; + } + } else { + /* + * backwards search. Doesn't have to be concerned about searchall, since those + * always occur forward. Otherwise, the same as above, only backwards. + */ + assert (!fAll); + if (flCur.col < 0) { + flCur.lin--; + } + yMac = 0; + while (flCur.lin >= yMac) { + if (fCtrlc) { + break; + } + l = GetLine (flCur.lin, sbuf, pFile); + if (flCur.col < 0) { + flCur.col = l; + } + fAgain = TRUE; + do { + switch (rem = REMatch (pat, sbuf, pLog (sbuf, flCur.col, TRUE), REStack, MaxREStack, FALSE)) { + case REM_MATCH: + pflStart->col = colPhys (sbuf, REStart ((struct patType *) patBuf)); + pflStart->lin = flCur.lin; + FREE (REStack); + return colPhys (sbuf, REStart ((struct patType *) patBuf) + RELength (pat, 0)) + - colPhys (sbuf, REStart ((struct patType *) patBuf)); + + case REM_STKOVR: + MaxREStack += 128; + REStack = (RE_OPCODE **)ZEROREALLOC ((PVOID)REStack, MaxREStack * sizeof(*REStack)); + break; + + default: + printerror ("Internal Error: RE error %d, line %ld", rem, flCur.lin); + + case REM_NOMATCH: + fAgain = FALSE; + break; + } + } while (fAgain); + + flCur.col = -1; + noise (flCur.lin--); + if (fWrap && (flCur.lin < 0)) { + yMac = pflStart->lin; + flCur.lin = pFile->cLines-1; + } + } + } + + FREE (REStack); + + /* + * end of search. if a search for all, and found at least one, then return the + * pattern length. Else, return -1. + */ + if (fAll && cAll) { + return RELength (pat, 0); + } + return -1; + + fCase; +} + + + + +/*** REsearchS - look for a pattern in a file +* +* REsearchS will begin a scan of the file looking for a particular pattern +* in the specified file beginning at the specified location. We perform +* regular expression matching. We return the length and location of the +* match. +* +* REsearchS is the same as REsearch, except that is takes an uncompiled +* string. +* +* Input: +* pFile = pointer to file structure to be searched +* fForward = TRUE => search forward from the specified location +* fAll = TRUE => find and highlight all ocurrances +* fCase = TRUE => case is significant in comparisons +* fWrap = TRUE => search wraps around ends of file +* pat = pointer to RE character string +* pflStart = pointers to the location of the beginning of search. Updated +* to reflect the actually found location (or the first found +* for a searchall). +* +* Output: +* Returns length of (first) match if found, -1 if not found +* +*************************************************************************/ +int +REsearchS ( + PFILE pFile, + flagType fForward, + flagType fAll, + flagType fCase, + flagType fWrap, + char *pat, + fl *pflStart + ) +{ + assert (pat && pflStart && pFile); + if (patBuf != NULL) { + FREE ((char *) patBuf); + } + patBuf = RECompile (pat, fCase, (flagType)!fUnixRE); + if (patBuf == NULL) { + printerror ( (RESize == -1) ? "Invalid pattern" : "Not enough memory for pattern"); + return -1; + } + return REsearch (pFile, fForward, fAll, fCase, fWrap, patBuf, pflStart); + +} |