home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / dos / edit / point20 / search.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-02-04  |  22.9 KB  |  904 lines

  1. #include "pt.h"
  2. #include "string.h"
  3.  
  4. static unsigned char originalFromString[STRINGSIZE+1];
  5. static unsigned char fromString[STRINGSIZE+1];
  6. static unsigned char originalToString[STRINGSIZE+1];
  7. static unsigned char toString[STRINGSIZE+1];
  8.  
  9. void pascal
  10. /* XTAG:replaceText */
  11. replaceText(w)
  12.     struct window *w;
  13. {
  14.     extern struct window *selWindow;
  15.     extern long selBegin, selEnd;
  16.     extern int selMode;
  17.     extern unsigned char msgBuffer[];
  18.     extern unsigned char textBuffer[];
  19.     extern int ignoreCase;
  20.     extern int topOnFind;
  21.     extern long addPosition;
  22.     extern int nextChange;
  23.     extern struct changeItem *change;
  24.     extern unsigned int bytesLeft;
  25.     extern unsigned char *userMessages[];
  26.     extern unsigned int piecesLeft;
  27.     extern int debug;
  28.     extern struct openFile *files;
  29.  
  30.     struct window *saveSelWindow;
  31.     long saveSelBegin, saveSelEnd, repEnd;
  32.     int n, fileId, fromLength;
  33.     int nLines, verify, replace, nReplaces;
  34.     int inSelection, diffLengths;
  35.     int saveIgnoreCase;
  36.     long cp, toLength, fSize;
  37.     unsigned char ch, *s;
  38.     struct piece *tempPP, *newPP;
  39.     struct changeItem *thisChange;
  40.  
  41.     fileId = w->fileId;
  42.     fSize = fileSize(fileId);
  43.     nReplaces = 0;
  44.     
  45.     /* check if this is a readOnly file */
  46.     if( files[fileId].readOnly ) {
  47.         sprintf(msgBuffer, userMessages[READONLYFILE],
  48.             files[fileId].origName);
  49.         msg(msgBuffer, 1);
  50.         return;
  51.     }
  52.  
  53.     /* get the string to search for */
  54.     s = getInput("String to replace: ", originalFromString, 0);
  55.     /* ESCape or empty string cancels the replace */
  56.     if( s == NULL || s[0] == '\0' )
  57.         goto cancelReplace;
  58.     strncpy(originalFromString, s, STRINGSIZE+1);
  59.     s = originalFromString;
  60.  
  61.     /* process the string to handle the newline, CR, and LF escapes */
  62.     n = 0;
  63.     saveIgnoreCase = ignoreCase;
  64.     while( 1 ) {
  65.         ch = *s;
  66.         if( isupper(ch) && ignoreCase /* case insensitive */)
  67.             ch = tolower(ch);
  68.         switch( ch ) {
  69.         case '\\':
  70.             ch = *++s;
  71.             if( ch == 'r' )
  72.                 ch = '\r';
  73.             else if( ch == 'N' )
  74.                 ch = '\n';
  75.             else if( ch == 'n' ) {
  76.                 fromString[n++] = '\r';
  77.                 ch = '\n';
  78.             }
  79.             break;
  80.         default:
  81.             break;
  82.         }
  83.         fromString[n++] = ch;
  84.         if( ch == '\0' )
  85.             break;
  86.         ++s;
  87.         if( n >= STRINGSIZE )
  88.             --n;
  89.     }
  90.  
  91.     /* get the replacment string */
  92.     sprintf(msgBuffer, "Replace `%s' with: ", originalFromString);
  93.     s = getInput(msgBuffer, originalToString, 0);
  94.     if( s == NULL )
  95.         goto cancelReplace;
  96.     strncpy(originalToString, s, STRINGSIZE);
  97.     s = originalToString;
  98.     /* process the replacement string for escapes */
  99.     n = 0;
  100.     while( 1 ) {
  101.         ch = *s++;
  102.         switch( ch ) {
  103.         case '\\':
  104.             ch = *s++;
  105.             if( ch == 'r' )
  106.                 ch = '\r';
  107.             else if( ch == 'N' )
  108.                 ch = '\n';
  109.             else if( ch == 'n' ) {
  110.                 toString[n++] = '\r';
  111.                 ch = '\n';
  112.             }
  113.             break;
  114.         default:
  115.             break;
  116.         }
  117.         toString[n++] = ch;
  118.         if( ch == '\0' )
  119.             break;
  120.     }
  121.     
  122.     /* replace in the selection only? */
  123.     s = getInput("Globally (g) or Within Selection (s): ", "g", 1);
  124.     if( s == NULL )
  125.         goto cancelReplace;
  126.     else if( tolower(s[0]) == 'g' || s[0] == 'y' )
  127.         /* the getInput will return a 'y' of the left mouse button */
  128.         /* is clicked. Construe that as a 'g' and RMB ar an 's' */
  129.         inSelection = 0;
  130.     else
  131.         inSelection = 1;
  132.  
  133.     /* verify each replacement? */
  134.     s = getInput("Verify each change? (y or n): ", "y", 1);
  135.     if( s == NULL ) {
  136. cancelReplace:
  137.         msg("Replace cancelled", 1);
  138.         ignoreCase = saveIgnoreCase;
  139.         return;
  140.     }
  141.     /* save the verify boolean for later use */
  142.     verify = !(tolower(s[0]) == 'n');
  143.  
  144.     /* Create a piece for the replacement string and record it in */
  145.     /* the piece buffer.  This makes it easy to insert the replace */
  146.     /* string by copying this piece */
  147.     toLength = strlen(toString);
  148.     tempPP = getFreePiece();
  149.  
  150.     tempPP->file = ADDFILE;
  151.     tempPP->position = addPosition;
  152.     for(n = 0; n < (int)toLength; n++ )
  153.         writeChar(toString[n], addPosition++);
  154.     tempPP->length = toLength;
  155.  
  156.     /* start from the selection or the beginning */
  157.     if( inSelection ) {
  158.         cp = selBegin;
  159.         repEnd = selEnd;
  160.         w = selWindow;
  161.     } else {
  162.         if( w == selWindow )
  163.             cp = selBegin;
  164.         else
  165.             cp = 0;
  166.         repEnd = fSize;
  167.     }
  168.     
  169.     /* How will the replace change character counts? */
  170.     /* we need to adjust repEnd after each replace */
  171.     diffLengths = strlen(toString) - strlen(fromString);
  172.  
  173.     /* set things up so the line counts will be right */
  174.     if( readChar(fileId, cp) == '\n' )
  175.         nLines = 1;
  176.     else
  177.         nLines = 0;
  178.  
  179.     /* save the location of the current selection */
  180.     if( !verify ) {
  181.         saveSelWindow = selWindow;
  182.         saveSelBegin = selBegin;
  183.         saveSelEnd = selEnd;
  184.     }
  185.     
  186.     fromLength = strlen(fromString);
  187.  
  188. /* while loop to repeat the replace */
  189. while( 1 ) {
  190.  
  191.     if( !verify ) {
  192.         sprintf(msgBuffer, "Replace is %d%% completed",
  193.             (int)((100*cp)/fSize));
  194.         msg(msgBuffer, 1);
  195.     }
  196.  
  197.     /* find the string */
  198.     cp = searchSpans(fileId, cp, repEnd, fromString, fromLength, &n);
  199.     nLines += n;
  200.     if( cp == (long)(-1) )
  201.         break;
  202.     if( selWindow != w ) {
  203.         eraseSelection();
  204.         selWindow = w;
  205.     }
  206.     selBegin = cp;
  207.     selEnd = selBegin + fromLength - 1;
  208.     selMode = SELCHAR;
  209.  
  210.     /* remember where we came from */
  211.     selWindow->rowLastline = selWindow->numTopline;
  212.     
  213.     /* replace? */
  214.     if( verify ) {
  215.         /* put the selection on the third line */
  216.         if( selBegin >= selWindow->posBotline 
  217.          || selBegin < selWindow->posTopline ) {
  218.             n = 3;
  219.             selWindow->posTopline = prevLine(fileId, selBegin, &n);
  220.             selWindow->numTopline += nLines - n;
  221.         }
  222.         (void)indentToShowSelection(-1);
  223.         /* show the string we found */
  224.         if( topOnFind )
  225.             topWindow(selWindow);
  226.         redrawWindow(selWindow);
  227.         sprintf(msgBuffer,
  228. "[At %d%% of file] Replace this one? (y or n -- Esc to cancel) ",
  229.             (int)((100*cp)/fSize) );
  230.         s = getInput(msgBuffer, "y", 1);
  231.         if( s == NULL )
  232.             goto notFound;
  233.         replace = tolower(s[0])=='y';
  234.     } else
  235.         replace = 1;
  236.     
  237.     /* do the replace */
  238.     if( replace ) {
  239.         deleteChars(selWindow->fileId, NOUPDATE, 0);
  240.         
  241.         /* record in the change history */
  242.         IncrementNextChange();
  243.         thisChange = &change[nextChange];
  244.         thisChange->type = CINSERT;
  245.         thisChange->position = selBegin;
  246.         thisChange->length = toLength;
  247.         thisChange->fileId = selWindow->fileId;
  248.         newPP = getFreePiece();
  249.         newPP->file = ADDFILE;
  250.         newPP->position = tempPP->position;
  251.         newPP->length = toLength;
  252.         thisChange->firstPiece = newPP;
  253.         
  254.         copyPieces(tempPP, selWindow, selBegin, toLength, verify);
  255.         cp = selBegin;
  256.         /* as we change the length of the text in the file with */
  257.         /* a replacement, we have to adjust repEnd so that we  */
  258.         /* will not quit early */
  259.         repEnd += diffLengths;
  260.  
  261.         if( inSelection ) {
  262.             /* if we are not verifying, we want the final */
  263.             /* selection to be the same as the original */
  264.             /* selection even though we are replaceing */
  265.             /* inside it.  This makes the adjustment */
  266.             if( !verify )
  267.                 saveSelEnd += diffLengths;
  268.         }
  269.         ++nReplaces;
  270.         /* see if we are running out of space */
  271.         if( (bytesLeft < SPACELOW)  && (piecesLeft <= 10) ) {
  272.             msg(userMessages[LOWSPACEMSG], 3);
  273.             goto notFound;
  274.         }
  275.     } else
  276.         cp = selBegin + 1;
  277. }
  278.  
  279. notFound:
  280.     /* free the temp piece */
  281.     freePieces(tempPP);
  282.  
  283.     /* restore the previous selection */
  284.     if( !verify ) {
  285.         selWindow = saveSelWindow;
  286.         selBegin = saveSelBegin;
  287.         selEnd = saveSelEnd;
  288.         redrawWindow(selWindow);
  289.     }
  290.     sprintf(msgBuffer, "Made %d replacement%s", nReplaces,
  291.         nReplaces==1?"":"s");
  292.     msg(msgBuffer, 1);
  293.     ignoreCase = saveIgnoreCase;
  294. }
  295.  
  296. static unsigned char originalSearchString[STRINGSIZE+1];
  297. static unsigned char searchString[STRINGSIZE+1];
  298. static long foundCp;    /* used to return cp in on-interactive search */
  299.  
  300. long pascal
  301. /* XTAG:searchExternal */
  302. searchExternal(s, w, newSearchMode, newIgnoreCase)
  303.     unsigned char *s;
  304.     struct window *w;
  305.     int newSearchMode, newIgnoreCase;
  306. {
  307.     extern int ignoreCase;
  308.     extern int searchMode;
  309.  
  310.     int saveSearchMode, saveIgnoreCase;
  311.  
  312.     /* save and change the search mode state */
  313.     saveSearchMode = searchMode;
  314.     searchMode = newSearchMode;
  315.     saveIgnoreCase = ignoreCase;
  316.     ignoreCase = newIgnoreCase;
  317.  
  318.     strncpy(originalSearchString, s, STRINGSIZE+1);
  319.     searchFor(3, w);    /* 3 means non-interactive */
  320.  
  321.     /* restore the old search mode state */
  322.     searchMode = saveSearchMode;
  323.     ignoreCase = saveIgnoreCase;
  324.  
  325.     return foundCp;
  326. }
  327.  
  328. int pascal
  329. /* XTAG:searchFor */
  330. searchFor(repeatLast, w)
  331.     int repeatLast;
  332.     struct window *w;
  333. {
  334.     extern struct window *selWindow;
  335.     extern long selBegin, selEnd;
  336.     extern int selMode;
  337.     extern unsigned char msgBuffer[];
  338.     extern unsigned char textBuffer[];
  339.     extern int ignoreCase;
  340.     extern int searchMode;
  341.     extern int realSearchMode;
  342.     extern int topOnFind;
  343.     extern int linesOverFind;
  344.     extern int pathNames;
  345.     extern struct openFile *files;
  346.     extern int debug;
  347.     extern int reSearch;
  348.     extern int reLength;
  349.     extern char reIn[];
  350.  
  351.     int n, i, linesFromTop, fileId, fid2, nLines;
  352.     int patLength;
  353.     int saveIgnoreCase, wrappedAround = 0;
  354.     long cp, cp2, startCp, stopCp;
  355.     unsigned char ch, *p, *s;
  356.  
  357.     fileId = w->fileId;
  358.     saveIgnoreCase = ignoreCase;
  359.  
  360.     switch( repeatLast ) {
  361.  
  362.     case 0:        /* ask for the search string */
  363.         /* get the string to search for */
  364.         s = getInput("Search string: ", originalSearchString, 0);
  365.         if( s == NULL ) {
  366.             msg("Search for string cancelled", 1);
  367.             return 1;
  368.         }
  369.         /* first make a copy of the search string */
  370.         strncpy(originalSearchString, s, STRINGSIZE+1);
  371.         if( reSearch ) {
  372.             strcpy(searchString, originalSearchString);
  373.             RETableSetup();
  374.             strcpy(reIn, originalSearchString);
  375.             if( !RECompile() ) {
  376.                 return 1;
  377.             }
  378.             break;
  379.         }
  380.     processString:
  381.         /* then get a pointer to it that we can change */
  382.         s = originalSearchString;
  383.         if( s[0] != '\0' ) {    /* non-empty string? */
  384.             p = searchString;
  385.             while( 1 ) {
  386.                 ch = *s;
  387.                 /* case insensitive search? */
  388.                 if( isupper(ch) && ignoreCase )
  389.                     ch = tolower(ch);
  390.                 switch( ch ) {
  391.                 case '\\':
  392.                     ch = *++s;
  393.                     if( ch == 'r' )
  394.                         ch = '\r';
  395.                     else if( ch == 'N' )
  396.                         ch = '\n';
  397.                     else if( ch == 'n' ) {
  398.                         *p++ = '\r';
  399.                         ch = '\n';
  400.                     }
  401.                     break;
  402.                 default:
  403.                     break;
  404.                 }
  405.                 *p = ch;
  406.                 if( *p++ == '\0' )
  407.                     break;
  408.                 ++s;
  409.                 if( p-searchString >= STRINGSIZE ) {
  410.                     *--p = '\0';
  411.                     *--s = '\0';
  412.                     break;
  413.                 }
  414.             }
  415.         }
  416.         /* else if string is empty, reuse the last string entered */
  417.         break;
  418.  
  419.     case 1:        /* use the selection as a search string */
  420.         /* we will make an original copy and a processed copy */
  421.         s = originalSearchString;
  422.         p = searchString;
  423.         cp = selBegin;
  424.         fid2 = selWindow->fileId;
  425.         while( cp <= selEnd ) {
  426.             ch = readChar(fid2, cp++);
  427.             *s++ = ch;    /* original copy */
  428.             /* case insensitive search? */
  429.             if( isupper(ch) && ignoreCase )
  430.                 ch = tolower(ch);
  431.             *p++ = ch;    /* processed copy */
  432.             if( (p-searchString) >= STRINGSIZE ) {
  433.                 /* truncate long search strings */
  434.                 --p;
  435.                 --s;
  436.                 break;
  437.             }
  438.         }
  439.         *p = '\0';
  440.         *s = '\0';
  441.         if( reSearch ) {
  442.             strcpy(searchString, originalSearchString);
  443.             RETableSetup();
  444.             strcpy(reIn, originalSearchString);
  445.             if( !RECompile() ) {
  446.                 return 1;
  447.             }
  448.             break;
  449.         }
  450.         break;
  451.  
  452.     case 2:        /* use the last entered string */
  453.     case 3:
  454.         goto processString;
  455.     }
  456.     /* do not allow searching for the empty string */
  457.     if( searchString[0] == '\0' ) {
  458.         sprintf(msgBuffer, "Search string is empty");
  459.         goto errorExit;
  460.     }
  461.  
  462.     switch( searchMode ) {
  463.     case 0:
  464.         s = "forwards";
  465.         break;
  466.     case 1:
  467.         s = "backwards";
  468.         break;
  469.     case 2:
  470.         s = "circularly";
  471.         break;
  472.     case 3:
  473.         n = (pathNames ? 0 : w->nameOffset);
  474.         s = &((files[w->fileId].origName)[n]);
  475.         break;
  476.     }
  477.     if( repeatLast != 3 ) {
  478.         sprintf(msgBuffer, "Searching %s for `%s'", s,
  479.             originalSearchString);
  480.         msg(msgBuffer, 1);
  481.     }
  482.     patLength = strlen(searchString);
  483.     n = -1;
  484.     if( readChar(fileId, cp) == '\n' )
  485.         nLines = 1;
  486.     else
  487.         nLines = 0;
  488.     cp = fileSize(w->fileId);
  489.     if( searchMode == 1 ) {
  490.         startCp = 0;
  491.         if( w == selWindow )
  492.             stopCp = selBegin - 1;
  493.         else
  494.             stopCp = cp - 1;
  495.     } else {    /* seachMode == 0 or == 2 */
  496.         stopCp = cp;
  497.         if( w == selWindow ) {
  498.             startCp = selBegin + 1;
  499.             if( startCp >= stopCp ) {    /* already done? */
  500.                 if( searchMode == 0 || searchMode == 3 )
  501.                     goto notFound;
  502.                 else    /* searchMode==2 */
  503.                     startCp = 0;
  504.             }
  505.         } else
  506.             startCp = 0;
  507.     }
  508.     linesFromTop = 0;
  509.     /* adjust the line number */
  510.     /* just put in the two while loops and forget the IF test */
  511.     /* at most one of the WHILE loops will actually loop */
  512.     /* adjust for backwards searching */
  513.     cp2 = w->posTopline;
  514.     if( searchMode == 1 ) {
  515.         cp = stopCp + 1;
  516.         if( cp > fileSize(w->fileId) )
  517.             --cp;
  518.     } else {
  519.         cp = startCp - 1;
  520.         if( cp < 0 )
  521.             cp = 0;
  522.     }
  523.     /* normalize cp to the beginning of its line */
  524.     i = -1;
  525.     cp = prevLine(fileId, cp, &i);
  526.     while( cp2 < cp ) {
  527.         ++linesFromTop;
  528.         i = 1;
  529.         cp2 = nextLine(fileId, cp2, &i);
  530.     }
  531.     while( cp2 > cp ) {
  532.         --linesFromTop;
  533.         i = 1;
  534.         cp2 = prevLine(fileId, cp2, &i);
  535.     }
  536.  
  537.     switch( searchMode ) {
  538.     default:
  539.     case 3:
  540.     case 0:
  541.         if( reSearch )
  542.             cp = reSpans(fileId, startCp, stopCp,
  543.                 &patLength, &n);
  544.         else
  545.             cp = searchSpans(fileId, startCp, stopCp,
  546.                 searchString, patLength, &n);
  547.         nLines += n;
  548.         break;
  549.     case 1:
  550.         cp = searchReverseSpans(fileId, startCp, stopCp,
  551.                 searchString, patLength, &n);
  552.         nLines -= n;
  553.         /* a fix so that backwards search from the backwards */
  554.         /* search command is circular if the normal search */
  555.         /* mode is circular */
  556. /********************* DO NOT DO THIS YET ************
  557.  THE PROBLEM IS GETTING THE LINE NUMBERS TO WORK OUT
  558.  FINISH IT LATER
  559.         if( cp == -1 && realSearchMode == 2 ) {
  560.             wrappedAround = 1;
  561.             cp = searchReverseSpans(fileId, stopCp,
  562.                 fileSize(w->fileId) - patLength,
  563.                 searchString, patLength, &n);
  564.             nLines = n;
  565.             linesFromTop = -(selWindow->numTopline);
  566.         }
  567. *******************************************************/
  568.         break;
  569.     case 2:
  570.         if( reSearch )
  571.             cp = reSpans(fileId, startCp, stopCp,
  572.                 &patLength, &n);
  573.         else
  574.             cp = searchSpans(fileId, startCp, stopCp,
  575.                 searchString, patLength, &n);
  576.         nLines += n;
  577.         if( cp == -1 ) {
  578.             wrappedAround = 1;
  579.             if( reSearch )
  580.                 cp = reSpans(fileId, 0L, startCp,
  581.                     &patLength, &n);
  582.             else
  583.                 cp = searchSpans(fileId, 0L, startCp,
  584.                     searchString, patLength, &n);
  585.             nLines = n;
  586.             linesFromTop = -(selWindow->numTopline);
  587.         }
  588.         break;
  589.     }
  590.  
  591.     if( repeatLast == 3 ) {
  592.         foundCp = cp;
  593.         return 0;
  594.     }
  595.  
  596.     if( cp != -1 ) {
  597.         if( selWindow != w ) {
  598.             eraseSelection();
  599.             selWindow = w;
  600.         }
  601.         selBegin = cp;
  602.         selEnd = selBegin + patLength - 1;
  603.         selMode = SELCHAR;
  604.     } else
  605.         goto notFound;
  606.  
  607.     if( selBegin >= selWindow->posBotline 
  608.      || selBegin < selWindow->posTopline ) {
  609.         /* remember where we came from */
  610.         selWindow->rowLastline = selWindow->numTopline;
  611.          n = -1;
  612.         cp2 = prevLine(fileId, selBegin, &n);
  613.         /* find the number of lines in the window */
  614.         n = selWindow->row2 - selWindow->row1 - 2;
  615.         if( linesOverFind > n )
  616.             /* if linesOverFind would place it outside the */
  617.             /* window then put it in the middle of the window */
  618.             n >>= 1;
  619.         else
  620.             /* otherwise put it linesOverFind lines down */
  621.             n = linesOverFind;
  622.         selWindow->posTopline = prevLine(fileId, cp2, &n);
  623.         selWindow->numTopline += linesFromTop + nLines - n;
  624.     }
  625.     (void)indentToShowSelection(-1);
  626.     if( topOnFind )
  627.         topWindow(selWindow);
  628.     redrawWindow(selWindow);
  629.     /* this will erase the "Searching for..." msg in the case where */
  630.     /* the selWindow does not extend to the bottom line */
  631.     if( wrappedAround )
  632.         msg( "Circular search has wrapped around"
  633.             " the beginning of the file", 1);
  634.     else
  635.         msg("", 1);
  636.     ignoreCase = saveIgnoreCase;
  637.     return 1;
  638. notFound:
  639.     sprintf(msgBuffer, "String `%s' not found.", searchString);
  640. errorExit:
  641.     msg(msgBuffer, 1);
  642.     ignoreCase = saveIgnoreCase;
  643.     return 0;
  644. }
  645.  
  646. extern unsigned    char *
  647.     match1dn( unsigned char far *, int, unsigned char, unsigned char );
  648. extern unsigned char *
  649.     match2dn( unsigned char far *, int, unsigned char );
  650. extern int countnl( unsigned char far *, int );
  651.  
  652. long pascal
  653. /* XTAG:searchSpans */
  654. searchSpans(fileId, startCp, stopCp, patString, patLength, linesPassed)
  655.     int fileId, patLength, *linesPassed;
  656.     long startCp, stopCp;
  657.     unsigned char *patString;
  658. {
  659.     extern unsigned char msgBuffer[];
  660.     extern int ignoreCase;
  661.     extern int findWholeWords;
  662.     extern int debug;
  663.  
  664.     unsigned char *pat;
  665.     unsigned char far *firstChar;
  666.     unsigned char far *lastChar;
  667.     unsigned char *p;
  668.     unsigned char ch1, ch2, ch3;
  669.     int matched, len, nLines;
  670.     long cp, longPatLength;
  671.  
  672.     /* find the upper and lower case character */
  673.     ch1 = *patString;
  674.     if( !ignoreCase )
  675.         ch2 = ch1;
  676.     else if( 'a' <= ch1 && ch1 <= 'z' )
  677.         ch2 = ch1 - 'a' + 'A';
  678.     else if( 'A' <= ch1 && ch1 <= 'Z' )
  679.         ch2 = ch1 - 'A' + 'a';
  680.     else
  681.         ch2 = ch1;
  682.  
  683.     /* set up a long version of patLength-1 for comparisons */
  684.     longPatLength = (long)(patLength - 1);
  685.     
  686.     nLines = 0;
  687.     
  688.     /* set things up so getSpan is called right away */
  689.     firstChar = (unsigned char far *)1;
  690.     lastChar = (unsigned char far *)0;
  691.  
  692.     /* each iteration of this loop scans one span */
  693.     while( 1 ) {
  694.         /* see if there are enough characters left in the */
  695.         /* area we are searching to match the pattern */
  696.         if( (stopCp - startCp) < longPatLength )
  697.             break;
  698.  
  699.         /* find the first character of the string */
  700.         if( firstChar > lastChar ) {
  701.             if(getSpan(fileId,startCp,&firstChar,&lastChar,0))
  702.                 /* getSpan says startCp at EOF */
  703.                 break;
  704.             /* check to see if the span is longer than the */
  705.             /* area we are supposed to search */
  706.             if( (long)(lastChar-firstChar) > (stopCp-startCp) ) {
  707.                 /* if it is too long then adjust lastChar */
  708.                 lastChar = firstChar + (stopCp - startCp);
  709.             }
  710.         }
  711.         len = (int)(lastChar - firstChar) + 1;
  712.         if( ch1 == ch2 )
  713.             p = match2dn(firstChar, len, ch1);
  714.         else
  715.             p = match1dn(firstChar, len, ch1, ch2);
  716.         if( p == (unsigned char *)0xFFFE ) {
  717.             startCp += len;
  718.             nLines += countnl(firstChar, len);
  719.             firstChar = (unsigned char far *)1;
  720.             lastChar = (unsigned char far *)0;
  721.             continue;
  722.         }
  723.         /* move startCp up past the matched character */
  724.         len = p - (unsigned char *)(FP_OFF(firstChar));
  725.         nLines += countnl(firstChar, len);
  726.         startCp += len;
  727.         
  728.         /* change the offset of firstChar, segment not changed */
  729.         *( (unsigned char **)(&firstChar) ) = p;
  730.  
  731.         /* start looking at the second character of the pattern */
  732.         pat = patString + 1;
  733.         matched = 1;    /* 1 character matched so far */
  734.         
  735.         /* search for a match at startCp */
  736.         cp = startCp;
  737.         while( matched < patLength ) {
  738.             /* see if we are still in the span */
  739.             if( firstChar > lastChar )
  740.                 getSpan(fileId, cp, &firstChar, &lastChar, 0);
  741.             /* stop at a mismatch */
  742.             ch3 = *firstChar++;
  743.             ++cp;
  744.             if( ignoreCase && 'A' <= ch3 && ch3 <= 'Z' )
  745.                 ch3 = ch3 - 'A' + 'a';
  746.             if( *pat++ != ch3 )
  747.                 break;
  748.             if( ch3 == '\n' )
  749.                 ++nLines;
  750.             ++matched;
  751.         }
  752.         if( matched == patLength ) {
  753.             /* we found the string */
  754.             /* now does it have to be a whole word? */
  755.             if( findWholeWords ) {
  756.                 /* make sure the character before it is */
  757.                 /* not alphanumeric or "_" */
  758.                 ch3 = readChar(fileId, startCp-2);
  759.                 matched = !isalnum(ch3) && ch3 != '_';
  760.                 if( matched ) {
  761.                     /* and the char after it also */
  762.                     ch3 = readChar(fileId,
  763.                         startCp+patLength-1);
  764.                     matched =
  765.                         !isalnum(ch3) && ch3 != '_';
  766.                 }
  767.             } else
  768.                 matched = 1;
  769.             if( matched ) {
  770.                 *linesPassed = nLines;
  771.                 return startCp - 1;
  772.             }
  773.         }
  774.         firstChar = (unsigned char far *)1;
  775.         lastChar = (unsigned char far *)0;
  776.     }
  777.     *linesPassed = nLines;
  778.     return (long)(-1);
  779. }
  780.  
  781. extern unsigned char *
  782.     match1up( unsigned char far *, int, unsigned char, unsigned char );
  783.  
  784. long pascal
  785. /* XTAG:searchReverseSpans */
  786. searchReverseSpans(fileId, startCp, stopCp, patString, patLength, linesPassed)
  787.     int fileId, patLength, *linesPassed;
  788.     long startCp, stopCp;
  789.     unsigned char *patString;
  790. {
  791.     extern unsigned char msgBuffer[];
  792.     extern int ignoreCase;
  793.     extern int debug;
  794.     extern int findWholeWords;
  795.  
  796.     unsigned char *pat;
  797.     unsigned char far *firstChar;
  798.     unsigned char far *lastChar;
  799.     unsigned char *p;
  800.     unsigned char ch1, ch2, ch3;
  801.     int matched, len, nLines;
  802.     long cp;
  803.  
  804.     /* find the upper and lower case character */
  805.     ch1 = *patString;
  806.     if( !ignoreCase )
  807.         ch2 = ch1;
  808.     else if( 'a' <= ch1 && ch1 <= 'z' )
  809.         ch2 = ch1 - 'a' + 'A';
  810.     else if( 'A' <= ch1 && ch1 <= 'Z' )
  811.         ch2 = ch1 - 'A' + 'a';
  812.     else
  813.         ch2 = ch1;
  814.  
  815.     /* set up nLines correctly */
  816.     nLines = 0;
  817.     len = patLength - 1;
  818.  
  819.     /* set things up so getSpan is called right away */
  820.     firstChar = (unsigned char far *)1;
  821.     lastChar = (unsigned char far *)0;
  822.  
  823.     /* each iteration of this loop scans one span */
  824.     while( stopCp >= startCp ) {
  825.  
  826.         /* find the first character of the string */
  827.         if( firstChar > lastChar ) {
  828.             /* '1' (last argument) means get a reversed span */
  829.             getSpan(fileId, stopCp, &firstChar, &lastChar, 1);
  830.         }
  831.         len = (int)(lastChar - firstChar) + 1;
  832.         p = match1up(lastChar, len, ch1, ch2);
  833.         if( p == (unsigned char *)0xFFFE ) {
  834.             stopCp -= len;
  835.             nLines += countnl(firstChar, len);
  836.             firstChar = (unsigned char far *)1;
  837.             lastChar = (unsigned char far *)0;
  838.             continue;
  839.         }
  840.         /* move stopCp up past the matched character */
  841.         /* (remember that match1up returns a pointer to the */
  842.         /* character BEFORE the one matched) */
  843.         len = FP_OFF(lastChar) - (unsigned)p;
  844.         stopCp -= len;
  845.         /* Special case: If the character was found in position */
  846.         /* 0 then match1up returns -1 (0xFFFF) to p.  The len */
  847.         /* calculation above works but this makeFarPointer will */
  848.         /* not so we change it to 0 so the line count is okay. */
  849.         if( (unsigned)p == 0xFFFF )
  850.             p = 0;
  851.         firstChar = makeFarPointer((unsigned int)p, FP_SEG(lastChar));
  852.         nLines += countnl(firstChar, len);
  853.         firstChar = (unsigned char far *)1;
  854.         lastChar = (unsigned char far *)0;
  855.  
  856.         /* start looking at the second character of the pattern */
  857.         pat = patString + 1;
  858.         matched = 1;    /* 1 matched character so far */
  859.         
  860.         /* search for a match at startCp */
  861.         cp = stopCp + 2;
  862.         while( matched < patLength ) {
  863.             /* see if we are still in the span */
  864.             if( firstChar > lastChar ) {
  865.                 getSpan(fileId, cp, &firstChar, &lastChar, 0);
  866.             }
  867.             /* stop at a mismatch */
  868.             ch3 = *firstChar++;
  869.             ++cp;
  870.             if( ignoreCase && 'A' <= ch3 && ch3 <= 'Z' )
  871.                 ch3 = ch3 - 'A' + 'a';
  872.             if( *pat++ != ch3 )
  873.                 break;
  874.             ++matched;
  875.         }
  876.         if( matched == patLength ) {
  877.             /* we found the string */
  878.             /* now does it have to be a whole word? */
  879.             if( findWholeWords ) {
  880.                 /* make sure the character before it is */
  881.                 /* not alphanumeric or "_" */
  882.                 ch3 = readChar(fileId, stopCp);
  883.                 matched = !isalnum(ch3) && ch3 != '_';
  884.                 if( matched ) {
  885.                     /* and the char after it also */
  886.                     ch3 = readChar(fileId,
  887.                         stopCp+patLength+1);
  888.                     matched =
  889.                         !isalnum(ch3) && ch3 != '_';
  890.                 }
  891.             } else
  892.                 matched = 1;
  893.             if( matched ) {
  894.                 *linesPassed = nLines;
  895.                 return stopCp + 1;
  896.             }
  897.         }
  898.         firstChar = (unsigned char far *)1;
  899.         lastChar = (unsigned char far *)0;
  900.     }
  901.     *linesPassed = nLines;
  902.     return (long)(-1);
  903. }
  904.