/*
 * File: lrec.c
 *  Contents: field, mkrec
 */

#include "..\h\config.h"
#include "..\h\rt.h"
#include "rproto.h"


/*
 * x.y - access field y of record x.
 */

LibDcl(field,2,".")
   {
   register word fnum;
   register struct b_record *rp;
   register dptr dp;
   extern word *ftabp, *records;

#if MACINTOSH
#if MPW
/* #pragma unused(nargs) */
#endif					/* MPW */
#endif					/* MACINTOSH */

   if (DeRef(Arg1) == Error) 
      RunErr(0, NULL);

   /*
    * Arg1 must be a record and Arg2 must be a field number.
    */
   if (Arg1.dword != D_Record) 
      RunErr(107, &Arg1);

   /*
    * Map the field number into a field number for the record x.
    */
   rp = (struct b_record *) BlkLoc(Arg1);
   fnum = ftabp[IntVal(Arg2) * *records + rp->recdesc->proc.recnum - 1];
   /*
    * If fnum < 0, x doesn't contain the specified field.
    */
   if (fnum < 0) 
      RunErr(207, &Arg1);

   /*
    * Return a pointer to the descriptor for the appropriate field.
    */
   dp = &rp->fields[fnum];
   Arg0.dword = D_Var + ((word *)dp - (word *)rp);
   VarLoc(Arg0) = (dptr)rp;
   Return;
   }


/*
 * mkrec - create a record.
 */

LibDcl(mkrec,-1,"mkrec")
   {
   register int i;
   register struct b_proc *bp;
   register struct b_record *rp;

   /*
    * Be sure that call is from a procedure.
    */

   /*
    * Ensure space for the record to be created.
    */
   if (blkreq((uword)sizeof(struct b_record) +
         BlkLoc(Arg(0))->proc.nfields*sizeof(struct descrip)) == Error) 
      RunErr(0, NULL);

   /*
    * Get a pointer to the record constructor procedure and allocate
    *  a record with the appropriate number of fields.
    */
   bp = (struct b_proc *) BlkLoc(Arg(0));
   rp = alcrecd((int)bp->nfields, (union block **)bp);
   rp->id = (bp->recid)++;

   /*
    * Set all fields in the new record to null value.
    */
   for (i = (int)bp->nfields; i > nargs; i--)
      rp->fields[i-1] = nulldesc;

   /*
    * Assign each argument value to a record element and dereference it.
    */
   for ( ; i > 0; i--) {
      rp->fields[i-1] = Arg(i);
      if (DeRef(rp->fields[i-1]) == Error) 
         RunErr(0, NULL);
      }

   ArgType(0) = D_Record;
   Arg(0).vword.bptr = (union block *)rp;
   Return;
   }
