+
+ /*
+ * descend namelist entry for a record and assign offsets.
+ * fields go at the next higher offset that suits their alignment.
+ * all variants of a record start at the same offset, which is suitable
+ * for the alignment of their worst aligned field. thus the size of a
+ * record is independent of whether or not it is a variant
+ * (a desirable property).
+ * records come to us in the namelist, where they have been annotated
+ * with the maximum alignment their fields require.
+ * the starting offset is passed to us, and is passed recursively for
+ * variant records within records.
+ * the final maximum size of each record is recorded in the namelist
+ * in the value[NL_OFFS] field of the namelist for the record.
+ *
+ * this is supposed to match the offsets used by the c compiler
+ * so people can share records between modules in both languages.
+ */
+rec_offsets(recp, offset)
+ struct nl *recp; /* pointer to the namelist record */
+ long offset; /* starting offset for this record/field */
+{
+ long origin; /* offset of next field */
+ struct nl *fieldnlp; /* the current field */
+ struct nl *varntnlp; /* the current variant */
+ struct nl *vrecnlp; /* record for the current variant */
+ long alignment; /* maximum alignment for any variant */
+
+ if ( recp == NIL ) {
+ return;
+ }
+ origin = roundup(offset,recp->align_info);
+ if (origin != offset) {
+ fprintf(stderr,
+ "[rec_offsets] offset=%d recp->align_info=%d origin=%d\n",
+ offset, recp->align_info, origin);
+ panic("rec_offsets");
+ }
+ DEBUG_RECORDS(
+ fprintf(stderr,
+ "[rec_offsets] offset %d recp->align %d origin %d\n",
+ offset, recp->align_info, origin));
+ /*
+ * fixed fields are forward linked though ->ptr[NL_FIELDLIST]
+ * give them all suitable offsets.
+ */
+ for ( fieldnlp = recp->ptr[NL_FIELDLIST];
+ fieldnlp != NIL;
+ fieldnlp = fieldnlp->ptr[NL_FIELDLIST] ) {
+ origin = roundup(origin,align(fieldnlp->type));
+ fieldnlp->value[NL_OFFS] = origin;
+ DEBUG_RECORDS(
+ fprintf(stderr,"[rec_offsets] symbol %s origin %d\n",
+ fieldnlp->symbol, origin));
+ origin += lwidth(fieldnlp->type);
+ }
+ /*
+ * this is the extent of the record, so far
+ */
+ recp->value[NL_OFFS] = origin;
+ /*
+ * if we have a tag field, we have variants to deal with
+ */
+ if ( recp->ptr[NL_TAG] ) {
+ /*
+ * if tag field is unnamed, then don't allocate space for it.
+ */
+ fieldnlp = recp->ptr[NL_TAG];
+ if ( fieldnlp->symbol != NIL ) {
+ origin = roundup(origin,align(fieldnlp->type));
+ fieldnlp->value[NL_OFFS] = origin;
+ DEBUG_RECORDS(fprintf(stderr,"[rec_offsets] tag %s origin\n",
+ fieldnlp->symbol, origin));
+ origin += lwidth(fieldnlp->type);
+ }
+ /*
+ * find maximum alignment of records of variants
+ */
+ for ( varntnlp = recp->ptr[NL_VARNT];
+ varntnlp != NIL;
+ varntnlp = varntnlp -> chain ) {
+ vrecnlp = varntnlp->ptr[NL_VTOREC];
+ DEBUG_RECORDS(
+ fprintf(stderr,
+ "[rec_offsets] maxing variant %d align_info %d\n",
+ varntnlp->value[0], vrecnlp->align_info));
+ origin = roundup(origin,vrecnlp->align_info);
+ }
+ DEBUG_RECORDS(
+ fprintf(stderr, "[rec_offsets] origin of variants %d\n", origin));
+ /*
+ * assign offsets to fields of records of the variants
+ * keep maximum length of the current record.
+ */
+ for ( varntnlp = recp->ptr[NL_VARNT];
+ varntnlp != NIL;
+ varntnlp = varntnlp -> chain ) {
+ vrecnlp = varntnlp->ptr[NL_VTOREC];
+ /*
+ * assign offsets to fields of the variant.
+ * recursive call on rec_offsets.
+ */
+ rec_offsets(vrecnlp,origin);
+ /*
+ * extent of the record is the
+ * maximum extent of all variants
+ */
+ if ( vrecnlp->value[NL_OFFS] > recp->value[NL_OFFS] ) {
+ recp->value[NL_OFFS] = vrecnlp->value[NL_OFFS];
+ }
+ }
+ }
+ /*
+ * roundup the size of the record to its alignment
+ */
+ DEBUG_RECORDS(
+ fprintf(stderr,
+ "[rec_offsets] recp->value[NL_OFFS] %d ->align_info %d\n",
+ recp->value[NL_OFFS], recp->align_info));
+ recp->value[NL_OFFS] = roundup(recp->value[NL_OFFS],recp->align_info);
+}