🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: mod.amiga.sources
Article #25

sdb Database (2 of 3)

#25
From: doc
Date: Fri, 22 Aug 1986 22:46
2129 lines
52837 bytes
#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	int.c
#	io.c
#	scn.c
#	cmd.c
# This archive created: Fri Aug 22 17:39:48 1986
# By:	Craig Norborg (Purdue University Computing Center)
cat << \SHAR_EOF > int.c
/* SDB - boolean expression evaluator */

#include "sdbio.h"

static struct operand *stack[STACKMAX],**sptr;
static union codecell *cptr;

/* db_interpret - interpret a boolean expression */
int db_interpret(slptr)
  struct sel *slptr;
{
    struct operand *result;
    int r;

    /* check for empty where clause */
    if ((cptr = slptr->sl_where) == NULL)
        return (TRUE);

    /* setup stack */
    sptr = stack;

    /* execute the code */
    while ((*(*cptr++).c_operator)())
        ;

    /* get the result from the top of stack */
    result = *--sptr;
    r = result->o_value.ov_boolean;
    if (result->o_type == TEMP)
        free(result);

    /* make sure the stack is empty */
    while (sptr != stack) {
        if ((*sptr)->o_type == TEMP)
            free(*sptr);
        sptr -= 1;
    }

    /* return result */
    return (r);
}

int db_xstop()
{
    return (FALSE);
}

int db_xpush()
{
    *sptr++ = (*cptr++).c_operand;
}

int db_xand()
{
    return (boolean('&'));
}

int db_xor()
{
    return (boolean('|'));
}

static int boolean(opr)
{
    struct operand *lval,*rval,*result;
    int lv,rv,r;

    rval = *--sptr; lval = *--sptr;
    lv = lval->o_value.ov_boolean;
    rv = rval->o_value.ov_boolean;

    if ((result = malloc(sizeof(struct operand))) == NULL)
        return (db_ferror(INSMEM));
    result->o_type = TEMP;
    switch (opr) {
    case '&':   r = (lv && rv);
                break;
    case '|':   r = (lv || rv);
                break;
    }
    result->o_value.ov_boolean = r;
    *sptr++ = result;
    if (lval->o_type == TEMP)
        free(lval);
    if (rval->o_type == TEMP)
        free(rval);
    return (TRUE);
}

int db_xnot()
{
    struct operand *val,*result;

    val = *--sptr;
    if ((result = malloc(sizeof(struct operand))) == NULL)
        return (db_ferror(INSMEM));
    result->o_type = TEMP;
    result->o_value.ov_boolean = !val->o_value.ov_boolean;
    *sptr++ = result;
    if (val->o_type == TEMP)
        free(val);
    return (TRUE);
}

int db_xlss()
{
    return (compare(LSS));
}

int db_xleq()
{
    return (compare(LEQ));
}

int db_xeql()
{
    return (compare(EQL));
}

int db_xgeq()
{
    return (compare(GEQ));
}

int db_xgtr()
{
    return (compare(GTR));
}

int db_xneq()
{
    return (compare(NEQ));
}

static int compare(cmp)
{
    struct operand *lval,*rval,*result;
    int i;

    rval = *--sptr; lval = *--sptr;
    if ((result = malloc(sizeof(struct operand))) == NULL)
        return (db_ferror(INSMEM));
    result->o_type = TEMP;

    if (lval->o_value.ov_char.ovc_type == TCHAR)
        i = comp(lval,rval);
    else
        i = ncomp(lval,rval);

    switch (cmp) {
    case LSS:   i = (i < 0);
                break;
    case LEQ:   i = (i <= 0);
                break;
    case EQL:   i = (i == 0);
                break;
    case GEQ:   i = (i >= 0);
                break;
    case GTR:   i = (i > 0);
                break;
    case NEQ:   i = (i != 0);
                break;
    }
    result->o_value.ov_boolean = i;
    *sptr++ = result;
    if (lval->o_type == TEMP)
        free(lval);
    if (rval->o_type == TEMP)
        free(rval);
    return (TRUE);
}

static int comp(lval,rval)
  struct operand *lval,*rval;
{
    char *lptr,*rptr; int lctr,rctr;
    int len;

    lptr = lval->o_value.ov_char.ovc_string;
    lctr = lval->o_value.ov_char.ovc_length;
    rptr = rval->o_value.ov_char.ovc_string;
    rctr = rval->o_value.ov_char.ovc_length;

    while (lctr > 0 && (lptr[lctr-1] == 0 || lptr[lctr-1] == ' '))
        lctr--;
    while (rctr > 0 && (rptr[rctr-1] == 0 || rptr[rctr-1] == ' '))
        rctr--;

    if (lctr < rctr)
        len = lctr;
    else
        len = rctr;

    while ((len--) > 0) {
        if (*lptr++ != *rptr++)
            if (*--lptr < *--rptr)
                return (-1);
            else
                return (1);
    }

    if (lctr == rctr)
        return (0);
    else if (lctr < rctr)
        return (-1);
    else
        return (1);
}

static int ncomp(lval,rval)
  struct operand *lval,*rval;
{
    char lstr[NUMBERMAX+1],rstr[NUMBERMAX+1];
    int len;

    strncpy(lstr,lval->o_value.ov_char.ovc_string,
          (len = lval->o_value.ov_char.ovc_length)); lstr[len] = EOS;
    strncpy(rstr,rval->o_value.ov_char.ovc_string,
          (len = rval->o_value.ov_char.ovc_length)); rstr[len] = EOS;

    return (db_cmp(lstr,rstr));
}
SHAR_EOF
cat << \SHAR_EOF > io.c
/* SDB - relation file I/O routines */

#include <stdio.h>
#include "sdbio.h"

/* global error code variable */
int dbv_errcode;

/* list of currently loaded relation definitions */
static struct relation *relations = NULL;

/* rfind - find the specified relation */
static struct relation *rfind(rname)
  char *rname;
{
    int fd;
    char filename[RNSIZE+5];
    struct relation *rptr;

    /* look for relation in list currently loaded */
    for (rptr = relations; rptr != NULL; rptr = rptr->rl_next)
        if (db_sncmp(rname,rptr->rl_name,RNSIZE) == 0)
            return (rptr);

    /* create a file name */
    make_fname(filename,rname);

    /* lookup the relation file */
#ifdef Lattice
    if ((fd = open(filename,0x8000)) == -1)  /*dns*/
#else
    if ((fd = open(filename,0)) == -1)
#endif
        return (db_nerror(RELFNF));

    /* allocate a new relation structure */
    if ((rptr = malloc(sizeof(struct relation))) == NULL) {
        close(fd);
        return (db_nerror(INSMEM));
    }

    /* initialize the relation structure */
    rptr->rl_scnref = 0;

    /* read the header block */
    if ( read(fd,&rptr->rl_header,512) != 512) {
        free(rptr);
        close(fd);
        return (db_nerror(BADHDR));
    }

    /* close the relation file */
    close(fd);

    /* extract header information */
    rptr->rl_tcnt = db_cvword(rptr->rl_header.hd_tcnt);
    rptr->rl_tmax = db_cvword(rptr->rl_header.hd_tmax);
    rptr->rl_data = db_cvword(rptr->rl_header.hd_data);
    rptr->rl_size = db_cvword(rptr->rl_header.hd_size);

    /* store the relation name */
    strncpy(rptr->rl_name,rname,RNSIZE);

    /* link new relation into relation list */
    rptr->rl_next = relations;
    relations = rptr;

    /* return the new relation structure pointer */
    return (rptr);
}

/* db_ropen - open a relation file */
struct scan *db_ropen(rname)
  char *rname;
{
    struct relation *rptr;
    struct scan *sptr;
    char filename[RNSIZE+5];

    /* find the relation definition */
    if ((rptr = rfind(rname)) == NULL)
        return (NULL);

    /* allocate a new scan structure */
    if ((sptr = malloc(sizeof(struct scan))) == NULL)
        return (db_nerror(INSMEM));

    /* allocate a tuple buffer */
    if ((sptr->sc_tuple = malloc(rptr->rl_size)) == NULL) {
        free(sptr);
        return (db_nerror(INSMEM));
    }

    /* initialize the scan structure */
    sptr->sc_relation = rptr;           /* store the relation struct addrs */
    sptr->sc_dtnum = 0;                 /* desired tuple (non-existant) */
    sptr->sc_atnum = 0;                 /* actual tuple (non-existant) */
    sptr->sc_store = FALSE;             /* no store done since open */

    /* open relation file if necessary */
    if (rptr->rl_scnref++ == 0) {

        /* create the relation file name */
        make_fname(filename,rname);

        /* open the relation file */
#ifdef Lattice
        if ((rptr->rl_fd = open(filename,0x8002)) == -1) {  /*dns*/
#else
        if ((rptr->rl_fd = open(filename,2)) == -1) {
#endif
            rptr->rl_scnref--;
            free(sptr->sc_tuple); free(sptr);
            return (db_nerror(RELFNF));
        }
    }

    /* return the new scan structure pointer */
    return (sptr);
}

/* db_rclose - close the relation file */
int db_rclose(sptr)
  struct scan *sptr;
{
    struct relation *rptr,*lastrptr;

    /* close relation file if this is the last reference */
    if (--sptr->sc_relation->rl_scnref == 0) {

        /* rewrite header if any stores took place */
        if (sptr->sc_store) {

            /* store the tuple count back in the header */
            db_cvbytes(sptr->sc_relation->rl_tcnt,
                       sptr->sc_relation->rl_header.hd_tcnt);

            /* write the header block */
            lseek(sptr->sc_relation->rl_fd,0L,0);
            if (write(sptr->sc_relation->rl_fd,
                      &sptr->sc_relation->rl_header,512) != 512) {
                close(sptr->sc_relation->rl_fd);
                free(sptr->sc_tuple); free(sptr);
                return (db_ferror(BADHDR));
            }
        }

        /* close the relation file */
        close(sptr->sc_relation->rl_fd);

        /* free the relation header */
        lastrptr = NULL;
        for (rptr = relations; rptr != NULL; rptr = rptr->rl_next) {
            if (rptr == sptr->sc_relation) {
                if (lastrptr == NULL)
                    relations = rptr->rl_next;
                else
                    lastrptr->rl_next = rptr->rl_next;
            }
            lastrptr = rptr;
        }
        free(sptr->sc_relation);
    }

    /* free the scan structure */
    free(sptr->sc_tuple); free(sptr);

    /* return successfully */
    return (TRUE);
}

/* db_rcompress - compress a relation file */
int db_rcompress(sptr)
  struct scan *sptr;
{
    unsigned int next,nextfree,tcnt;

    /* get the last used tuple */
    tcnt = sptr->sc_relation->rl_tcnt;

    /* loop through all of the tuples */
    for (next = nextfree = 1; next <= tcnt; next++) {

        /* read the tuple */
        seek(sptr,next);
        if (read(sptr->sc_relation->rl_fd,
                 sptr->sc_tuple,sptr->sc_relation->rl_size)
                        != sptr->sc_relation->rl_size)
            return (db_ferror(TUPINP));

        /* rewrite the tuple if it is active */
        if (sptr->sc_tuple[0] == ACTIVE) {

            /* rewrite it only if it must move */
            if (next != nextfree) {

                /* write the tuple */
                seek(sptr,nextfree);
                if (write(sptr->sc_relation->rl_fd,
                          sptr->sc_tuple,sptr->sc_relation->rl_size)
                                != sptr->sc_relation->rl_size)
                    return (db_ferror(TUPOUT));
            }

            /* update the next free tuple number */
            nextfree += 1;
        }
    }

    /* update the tuple count */
    sptr->sc_relation->rl_tcnt = nextfree - 1;

    /* remember which tuple is in the buffer */
    sptr->sc_atnum = sptr->sc_relation->rl_tcnt;

    /* reset the desired tuple */
    sptr->sc_dtnum = 0;

    /* remember that the index needs rewriting */
    sptr->sc_store = TRUE;

    /* return successfully */
    return (TRUE);
}

/* db_rbegin - begin scan at first tuple in relation */
db_rbegin(sptr)
  struct scan *sptr;
{
    /* begin with the first tuple in the file */
    sptr->sc_dtnum = 0;
}

/* db_rfetch - fetch the next tuple from the relation file */
int db_rfetch(sptr)
  struct scan *sptr;
{
    /* look for an active tuple */
    while (TRUE) {

        /* check for this being the last tuple */
        if (!db_rget(sptr,sptr->sc_dtnum + 1))
            return (FALSE);

        /* increment the tuple number */
        sptr->sc_dtnum += 1;

        /* return if the tuple found is active */
        if (sptr->sc_tuple[0] == ACTIVE)
            return (TRUE);
    }
}

/* db_rupdate - update the current tuple */
int db_rupdate(sptr)
  struct scan *sptr;
{
    /* make sure the status byte indicates an active tuple */
    sptr->sc_tuple[0] = ACTIVE;

    /* write the tuple */
    return (db_rput(sptr,sptr->sc_atnum));
}

/* db_rdelete - delete the current tuple */
int db_rdelete(sptr)
  struct scan *sptr;
{
    /* make sure the status byte indicates a deleted tuple */
    sptr->sc_tuple[0] = DELETED;

    /* write the tuple */
    return (db_rput(sptr,sptr->sc_atnum));
}

/* db_rstore - store a new tuple */
int db_rstore(sptr)
  struct scan *sptr;
{
    /* make sure there's room for this tuple */
    if (sptr->sc_relation->rl_tcnt == sptr->sc_relation->rl_tmax)
        return (db_ferror(RELFUL));

    /* make sure the status byte indicates an active tuple */
    sptr->sc_tuple[0] = ACTIVE;

    /* write the tuple */
    if (!db_rput(sptr,sptr->sc_relation->rl_tcnt + 1))
        return (FALSE);

    /* update the tuple count */
    sptr->sc_relation->rl_tcnt += 1;

    /* remember that a tuple was stored */
    sptr->sc_store = TRUE;

    /* return successfully */
    return (TRUE);
}

/* db_rget - get a tuple from the relation file */
int db_rget(sptr,tnum)
  struct scan *sptr; unsigned int tnum;
{
    /* check to see if the tuple is already in the buffer */
    if (tnum == sptr->sc_atnum)
        return (TRUE);

    /* check for this being beyond the last tuple */
    if (tnum > sptr->sc_relation->rl_tcnt)
        return (db_ferror(TUPINP));

    /* read the tuple */
    seek(sptr,tnum);
    if (read(sptr->sc_relation->rl_fd,
             sptr->sc_tuple,sptr->sc_relation->rl_size)
                != sptr->sc_relation->rl_size)
        return (db_ferror(TUPINP));

    /* remember which tuple is in the buffer */
    sptr->sc_atnum = tnum;

    /* return successfully */
    return (TRUE);
}

/* db_rput - put a tuple to a relation file */
int db_rput(sptr,tnum)
  struct scan *sptr; unsigned int tnum;
{
    /* check for this being beyond the maximum tuple */
    if (tnum > sptr->sc_relation->rl_tmax)
        return (db_ferror(TUPOUT));

    /* write the tuple */
    seek(sptr,tnum);
    if (write(sptr->sc_relation->rl_fd,
              sptr->sc_tuple,sptr->sc_relation->rl_size)
                != sptr->sc_relation->rl_size)
        return (db_ferror(TUPOUT));

    /* remember which tuple is in the buffer */
    sptr->sc_atnum = tnum;

    /* return successfully */
    return (TRUE);
}

/* seek - seek a tuple in a relation file */
static seek(sptr,tnum)
  struct scan *sptr; unsigned int tnum;
{
    long offset;

    offset = (long) sptr->sc_relation->rl_data +
                ((long) (tnum - 1) * (long) sptr->sc_relation->rl_size);
    lseek(sptr->sc_relation->rl_fd,offset,0);
}

/* make_fname - make a relation name into a file name */
static make_fname(fname,rname)
  char *fname,*rname;
{
    strncpy(fname,rname,RNSIZE); fname[RNSIZE] = 0;
    strcat(fname,".sdb");
}

/* db_nerror - store the error code and return NULL */
int db_nerror(errcode)
  int errcode;
{
    dbv_errcode = errcode;
    return (NULL);
}

/* db_ferror - store the error code and return FALSE */
int db_ferror(errcode)
  int errcode;
{
    dbv_errcode = errcode;
    return (FALSE);
}

/* db_cvword - convert 2 bytes to a word */
int db_cvword(bytes)
  char bytes[2];
{
    return (((bytes[1] & 0377) << 8) + (bytes[0] & 0377));
}

/* db_cvbytes - convert a word to 2 bytes */
db_cvbytes(word,bytes)
  int word; char bytes[2];
{
    bytes[0] = word;
    bytes[1] = word >> 8;
}
SHAR_EOF
cat << \SHAR_EOF > scn.c
/* SDB - token scanning routines */

#include <stdio.h>
#include "sdbio.h"

int dbv_token;                          /* current token */
int dbv_tvalue;                         /* integer token value */
char dbv_tstring[STRINGMAX+1];          /* string token value */
struct ifile *dbv_ifp;                  /* indirect file context */
struct macro *dbv_macros;               /* macro definitions */
int dbv_fold;                           /* case fold alpha comparisons */

static char *iprompt,*cprompt;          /* input prompts */
static char cmdline[LINEMAX+2],*lptr;   /* current line and pointer */
static int atbol;                       /* flag indicating at bol */
static int savech;                      /* lookahead character */
static int savetkn;                     /* lookahead token */
static char *keywords[] = {             /* keyword table */
    "ascending",
    "by",
    "char",
    "compress",
    "create",
    "define",
    "delete",
    "descending",
    "exit",
    "export",
    "extract",
    "from",
    "help",
    "insert",
    "import",
    "into",
    "num",
    "print",
    "quit",
    "select",
    "set",
    "show",
    "sort",
    "update",
    "using",
    "where",
    NULL
};
static int keytokens[] = {              /* token values for each keyword */
    ASCENDING,
    BY,
    CHAR,
    COMPRESS,
    CREATE,
    DEFINE,
    DELETE,
    DESCENDING,
    EXIT,
    EXPORT,
    EXTRACT,
    FROM,
    HELP,
    INSERT,
    IMPORT,
    INTO,
    NUM,
    PRINT,
    EXIT,
    SELECT,
    SET,
    SHOW,
    SORT,
    UPDATE,
    USING,
    WHERE,
    NULL
};

/* db_sinit - initialize the scanner */
db_sinit()
{
    /* at beginning of line */
    atbol = TRUE;

    /* make the command line null */
    lptr = NULL;

    /* no lookahead yet */
    savech = EOS;
    savetkn = NULL;

    /* no indirect command files */
    dbv_ifp = NULL;

    /* no macros defined */
    dbv_macros = NULL;

    /* fold alpha comparisons */
    dbv_fold = TRUE;
}

/* db_prompt(ip,cp) - initialize prompt strings */
db_prompt(ip,cp)
  char *ip,*cp;
{
    /* save initial and continuation prompt strings */
    iprompt = ip;
    cprompt = cp;
}

/* db_scan(fmt,args) - initiate line scan command parsing */
db_scan(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
{
    /* convert the command line and arguments */
    sprintf(cmdline,fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10);

    /* start at the beginning of the command line */
    lptr = cmdline;
    iprompt = NULL;
    dbv_ifp = NULL;

    /* no lookahead yet */
    savech = EOS;
    savetkn = NULL;

    /* fold alpha comparisons */
    dbv_fold = TRUE;
}

/* db_flush - flush the current input line */
int db_flush()
{
    while (savech != '\n')
        if (savech > ' ')
            return (db_ferror(SYNTAX));
        else
            savech = getchx();

    savech = EOS;
    atbol = TRUE;
    return (TRUE);
}

/* db_gline - get a line from the current input */
char *db_gline(buf)
  char *buf;
{
    int ch,i;

    for (i = 0; (ch = getch()) != '\n' && ch != -1; )
        if (i < LINEMAX)
            buf[i++] = ch;
        else {
            printf("*** line too long ***\nRetype> ");
            i = 0;
        }
    buf[i] = EOS;

    return (buf);
}

/* db_ifile - setup an indirect command file */
int db_ifile(fname)
  char *fname;
{
    struct ifile *new_ifp;

    if ((new_ifp = malloc(sizeof(struct ifile))) == NULL)
        return (db_ferror(INSMEM));
    else if ((new_ifp->if_fp = fopen(fname,"r")) == NULL) {
        free(new_ifp);
        return (db_ferror(INDFNF));
    }
    new_ifp->if_mtext = NULL;
    new_ifp->if_savech = savech;
    new_ifp->if_lptr = lptr;
    new_ifp->if_next = dbv_ifp;
    dbv_ifp = new_ifp;

    /* return successfully */
    return (TRUE);
}

/* db_kill - kill indirect command file input */
db_kill()
{
    struct ifile *old_ifp;

    while ((old_ifp = dbv_ifp) != NULL) {
        dbv_ifp = old_ifp->if_next;
        if (old_ifp->if_fp != NULL)
            fclose(old_ifp->if_fp);
        savech = old_ifp->if_savech;
        lptr = old_ifp->if_lptr;
        free(old_ifp);
    }

    while (savech != '\n')
        savech = getchx();

    savech = EOS;
    savetkn = NULL;
    atbol = TRUE;
}

/* db_token - return the current input token */
int db_token()
{
    struct macro *mptr;
    struct ifile *new_ifp;

    /* find a token that's not a macro call */
    while (db_xtoken() == ID) {

        /* check for a macro call */
        for (mptr = dbv_macros; mptr != NULL; mptr = mptr->mc_next)
            if (db_scmp(dbv_tstring,mptr->mc_name) == 0) {
                if ((new_ifp = malloc(sizeof(struct ifile))) == NULL)
                    printf("*** error expanding macro: %s ***\n",dbv_tstring);
                else {
                    new_ifp->if_fp = NULL;
                    new_ifp->if_mtext = mptr->mc_mtext->mt_next;
                    new_ifp->if_lptr = lptr; lptr = mptr->mc_mtext->mt_text;
                    new_ifp->if_savech = savech; savech = EOS;
                    new_ifp->if_next = dbv_ifp;
                    dbv_ifp = new_ifp;
                }
                savetkn = NULL;
                break;
            }

        if (mptr == NULL)
            break;
    }

    return (dbv_token);
}

/* db_xtoken - return the current input token */
int db_xtoken()
{
    int ch;

    /* check for a saved token */
    if ((dbv_token = savetkn) != NULL)
        return (dbv_token);

    /* get the next non-blank character */
    ch = nextch();

    /* check type of character */
    if (isalpha(ch))                    /* identifier or keyword */
        get_id();
    else if (isdigit(ch))               /* number */
        get_number();
    else if (ch == '"')                 /* string */
        get_string();
    else if (get_rel())                 /* relational operator */
        ;
    else                                /* single character token */
        dbv_token = getch();

    /* save the lookahead token */
    savetkn = dbv_token;

    /* return the token */
    return (dbv_token);
}

/* db_ntoken - get next token (after skipping the current one) */
int db_ntoken()
{
    /* get the current token */
    db_token();

    /* make sure another is read on next call */
    savetkn = NULL;

    /* return the current token */
    return (dbv_token);
}

/* db_xntoken - get next token (after skipping the current one) */
int db_xntoken()
{
    /* get the current token */
    db_xtoken();

    /* make sure another is read on next call */
    savetkn = NULL;

    /* return the current token */
    return (dbv_token);
}

/* db_scmp - compare two strings */
int db_scmp(str1,str2)
  char *str1,*str2;
{
    if (dbv_fold)
        return (scmp(str1,str2));
    else
        return (strcmp(str1,str2));
}

/* db_sncmp - compare two strings with a maximum length */
int db_sncmp(str1,str2,len)
  char *str1,*str2; int len;
{
    if (dbv_fold)
        return (sncmp(str1,str2,len));
    else
        return (strncmp(str1,str2,len));
}

/* scmp - compare two strings with alpha case folding */
static int scmp(str1,str2)
  char *str1,*str2;
{
    int ch1,ch2;

    /* compare each character */
    while (*str1 && *str2) {

        /* fold the character from the first string */
        if (isupper(*str1))
            ch1 = tolower(*str1++);
        else
            ch1 = *str1++;

        /* fold the character from the second string */
        if (isupper(*str2))
            ch2 = tolower(*str2++);
        else
            ch2 = *str2++;

        /* compare the characters */
        if (ch1 != ch2)
            if (ch1 < ch2)
                return (-1);
            else
                return (1);
    }

    /* check for strings of different lengths */
    if (*str1 == *str2)
        return (0);
    else if (*str1 == 0)
        return (-1);
    else
        return (1);
}

/* sncmp - compare two strings with alpha case folding and a maximum length */
static int sncmp(str1,str2,len)
  char *str1,*str2; int len;
{
    int ch1,ch2;

    /* compare each character */
    while (*str1 && *str2 && len > 0) {

        /* fold the character from the first string */
        if (isupper(*str1))
            ch1 = tolower(*str1++);
        else
            ch1 = *str1++;

        /* fold the character from the second string */
        if (isupper(*str2))
            ch2 = tolower(*str2++);
        else
            ch2 = *str2++;

        /* compare the characters */
        if (ch1 != ch2)
            if (ch1 < ch2)
                return (-1);
            else
                return (1);

        /* decrement the string length */
        len--;
    }

    /* check for strings of different lengths */
    if (len == 0 || *str1 == *str2)
        return (0);
    else if (*str1 == 0)
        return (-1);
    else
        return (1);
}

/* get_id - get a keyword or a user identifier */
static get_id()
{
    int ch,nchars,i;

    /* input letters and digits */
    ch = nextch();
    nchars = 0;
    while (isalpha(ch) || isdigit(ch)) {
        if (nchars < KEYWORDMAX)
            dbv_tstring[nchars++] = ch;
        getch(); ch = thisch();
    }

    /* terminate the keyword */
    dbv_tstring[nchars] = EOS;

    /* assume its an identifier */
    dbv_token = ID;

    /* check for keywords */
    for (i = 0; keywords[i] != NULL; i++)
        if (db_scmp(dbv_tstring,keywords[i]) == 0)
            dbv_token = keytokens[i];
}

/* get_number - get a number */
static get_number()
{
    int ch,ndigits,nodot;

    /* read digits and at most one decimal point */
    ch = nextch();
    ndigits = 0; nodot = TRUE;
    while (isdigit(ch) || (nodot && ch == '.')) {
        if (ch == '.')
            nodot = FALSE;
        if (ndigits < NUMBERMAX)
            dbv_tstring[ndigits++] = ch;
        getch(); ch = thisch();
    }

    /* terminate the number */
    dbv_tstring[ndigits] = EOS;

    /* get the value of the number */
    sscanf(dbv_tstring,"%d",&dbv_tvalue);

    /* token is a number */
    dbv_token = NUMBER;
}

/* get_string - get a string */
static get_string()
{
    int ch,nchars;

    /* skip the opening quote */
    getch();

    /* read characters until a closing quote is found */
    ch = thisch();
    nchars = 0;
    while (ch && ch != '"') {
        if (nchars < STRINGMAX)
            dbv_tstring[nchars++] = ch;
        getch(); ch = thisch();
    }

    /* terminate the string */
    dbv_tstring[nchars] = EOS;

    /* skip the closing quote */
    getch();

    /* token is a string */
    dbv_token = STRING;
}

/* get_rel - get a relational operator */
static int get_rel()
{
    int ch;

    switch (ch = nextch()) {
    case '=':
            getch();
            dbv_token = EQL;
            return (TRUE);;
    case '<':
            getch(); ch = nextch();
            if (ch == '>') {
                getch();
                dbv_token = NEQ;
            }
            else if (ch == '=') {
                getch();
                dbv_token = LEQ;
            }
            else
                dbv_token = LSS;
            return (TRUE);;
    case '>':
            getch(); ch = nextch();
            if (ch == '=') {
                getch();
                dbv_token = GEQ;
            }
            else
                dbv_token = GTR;
            return (TRUE);;
    default:
            return (FALSE);
    }
}

/* getch - get the next character */
static int getch()
{
    char fname[STRINGMAX+1];
    int ch,i;

    /* return the lookahead character if there is one */
    if (savech != EOS) {
        ch = savech;
        savech = EOS;
        return (ch);
    }

    /* get a character */
    ch = getchx();

    /* skip spaces at the beginning of a command */
    if (atbol && iprompt != NULL)
        while (ch <= ' ')
            ch = getchx();

    /* use continuation prompt next time */
    iprompt = NULL;

    /* check for indirect command file */
    while (ch == '@') {
        for (i = 0; (savech = getchx()) > ' '; )
            if (i < STRINGMAX)
                fname[i++] = savech;
        fname[i] = 0;
        if (db_ifile(fname) != TRUE)
            printf("*** error opening command file: %s ***\n",fname);
        ch = getchx();
    }

    /* return the character */
    return (ch);
}

/* getchx - get the next character */
static int getchx()
{
    struct ifile *old_ifp;
    int ch;

    /* check for input from buffer */
    if (lptr != NULL) {
        while (*lptr == EOS)
            if (dbv_ifp != NULL)
                if (dbv_ifp->if_mtext == NULL) {
                    old_ifp = dbv_ifp;
                    ch = dbv_ifp->if_savech; savech = EOS;
                    lptr = dbv_ifp->if_lptr;
                    dbv_ifp = dbv_ifp->if_next;
                    free(old_ifp);
                    if (ch != EOS)
                        return (ch);
                    if (lptr == NULL)
                        break;
                }
                else {
                    lptr = dbv_ifp->if_mtext->mt_text;
                    dbv_ifp->if_mtext = dbv_ifp->if_mtext->mt_next;
                }
            else
                return (EOS);

        if (lptr != NULL)
            return (*lptr++);
    }

    /* print prompt if necessary */
    if (atbol && dbv_ifp == NULL)  {  /*dns*/
        if (iprompt != NULL)
            printf("%s",iprompt);
        else if (cprompt != NULL)
            printf("%s",cprompt);
#ifdef Lattice
        fflush(stdout); /*dns*/
#endif
        } /*dns*/

    if (dbv_ifp == NULL)
        if ((ch = getcx(stdin)) == '\n')
            atbol = TRUE;
        else
            atbol = FALSE;
    else {
        if ((ch = getcx(dbv_ifp->if_fp)) == -1) {
            old_ifp = dbv_ifp;
            ch = dbv_ifp->if_savech; savech = EOS;
            lptr = dbv_ifp->if_lptr;
            dbv_ifp = dbv_ifp->if_next;
            fclose(old_ifp->if_fp);
            free(old_ifp);
        }
    }

    /* return the character */
    return (ch);
}

/* thisch - get the current character */
static int thisch()
{
    /* get a lookahead character */
    if (savech == EOS)
        savech = getch();

    /* return lookahead character */
    return (savech);
}

/* nextch - get the next non-blank character */
static int nextch()
{
    int ch;

    /* skip blank characters */
    while ((ch = thisch()) <= ' ' && ch != EOS)
        getch();

    /* return the first non-blank */
    return (ch);
}
SHAR_EOF
cat << \SHAR_EOF > cmd.c
/* SDB - command parser */

#include <stdio.h>
#include "sdbio.h"

extern int dbv_token;
extern char dbv_tstring[];
extern int dbv_tvalue;
extern struct ifile *dbv_ifp;
extern struct macro *dbv_macros;
extern int dbv_fold;

#ifdef Lattice
int _fmode = 0;  /*dns*/
#endif

/* db_parse - parse a command */
int db_parse(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9)
  char *fmt;
{
    int sts;

    /* check for a command line */
    if (fmt != NULL)
        db_scan(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9);

    /* determine the statement type */
    switch (db_ntoken()) {
    case ';':   sts = TRUE;
                break;
    case COMPRESS:
                sts = db_squeeze(NULL);
                break;
    case CREATE:
                sts = create();
                break;
    case DEFINE:
                sts = mc_define();
                break;
    case DELETE:
                sts = delete();
                break;
    case EXIT:
                exit();
    case EXPORT:
                sts = db_export(NULL);
                break;
    case EXTRACT:
                sts = db_extract(NULL);
                break;
    case HELP:
                sts = help();
                break;
    case IMPORT:
                sts = db_import(NULL);
                break;
    case INSERT:
                sts = insert();
                break;
    case PRINT:
                sts = print();
                break;
    case SELECT:
                sts = select();
                break;
    case SET:
                sts = set();
                break;
    case SHOW:
                sts = mc_show();
                break;
    case SORT:
                sts = db_sort(NULL);
                break;
    case UPDATE:
                sts = update();
                break;
    default:
                return (db_ferror(SYNTAX));
    }

    return (sts);
}

/* help - print a short help message */
static int help()
{
    FILE *fp;
    int ch;

    if ((fp = fopen("sdb.hlp","r")) != NULL) {
     /* while ((ch = agetc(fp)) != EOF)    dns */
        while ((ch =  getc(fp)) != EOF)
            putchar(ch);
        fclose(fp);
    }
    else
        printf("No online help available.  Read the manual\n");

    /* return successfully */
    return (TRUE);
}

/* create - create a new relation */
static int create()
{
    struct relation *rptr;
    char aname[STRINGMAX+1];
    int atype;

    /* get relation name */
    if (db_ntoken() != ID)
        return (db_ferror(SYNTAX));

    /* start relation creation */
    if ((rptr = db_rcreate(dbv_tstring)) == NULL)
        return (FALSE);

    /* check for attribute list */
    if (db_ntoken() != '(') {
        free(rptr);
        return (db_ferror(SYNTAX));
    }

    /* parse the attributes */
    while (TRUE) {

        /* get the attribute name */
        if (db_ntoken() != ID) {
            free(rptr);
            return (db_ferror(SYNTAX));
        }
        strcpy(aname,dbv_tstring);

        /* get the attribute type */
        db_ntoken();
        if (dbv_token == CHAR)
            atype = TCHAR;
        else if (dbv_token == NUM)
            atype = TNUM;
        else {
            free(rptr);
            return (db_ferror(SYNTAX));
        }

        /* get the attribute size */
        if (db_ntoken() != NUMBER) {
            free(rptr);
            return (db_ferror(SYNTAX));
        }

        /* add the attribute */
        if (!db_rcattr(rptr,aname,atype,dbv_tvalue)) {
            free(rptr);
            return (FALSE);
        }

        /* check for end of attributes */
        if (db_token() != ID)
            break;
    }

    /* check for attribute list end */
    if (db_ntoken() != ')') {
        free(rptr);
        return (db_ferror(SYNTAX));
    }

    /* check for relation size */
    if (db_ntoken() != NUMBER) {
        free(rptr);
        return (db_ferror(SYNTAX));
    }

    /* finish relation creation */
    if (!db_rcheader(rptr))
        return (FALSE);
    if (!db_rctuples(rptr,dbv_tvalue))
        return (FALSE);
    if (!db_rcdone(rptr))
        return (FALSE);

    /* return successfully */
    return (TRUE);
}

/* insert - insert a tuple into a relation */
static int insert()
{
    struct scan *sptr;
    struct attribute *aptr;
    char aname[ANSIZE+1],avalue[STRINGMAX+1];
    int tcnt,astart,i;

    /* get relation name */
    if (db_token() == ID)
        db_ntoken();
    else
        strcpy(dbv_tstring,"sdbcur");

    /* make sure that the rest of the line is blank */
    if (!db_flush())
        return (FALSE);

    /* open the relation */
    if ((sptr = db_ropen(dbv_tstring)) == NULL)
        return (FALSE);

    /* insert tuples */
    for (tcnt = 0; ; tcnt++) {

        /* print separator if not the first tuple */
        if (tcnt != 0)
            printf("----\n");

        /* get attribute values */
        astart = 1;
        for (i = 0; i < NATTRS; i++) {

            /* get a pointer to the current attribute */
            aptr = &sptr->sc_relation->rl_header.hd_attrs[i];

            /* check for the last attribute */
            if (aptr->at_name[0] == 0)
                break;

            /* get the attribute name */
            strncpy(aname,aptr->at_name,ANSIZE); aname[ANSIZE] = 0;

            /* setup null prompt strings */
            db_prompt(NULL,NULL);

            /* prompt and input attribute value */
            while (TRUE) {
                if (dbv_ifp == NULL)
                    if (strlen(aname) < 8)
                        printf("%s\t\t: ",aname);
                    else
                        printf("%s\t: ",aname);
                if (db_gline(avalue) != NULL)
                    break;
            }

            /* check for last insert */
            if (i == 0 && avalue[0] == EOS)
                break;

            /* store the attribute value */
            db_aput(aptr,&sptr->sc_tuple[astart],avalue);

            /* update the attribute start */
            astart += aptr->at_size;
        }

        /* check for last insert */
        if (avalue[0] == EOS)
            break;

        /* store the new tuple */
        if (!db_rstore(sptr)) {
            db_rclose(sptr);
            return (FALSE);
        }
    }

    /* close the relation */
    db_rclose(sptr);

    /* check number of tuples inserted */
    if (tcnt != 0) {

        /* print tuple count */
        printf("[ %d inserted ]\n",tcnt);
    }
    else
        printf("[ none inserted ]\n");

    /* return successfully */
    return (TRUE);
}

/* delete - delete tuples from a relation */
static int delete()
{
    struct sel *slptr;
    struct srel *srptr;
    int tcnt;

    /* parse the retrieval clause */
    if ((slptr = db_retrieve(NULL)) == NULL)
        return (FALSE);

    /* loop through the retrieved tuples */
    for (tcnt = 0; db_fetch(slptr); tcnt++)

        /* delete the retrieved tuples */
        for (srptr = slptr->sl_rels; srptr != NULL; srptr = srptr->sr_next)
            if (!db_rdelete(srptr->sr_scan)) {
                db_done(slptr);
                return (FALSE);
            }

    /* finish the retrieval */
    db_done(slptr);

    /* check number of tuples deleted */
    if (tcnt != 0) {

        /* print tuple count */
        printf("[ %d deleted ]\n",tcnt);
    }
    else
        printf("[ none deleted ]\n");

    /* return successfully */
    return (TRUE);
}

/* update - update tuples from a relation */
static int update()
{
    struct sel *slptr;
    struct sattr *saptr;
    struct attribute *aptr;
    char aname[ANSIZE+1],avalue[STRINGMAX+1],*ap;
    int tcnt;

    /* parse the selection clause */
    if ((slptr = db_select(NULL)) == NULL)
        return (FALSE);

    /* make sure that the rest of the line is blank */
    if (!db_flush()) {
        db_done(slptr);
        return (FALSE);
    }

    /* loop through the selected tuples */
    for (tcnt = 0; db_fetch(slptr); tcnt++) {

        /* print separator if not the first tuple */
        if (tcnt != 0)
            printf("----\n");

        /* loop through the selected attributes */
        for (saptr = slptr->sl_attrs; saptr != NULL; saptr = saptr->sa_next) {

            /* get the attribute pointer */
            aptr = saptr->sa_attr;

            /* get the attribute name */
            strncpy(aname,aptr->at_name,ANSIZE); aname[ANSIZE] = 0;

            /* get the attribute value */
            db_aget(aptr,saptr->sa_aptr,avalue);
            for (ap = avalue; isspace(*ap); ap++)
                ;

            /* print it */
            if (strlen(aname) < 8)
                printf("%s\t\t: %s\n",aname,ap);
            else
                printf("%s\t: %s\n",aname,ap);

            /* setup null prompt strings */
            db_prompt(NULL,NULL);

            /* prompt and input attribute value */
            while (TRUE) {
                if (strlen(aname) < 8)
                    printf("%s\t\t: ",aname);
                else
                    printf("%s\t: ",aname);
                if (db_gline(avalue) != NULL)
                    break;
            }

            /* store the attribute value */
            if (avalue[0] != EOS) {
                db_aput(aptr,saptr->sa_aptr,avalue);
                saptr->sa_srel->sr_update = TRUE;
            }
        }

        /* update the tuples */
        db_update(slptr);
    }

    /* finish the selection */
    db_done(slptr);

    /* check number of tuples updated */
    if (tcnt != 0) {

        /* print tuple count */
        printf("[ %d updated ]\n",tcnt);
    }
    else
        printf("[ none updated ]\n");

    /* return successfully */
    return (TRUE);
}

/* print - print tuples from a set of relations */
static int print()
{
    struct sel *slptr;
    FILE *ffp,*ofp;
    int tcnt;

    /* parse the using clause */
    if (!using(&ffp,".frm"))
        return (FALSE);

    /* parse the select clause */
    if ((slptr = db_select(NULL)) == NULL)
        return (FALSE);

    /* parse the into clause */
    if (!db_to(&ofp,".txt")) {
        db_done(slptr);
        return (FALSE);
    }

    /* check for normal or formated output */
    if (ffp == NULL)
        tcnt = table(ofp,slptr);
    else
        tcnt = form(ofp,slptr,ffp);

    /* finish the selection */
    db_done(slptr);

    /* close the form definition file */
    if (ffp != NULL)
        fclose(ffp);

    /* close the output file */
    if (ofp != stdout)
        fclose(ofp);

    /* check number of tuples selected */
    if (tcnt != 0)
        printf("[ %d found ]\n",tcnt);
    else
        printf("[ none found ]\n");

    /* return successfully */
    return (TRUE);
}

/* select - select tuples from a set of relations */
static int select()
{
    struct sel *slptr;
    struct relation *rptr;
    struct sattr *saptr;
    char *aname,*tbuf;
    int tcnt,abase,i;

    /* parse the select clause */
    if ((slptr = db_select(NULL)) == NULL)
        return (FALSE);

    /* create a new relation */
    if ((rptr = db_rcreate("sdbcur")) == NULL) {
        db_done(slptr);
        return (FALSE);
    }

    /* create the selected attributes */
    for (saptr = slptr->sl_attrs; saptr != NULL; saptr = saptr->sa_next) {

        /* decide which attribute name to use */
        if ((aname = saptr->sa_name) == NULL)
            aname = saptr->sa_aname;

        /* add the attribute */
        if (!db_rcattr(rptr,aname,saptr->sa_attr->at_type,
                                  saptr->sa_attr->at_size)) {
            free(rptr);
            db_done(slptr);
            return (FALSE);
        }
    }

    /* create the relation header */
    if (!db_rcheader(rptr)) {
        db_done(slptr);
        return (FALSE);
    }

    /* allocate and initialize a tuple buffer */
    if ((tbuf = calloc(1,rptr->rl_size)) == NULL) {
        db_rcdone(rptr);
        return (db_ferror(INSMEM));
    }
    tbuf[0] = ACTIVE;

    /* loop through the selected tuples */
    for (tcnt = 0; db_fetch(slptr); tcnt++) {

        /* create the tuple from the selected attributes */
        abase = 1;
        for (saptr = slptr->sl_attrs; saptr != NULL; saptr = saptr->sa_next) {
            for (i = 0; i < saptr->sa_attr->at_size; i++)
                tbuf[abase + i] = saptr->sa_aptr[i];
            abase += i;
        }

        /* write the tuple */
        if (write(rptr->rl_fd,tbuf,rptr->rl_size) != rptr->rl_size) {
            db_rcdone(rptr);
            free(tbuf);
            return (db_ferror(INSBLK));
        }
        rptr->rl_tcnt++;
        rptr->rl_tmax++;
    }

    /* finish the selection */
    db_done(slptr);

    /* finish relation creation */
    if (!db_rcdone(rptr))
        return (FALSE);

    /* check number of tuples selected */
    if (tcnt != 0)
        printf("[ %d found ]\n",tcnt);
    else
        printf("[ none found ]\n");

    /* return successfully */
    return (TRUE);
}

/* mc_define - define a macro */
static int mc_define()
{
    struct macro *mptr,*mlast;
    struct mtext *tptr,*tlast;
    char textline[LINEMAX+1];

    /* get macro name */
    if (db_xntoken() != ID)
        return (db_ferror(SYNTAX));

    /* make sure that the rest of the line is blank */
    if (!db_flush())
        return (FALSE);

    /* find the macro in the macro table and free it */
    for (mptr = dbv_macros, mlast = NULL; mptr != NULL; mlast = mptr, mptr = mptr->mc_next)
        if (db_scmp(mptr->mc_name,dbv_tstring) == 0) {
            if (mlast == NULL)
                dbv_macros = mptr->mc_next;
            else
                mlast->mc_next = mptr->mc_next;
            mc_free(mptr);
        }

    /* allocate and initialize a macro structure */
    if ((mptr = malloc(sizeof(struct macro))) == NULL)
        return (db_ferror(INSMEM));
    if ((mptr->mc_name = malloc(strlen(dbv_tstring)+1)) == NULL) {
        free(mptr);
        return (db_ferror(INSMEM));
    }
    strcpy(mptr->mc_name,dbv_tstring);
    mptr->mc_mtext = NULL;

    /* setup null prompt strings */
    db_prompt(NULL,"SDB-DEF> ");

    /* get definition text */
    for (tlast = NULL; ; tlast = tptr) {

        /* get a line */
        db_gline(textline);
        if (textline[0] == EOS || textline[0] == '\n')
            break;

        /* allocate a macro text structure */
        if ((tptr = malloc(sizeof(struct mtext))) == NULL) {
            mc_free(mptr);
            return (db_ferror(INSMEM));
        }
        if ((tptr->mt_text = malloc(strlen(textline)+1)) == NULL) {
            mc_free(mptr);
            return (db_ferror(INSMEM));
        }
        strcpy(tptr->mt_text,textline);
        tptr->mt_next = NULL;

        /* link it into the macro list */
        if (tlast == NULL)
            mptr->mc_mtext = tptr;
        else
            tlast->mt_next = tptr;
    }

    /* link the new macro into the macro list */
    if (tlast == NULL)
        mc_free(mptr);
    else {
        mptr->mc_next = dbv_macros;
        dbv_macros = mptr;
    }

    /* return successfully */
    return (TRUE);
}

/* mc_show - show a macro */
static int mc_show()
{
    struct macro *mptr;
    struct mtext *tptr;

    /* get macro name */
    if (db_xntoken() != ID)
        return (db_ferror(SYNTAX));

    /* find the macro in the macro table */
    for (mptr = dbv_macros; mptr != NULL; mptr = mptr->mc_next)
        if (db_scmp(mptr->mc_name,dbv_tstring) == 0) {
            for (tptr = mptr->mc_mtext; tptr != NULL; tptr = tptr->mt_next)
                printf("\t%s\n",tptr->mt_text);
            break;
        }

    /* check for successful search */
    if (mptr == NULL)
        printf("*** no macro named: %s ***\n",dbv_tstring);

    /* return successfully */
    return (TRUE);
}

/* mc_free - free a macro definition */
static mc_free(mptr)
  struct macro *mptr;
{
    struct mtext *tptr;

    while ((tptr = mptr->mc_mtext) != NULL) {
        mptr->mc_mtext = tptr->mt_next;
        free(tptr->mt_text);
        free(tptr);
    }
    free(mptr->mc_name);
    free(mptr);
}

/* db_to - redirect output into a file */
int db_to(pfp,ext)
  FILE **pfp; char *ext;
{
#ifdef vms
    int fd;
#endif

    /* assume no into clause */
    *pfp = stdout;

    /* check for "into <fname>" */
    if (db_token() != INTO)
        return (TRUE);
    db_ntoken();
    if (db_ntoken() == ID)
        strcat(dbv_tstring,ext);
    else if (dbv_token != STRING)
        return (db_ferror(SYNTAX));

    /* open the output file */
#ifdef vms
    if ((fd = creat(dbv_tstring,0,"rfm=var","rat=cr")) == -1)
        return (db_ferror(OUTCRE));
    *pfp = fdopen(fd,"w");
#else
#ifdef Lattice
    _fmode = 0x8000;  /*dns*/
#endif
    *pfp = fopen(dbv_tstring,"w");  /*dns*/
#ifdef Lattice
    _fmode = 0;       /*dns*/
#endif
    if (*pfp == NULL)               /*dns*/
        return (db_ferror(OUTCRE)); /*dns*/
#endif

    /* return successfully */
    return (TRUE);
}

/* using - get form definition file spec */
static int using(pfp,ext)
  FILE **pfp; char *ext;
{
    /* assume no using clause */
    *pfp = NULL;

    /* check for "using <fname>" */
    if (db_token() != USING)
        return (TRUE);
    db_ntoken();
    if (db_ntoken() == ID)
        strcat(dbv_tstring,ext);
    else if (dbv_token != STRING)
        return (db_ferror(SYNTAX));

    /* open the input file */
    if ((*pfp = fopen(dbv_tstring,"r")) == NULL)
        return (db_ferror(INPFNF));

    /* return successfully */
    return (TRUE);
}

/* table - output a relation table */
static int table(fp,slptr)
  FILE *fp; struct sel *slptr;
{
    int tcnt;

    /* loop through the selected tuples */
    for (tcnt = 0; db_fetch(slptr); tcnt++) {

        /* print table head on first tuple selected */
        if (tcnt == 0)
            db_thead(fp,slptr);

        /* print the tuple */
        db_tentry(fp,slptr);
    }

    /* print table foot */
    if (tcnt != 0)
        db_tfoot(fp,slptr);

    /* return the tuple count */
    return (tcnt);
}

/* form - process a form */
static int form(ofp,slptr,ffp)
  FILE *ofp; struct sel *slptr; FILE *ffp;
{
    char aname[ANSIZE+1];
    int ch,tcnt,pad;

    /* loop through the selected tuples */
    for (tcnt = 0; db_fetch(slptr); tcnt++) {

        /* reposition the form definition file */
        fseek(ffp,0L,0);

        /* process the form */
        while ((ch = getc(ffp)) != -1)
            if (ch == '<') {
                get_aname(ffp,aname,&pad);
                put_avalue(ofp,slptr,aname,pad);
            }
            else
                putc(ch,ofp);
    }

    /* return the tuple count */
    return (tcnt);
}

/* get_aname - get an attribute name (and padding flag [mpk]) */
static get_aname(fp,aname,pad)
  FILE *fp; char *aname; int *pad;
{
    int ch;

    if ((ch = getc(fp)) != '$') { /* mpk */
	ungetc(ch,fp);	/* put it back! */
	*pad = 1;
    }
    else
        *pad = 0;
    while ((ch = getc(fp)) != '>')
        if (!isspace(ch))
            *aname++ = ch;
    *aname = 0;
}

/* put_avalue - output attribute value */
static put_avalue(fp,slptr,aname,pad)
  FILE *fp; struct sel *slptr; char *aname; int pad;
{
    struct sattr *saptr;
    char *saname;
    int i;

    /* loop through the selected attributes */
    for (saptr = slptr->sl_attrs; saptr != NULL; saptr = saptr->sa_next) {

        /* check the selected attribute name */
        if ((saname = saptr->sa_name) == NULL)
            saname = saptr->sa_aname;
        if (db_scmp(saname,aname) == 0)
            break;
    }

    if (saptr == NULL) {
        fprintf(fp,"<error>");
        return;
    }

    /* get the attribute value */
    for (i = 0; i < saptr->sa_attr->at_size; i++)
        if (saptr->sa_aptr[i] != 0)
            putc(saptr->sa_aptr[i],fp);
        else if (pad)	/* MPK 25-Mar-1986 */
            putc(' ',fp);
}

/* set - set internal parameters */
static int set()
{
    int value;

    /* process each set request */
    while (db_token() == ID) {

        /* skip the identifier */
        db_ntoken();

        /* check for "no" */
        if (db_scmp(dbv_tstring,"no") == 0) {
            value = FALSE;
            if (db_token() != ID)
                return (db_ferror(BADSET));
            db_ntoken();
        }
        else
            value = TRUE;

        /* check for parameter to set */
        if (db_scmp(dbv_tstring,"fold") == 0)
            dbv_fold = value;
        else
            return (db_ferror(BADSET));
    }

    /* return successfully */
    return (TRUE);
}

SHAR_EOF
#	End of shell archive
exit 0
Technical Details
Message-ID: <1851@j.cc.purdue.edu>
Path: arc1-ca.pugleaf.net!utzoo!mnetor!seismo!gatech!akgua!mhuxv!mhuxf!mhuxm!mhuxn!ihnp4!inuxc!pur-ee!j.cc.purdue.edu!doc

Show Full Headers
Complete Article Headers
Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: arc1-ca.pugleaf.net!utzoo!mnetor!seismo!gatech!akgua!mhuxv!mhuxf!mhuxm!mhuxn!ihnp4!inuxc!pur-ee!j.cc.purdue.edu!doc
From: doc@pucc-j.UUCP
Newsgroups: mod.amiga.sources
Subject: sdb Database (2 of 3)
Message-ID: <1851@j.cc.purdue.edu>
Date: Fri, 22-Aug-86 18:46:03 EDT
Article-I.D.: j.1851
Posted: Fri Aug 22 18:46:03 1986
Date-Received: Sun, 24-Aug-86 09:03:49 EDT
Sender: doc@j.cc.purdue.edu
Organization: Purdue University Computing Center
Lines: 2129
Approved: doc@pucc-j.UUCP