/*** fscan.c - iterate a function across all characters in a file
*
*   Copyright <C> 1988, Microsoft Corporation
*
*   Revision History:
*
*	27-Nov-1991 mz	Strip procedure qualifiers
*
*************************************************************************/
#include "mep.h"

/*** fScan - Apply (*pevent)() until it returns TRUE
*
*  Starting one character to the right of (x, y) (left for !fFor), move
*  through the file forward (backward for !fFor) and call pevent on each
*  character. Also call once at the end of each line on the '\0' character.
*
* Input:
*  flStart	- location in pFileHead at which to start scan
*  pevent	- function to call for done signal
*  fFor 	- TRUE means go forward through file, FALSE backwards
*  fWrap	- TRUE means wrap around the ends of the file, ending at the
*		  starting position. The range to be scanned (defined below)
*		  must include the appropriate start/end of the file.
*
* Globals:
*  rnScan	- Region to confine scan to.
*
*  Returns TRUE if pevent returned true for some file position FALSE if we
*  ran out of scanning region first.
*
*  During the life of fScan, the following globals are valid, and maybe
*  used by pevent:
*
*      flScan	    - Position in file pevent should look at.
*      scanbuf	    - Contents of line to be looking at.
*      scanreal     - Un-Detabbed version of same.
*      scanlen	    - Number of characters in scanbuf.
*
*  The line in scanbuf is detabbed, howver the pevent routine is called once
*  per physical character, if fRealTabs is true.
*
*************************************************************************/
flagType
fScan (
    fl      flStart,
    flagType (*pevent) (void),
    flagType fFor,
    flagType fWrap
    ) {

    LINE    yLim;                           /* limitting line for scanning  */

    flScan = flStart;

    if (!fFor) {
        /*
         * backwards scan.
         *
         * dec current column. If it steps outside of rnScan, then back up a line, and
         * set the column to the right hand column.
         */
        if (--flScan.col < rnScan.flFirst.col) {
            flScan.lin--;
            flScan.col = rnScan.flLast.col;
        }
        /*
         * While we are within the line range of rnScan, check for CTRL-C aborts, and
         * get each line.
         */
        yLim = rnScan.flFirst.lin;
        while (flScan.lin >= yLim) {
            if (fCtrlc) {
                return (flagType)!DoCancel();
            }
            scanlen = GetLine (flScan.lin, scanreal, pFileHead) ;
            scanlen = Untab (fileTab, scanreal, scanlen, scanbuf, ' ');
            /*
             * ensure that the scan column position is within range, and then for every
             * column in the rane of the current line, call the pevent routine
             */
            flScan.col = min ( (  flScan.col < 0
                                ? rnScan.flLast.col
                                : flScan.col)
                              , scanlen);

            while (flScan.col >= rnScan.flFirst.col) {
                if ((*pevent)()) {
                    return TRUE;
                }
                if (fRealTabs) {
                    flScan.col = colPhys (scanreal, (pLog (scanreal, flScan.col, TRUE) - 1));
                } else {
                    flScan.col--;
                }
            }
            /*
             * display status to user. If we just scanned to begining of file, and we are
             * to wrap, then set the new stop limit as the old start position, and set the
             * next line to be scanned as the last in the file.
             */
            noise (flScan.lin--);
            if ((flScan.lin < 0) && fWrap) {
                yLim = flStart.lin;
                flScan.lin = pFileHead->cLines - 1;
            }
        }
    } else {
        /*
         * forwards scan. Same structure as above, only in the other direction.
         */
        flScan.col++;
        yLim = rnScan.flLast.lin;
        while (flScan.lin <= yLim) {
            if (fCtrlc) {
                return (flagType)!DoCancel();
            }
            scanlen = GetLine (flScan.lin, scanreal, pFileHead);
            scanlen = Untab (fileTab, scanreal, scanlen, scanbuf, ' ');
            scanlen = min (rnScan.flLast.col, scanlen);
            while (flScan.col <= scanlen) {
                if ((*pevent)()) {
                    return TRUE;
                }
                if (fRealTabs) {
                    flScan.col = colPhys (scanreal, (pLog (scanreal, flScan.col, TRUE) + 1));
                } else {
                    flScan.col++;
                }
            }
            flScan.col = rnScan.flFirst.col;
            noise (++flScan.lin);
            if (fWrap && (flScan.lin >= pFileHead->cLines)) {
                flScan.lin = 0;
                if (flStart.lin) {
                    yLim = flStart.lin - 1;
                } else {
                    break;
                }
            }
        }
    }
    return FALSE;
}




/*** setAllScan - set maximal scan range
*
*  Sets scan range such that fScan operates on the entire file.
*
* Input:
*  fDir 	= TRUE => scan will procede forwards, else backwards
*
* Output:
*  Returns nothing
*
*************************************************************************/
void
setAllScan (
    flagType fDir
    ) {
    rnScan.flFirst.col = 0;
    rnScan.flFirst.lin = fDir ? YCUR(pInsCur) : 0;
    rnScan.flLast.col  = sizeof(linebuf)-1;
    rnScan.flLast.lin  = pFileHead->cLines - 1;
}
