static char rcsver[] = "$Id: buffs.c,v 2.2 1999/07/12 23:14:08 gorelick Exp $";
 
/**
 ** $Source: /tes/src/vanilla/RCS/buffs.c,v $
 **
 ** $Log: buffs.c,v $
 ** Revision 2.2  1999/07/12 23:14:08  gorelick
 ** *** empty log message ***
 **
 ** Revision 2.1  1999/02/10 04:00:50  gorelick
 ** *** empty log message ***
 **
 ** Revision 2.0  1998/12/22 22:47:04  gorelick
 ** release version
 **
 ** Revision 2.0  1998/12/18 01:26:03  gorelick
 ** release version
 **
 ** Revision 1.7  1998/12/18 01:04:48  gorelick
 ** *** empty log message ***
 **
 ** Revision 1.6  1998/12/01 22:42:06  gorelick
 ** *** empty log message ***
 **
 ** Revision 1.5  1998/11/18 00:13:47  gorelick
 ** extensive loop optimzations
 **
 ** Revision 1.4  1998/11/13 23:33:24  gorelick
 ** *** empty log message ***
 **
 ** Revision 1.3  1998/11/12 22:58:55  gorelick
 ** first release version
 **
 **/


#include <malloc.h>
#include <sys/types.h>
#include <string.h>
#include "header.h"

#ifndef MAP_PRIVATE
#define MAP_PRIVATE 0
#endif

/* Creates a new TBLBUFF object for a given table object. User
 * supplies the record count for the buffer and the overlap count.
 * IMPORTANT: The overlap count MUST be at least two times the size of
 * the largest possible keyblock.
 */


PTR
RefillTblBuff(TBLBUFF *b)
{
    int fd;
    FRAGMENT *frag;
    char *fname;

    if (b->buf != NULL) {
        munmap(b->buf, b->len);
        if (b->varbuf) {
            munmap(b->varbuf, b->varlen);
            b->varbuf = NULL;
        }
#ifdef DEBUG
		fname = (char *)b->tbl->files->ptr[b->fileidx];
		fprintf(stderr, "Unmapping %s\n", fname);
#endif
        b->fileidx++;
    }

    if (b->fileidx >= b->tbl->files->number) {
        return(NULL);
    }

    fname = (char *)b->tbl->files->ptr[b->fileidx];
    frag = LoadFragment(fname, b->tbl);
    b->len = frag->sbuf.st_size;

#ifdef _WINDOWS
    fd = open(fname, O_RDONLY | O_BINARY);
#else 
    fd = open(fname, O_RDONLY);
#endif

#ifdef DEBUG
	fprintf(stderr, "mapping: %s\n", fname);
#endif

    b->buf = mmap(NULL, b->len, PROT_READ, MAP_PRIVATE, fd, 0);
    close(fd);
    b->curr = b->buf + frag->offset;

    b->end = b->buf + b->len;
    b->reclen = b->tbl->label->reclen;
    return(b->curr);
}

PTR   GiveMeVarPtr(PTR raw, TABLE *table, int offset)
{
    TBLBUFF *b = table->buff;
    struct stat sbuf;
    char *fname, buf[256], *p;
    int fd;

    if (b->varbuf == NULL) {
        fname = ((char **)(table->files->ptr))[b->fileidx];
        strcpy(buf, fname);
		p = &buf[strlen(buf)-4];
        strcpy(p, ".var");
        if (stat(buf, &sbuf) != 0) {
			p = &buf[strlen(buf)-4];
			strcpy(p, ".VAR");		/* try capital case */
			if (stat(buf, &sbuf) != 0) {;
				fprintf(stderr, "Unable to open var file: %s\n", buf);
				return(NULL);
			}
        }
#ifdef _WINDOWS
    	fd = open(buf, O_RDONLY | O_BINARY);
#else 
    	fd = open(buf, O_RDONLY);
#endif
        if (fd < 0) {
            fprintf(stderr, "Unable to open var file: %s\n", buf);
            return(NULL);
        }
        b->varlen = sbuf.st_size;
        b->varbuf = mmap(NULL, b->varlen, PROT_READ, MAP_PRIVATE, fd, 0);
        close(fd);
    }

	 /* Saadat -- Feb 15, 1999 */
	 if (offset >= b->varlen){
		fprintf(stderr, "Variable Pointer after EOF: File: %s. Aborting...", buf);
		abort();
	 }

    return(b->varbuf+offset);
}

short ConvertVaxVarByteCount(PTR raw, VARDATA *vdata)  
{
	char buf[4];
	short s;

	memcpy(buf, raw, 2);
	s = ((short *)MSB2(buf))[0];

	return(s);
}

TBLBUFF *
NewTblBuff(TABLE *t)
{
    TBLBUFF *b = calloc(1,sizeof(TBLBUFF));
    b->tbl = t;
    if (RefillTblBuff(b) == NULL) return(NULL);
    return(b);
}

/* Returns the first record in a table. This will ONLY WORK if it's the
 * first operation performed on the table. Calling this function after
 * we've done find's on the table will give useless results.
 */
PTR
GetFirstRec(TABLE * t)
{
    if (t->buff == NULL) {
        t->buff = NewTblBuff(t);
    }
    return t->buff->curr;
}

/**
 **/

PTR
find_jump(TABLE * t, FIELD * f, DATA d, PTR beg, PTR end)
{
    TBLBUFF *b = t->buff;
    int refill = 0;
    
    if (beg == NULL)  {
        beg = GetFirstRec(t);
    	b = t->buff;
    }

    if (end == NULL) {
        end = b->end;
        refill = 1;
    }

    while (1) {
        while (beg < end && CompareData(ConvertFieldData(beg,f),d,f) < 0) {
            beg += b->reclen;
#ifdef DEBUG
			fprintf(stderr, "find_jump[1], ");
			fprintf(stderr, "%d / %d  %s\n", 
				(beg - b->buf)/b->reclen,
				(end - b->buf)/b->reclen,
				b->tbl->files->ptr[b->fileidx]);
#endif
        }
        if (beg == end) {
            if (refill) {
                if ((beg = RefillTblBuff(b)) == NULL) return(NULL);
                end = b->end;
#ifdef DEBUG
				printf("find_jump[2], refill %s\n", 
							(char *)b->tbl->files->ptr[b->fileidx]);
#endif
                continue;
            } else {
                return(NULL);
            }
        }
#ifdef DEBUG
		fprintf(stderr, "find_jump[3], match ");
		fprintf(stderr, "%d %s\n",(beg - b->buf)/b->reclen,
				b->tbl->files->ptr[b->fileidx]);
#endif
        return(beg);
    }
}
    

PTR
find_until(TABLE * t, FIELD * f, PTR beg, PTR end)
{
    TBLBUFF *b  = t->buff;
    DATA d = ConvertFieldData(beg, f);
    PTR e;

    if (end == NULL) end = b->end;

    while ((beg += b->reclen) < end && 
           EquivalentData(ConvertFieldData(beg, f), d, f))  {
#ifdef DEBUG		   
			fprintf(stderr, "find_until: ");
			fprintf(stderr, "%d  %s\n",(beg - b->buf)/b->reclen, 
				b->tbl->files->ptr[b->fileidx]);
#endif
	}
    return(beg);
}


/* */
PTR
find_select(TABLE * t, PTR beg, PTR end)
{
    DATA d;
    SELECT **s;
    int i, n, count = 0;
    TBLBUFF *b = t->buff;
    int refill = 0;
    PTR last = NULL;

    if (t->selects == NULL)  return(beg);
    s = (SELECT **)t->selects->ptr;
    n = t->selects->number;


    if (end == NULL) {
        end = b->end;
        refill = 1;
    }

	i = 0;
    while (1) {
        while (beg < end) {
            d = ConvertFieldData(beg, s[i]->field);
            if (CompareData(d, s[i]->low, s[i]->field) < 0 ||
                CompareData(d, s[i]->high, s[i]->field) > 0)  {
                beg += b->reclen;
                continue;
            }
            /* selection matched */
            if (beg != last) {
                last = beg; 
                count = 0;
            }
            i = (i+1)%n;
            if (++count == n) {
#ifdef DEBUG
				fprintf(stderr, "find_select[2]: match, ");
				fprintf(stderr, "%d  %s\n",(beg - b->buf)/b->reclen,
				b->tbl->files->ptr[b->fileidx]);
#endif
				return(beg);
			}
        }
        if (refill) {
            if ((beg = RefillTblBuff(b)) == NULL) return(NULL);
            end = b->end;
#ifdef DEBUG
			fprintf(stderr, "find_select[3]: refill  %s\n",
				b->tbl->files->ptr[b->fileidx]);
#endif
        } else {
            return(NULL);
        }
    }
}

/**
 ** Get the maximum value of the next record across all tables.
 ** This function also moves us across a fragment boundary (and sets up the
 ** first fragment) when necessary.
 **/
DATA *
maxFieldVal(SLICE * s, int dim, TABLE **tbl, DATA *maxValue)
{
    int i, rv = 0;
    DATA value;
	PTR beg;
 
    for (i = 0; i < dim; i++) {
        if (s[i].party_key == NULL)
            continue;
 
		if (s[i].start_rec == NULL) {		 /* No buffer loaded yet */
			s[i].start_rec = GetFirstRec(tbl[i]);
		} else if (s[i].start_rec == tbl[i]->buff->buf + tbl[i]->buff->len) {
			/* EOF of current bufer */
				
				if ((beg = RefillTblBuff(tbl[i]->buff)) == NULL) return(NULL);
				s[i].start_rec = beg;
        }
 
        value = ConvertFieldData(s[i].start_rec, s[i].party_key);
 
        if (!rv) {
            *maxValue = value;
            rv++;
        } else if (CompareData(value, *maxValue, s[i].party_key) > 0)
            *maxValue = value;
    }
    return maxValue;
}