/*static char *SCCSID = "@(#)fs_cfptr.c 6.3 92/01/31";*/
#define _BTXT _BTXT
#define INCL_DOSERRORS
#include <os2.h>
#include <limits.h>
#include <pvwxport.h>

#include "heap.h"
#include "api.h"
#include "const.h"
#include "misc.h"
#include "chain.h"
#include "buf.h"
#include "dir.h"
#include "storage.h"
#include "volume.h"
#include "tables.h"
#include "pb_ifs.h"
#include "superb.h"
#include "pbmacros.h"
#include "lw.h"
#include "frame.h"
#include "fsdata.h"
#include "rahead.h"
#include "pvw.h"

#include "pr_fsd.h"
#include "pr_FCN.h"
#include "pr_HEAP.h"
#include "pr_MISC.h"
#include "pr_DEBUG.h"

/* put stand-alone fs_xxx functions in separate code segment */

int far pascal
FS_CHGFILEPTR (struct sffsi far * psffsi,
               struct sffsd far * psffsd,
               LONG offlSeek,
               USHORT type,
               USHORT IOflag)
{

    PFHT    pfht;   /* work copy of pfht in psffsd */
    POFT    poft;
#if defined(RAHEAD) || defined(PERFVIEW)
    ULONG ulTmp;
#endif

    /* dereference psffsd copy of pfht */
    pfht = ((PPB_SFD)psffsd->sfd_work)->pfht;
    poft = pfht->poft;

#if defined(RAHEAD) || defined (PERFVIEW)
    ulTmp = pfht->offSeek;
#endif

    if( poft->bCorrupt != 0 ) {
        /*
         * File is Corrupted, return code
         */

        return ERROR_READ_FAULT;
    }


    /*
     * Do the seek
     */
    switch ( type ) {

    case CFP_RELBEGIN:

        /* Absolute Seek */

        /*
         * Allow negative seek for 3x Box
         */
        if (offlSeek < 0) {
            pfht->offSeek = poft->ulFActualLen;
            break;
        }

        /*
         * Otherwise, just use the new offset as the seek pointer
         */
        pfht->offSeek = offlSeek;
        break;

    case CFP_RELCUR:

        /*
         * It's a relative seek.
         * The offset value is a signed number, so if it's negative
         * we'll come up with a value which is less than the current
         * position else we'll declare underflow and call the position
         * 0.
         *
         * If the offset is positive, we'll come up with a value > then
         * the current position or else we'll declare "off end" and
         * set the value to the file size.
         *
         * All this grief comes up because we can have files > 2^31
         * bytes long, at least in theory.
         *
         * We can't use 'C' or 'O' because we're an amalgam of signed
         * and unsigned.
         */

        if (offlSeek >= 0) {

            /* if there's no overflow problem... */
            if (ULONG_MAX - (pfht->offSeek) >= offlSeek) {
                pfht->offSeek += offlSeek;
            } else {
                /* BUGBUG what should we do here? ( > 32Bit seek!) */
                pfht->offSeek = poft->ulFActualLen;
            }
            break;
        }

        /* Have a negative offset */
        if ((ULONG) (-offlSeek) > pfht->offSeek) {
            /* Allow negative seek for 3x Box */
            pfht->offSeek = poft->ulFActualLen;
        } else
            pfht->offSeek += offlSeek;

        break;

    case CFP_RELEND:

        /*
         * Seek is based from the end of the file.
         * That means that we treat the offset as an unsigned number
         * and subtract that from the file length
         */

        /* BUGBUG - should we be checking for > 32 bit seek? */
        if (offlSeek > 0) {
            pfht->offSeek = poft->ulFActualLen + offlSeek;
            break;
        }

        /* Have a negative offset */
        if ((ULONG) (-offlSeek) > poft->ulFActualLen) {
            pfht->offSeek = poft->ulFActualLen;
            break;
        }

        pfht->offSeek = poft->ulFActualLen + offlSeek;

        break;

    default:

#ifdef DEBUG
        dprintf ("fs_cfptr: bad mode (%d)\n", type);
#endif
        return (ERROR_NOT_SUPPORTED);

    } /* switch */

    /* make both pointers agree */
    psffsi->sfi_position = pfht->offSeek;

#ifdef PERFVIEW
    /*
     *  If the seek pointer has moved, then the file is not read
     *  strictly sequentially, so we strip that flag. Note that a
     *  DosChgFilePtr does not reset this flag unless the
     *  seek pointer really changes.
     */
    if (ulTmp != pfht->offSeek)
//      pfht->bHint ^= (FHH_READSEQ);                                  //aa04398
        pfht->bHint &= ~(FHH_READSEQ);
#endif

#ifdef RAHEAD
    /* We treat small distance seeks as if they were small sequential reads */
    /* Check for non-seq reads only if we didn't cache the whole file */
    if (!(pfht->bRAFlags & RA_CACHE)) {
        /* Get absolute distance between old & new positions */
        if (ulTmp < pfht->offSeek)
            ulTmp = pfht->offSeek - ulTmp;
        else
            ulTmp -= pfht->offSeek;

//#132506
        if (ulTmp > MAX_READLEN) { /* Turn off readahead */
            pfht->bRAReads = 0;
            pfht->bRABigReads = 0;
            pfht->bRAFlags &= ~(RA_ON | RA_BIG);
        }
        else
//#114986
        if (ulTmp > (MAX_READLEN / 2)) { /* Turn off readahead */
            pfht->bRAReads = RA_LOW;
            pfht->bRABigReads = RA_LOW;
            pfht->bRAFlags &= ~(RA_ON | RA_BIG);
        }
    }
#endif

    return NO_ERROR;

    /* to prevent compiler warnings */
    IOflag;
}
