/*
*      Copyright Microsoft Corporation, 1983-1989
*
*      This Module contains Proprietary Information of Microsoft
*      Corporation and should be treated as Confidential.
*/
    /****************************************************************
    *                                                               *
    *                           NEWTP1.C                            *
    *                                                               *
    *  Pass 1 object module processing routines.                    *
    *                                                               *
    ****************************************************************/

#include                <minlit.h>      /* Basic types and constants */
#include                <bndtrn.h>      /* More types and constants */
#include                <bndrel.h>      /* Relocation record definitions */
#include                <lnkio.h>       /* Linker I/O definitions */
#include                <newexe.h>      /* DOS & 286 .EXE data structures */
#if EXE386
#include                <exe386.h>      /* 386 .EXE data structures */
#endif
#include                <lnkmsg.h>      /* Error messages */
#if OXOUT OR OIAPX286
#include                <xenfmt.h>      /* Xenix format definitions */
#endif
#include                <extern.h>      /* External declarations */
#include                <undname.h>
#if OVERLAYS
      WORD              iovFile;        /* Overlay number of input file */
#endif
LOCAL FTYPE             fP2Start;       /* Start of Pass 2 records */
LOCAL FTYPE             fModEnd;        /* MODEND seen */
LOCAL WORD              cSegCode;       /* Number of code seg's in module */

#if O68K
#define F68KCODE(ch)    ((ch) >= 'A' && (ch) <= 'E')
#endif /* O68K */
/*
 *  LOCAL FUNCTION PROTOTYPES
 */

LOCAL void NEAR TypErr(MSGTYPE msg,unsigned char *sb);
LOCAL void NEAR DoCommon(APROPUNDEFPTR apropUndef,
                          long length,
                          unsigned short cbEl,
                          unsigned char *sb);
LOCAL void NEAR SegUnreliable(APROPSNPTR apropSn);
LOCAL void NEAR redefinition(WORD iextWeak, WORD iextDefRes, RBTYPE oldDefRes);
LOCAL void NEAR SegRc1(void);
LOCAL void NEAR TypRc1(void);
LOCAL void NEAR ComDf1(void);
LOCAL void NEAR GrpRc1(void);
LOCAL void NEAR PubRc1(void);
LOCAL void NEAR ExtRc1(void);
LOCAL void NEAR imprc1(void);
LOCAL void NEAR exprc1(void);
LOCAL void NEAR ComRc1(void);
LOCAL void NEAR EndRc1(void);

extern  void NEAR FixRc1(void);

LOCAL void NEAR     redefinition(WORD iextWeak, WORD iextDefRes, RBTYPE oldDefRes)
{
    // Redefinition of default resolution.
    // Warn the user.

    SBTYPE          oldDefault;
    SBTYPE          newDefault;
    APROPUNDEFPTR   undef;
    AHTEPTR         rhte;

    undef = (APROPUNDEFPTR ) FetchSym(oldDefRes, FALSE);
    while (undef->au_attr != ATTRNIL)
    {
        rhte = (AHTEPTR) undef->au_next;
                /* Try next entry in list */
        undef = (APROPUNDEFPTR ) FetchSym((RBTYPE)rhte,FALSE);
                /* Fetch it from VM */
    }
    strcpy(oldDefault, GetFarSb(rhte->cch));
    undef = (APROPUNDEFPTR ) FetchSym(mpextprop[iextDefRes], FALSE);
    while (undef->au_attr != ATTRNIL)
    {
        rhte = (AHTEPTR) undef->au_next;
                /* Try next entry in list */
        undef = (APROPUNDEFPTR ) FetchSym((RBTYPE)rhte,FALSE);
                /* Fetch it from VM */
    }
    strcpy(newDefault, GetFarSb(rhte->cch));
    undef = (APROPUNDEFPTR ) FetchSym(mpextprop[iextWeak], FALSE);
    while (undef->au_attr != ATTRNIL)
    {
        rhte = (AHTEPTR) undef->au_next;
                        /* Try next entry in list */
        undef = (APROPUNDEFPTR ) FetchSym((RBTYPE)rhte,FALSE);
                        /* Fetch it from VM */
    }
    OutWarn(ER_weakredef, 1 + GetFarSb(rhte->cch), &oldDefault[1], &newDefault[1]);
}

/*** IsDebSeg - check is segment is one of the special debug segments
*
* Purpose:
*   Check if segment name and class name match reserved debugger
*   segment names.
*
* Input:
*   - rhteClass - pointer to class name
*   - rhteSeg   - pointer to segment name
*
* Output:
*   If this is a debug segment function returns 1 for $$TYPES, and 2
*   for $$SYMBOLS.  For non-debug segments it returns FALSE.
*
* Exceptions:
*   None.
*
* Notes:
*   None.
*
*************************************************************************/

WORD NEAR               IsDebSeg(RBTYPE rhteClass, RBTYPE rhteSeg)
{
    if (rhteClass == rhteDebTyp)
        return ((rhteSeg == rhteTypes || rhteSeg == rhte0Types) ? 1 : FALSE);
    else if (rhteClass == rhteDebSym)
        return ((rhteSeg == rhteSymbols || rhteSeg == rhte0Symbols) ? 2 : FALSE);
    else
        return(FALSE);
}


    /****************************************************************
    *                                                               *
    *  ModRc1:                                                      *
    *                                                               *
    *  This function reads the name from a THEADR record and makes  *
    *  an entry containing the name in the hash table.              *
    *  See p. 26 in "8086 Object Module Formats EPS."               *
    *                                                               *
    ****************************************************************/

void NEAR               ModRc1(void)
{
    APROPFILEPTR        apropFile;

    sbModule[0] = (BYTE) Gets();        /* Read in the length byte */
    GetBytes(&sbModule[1],B2W(sbModule[0]));
                                        /* Read in the name */
    PropSymLookup(sbModule, ATTRNIL, TRUE);
                                        /* Make entry in hash table */
    apropFile = (APROPFILEPTR ) FetchSym(vrpropFile,TRUE);
                                        /* Allocate space in virt mem */


    // The name of a module is given by the very first THEADR record

    if(apropFile->af_rMod == 0)
            apropFile->af_rMod = vrhte;         /* Load pointer into hash table */
#if FDEBUG
    if(fDebug)                          /* If runtime debugging on */
    {
        OutFileCur(stderr);             /* Write current file and module */
        NEWLINE(stderr);
    }
#endif
}

long NEAR               TypLen()        /* Get type length */
{
    WORD                b;              /* Byte value */
    long                l;              /* Size */

    if(cbRec < 2) InvalidObject();      /* Make sure record long enough */
    b = Gets();                         /* Get length byte */
    if(b < 128) return(B2L(b));         /* One byte length field */
    if(b == 129)                        /* If two byte length */
    {
        if(cbRec < 3) InvalidObject();  /* Make sure record long enough */
        return((long) WGets());         /* Return the length */
    }
    if(b == 132)                        /* If three byte length */
    {
        if(cbRec < 4) InvalidObject();  /* Make sure record long enough */
        l = (long) WGets();             /* Get the low word */
        return(l + ((long) Gets() << WORDLN));
                                        /* Return the length */
    }
    if(b == 136)                        /* If four byte length */
    {
        if(cbRec < 5) InvalidObject();  /* Make sure record long enough */
        l = (long) WGets();             /* Get the low word */
        return(l + ((long) WGets() << WORDLN));
                                        /* Return the length */
    }
    InvalidObject();                    /* Bad length specification */
}

    /****************************************************************
    *                                                               *
    *  TypRc1:                                                      *
    *                                                               *
    *  This function processes  TYPDEF records.  These records are  *
    *  difficult  to  understand.  They are (poorly) described  on  *
    *  pp. 40-43 of "8086  Object  Module  Formats EPS," with some  *
    *  additional  information on pp. 89-90.                        *
    *  Microsoft used to used them for communal variables but they  *
    *  have been superseded by COMDEF records.                      *
    *                                                               *
    ****************************************************************/

LOCAL void NEAR         TypRc1(void)
{
    long                l;
    WORD                b;
    WORD                typ;            /* Near or FAR */
    WORD                ityp;           /* Type index */

    if(typMac >= TYPMAX)
        Fatal(ER_typdef);
    SkipBytes(Gets());                  /* Skip the name field */
    Gets();                             /* Skip the EN byte */
    l = -1L;                            /* Initialize */
    mpityptyp[typMac] = 0;              /* Assume no element type */
    if(cbRec > 3)                       /* If at least four bytes left */
    {
        typ = Gets();                   /* Get type leaf */
        b = Gets();                     /* Get next leaf */
        if(typ == TYPENEAR)             /* If near variable */
        {
            if(b != 0x7B && b != 0x79 && b != 0x77) InvalidObject();
                                        /* Scalar, structure, or array */
            fCommon = (FTYPE) TRUE;     /* We have communal variables */
            l = (TypLen() + 7) >> 3;    /* Round length to nearest byte */
        }
        else if(typ == TYPEFAR)         /* Else if FAR variable */
        {
            if(b != 0x77) InvalidObject();
                                        /* Must have an array */
            fCommon = (FTYPE) TRUE;     /* We have communal variables */
            l = TypLen();               /* Get number of elements */
            ityp = GetIndex(1, (WORD) (typMac - 1));
                                        /* Get type index */
            if(mpityptyp[ityp] || mpitypelen[ityp] == -1L) InvalidObject();
                                        /* Must index valid TYPDEF */
            mpityptyp[typMac] = ityp;   /* Save type index */
            /* If element length too big, treat as TYPENEAR */
            if(mpitypelen[ityp] > CBELMAX)
            {
                l *= mpitypelen[ityp];
                mpitypelen[ityp] = 0;
            }
        }
    }
    mpitypelen[typMac++] = l;           /* Store length */
    SkipBytes((WORD) (cbRec - 1));      /* Skip all but the checksum */
}

LOCAL void NEAR         TypErr(msg,sb)  /* Type error message routine */
MSGTYPE                 msg;            /* Message */
BYTE                    *sb;            /* Symbol to which error refers */
{
    sb[B2W(sb[0]) + 1] = '\0';          /* Null-terminate */
    OutError(msg,1 + sb);
}

/*
 *  DoCommon
 *
 *  Resolves old and new communal definitions of the same symbol.
 *  Does work for both ComDf1() and ExtRc1().
 */

LOCAL void NEAR         DoCommon (apropUndef, length, cbEl, sb)
APROPUNDEFPTR           apropUndef;     /* Ptr to property cell */
long                    length;         /* Length or number of elements */
WORD                    cbEl;           /* # bytes per array element */
BYTE                    *sb;            /* Name of symbol */
{
    if(apropUndef->au_len == -1L)       /* If not previously a communal */
    {
        apropUndef->au_cbEl = cbEl;     /* Set the element size */
        MARKVP();                       /* Page has changed */
    }
    else if (cbEl == 0 && apropUndef->au_cbEl != 0)
    {                                   /* Else if near reference to FAR */
        apropUndef->au_len *= apropUndef->au_cbEl;
                                        /* Calculate FAR variable length */
        apropUndef->au_cbEl = 0;        /* Force DS-type to near */
        MARKVP();                       /* Page has changed */
        if (apropUndef->au_len > LXIVK) /* If huge variable */
        {
            TypErr(ER_nearhuge,sb);     /* Issue error message */
            return;                     /* Skip this symbol */
        }
    }
    else if (cbEl != 0 && apropUndef->au_cbEl == 0)
    {                                   /* Else if FAR reference to near */
        length *= cbEl;                 /* Calculate FAR variable length */
        cbEl = 0;                       /* Force DS-type to near */
        if (length > LXIVK)             /* If huge variable */
        {
            TypErr(ER_nearhuge,sb);     /* Issue error message */
            return;                     /* Skip this symbol */
        }
    }
    else if (cbEl != apropUndef->au_cbEl)
    {                                   /* If array element sizes don't match */
        TypErr(ER_arrmis,sb);
        return;                         /* Skip this symbol */
    }
    if (apropUndef->au_len < length)
    {                                   /* If new length is larger */
        apropUndef->au_len = length;    /* Save it */
        MARKVP();
    }
}

/*
 *  ComDf1
 *
 *  This function processes COMDEF records on pass 1.
 */
LOCAL void NEAR         ComDf1 (void)
{
        int tmp;                        /* workaround a cl bug */
    SBTYPE              sb;             /* COMDEF symbol */
    REGISTER APROPUNDEFPTR
                        apropUndef;     /* Pointer to symbol entry */
    long                length;         /* Communal variable length */
    long                cbEl;           /* Size of array element */
    WORD                itype;          /* Type index */

    while(cbRec > 1)                    /* While there are symbols left */
    {
        if(extMac >= EXTMAX - 1)        /* Check for table overflow */
            Fatal(ER_extdef);
        sb[0] = (BYTE) Gets();          /* Get symbol length */
        if(rect == COMDEF)
            GetBytes(&sb[1],B2W(sb[0]));/* Read in text of symbol */
        else
            GetLocName(sb);             /* Transform local name */
#if CMDXENIX
        if(symlen && B2W(sb[0]) > symlen) sb[0] = symlen;
                                        /* Truncate if necessary */
#endif
        itype = GetIndex(0,0x7FFF);     /* Get type index */
        tmp =  Gets();
        switch(tmp)                     /* Get data seg type */
        {
            case TYPENEAR:
                length = TypLen();      /* Get length */
                cbEl = 0;
                break;
            case TYPEFAR:
                length = TypLen();      /* Get number of elements */
                /* Get element length.  If too big, treat as near.  Cmerge
                 * will never generate cbEl > 64K so this is not a problem.
                 */
                if((cbEl = TypLen()) > CBELMAX)
                {
                    length *= cbEl;
                    cbEl = 0;
                }
                break;
            default:
                InvalidObject();        /* Unrecognized DS type */
        }
#if FALSE
if(fDebug)
{
sb[sb[0]+1] = '\0';
fprintf(stdout, "%s has index = %u\r\n", sb+1, extMac);
}
#endif
        apropUndef = (APROPUNDEFPTR) PropSymLookup(sb, ATTRPNM, FALSE);
                                        /* Look for a matching PUBDEF */
        if(apropUndef == PROPNIL)       /* If there isn't one */
        {
            /* Insert as undefined symbol */

            if (vrhte == RHTENIL)
               apropUndef = (APROPUNDEFPTR) PropSymLookup(sb, ATTRUND, TRUE);
            else
               apropUndef = (APROPUNDEFPTR) PropRhteLookup(vrhte, ATTRUND, TRUE);

            mpextprop[extMac++] = vrprop;
            fCommon = (FTYPE) TRUE;     /* There are communals */
            if (vfCreated)
                apropUndef->au_flags |= UNDECIDED;
            else if (apropUndef->au_flags & UNDECIDED)
            {
                apropUndef->au_flags &= ~(UNDECIDED | WEAKEXT | SUBSTITUTE);
                apropUndef->au_flags |= STRONGEXT;
            }
            else if (apropUndef->au_flags & WEAKEXT)
                apropUndef->au_flags |= UNDECIDED;

            if (vfCreated || !(apropUndef->au_flags & COMMUNAL))
            {                           /* If not previously defined */
                apropUndef->au_flags |= COMMUNAL;
                                        /* Mark as communal */
                apropUndef->au_len = -1L;
#if ILINK
                apropUndef->u.au_module = imodFile;
                                        /* Save module index.  */
#endif
                DoCommon(apropUndef, length, (WORD) cbEl, sb);
#if SYMDEB
                if (fSymdeb && (sb[0] != '\0' && sb[1] > ' ' && sb[1] <= '~'))
                {
#if O68K
                    /* REVIEW: This should not be under the O68K flag. */
                    apropUndef->au_CVtype = itype;
#endif /* O68K */
                    DebPublic(mpextprop[extMac-1], rect);
                }
#endif
            }
            else
                DoCommon(apropUndef, length, (WORD) cbEl, sb);
        }
        else
        {
            mpextprop[extMac++] = vrprop;
            if (mpgsnfCod[((APROPNAMEPTR )apropUndef)->an_gsn])
                                        /* Communal matches code PUBDEF */
                DupErr(sb);             /* Duplicate definition */
        }
    }
}


    /****************************************************************
    *                                                               *
    *  LNmRc1:                                                      *
    *                                                               *
    *  This function  reads LNAME records and  stores the names in  *
    *  the  hash table.  The function does not return a meaningful  *
    *  value.                                                       *
    *  See p. 31 in "8086 Object Module Formats EPS."               *
    *                                                               *
    ****************************************************************/

void NEAR               LNmRc1(WORD fLocal)
{
    SBTYPE              lname;          /* Buffer for lnames */
    RBTYPE FAR          *lnameTab;
#if NOT ALIGN_REC
    FILE *f;
#endif
    WORD cb;


    while(cbRec > 1)                    /* While not at end of record */
    {
        if (lnameMac >= lnameMax)
        {
            if (lnameMax >= (LXIVK >> 2))
                Fatal(ER_nammax);
            lnameTab = (RBTYPE FAR *) FREALLOC(mplnamerhte, 2*lnameMax*sizeof(RBTYPE));
            if (lnameTab == NULL)
                Fatal(ER_nammax);
            mplnamerhte = lnameTab;
            lnameMax <<= 1;
        }

#if ALIGN_REC
        if (!fLocal)
        {
            cb = 1 + *pbRec;
            PropSymLookup(pbRec, ATTRNIL, TRUE);
            cbRec   -= cb;
            pbRec   += cb;
        }
        else
        {
            lname[0] = (BYTE)Gets();    /* Get name length */
            GetLocName(lname);  /* Read in text of name */
            PropSymLookup(lname, ATTRNIL, TRUE);
        }
#else
        f = bsInput;

        if (!fLocal && f->_cnt && (WORD)f->_cnt > (cb = 1 + *(BYTE *)f->_ptr))
        {
            PropSymLookup((BYTE *)f->_ptr, ATTRNIL, TRUE);
            f->_cnt -= cb;
            f->_ptr += cb;
            cbRec   -= cb;
        }
        else
        {
            lname[0] = (BYTE) Gets();   /* Get name length */
            DEBUGVALUE(B2W(lname[0]));  /* Length of name */
            if (lname[0] > SBLEN - 1)
                Fatal(ER_badobj);
            if (fLocal)
                GetLocName(lname);
            else
                GetBytes(&lname[1],B2W(lname[0]));
                                        /* Read in text of name */
            DEBUGSB(lname);             /* The name itself */
            PropSymLookup(lname, ATTRNIL, TRUE);
        }
#endif
                                        /* Insert symbol in hash table */
        mplnamerhte[lnameMac++] = vrhte;/* Save address of hash table entry */
    }
}

/*
 *  GetPropName - get the name of a property cell.
 *
 *  Return pointer to the result, stored in a static buffer.
 *  Alternate between two buffers so we can be used in multi-part
 *  messages.
 *  Terminate result with null byte.
 */

typedef BYTE            SBTYPE1[SBLEN+1];/* 1 extra for null byte */

BYTE * NEAR             GetPropName(ahte)
AHTEPTR                 ahte;
{
    static SBTYPE1      msgbuf[2];
    static int          toggle = 0;
    char                *p;

    while(ahte->attr != ATTRNIL)
        ahte = (AHTEPTR ) FetchSym(ahte->rhteNext,FALSE);
    p = msgbuf[toggle ^= 1];

    /* Copy string to buffer */

    FMEMCPY((char FAR *) p, ahte->cch, B2W(ahte->cch[0]) + 1);
    p[1 + B2W(p[0])] = '\0';            /* Null-terminate */
    return(p);
}

/*
 * SegUnreliable - warning message for 286 bug
 */

LOCAL void NEAR         SegUnreliable (apropSn)
APROPSNPTR              apropSn;
{
    static FTYPE        fReported = FALSE;


    MARKVP();                           /* Take care of current vp */
    if (!fReported)
    {
        OutWarn(ER_segunsf,1 + GetPropName(apropSn));
        fReported = (FTYPE) TRUE;
    }
}


/*** CheckClass - check segment's class name
*
* Purpose:
*   Check if we have the segment with the same name but with different
*   class name.
*
* Input:
*   apropSn      - real pointer to segment symbol table descriptor
*   rhteClass    - hash vector entry for class name
*
* Output:
*   Returns real pointer to segment symbol table descriptor.
*
* Exceptions:
*   Found same segment with different class name - display error.
*
* Notes:
*   None.
*
*************************************************************************/

APROPSNPTR              CheckClass(APROPSNPTR apropSn, RBTYPE rhteClass)
{
#if ILINK
    FTYPE fDifClass = FALSE;
#endif


    while(apropSn->as_attr != ATTRNIL)
    {                                   /* Look for class match or list end */
        if(apropSn->as_attr == ATTRPSN &&
          apropSn->as_rCla == rhteClass) break;
                                        /* Break if pub. with matching class */
        apropSn = (APROPSNPTR ) FetchSym(apropSn->as_next,FALSE);
                                        /* Advance down the list */
#if ILINK
        fDifClass = (FTYPE) TRUE;       /* Same seg exists with dif. class */
#endif
    }
#if ILINK
    if(fIncremental && fDifClass)
        OutError(ER_difcls, 1 + GetPropName(apropSn));
#endif
    if(apropSn->as_attr == ATTRNIL)
    {                                   /* If attribute not public */
        vfCreated = (FTYPE) TRUE;       /* New cell */
        apropSn = (APROPSNPTR ) PropAdd(vrhte, ATTRPSN);
                                        /* Segment is public */
    }
    return(apropSn);
}

#if OVERLAYS
void                    CheckOvl(APROPSNPTR apropSn, WORD iovFile)
{
    SNTYPE              gsn;
    WORD                fCanOverlayData;
    WORD                fOverlaySegment;


    if (fOverlays)
    {

        // First check if mapping tables are allocated.
        //
        //      SNTYPE  mposngsn[OSNMAX];
        //      SNTYPE  htgsnosn[OSNMAX];

        if (mposngsn == NULL && htgsnosn == NULL)
        {
            mposngsn = (SNTYPE FAR *) GetMem(2*OSNMAX*sizeof(SNTYPE));
            htgsnosn = (SNTYPE FAR *) &mposngsn[OSNMAX];
        }

        fCanOverlayData = IsDataFlg(apropSn->as_flags) &&
                          apropSn->as_ggr != ggrDGroup &&
                          apropSn->as_fExtra & FROM_DEF_FILE &&
                          apropSn->as_iov != (IOVTYPE) NOTIOVL;
        fOverlaySegment = IsCodeFlg(apropSn->as_flags) || fCanOverlayData;
        if (fOverlaySegment)
        {
            // We allow DATA segment overlaying ONLY if they ar NOT a members
            // of DGROUP and HAVE preassigned overlay number form .DEF file.
            // If segment is to be overlaid - check overlay number assigments

            if ((apropSn->as_iov != (IOVTYPE) NOTIOVL) && (iovFile != apropSn->as_iov))
            {
                if (apropSn->as_fExtra & FROM_DEF_FILE)
                {
                    // Use .DEF file overlay assigment

                    iovFile = apropSn->as_iov;
                }
                else
                {
                    // Use current .OBJ file overlay assigment

                    OutWarn(ER_badsegovl, 1 + GetPropName(apropSn), apropSn->as_iov, iovFile);
                }
            }
        }

        if (iovFile != IOVROOT && fOverlaySegment)
        {
            if (osnMac < OSNMAX)
            {
                gsn = (SNTYPE)(apropSn->as_gsn & ((LG2OSN << 1) - 1));
                                            // Get initial hash index
                while (htgsnosn[gsn] != SNNIL)
                {                           // While buckets are full
                        if ((gsn += HTDELTA) >= OSNMAX)
                        gsn -= OSNMAX;      // Calculate next hash index
                }
                htgsnosn[gsn] = osnMac;     // Save overlay segment number
                mposngsn[osnMac++] = apropSn->as_gsn;
                                            // Map osn to gsn
                apropSn->as_iov = iovFile;  // Save overlay number
            }
            else
            {
                if (osnMac++ == OSNMAX)
                    OutWarn(ER_osnmax, OSNMAX);
                apropSn->as_iov = IOVROOT;
            }
        }
        else
            apropSn->as_iov = IOVROOT;      // Not an overlay
    }
    else
        apropSn->as_iov = IOVROOT;
}
#endif


    /****************************************************************
    *                                                               *
    *  SegRc1:                                                      *
    *                                                               *
    *  This function processes SEGDEF records.                      *
    *  See pp. 32-35 in "8086 Object Module Formats EPS."           *
    *                                                               *
    ****************************************************************/

LOCAL void NEAR         SegRc1(void)
{
    WORD                tysn;           /* ACBP byte */
    LNAMETYPE           lname;          /* Index into mplnamerhte */
    APROPSNPTR          apropSn;        /* Pointer to seg. record */
    SNTYPE              gsn;            /* Global SEGDEF number */
    WORD                align;          /* This contributuion alignment */
    WORD                prevAlign;      /* Logical segment aligment so FAR */
    WORD                comb;           /* Segment combine-type */
    DWORD               seglen;         /* Segment length */
    DWORD               contriblen;     /* Contribution length */
    DWORD               cbMaxPrev;      /* Segment length previously */
    AHTEPTR             ahte;           /* Pointer to hash table entry */
    SATYPE              saAbs;          /* Address for absolute seg */
    BYTE                flags;          /* Segment attribute flags */
    RBTYPE              rhteClass;      /* Class hash table address */
#if SYMDEB
    APROPFILEPTR        apropFile;
    CVINFO FAR          *pCvInfo;       // Pointer to CodeView information
#endif

    if(snMac >= SNMAX)
        Fatal(ER_segdef);
    tysn = Gets();                      /* Read in the ACBP byte */
    align = (WORD) ((tysn >> 5) & 7);   /* Get the alignment field */
    ASSERT(align != 6);                 /* Not supported by this linker */
    if(align == ALGNABS)                /* If absolute LSEG */
    {
        saAbs = (SATYPE) WGets();       /* Get the frame number */
        Gets();                         /* Punt the frame offset */
    }
#if OMF386
    if(rect & 1)                        /* If 386 extension */
        seglen = LGets();
    else
#endif
        seglen = (DWORD) WGets();       /* Get segment length */
    if(tysn & BIGBIT)
    {
#if OMF386
        if(rect & 1)
            seglen = CBMAXSEG32 + 1;    /* Force fatal error below */
        else
#endif
        seglen = LXIVK;                 /* Sixty-four K */
    }
    contriblen = seglen;
    lname = (LNAMETYPE) GetIndex(1, (WORD) (lnameMac - 1));
                                        /* Get segment name index */
    ahte = (AHTEPTR ) FetchSym(mplnamerhte[lname],FALSE);
    rhteClass = mplnamerhte[(LNAMETYPE) GetIndex(1, (WORD) (lnameMac - 1))];
                                        /* Get class name rhte */
#if SYMDEB
    if (IsDebSeg(rhteClass, mplnamerhte[lname]))
    {                                   /* If MS debug segment */
        mpsngsn[snMac++] = 0;
        if (fSymdeb)                    /* If debugger support on */
        {
            apropFile = (APROPFILEPTR) FetchSym(vrpropFile, TRUE);
            if (apropFile->af_cvInfo == NULL)
                apropFile->af_cvInfo = (CVINFO FAR *) GetMem(sizeof(CVINFO));
            pCvInfo = apropFile->af_cvInfo;
            if (rhteClass == rhteDebTyp)
            {
                // "DEBTYP"

                pCvInfo->cv_cbTyp = (DWORD) seglen;
#ifdef RGMI_IN_PLACE
                pCvInfo->cv_typ = NULL; // defer allocation until pass 2 (!)
#else
                pCvInfo->cv_typ = GetMem(seglen);
#endif
            }
            else if (rhteClass == rhteDebSym)
            {
                // "DEBSYM"

                pCvInfo->cv_cbSym = (DWORD) seglen;
#ifdef RGMI_IN_PLACE
                pCvInfo->cv_sym = NULL; // defer allocation until pass 2 (!)
#else
                pCvInfo->cv_sym = GetMem(seglen);
#endif
            }
        }
        SkipBytes((WORD) (cbRec - 1));
        return;
    }
#endif
    GetIndex(0, (WORD) (lnameMac - 1)); /* Eat overlay name index */
    DEBUGVALUE(seglen);                 /* Debug info */
    DEBUGVALUE(lname);                  /* Debug info */
    ahte = (AHTEPTR ) FetchSym(rhteClass,FALSE);
                                        /* Fetch hash table entry from VM */
    if(SbSuffix(GetFarSb(ahte->cch),"\004CODE",TRUE))
        flags = FCODE;
    else
        flags = 0;
#if OMF386
    /* Remember if 32-bit segment */
    if(tysn & CODE386BIT)
    {
        flags |= FCODE386;
#if EXE386
        /* Must set f386 here because newdeb needs to know in pass 1 */
        f386 = (FTYPE) TRUE;
#endif
    }
#endif
#if ILINK
    else
    if (fIncremental && !fLibraryFile && seglen && seglen != LXIVK)
    {
        /* Add padding to non-zero-length, non-library, non-64K segment
         * contributions.  (64K from huge model)
         * UNDONE:  More general overflow check, accounting for previous
         * UNDONE:  contributions.
         */
        seglen += (flags & FCODE) ? cbPadCode : cbPadData;
    }
#endif
    switch(align)                       /* Switch on alignment type */
    {
        case ALGNABS:                   /* Absolute LSEG */
        case ALGNBYT:                   /* Relocatable byte-aligned LSEG */
        case ALGNWRD:                   /* Relocatable word-aligned LSEG */
        case ALGNPAR:                   /* Relocatable para-aligned LSEG */
        case ALGNPAG:                   /* Relocatable page-aligned LSEG */
#if OMF386
        case ALGNDBL:                   /* double-word-aligned */
#endif
            break;

    default:                            /* ABSMAS, LTL LSEG, or error */
        mpsngsn[snMac++] = 0;
        return;
    }
    ++snkey;                            /* Increment segment i.d. key */
    if(comb = (WORD) ((tysn >> 2) & 7)) /* If "public" segment */
    {
        apropSn = (APROPSNPTR )
          PropRhteLookup(mplnamerhte[lname], ATTRPSN, (FTYPE) TRUE);
                                        /* Look up symbol table entry */
        if(!vfCreated)                  /* If it was already there */
        {
            apropSn = CheckClass(apropSn, rhteClass);
#if OSEGEXE
            if (apropSn->as_fExtra & FROM_DEF_FILE)
            {                           /* Override .DEF file segment attributes */
                mpgsnfCod[apropSn->as_gsn] = (FTYPE) (flags & FCODE);
                apropSn->as_tysn = (TYSNTYPE) tysn;
                                        /* Save ACBP field */
#if NOT EXE386
                if (flags & FCODE386 || seglen > LXIVK)
                    apropSn->as_flags |= NS32BIT;
                                        /* Set Big/Default bit */
#endif
                apropSn->as_key = snkey;/* Save the key value */
            }
#endif
        }
    }
    else                                /* Else if private segment */
    {
        apropSn = (APROPSNPTR )
          PropRhteLookup(mplnamerhte[lname], ATTRPSN, (FTYPE) FALSE);
        /* Check if defined in .def file - caviar:4767             */
        if(apropSn && apropSn->as_fExtra & FROM_DEF_FILE)
        {
            OutWarn(ER_farovl, GetPropName(apropSn)+1, "root");
        }

        vfCreated = (FTYPE) TRUE;       /* This is a new segment */
        apropSn = (APROPSNPTR ) PropAdd(mplnamerhte[lname],ATTRLSN);
    }
    if(vfCreated)                       /* If a new cell was created */
    {
        if(gsnMac >= gsnMax)
                Fatal(ER_segmax);
                                        /* Check for table overflow */
        apropSn->as_gsn = gsnMac;       /* Assign new global SEGDEF number */
        mpgsnrprop[gsnMac++] = vrprop;  /* Save address of property list */
        apropSn->as_rCla = rhteClass;   /* Save ptr to class hash tab ent */
                                        /* Superclass hash table entry */
        DEBUGVALUE(apropSn);            /* Debug info */
        DEBUGVALUE(apropSn->as_rCla);   /* Debug info */
        apropSn->as_tysn = (TYSNTYPE) tysn;
                                        /* Save ACBP field */
        mpgsnfCod[apropSn->as_gsn] = (FTYPE) (flags & FCODE);
#if OSEGEXE
#if EXE386
        apropSn->as_flags = flags & FCODE ? dfCode : dfData;
                                        /* Assume default flags */
#else
        apropSn->as_flags = (WORD) (flags & FCODE ? dfCode : dfData);
                                        /* Assume default flags */
        if (flags & FCODE386 || seglen > LXIVK)
            apropSn->as_flags |= NS32BIT;
                                        /* Set Big/Default bit */
#endif
#else
        apropSn->as_flags = flags;
#endif
        apropSn->as_key = snkey;        /* Save the key value */
        apropSn->as_ComDat = NULL;      /* No COMDATs yet */
#if OVERLAYS
        apropSn->as_iov = (IOVTYPE) NOTIOVL;
                                        // No overlay assigment yet
#endif
    }
#if OMF386 AND NOT EXE386
    else
    {
        /* If segment defined as both 16- and 32-bit, fatal error */

        WORD    fNew, fOld;

        fNew = (WORD) ((flags & FCODE386) ? 1 : 0);
        fOld = (WORD) (
#if OSEGEXE
               (apropSn->as_flags & NS32BIT) ?
#else
               (apropSn->as_flags & FCODE386) ?
#endif
                                                1 : 0);
            if (fNew != fOld)
                Fatal(ER_16seg32,1 + GetPropName(apropSn));
    }
#endif
#if OVERLAYS
    CheckOvl(apropSn, iovFile);
#endif
#if SYMDEB
    if (seglen && (flags & FCODE))
        cSegCode++;                     /* Count code seg's, so CV gets proper */
                                        /* number of sstModule subsections */
#endif
    gsn = apropSn->as_gsn;              /* Save global SEGDEF no. */
    if(comb == COMBSTK)                 /* If segment combines like stack */
    {
        gsnStack = gsn;                 /* Set stack global SEGDEF number */
        align = ALGNBYT;                /* Force to byte alignment */
        if (cbStack)
            seglen = 0L;                /* Ignore stack segment size if /STACK given */
    }
    else if(comb == COMBCOM)            /* If segment combines like common */
    {
        cbMaxPrev = apropSn->as_cbMx;   /* Get previous segment size */
        apropSn->as_cbMx = 0L;          /* Set size to zero */
        if(seglen < cbMaxPrev) seglen = cbMaxPrev;
                                        /* Take the larger of the two sizes */
    }
    cbMaxPrev = apropSn->as_cbMx;       /* Get previous size */
    if(align == ALGNWRD) cbMaxPrev = (~0L<<1) & (cbMaxPrev + (1<<1) - 1);
                                        /* Round size up to word boundary */
#if OMF386
    else if(align == ALGNDBL) cbMaxPrev = (~0L<<2) & (cbMaxPrev + (1<<2) - 1);
#endif                                  /* Round size up to double boundary */
    else if(align == ALGNPAR) cbMaxPrev = (~0L<<4) & (cbMaxPrev + (1<<4) - 1);
                                        /* Round size up to para. boundary */
    else if(align == ALGNPAG) cbMaxPrev = (~0L<<8) & (cbMaxPrev + (1<<8) - 1);
                                        /* Round size up to word boundary */

    prevAlign = (WORD) ((apropSn->as_tysn >> 5) & 7);

    // In Assign Addresses pass the aligment of the whole logical
    // segment has to be equal to the biggest aligment of all
    // contributions for given logical segment. Here we are checking
    // if current contribution has bigger aligment then the
    // contributions seen so FAR. The bigger aligment criteria is a
    // bit tricky - the aligment constants are defined as follows:
    //
    //      1 - byte aligment
    //      2 - word aligment
    //      3 - paragraph aligment
    //      4 - page aligment
    //      5 - double word aligment
    //
    // The aligment ordering is as follows:
    //
    //      byte < word < dword < para < page
    //        1     2       5       3      4
    //

    // If align greater than prev. val.

    if (prevAlign == ALGNDBL || align == ALGNDBL)
    {
        if (prevAlign == ALGNDBL && align >= ALGNPAR)
            apropSn->as_tysn = (BYTE) ((apropSn->as_tysn & 31) | (align << 5));
                                        /* Use new value */
        else if (align == ALGNDBL && prevAlign <= ALGNWRD)
            apropSn->as_tysn = (BYTE) ((apropSn->as_tysn & 31) | (align << 5));
                                        /* Use new value */
    }
    else if (align > prevAlign)
        apropSn->as_tysn = (BYTE) ((apropSn->as_tysn & 31) | (align << 5));
                                        /* Use new value */

    if (align != ALGNABS)               /* If not an absolute LSEG */
    {
        seglen += cbMaxPrev;
#if EXE386 OR OMF386
        if ((flags & FCODE386) != 0
#if O68K
            && iMacType == MAC_NONE
#endif
        )
        {
#if EXE386
            if (seglen < cbMaxPrev)     /* errmsg takes # megabytes */
                Fatal(ER_seg386, 1 + GetPropName(apropSn), 1 << (LG2SEG32 - 20));
#else
            if (seglen > CBMAXSEG32)    /* errmsg takes # megabytes */
                Fatal(ER_seg386,1 + GetPropName(apropSn),1 << (LG2SEG32 - 20));
#endif
        }
        else
#endif
             if (seglen > LXIVK)
             {
                if (comb != COMBSTK)
                    OutError(ER_segsize,1 + GetPropName(apropSn));
                                        /* Check for segment overflow */
                else
                {
                    if (!cbStack)
                        OutWarn(ER_stack64);
                    cbStack = LXIVK - 2;/* Assume 64k stack segment */
                }
             }
        apropSn->as_cbMx = seglen;      /* Save new segment size */
        /*
         * If this is a 16-bit code segment, check for unreliable
         * lengths due to the 286 bug.  For DOS exes, assume worst
         * case, i.e. real mode limit.
         */
        if((flags & FCODE) && !(EXE386 && (flags & FCODE386)))
#if OIAPX286
            if(seglen == LXIVK)
#else
            if(seglen > LXIVK - 36)
#endif
                SegUnreliable(apropSn);
    }
    else apropSn->as_cbMx = (long) saAbs;
                                        /* "Hack to save origin of abs seg" */
    mpgsndra[gsn] = cbMaxPrev;          /* Save previous size */
    mpsngsn[snMac++] = gsn;             /* Map SEGDEF no to global SEGDEF no */
    MARKVP();                           /* Virtual page has changed */
    if (fFullMap && contriblen)
        AddContributor(gsn, (unsigned long) -1L, contriblen);
}

    /****************************************************************
    *                                                               *
    *  GrpRc1:                                                      *
    *                                                               *
    *  This function processes GRPDEF records on pass 1.            *
    *  See pp. 36-39 in "8086 Object Module Formats EPS."           *
    *                                                               *
    ****************************************************************/

LOCAL void NEAR         GrpRc1(void)
{
    LNAMETYPE           lnameGroup;     /* Group LNAME number */
    SNTYPE              sn;             /* Group (local) segment number */
    APROPSNPTR          apropSn;
    APROPGROUPPTR       apropGroup;
    GRTYPE              ggr;            /* Global GRPDEF number */
    WORD                gcdesc;         /* GRPDEF component descriptor */
#if EXE386
    BYTE                *pGrName;       /* Group name */
#endif


    if(grMac >= GRMAX) Fatal(ER_grpdef);
    lnameGroup = GetIndex(1, (WORD) (lnameMac - 1));
                                        /* Read in group name index */
    apropGroup = (APROPGROUPPTR )
      PropRhteLookup(mplnamerhte[lnameGroup], ATTRGRP, (FTYPE) TRUE);
                                        /* Look up cell in hash table */
    if(vfCreated)                       /* If entry did not exist before */
    {
        if(ggrMac >= GGRMAX) Fatal(ER_grpmax);
        apropGroup->ag_ggr = ggrMac++;  /* Save global GRPDEF no. */
    }
    ggr = apropGroup->ag_ggr;           /* Get global GRPDEF no. */
    mpggrrhte[ggr] = mplnamerhte[lnameGroup];
                                        /* Save pointer to name */
    mpgrggr[grMac++] = ggr;             /* Map local to global */
#if EXE386
    /* Check for pseudo-group FLAT here */
    pGrName = GetFarSb(((AHTEPTR)(FetchSym(mpggrrhte[ggr], FALSE)))->cch);
    if (SbCompare(pGrName, sbFlat, TRUE))
        ggrFlat = ggr;
#endif
    while(cbRec > 1)                    /* While not at end of record */
    {
        gcdesc = Gets();                /* Read in the descriptor */
        ASSERT(gcdesc == 0xFF);         /* Linker doesn't handle others */
        sn = GetIndex(1,snMac);         /* Get local SEGDEF index */
        apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[mpsngsn[sn]],TRUE);
                                        /* Fetch from virt mem */
        if(apropSn->as_ggr == GRNIL)
        {                               /* Store global GRPDEF no. if none */
            apropSn->as_ggr = ggr;
#if OSEGEXE
            /*
             * Check if a segment which is part of DGROUP was defined
             * as class "CODE", also if it was given a sharing attribute
             * that conflicts with the autodata type.
             * Could only happen if seg defined in a def-file.  Must be
             * done here because only now do we know that it's in DGROUP.
             */
            if(ggr == ggrDGroup && (apropSn->as_fExtra & FROM_DEF_FILE))
            {

#if EXE386
                if (IsEXECUTABLE(apropSn->as_flags))
                {
                    SetREADABLE(apropSn->as_flags);
                    SetWRITABLE(apropSn->as_flags);
                    apropSn->as_rCla = rhteBegdata;
                    mpgsnfCod[apropSn->as_gsn] = FALSE;
                    OutWarn(ER_cod2dat,1 + GetPropName(apropSn));
                    apropSn = (APROPSNPTR )
                        FetchSym(mpgsnrprop[mpsngsn[sn]],TRUE);
                }
                if (((vFlags & NESOLO) && !IsSHARED(apropSn->as_flags)) ||
                    ((vFlags & NEINST) && IsSHARED(apropSn->as_flags)))
                {
                    if (vFlags & NESOLO)
                        SetSHARED(apropSn->as_flags);
                    else
                        apropSn->as_flags &= ~OBJ_SHARED;
                    OutWarn(ER_adcvt,1 + GetPropName(apropSn));
                }

#else
                if((apropSn->as_flags & NSTYPE) != NSDATA)
                {
                    apropSn->as_flags &= ~NSTYPE;
                    apropSn->as_flags |= NSDATA;
                    apropSn->as_rCla = rhteBegdata;
                    mpgsnfCod[apropSn->as_gsn] = FALSE;
                    OutWarn(ER_cod2dat,1 + GetPropName(apropSn));
                    apropSn = (APROPSNPTR )
                        FetchSym(mpgsnrprop[mpsngsn[sn]],TRUE);
                }
                if(((vFlags & NESOLO) && !(apropSn->as_flags & NSSHARED)) ||
                    ((vFlags & NEINST) && (apropSn->as_flags & NSSHARED)))
                {
                    if(vFlags & NESOLO) apropSn->as_flags |= NSSHARED;
                    else apropSn->as_flags &= ~NSSHARED;
                    OutWarn(ER_adcvt,1 + GetPropName(apropSn));
                }
#endif /* EXE386 */
            }
#endif /* OSEGEXE */
        }
        else if (apropSn->as_ggr != ggr)/* If segment belongs to other group */
        {
            if(fLstFileOpen) fflush(bsLst);
                                        /* Flush list file, if any */
            OutWarn(ER_grpmul,1 + GetPropName(apropSn));
        }
    }
}

void NEAR               DupErr(BYTE *sb)/* Duplicate definition error */
                                        /* Symbol to which error refers */
{
    BSTYPE              bsTmp;          /* Temporary file pointer */
    MSGTYPE             msg;            /* Message to use */
#if OSMSDOS
    extern char         *pExtDic;       /* Pointer to extended dictionary */
#endif
    SBTYPE              sbUndecor;      /* a buffer for undecorated name */

    /* If this module is in an extended dictionary, suggest /NOEXT in error
     * message.
     */
    msg = (MSGTYPE) (
#if OSMSDOS
          pExtDic ? ER_symdup1 :
#endif
                    ER_symdup);

    UndecorateSb((char FAR*) sb, (char FAR*) sbUndecor, sizeof(sbUndecor) );

    OutError(msg,1 + sbUndecor);
    if(fLstFileOpen && bsErr != bsLst)
    {
        bsTmp = bsErr;
        bsErr = bsLst;
        OutError(msg,1 + sbUndecor);
        bsErr = bsTmp;
    }
}






    /****************************************************************
    *                                                               *
    *  PubRc1:                                                      *
    *                                                               *
    *  This function processes PUBDEF records on pass 1.            *
    *  See pp. 44-46 in "8086 Object Module Formats EPS."           *
    *                                                               *
    ****************************************************************/

LOCAL void NEAR         PubRc1(void)
{
    GRTYPE              ggr;            /* Group definition number */
    SNTYPE              sn;             /* Local SEGDEF no. */
    SNTYPE              gsn;            /* Global SEGDEF no. */
    RATYPE              dra;
    SBTYPE              sb;             /* Public symbol */
    RATYPE              ra;             /* Public symbol offset */
    APROPNAMEPTR        apropName;      /* Table entry for symbol name */
    WORD                type;           /* Local type no. */
    int                 fSkipCv = FALSE;/* Don't register DATA PUBDEF if a COMDEF
                                           for that symbol has already been seen */


    DEBUGVALUE(grMac - 1);              /* Debug info */
    ggr = (GRTYPE) GetIndex(0, (WORD) (grMac - 1));/* Get group index */
    DEBUGVALUE(ggr);                    /* Debug info */
    if (!(sn = GetIndex(0, (WORD) (snMac - 1))))/* If frame number present */
    {
        gsn = 0;                        /* No global SEGDEF no. */
        dra = 0;
        SkipBytes(2);                   /* Skip the frame number */
    }
    else                                /* Else if local SEGDEF no. given */
    {
        if (ggr != GRNIL)
            ggr = mpgrggr[ggr];         /* If group specified, get global no */
        gsn = mpsngsn[sn];              /* Get global SEGDEF no. */
        dra = mpgsndra[gsn];
    }
    DEBUGVALUE(cbRec);                  /* Debug info */
    while (cbRec > 1)                   /* While there are symbols left */
    {
        sb[0] = (BYTE) Gets();          /* Get symbol length */
        if (TYPEOF(rect) == PUBDEF)
            GetBytes(&sb[1],B2W(sb[0]));/* Read in symbol text */
        else
            GetLocName(sb);             /* Transform local name */
#if CMDXENIX
        if(symlen && B2W(sb[0]) > symlen) sb[0] = symlen;
                                        /* Truncate if necessary */
#endif
#if OMF386
        if (rect & 1)
            ra = LGets();
        else
#endif
            ra = WGets();               /* Get symbol segment offset */
        type = GetIndex(0,0x7FFF);      /* Get type index */
        if (!vfNewOMF)
            type = 0;

        /* Look for symbol among undefined */

        apropName = (APROPNAMEPTR) PropSymLookup(sb, ATTRUND, FALSE);

        if (apropName != PROPNIL)       /* Symbol known to be undefined */
        {
            if (((APROPUNDEFPTR )apropName)->au_flags & COMMUNAL)
            {
                if (mpgsnfCod[gsn])
                    DupErr(sb);         /* Communal matches code PUBDEF */
                fSkipCv = TRUE;
            }
            vfCreated = (FTYPE) TRUE;
        }
        else
        {
            /* Look for symbol among ALIASes */

            if (vrhte == RHTENIL)
                apropName = PROPNIL;
            else
                apropName = (APROPNAMEPTR) PropRhteLookup(vrhte, ATTRALIAS, FALSE);

            if (apropName != PROPNIL)
            {
#if FDEBUG
                if (fDebug)
                {
                    sb[sb[0] + 1] = '\0';
                    OutWarn(ER_ignoalias, &sb[1]);
                }
#endif
                continue;
            }

            else if (vrhte == RHTENIL)
            {
               apropName = (APROPNAMEPTR) PropSymLookup(sb, ATTRPNM, TRUE);
            }

            else
            {
                apropName = (APROPNAMEPTR) PropRhteLookup(vrhte, ATTRPNM, TRUE);
            }
        }

        if (vfCreated)                  /* If new PUBNAM entry created or */
        {                               /* old UNDEF entry to modify */

            // If printable symbol, increment counter and set flags

            if (sb[0] != '\0' && sb[1] > ' ' && sb[1] <= '~')
            {
                ++pubMac;
                apropName->an_flags = FPRINT;
            }
            else
            {
#if ILINK
                ++locMac;               /* Included in .SYM file */
#endif
            }

            apropName->an_attr = ATTRPNM;
                                        /* Symbol is a public name */
            apropName->an_ra = ra + dra;/* Give symbol its adjusted offset */
            apropName->an_gsn = gsn;    /* Save its global SEGDEF no. */
            apropName->an_ggr = ggr;    /* Save its global SEGDEF no. */
#if OVERLAYS
            apropName->an_thunk = THUNKNIL;
#endif
#if ILINK
            apropName->an_module = imodFile;
#endif
            MARKVP();                   /* Mark virtual page as changed */
#if SYMDEB
            if (fSymdeb && (apropName->an_flags & FPRINT) && !fSkipPublics && !fSkipCv)
            {
                // Remember CV type index

                apropName->an_CVtype = type;
                DebPublic(vrprop, rect);
            }
#endif
        }
        else if(apropName->an_gsn != gsn || apropName->an_ra != ra + dra)
        {
            DupErr(sb);                 /* Definitions do not match */
        }
    }
}

    /****************************************************************
    *                                                               *
    *  ExtRc1:                                                      *
    *                                                               *
    *  This function processes EXTDEF records on pass 1.            *
    *  See pp. 47-48 in "8086 Object Module Formats EPS."           *
    *                                                               *
    ****************************************************************/

LOCAL void NEAR         ExtRc1(void)
{
    SBTYPE              sb;             /* EXTDEF symbol */
    APROPUNDEFPTR       apropUndef;     /* Pointer to symbol entry */
    APROPALIASPTR       apropAlias;     /* Pointer to symbol entry */
    APROPNAMEPTR        apropName;      /* Pointer to symbol entry */
    APROPCOMDATPTR      apropComdat;    /* pointer to symbol entry */
    WORD                itype;          /* Type index */
    RBTYPE              rhte;           /* Virt. addr. of hash table entry */
    AHTEPTR             ahte;           // Symbol table hash entry

    while (cbRec > 1)                   /* While there are symbols left */
    {
        if (extMac >= EXTMAX - 1)       /* Check for table overflow */
            Fatal(ER_extdef);

        if (TYPEOF(rect) == CEXTDEF)
        {
            itype = GetIndex(0, (WORD) (lnameMac - 1));
            rhte = mplnamerhte[itype];
            ahte = (AHTEPTR) FetchSym(rhte, FALSE);
            FMEMCPY((char FAR *) sb, ahte->cch, ahte->cch[0] + 1);

            /* Look for a matching PUBDEF */

            apropUndef = (APROPUNDEFPTR) PropRhteLookup(rhte, ATTRPNM, FALSE);
        }
        else
        {
            rhte = RHTENIL;

            sb[0] = (BYTE) Gets();      /* Get symbol length */
            if (TYPEOF(rect) == EXTDEF)
                GetBytes(&sb[1], B2W(sb[0]));
                                        /* Read in text of symbol */
            else
                GetLocName(sb);         /* Get local name */
#if CMDXENIX
            if (symlen && B2W(sb[0]) > symlen)
                sb[0] = symlen;         /* Truncate if necessary */
#endif
            /* Look for a matching PUBDEF */

            apropUndef = (APROPUNDEFPTR) PropSymLookup(sb, ATTRPNM, FALSE);
        }

        DEBUGSB(sb);                    /* Print symbol */

        if (!vfNewOMF)                  /* If old-style OMF */
            itype = GetIndex(0, (WORD) (typMac - 1));/* Get type index */
        else
            itype = GetIndex(0, 0x7FFF); /* Get type index (any value OK) */

#if FALSE
        if (fDebug)
        {
            sb[sb[0]+1] = '\0';
            fprintf(stdout, "\r\n%s has index = %u", sb+1, extMac);
        }
#endif

        apropName  = PROPNIL;

        if (apropUndef == PROPNIL)      /* If there isn't one */
        {
            /* Look for a matching ALIAS */

            if (vrhte == RHTENIL)
                apropAlias = PROPNIL;
            else
                apropAlias = (APROPALIASPTR) PropRhteLookup(vrhte, ATTRALIAS, FALSE);

            if (apropAlias != PROPNIL)
            {
                /* ALIAS matches this EXTDEF */

                mpextprop[extMac++] = apropAlias->al_sym;
                apropName = (APROPNAMEPTR) FetchSym(apropAlias->al_sym, TRUE);
                if (apropName->an_attr == ATTRPNM)
                {
                    // If substitute name is a PUBDEF then use it

                    if (!vfNewOMF && itype && (mpitypelen[itype] > 0L) &&
                        mpgsnfCod[apropName->an_gsn])
                                         /* Communal matches code PUBDEF */
                        DupErr(sb);      /* Duplicate definition */
                }
                else
                {
                    // The substitute name is an EXTDEF
                    // Mark substitute name so it causes the library search, because
                    // we don't know neither the alias nor the substitute

                    apropUndef = (APROPUNDEFPTR) apropName;
                    apropUndef->au_flags |= SEARCH_LIB;
                    apropName = PROPNIL;
#if NEW_LIB_SEARCH
                    if (fStoreUndefsInLookaside)
                        StoreUndef((APROPNAMEPTR)apropUndef, RhteFromProp((APROPPTR)apropUndef),0,0);
#endif

#ifdef DEBUG_SHOWALIAS
                    sb[sb[0]+1] = '\0';
                    fprintf(stderr, "extdef alias: %s\r\n", sb+1);
                    fflush(stderr);
#endif
                }
            }
            else
            {
                /* Insert as undefined symbol */

                if (vrhte == RHTENIL)
                    apropUndef = (APROPUNDEFPTR) PropSymLookup(sb, ATTRUND, TRUE);
                else
                    apropUndef = (APROPUNDEFPTR) PropRhteLookup(vrhte, ATTRUND, TRUE);

                mpextprop[extMac++] = vrprop;
                if(vfCreated)
                {
                    apropUndef->au_flags |= UNDECIDED;
                    apropUndef->au_len = -1L;
#if NEWLIST
                    apropUndef->u.au_rbNxt = rbLstUndef;
                    rbLstUndef = vrprop;
#endif
                }
                else if (apropUndef->au_flags & UNDECIDED)
                {
                    apropUndef->au_flags &= ~(UNDECIDED | WEAKEXT | SUBSTITUTE);
                    apropUndef->au_flags |= STRONGEXT;

#if NEW_LIB_SEARCH
                    if (fStoreUndefsInLookaside)
                        StoreUndef((APROPNAMEPTR)apropUndef, RhteFromProp((APROPPTR)apropUndef),0,0);
#endif
                }
                else if (apropUndef->au_flags & WEAKEXT)
                    apropUndef->au_flags |= UNDECIDED;

                if (vfNewOMF) continue; /* Skip if module uses COMDEFs */
                if(itype)               /* If there is reference to TYPDEF */
                    DoCommon(apropUndef, mpitypelen[itype],
                        (WORD) (mpityptyp[itype] ? mpitypelen[mpityptyp[itype]] : 0),
                        sb);

                if (apropUndef->au_len > 0L)
                    apropUndef->au_flags |= COMMUNAL;
                                        /* Mark as true communal or not */
                MARKVP();               /* Mark virt page as changed */
            }
        }
        else
        {
            apropName = (APROPNAMEPTR ) apropUndef;
            mpextprop[extMac++] = vrprop;
            if (!vfNewOMF && itype && (mpitypelen[itype] > 0L) &&
                mpgsnfCod[((APROPNAMEPTR )apropUndef)->an_gsn])
                                        /* Communal matches code PUBDEF */
                DupErr(sb);             /* Duplicate definition */
        }

        // If we are processing CEXTDEF/EXTDEF and there is public symbol
        // matching the CEXTDEF/EXTDEF symbol, then mark COMDAT descriptor
        // as referenced

        if (apropName != PROPNIL)
        {
            apropComdat = (APROPCOMDATPTR) PropRhteLookup(vrhte, ATTRCOMDAT,
#if TCE
             FALSE
#else
             TRUE
#endif
             );

            if (apropComdat != PROPNIL)
            {
                apropComdat->ac_flags |= REFERENCED_BIT;
#if TCE_DEBUG
                fprintf(stdout, "\r\nEXTDEF1 referencing '%s' ", 1+GetPropName(apropComdat));
#endif
            }
        }
    }
}

#if OSEGEXE AND NOT QCLINK
    /****************************************************************
    *                                                               *
    *  imprc1:                                                      *
    *                                                               *
    *  This function processes  Microsoft OMF extension records of  *
    *  type IMPDEF (i.e. IMPort DEFinition records).                *
    *                                                               *
    ****************************************************************/

LOCAL void NEAR         imprc1(void)
{
    SBTYPE              sbInt;          /* Internal name */
    SBTYPE              sbMod;          /* Module name */
    SBTYPE              sbImp;          /* Imported name */
    FTYPE               fOrd;           /* Import-by-ordinal flag */

#if ODOS3EXE
    fNewExe = (FTYPE) TRUE;             /* Import forces new-format exe */
#endif
    fOrd = (FTYPE) Gets();              /* Get ordinal flag */
    sbInt[0] = (BYTE) Gets();           /* Get length of internal name */
    GetBytes(&sbInt[1],B2W(sbInt[0]));  /* Get the internal name */
    sbMod[0] = (BYTE) Gets();           /* Get length of module name */
    GetBytes(&sbMod[1],B2W(sbMod[0]));  /* Get the module name */
    if(!(fOrd & 0x1))                   /* If import by name */
    {
        sbImp[0] = (BYTE) Gets();       /* Get length of imported name */
        if(sbImp[0] != '\0')            /* If names differ */
        {
            GetBytes(&sbImp[1],B2W(sbImp[0]));
                                        /* Get the imported name */
#if EXE386
            NewImport(sbImp,0,sbMod,sbInt, (fOrd & 0x2));
#else
            NewImport(sbImp,0,sbMod,sbInt);
#endif
                                        /* Enter new import */
        }
        else
#if EXE386
            NewImport(sbInt,0,sbMod,sbInt, (fOrd & 0x2));
#else
            NewImport(sbInt,0,sbMod,sbInt);
#endif
                                        /* Enter new import */
    }
    else
#if EXE386
        NewImport(NULL,WGets(),sbMod,sbInt, (fOrd & 0x2));
#else
        NewImport(NULL,WGets(),sbMod,sbInt);
#endif
                                        /* Else import by ordinal */
}


    /****************************************************************
    *                                                               *
    *  exprc1:                                                      *
    *                                                               *
    *  This function processes  Microsoft OMF extension records of  *
    *  type EXPDEF (i.e. EXPort DEFinition records).                *
    *                                                               *
    ****************************************************************/

LOCAL void NEAR         exprc1(void)
{
    SBTYPE              sbInt;          /* Internal name */
    SBTYPE              sbExp;          /* Exported name */
    WORD                OrdNum;         /* Ordinal number */
    WORD                fRec;           /* Record flags */


#if ODOS3EXE
    fNewExe = (FTYPE) TRUE;             /* Export forces new-format exe */
#endif
    fRec = (BYTE) Gets();               /* Get record flags */
    sbExp[0] = (BYTE) Gets();           /* Get length of exported name */
    GetBytes(&sbExp[1],B2W(sbExp[0]));  /* Get the exported name */
    sbInt[0] = (BYTE) Gets();           /* Get length of internal name */
    if (sbInt[0])
        GetBytes(&sbInt[1],B2W(sbInt[0]));
                                        /* Get the internal name */
    if (fRec & 0x80)
    {                                   /* If ordinal number specified */
        OrdNum = WGets();               /* Read it and set highest bit */
        OrdNum |= ((fRec & 0x40) << 1); /* if resident name */
    }
    else
        OrdNum = 0;                     /* No ordinal number specified */

    // Convert flags:
    // OMF flags:
    //        80h = set if ordinal number specified
    //        40h = set if RESIDENTNAME
    //        20h = set if NODATA
    //        1Fh = # of parameter words
    // EXE flags:
    //        01h = set if entry is exported
    //        02h = set if entry uses global (shared) data segment (!NODATA)
    //        F8h = # of parameter words
    //
    // Since the logic is reversed for the NODATA flag, we toggle bit 0x20
    // in the OMF flags via the expression ((fRec & 0x20) ^ 0x20).

    fRec = (BYTE) (((fRec & 0x1f) << 3) | (((fRec & 0x20) ^ 0x20) >> 4) | 1);

    // Mark fRec, so NewExport doesn't try to free name buffers

    fRec |= 0x8000;

    if (sbInt[0])
        NewExport(sbExp, sbInt, OrdNum, fRec);
    else
        NewExport(sbExp, NULL, OrdNum, fRec);
}
#endif /* OSEGEXE */



    /****************************************************************
    *                                                               *
    *  ComRc1:                                                      *
    *                                                               *
    *  This function processes COMENT records on pass 1.            *
    *  See pp. 86-87 in "8086 Object Module Formats EPS."           *
    *                                                               *
    ****************************************************************/

#pragma check_stack(on)

LOCAL void NEAR         ComRc1(void)
{
#if OXOUT OR OIAPX286
    WORD                mismatch;       /* Model mismatch flag */
#endif
#if FALSE
    static BYTE         modtype = 0;    /* Initial model type */
    BYTE                curmodtype;     /* Current model type */
#endif
    SBTYPE              text;           /* Comment text */
    SBTYPE              LibName;
    APROPFILEPTR        aprop;
    WORD                iextWeak;
    WORD                iextDefRes;
    APROPUNDEFPTR       undefName;
    FTYPE               fIgnoreCaseSave;
    BYTE                flags;
    void FAR            *pTmp;
#if ILINK
    SNTYPE              noPadSn;
    APROPSNPTR          apropSn;        /* Pointer to seg. record */
#endif
#if O68K
    BYTE                chModel;
#endif /* O68K */


    Gets();                             /* Skip byte 1 of comment type field */
    switch(Gets())                      /* Switch on comment class */
    {
#if OEXE
        case 0:                         /* Translator record */
            if(fNewExe)
                break;
#if ODOS3EXE
            text[0] = (BYTE) (cbRec - 1);/* Get length of comment */
            GetBytes(&text[1],(WORD)(cbRec - 1));/* Read in text of comment */
            /*
             * If translator is pre-3.30 MS/IBM PASCAL or FORTRAN,
             * force on /DS and /NOG.
             */
            if(SbCompare(text,"\011MS PASCAL", TRUE) ||
                        SbCompare(text,"\012FORTRAN 77", TRUE))
                vfDSAlloc = fNoGrpAssoc = (FTYPE) TRUE;
#endif
            break;
#endif
        case 0x81:                      /* Library specifier */
#if OSMSDOS OR OSPCDOS
        case 0x9F:                      /* Library specifier (alt.) */
#endif
            text[0] = (BYTE) (cbRec - 1);/* Get length of comment */
            if (text[0] == 0)
                break;                  /* Skip empty spec */
            GetBytes(&text[1], (WORD) (cbRec - 1));/* Read in text of comment */
                                        /* Add name to search list */
#if CMDMSDOS
            strcpy(LibName, sbDotLib);
            UpdateFileParts(LibName, text);
#endif
#if CMDXENIX
            memcpy(LibName, text, B2W(text[0]) + 1);
                                        /* Leave name unchanged */
#endif
            if(!vfNoDefaultLibrarySearch)
            {
#if OSMSDOS
                fIgnoreCaseSave = fIgnoreCase;
                fIgnoreCase = (FTYPE) TRUE;

                /* If the name begins with a drive letter, skip it.  This
                 * is to allow compatibility with old compilers which
                 * generated comments of the form "A:FOO.LIB".
                 */
                if(LibName[2] == ':' && B2W(LibName[0]) > 1)
                {
                    LibName[2] = (BYTE) (LibName[0] - 2);
                    if (PropSymLookup(LibName+2,ATTRSKIPLIB,FALSE) == PROPNIL)
                      AddLibrary(LibName+2);
                }
                else
#endif
                    if (PropSymLookup(LibName,ATTRSKIPLIB,FALSE) == PROPNIL)
                      AddLibrary(LibName);
                fIgnoreCase = fIgnoreCaseSave;
            }
            break;
#if OEXE
        case 0x9E:                      /* Force segment order directive */
            SetDosseg();                /* Set switch */
            break;
#endif /* OEXE */

        case 0x9D:                      /* Model specifier */
#if FALSE
            /* Removed */
            mismatch = 0;               /* Assume all is well */
            while(cbRec > 1)            /* While bytes remain */
            {
                curmodtype = Gets();    /* Get byte value */
                switch(curmodtype)
                {
                    case 'c':           /* Compact model */
                    case 's':           /* Small model */
                    case 'm':           /* Medium model */
                    case 'l':           /* Large model */
                    case 'h':           /* Huge model */
                        if (modtype)
                            mismatch = curmodtype != modtype;
                        else
                            modtype = curmodtype;
                        break;
                }
            }
            if(mismatch) OutWarn(ER_memmodel);
                                        /* Warn if mismatch found */
#endif
#if OXOUT OR OIAPX286
            mismatch = 0;               /* Assume all is well */
            while(cbRec > 1)            /* While bytes remain */
            {
                modtype = Gets();       /* Get byte value */
                if (fMixed) continue;   /* Mixed model means we don't care */
                switch(modtype)
                {
                    case 'c':           /* Compact model */
                        if(!fLarge || fMedium) mismatch = 1;
                        break;          /* Warn if near data or FAR code */

                    case 's':           /* Small model */
                        if(fLarge || fMedium) mismatch = 1;
                                        /* Warn if FAR data or FAR code */
                        break;

                    case 'm':           /* Medium model */
                        if(fLarge || !fMedium) mismatch = 1;
                                        /* Warn if FAR data or near code */
                        break;

                    case 'l':           /* Large model */
                    case 'h':           /* Huge model */
                        if(!fLarge || !fMedium) mismatch = 1;
                                        /* Warn if near data or near code */
                        break;
                }
            }
            if(mismatch) OutError(ER_modelmis);
                                        /* Warn if mismatch found */
#endif /* OXOUT OR OIAPX286 */
#if O68K
            while (!f68k && cbRec > 1)  /* While bytes remain */
            {
                chModel = (BYTE) Gets();/* Get byte value */
                f68k = (FTYPE) F68KCODE(chModel);
            }
#endif /* O68K */
            break;

#if OSEGEXE AND NOT QCLINK
        case 0xA0:                      /* Microsoft OMF extension */
            switch(Gets())              /* Switch on extension record type */
            {
                case 0x01:              /* IMPort DEFinition */
                    imprc1();           /* Call the processing routine */
                    break;
                case 0x02:              /* EXPort DEFinition */
                    exprc1();           /* Call the processing routine */
                    break;
                case 0x03:
                    break;              /* In pass-1 skip INCDEF's for QC */
#if EXE386
                case 0x04:              // OMF extension - link386
//                  if (IsDLL(vFlags))
//                      vFlags |= E32PROTDLL;
                                        // Protected memory library module
                    break;
#endif
                case 0x05:              // C++ directives
                    flags = (BYTE) Gets();// Get flags field
#if NOT EXE386
                    if (flags & 0x01)
                        fNewExe = (FTYPE) TRUE; // PCODE forces segmented exe format
#endif
#if SYMDEB
                    if (flags & 0x02)
                        fSkipPublics = (FTYPE) TRUE;
                                        // In C++ they don't want PUBLIC subsection in CV info
#endif
                    if ((flags & 0x04) && !fIgnoreMpcRun) // ignore if /PCODE:NOMPC
                        fMPC = (FTYPE) TRUE;  // PCODE app - spawn MPC

                    break;
                case 0x06:              // target is a big-endian machine
#if O68K
                    fTBigEndian = (FTYPE) TRUE;
#endif /* O68K */
                    break;
                case 0x07:              // Use SSTPRETYPES instead of SSTTYPES4 in OutSSt
                    aprop = (APROPFILEPTR ) FetchSym(vrpropFile, TRUE);
                    aprop->af_flags |= FPRETYPES;
                    break;


                default:                /* Unknown */
                    InvalidObject();    /* Invalid object module */
            }
            break;
#endif

        case 0xA1:                      /* 1st OMF extension:  COMDEFs */
            vfNewOMF = (FTYPE) TRUE;
            aprop = (APROPFILEPTR ) FetchSym(vrpropFile, TRUE);
            aprop->af_flags |= FNEWOMF;
            break;

        case 0xA2:                      /* 2nd OMF extension */
            switch(Gets())
            {
                case 0x01:              /* Start linkpass2 records */
                /*
                 * WARNING:  It is assumed this comment will NOT be in a
                 * module whose MODEND record contains a program starting
                 * address.  If there are overlays, we need to see the
                 * starting address on pass 1 to define the symbol $$MAIN.
                 */
                    fP2Start = fModEnd = (FTYPE) TRUE;
                    break;
                default:
                    break;
            }
            break;

#if FALSE
        case 0xA3:                      // DON'T use - already used by LIB
             break;
#endif

        case 0xA4:                      /* OMF extension - EXESTR */
            fExeStrSeen = (FTYPE) TRUE;
                // WARNING: The code in this loop assumes:
                //
                //              ExeStrLen, cBrec and ExeStrMax are 16-bit unsigned WORDS
                //              An int is 32-bits
                //              All arithmetic and comparisons are 32-bit
                //
            while (cbRec > 1)
            {
                // Limit total EXESTR to 64K - 2 bytes.  We lose 1 because 0 means 0,
                // and we lose another because the buffer extension loop tops out at
                // 0xFFFE bytes.
                if (ExeStrLen + cbRec - 1 > 0xFFFEu)
                {
                        SkipBytes ( (WORD) (cbRec - 1) );
                }
                else
                if (ExeStrLen + cbRec - 1 > ExeStrMax)
                {
                    if (ExeStrBuf == NULL)
                    {
                        ExeStrBuf = GetMem(cbRec - 1);
                        ExeStrMax = cbRec - 1;
                    }
                    else
                    {
                        // This loop doubles the buffer size until it overflows 16 bits.  After this,
                        // it adds one half of the difference between the current value and 0xFFFF
                        //
                        while (ExeStrMax < ExeStrLen + cbRec - 1) {
                                ASSERT (ExeStrMax != 0);
                                if ((ExeStrMax << 1) >= 0x10000)
                                        ExeStrMax += (~ExeStrMax & 0xFFFF) >> 1;
                                else
                                ExeStrMax <<= 1;
                                }
                        pTmp = GetMem(ExeStrMax);
                        FMEMCPY(pTmp, ExeStrBuf, ExeStrLen);
                        FFREE(ExeStrBuf);
                        ExeStrBuf = pTmp;
                    }
                }
                // This must be done first because GetBytes() decrements
                // cbRec as a side effect.
        ExeStrLen += cbRec - 1;
                GetBytes(&ExeStrBuf[ExeStrLen-cbRec+1], (WORD) (cbRec - 1));

            }
            break;




        case 0xA6:                      /* OMF extension - INCERR */
            Fatal(ER_incerr);           /* Invalid object due to aborted incremental compile */
            break;
#if ILINK
        case 0xA7:                      /* OMF extension - NOPAD */
            if (fIncremental && !fLibraryFile)
            {
                /* Remove padding from non-zero-length, non-library,
                 * non-64K segment contributions.  (64K from huge model)
                 */
                while (cbRec > 1)
                {
                    noPadSn = GetIndex(1, snMac - 1);
                    apropSn = (APROPSNPTR) FetchSym(mpgsnrprop[mpsngsn[noPadSn]], TRUE);
                    if (apropSn->as_cbMx > 0L && apropSn->as_cbMx != LXIVK)
                    {
                        apropSn->as_cbMx -= mpgsnfCod[mpsngsn[noPadSn]] ? cbPadCode : cbPadData;
                        apropSn->as_fExtra |= NOPAD;
                    }
                }
            }
            break;
#endif

        case 0xA8:                      /* OMF extension - WeaK EXTern */
            while (cbRec > 1)
            {
                iextWeak = GetIndex(1, (WORD) (extMac - 1));
                                        /* Get weak extern index */
                iextDefRes = GetIndex(1, (WORD) (extMac - 1));
                                        /* Get default extern index */
#if FALSE
                DumpWeakExtern(mpextprop, iextWeak, iextDefRes);
#endif
                if (mpextprop[iextWeak] != PROPNIL && iextWeak < extMac)
                {
                    undefName = (APROPUNDEFPTR ) FetchSym(mpextprop[iextWeak], TRUE);
                    if (undefName->au_attr == ATTRUND)
                    {
                        // If this is EXTDEF

                        if (undefName->au_flags & UNDECIDED)
                        {
                            // This can be one of the following:
                            //  - weakness specified for the first time
                            //    if WEAKEXT is not set
                            //  - redefinition of weakness if the WEAKEXT
                            //    is set.
                            // In case of weakness redefinition check if
                            // it specified the same default resolution as
                            // the first one. Issue warning if different
                            // default resolutions and override old one
                            // with new. In both cases reset UNDECIDED bit.


                            undefName->au_flags &= ~UNDECIDED;
                            if (undefName->au_flags & WEAKEXT)
                            {
                                if (undefName->au_Default != mpextprop[iextDefRes])
                                    redefinition(iextWeak, iextDefRes, undefName->au_Default);
                                undefName->au_Default = mpextprop[iextDefRes];
                            }
                            else
                            {
                                undefName->au_Default = mpextprop[iextDefRes];
                                undefName->au_flags |= WEAKEXT;
                            }
                        }
                        // Ignore weakness - must be strong extern form
                        // some other .OBJ
                    }
                }
                else
                    InvalidObject();
            }
            break;
        default:                        /* Unrecognized */
            break;
    }
    if (cbRec > 1)
        SkipBytes((WORD) (cbRec - 1)); /* Punt rest of text */
}



/*** AliasRc1 - pass 1 ALIAS record processing
*
* Purpose:
*   Read and decode ALIAS OMF record (Microsoft OMF extension).
*   ALIAS record introduces pair of names - alias name and substitute
*   name. Enter both names into linker symbol table.
*
* Input:
*   No explicit value is passed. When this function is called the record
*   type and lenght are already read, so we can start reading name pairs.
*
* Output:
*   No explicit value is returned. Names are entered into symbol table.
*
* Exceptions:
*   Warning - redefinition of ALIAS <name>; substitute name changed
*   from <name1> to <name2>.
*
* Notes:
*   None.
*
*************************************************************************/

LOCAL void NEAR         AliasRc1(void)
{
    SBTYPE              alias;
    SBTYPE              substitute;
    APROPALIASPTR       aliasDsc;
    RBTYPE              vAliasDsc;
    APROPNAMEPTR        pubName;
    APROPUNDEFPTR       undefName;
    RBTYPE              vPtr;
    WORD                fReferenced;


    while (cbRec > 1)                   /* While there are symbols left */
    {
        /* Read alias and its substitute */

        alias[0] = (BYTE) Gets();
        GetBytes(&alias[1], B2W(alias[0]));
        substitute[0] = (BYTE) Gets();
        GetBytes(&substitute[1], B2W(substitute[0]));
        aliasDsc = (APROPALIASPTR) PropSymLookup(alias, ATTRALIAS, FALSE);
        vAliasDsc = vrprop;
        if (aliasDsc == PROPNIL)
        {
            /* New ALIAS - check if we have PUBDEF for the alias name */

            pubName = (APROPNAMEPTR ) PropSymLookup(alias, ATTRPNM, FALSE);
            if (pubName == PROPNIL)
            {
                /* Enter ALIAS name in to symbol table */

                aliasDsc = (APROPALIASPTR) PropSymLookup(alias, ATTRALIAS, TRUE);
                vAliasDsc = vrprop;
#if SYMDEB
                if (fSymdeb)
                    DebPublic(vrprop, ALIAS);
#endif
                // Check if we have an EXTDEF for alias name. If we have
                // this means, that substitute name has to be used in
                // the library search.

                undefName = (APROPUNDEFPTR ) PropSymLookup(alias, ATTRUND, FALSE);
                fReferenced = (WORD) (undefName != PROPNIL);

                // Check if we know the substitute name as PUBDEF or EXTDEF

                pubName = (APROPNAMEPTR ) PropSymLookup(substitute, ATTRPNM, FALSE);
                if (pubName != PROPNIL)
                    vPtr = vrprop;
                else
                {
                    undefName = (APROPUNDEFPTR ) PropSymLookup(substitute, ATTRUND, FALSE);
                    if (undefName != NULL)
                    {
                        vPtr = vrprop;
                        undefName->au_flags |= (SUBSTITUTE | SEARCH_LIB);
                        undefName->au_Default = vAliasDsc;
#if NEW_LIB_SEARCH
                    if (fStoreUndefsInLookaside)
                        StoreUndef((APROPNAMEPTR)undefName, RhteFromProp((APROPPTR)undefName),0,0);
#endif
                    }
                    else
                    {
                        /* Enter substitute name into symbol table */
                        /* as undefined symbol                     */

                        if (extMac >= EXTMAX - 1)
                            Fatal(ER_extdef);

                        undefName = (APROPUNDEFPTR ) PropSymLookup(substitute, ATTRUND, TRUE);
                        vPtr = vrprop;
                        mpextprop[extMac++] = vrprop;
                        if (fReferenced)
                            undefName->au_flags |= (STRONGEXT | SUBSTITUTE | SEARCH_LIB);
                        else
                            undefName->au_flags |= (UNDECIDED | SUBSTITUTE);
                        undefName->au_len = -1L;
                        undefName->au_Default = vAliasDsc;
#if NEWLIST
                        undefName->u.au_rbNxt = rbLstUndef;
                        rbLstUndef = vrprop;
#endif

                    }
                }

                /* Attach substitute symbol to the ALIAS */

                aliasDsc = (APROPALIASPTR) FetchSym(vAliasDsc, TRUE);
                aliasDsc->al_sym = vPtr;

            }
            else
            {
#if FDEBUG
                if (fDebug)
                {
                    alias[alias[0] + 1] = '\0';
                    OutWarn(ER_ignoalias, &alias[1]);
                }
#endif
            }
        }
        else
        {
            /* Check if we have redefinition */

            vPtr = aliasDsc->al_sym;
            pubName = (APROPNAMEPTR ) PropSymLookup(substitute, ATTRPNM, FALSE);
            if (pubName != PROPNIL)
            {
                if (vPtr != vrprop)
                {
                    aliasDsc = (APROPALIASPTR) FetchSym(vAliasDsc, TRUE);
                    aliasDsc->al_sym = vrprop;
                    OutWarn(ER_aliasredef, &alias[1], 1 + GetPropName(pubName), &substitute[1]);
                }
            }
            else
            {
                undefName = (APROPUNDEFPTR ) PropSymLookup(substitute, ATTRUND, FALSE);
                if (undefName != PROPNIL)
                {
                    if (vPtr != vrprop)
                    {
                        aliasDsc = (APROPALIASPTR) FetchSym(vAliasDsc, TRUE);
                        aliasDsc->al_sym = vrprop;
                        OutWarn(ER_aliasredef, &alias[1], 1 + GetPropName(undefName), &substitute[1]);
                    }
                }
            }
        }
    }
}

#pragma check_stack(off)


#if OVERLAYS
    /****************************************************************
    *                                                               *
    *  EndRc1:                                                      *
    *                                                               *
    *  This   function  is  called  to   process  the  information  *
    *  contained  in  a  MODEND  (type 8AH) record  concerning the  *
    *  program  starting address.  The function  does not return a  *
    *  meaningful value.                                            *
    *  See pp. 80-81 in "8086 Object Module Formats EPS."           *
    *                                                               *
    ****************************************************************/

LOCAL void NEAR         EndRc1(void)
{
    WORD                modtyp;         /* MODEND record modtyp byte */
    WORD                fixdat;         /* Fixdat byte */
    SNTYPE              gsn;            /* Global SEGDEF number */
    RATYPE              ra;             /* Symbol offset */
    APROPSNPTR          apropSn;        /* Pointer to segment info */
    WORD                frameMethod;


    if ((modtyp = Gets()) & FSTARTADDRESS)
    {                                   /* If execution start address given */
        ASSERT(modtyp & 1);             /* Must be logical start address */
        fixdat = Gets();                /* Get fixdat byte */
        ASSERT(!(fixdat & 0x8F));       /* Frame, target must be explicit,
                                         *  target must be given by seg index
                                         */
        frameMethod = (fixdat & 0x70) >> 4;
        if (frameMethod != F4 && frameMethod != F5)
            GetIndex(0,IMAX - 1);       /* Punt frame index */
        gsn = mpsngsn[GetIndex((WORD)1,(WORD)(snMac - 1))];
                                        /* Get gsn from target segment index */
#if OMF386
        if(rect & 1) ra = LGets() + mpgsndra[gsn];
        else
#endif
        ra = WGets() + mpgsndra[gsn];   /* Get offset */
        apropSn = (APROPSNPTR ) FetchSym(mpgsnrprop[gsn],FALSE);
                                        /* Get segment information */
        MkPubSym("\006$$MAIN",apropSn->as_ggr,gsn,ra);
                                        /* Make public symbol */
    }
}
#endif /* OVERLAYS */


    /****************************************************************
    *                                                               *
    *  ProcP1:                                                      *
    *                                                               *
    *  This function  controls the processing of an  object module  *
    *  on pass 1.                                                   *
    *                                                               *
    ****************************************************************/

#pragma check_stack(on)

void NEAR               ProcP1(void)
{
    long                typlen[TYPMAX];
    WORD                typtyp[TYPMAX];
    RBTYPE              extprop[EXTMAX];
    FTYPE               fFirstRec;      /* First record flag */
    FTYPE               fFirstMod;      /* First module flag */
    APROPFILEPTR        apropFile;      /* File name entry */

#if OXOUT OR OIAPX286
    RUNTYPE             xhdr;
    LFATYPE             lfa;
#endif

    mpitypelen = typlen;                /* Initialize pointer */
    mpityptyp = typtyp;                 /* Initialize pointer */
    mpextprop = (RBTYPE FAR *) extprop; /* Initialize pointer */
    FMEMSET(mpextprop, 0, sizeof(extprop));
    fFirstMod = (FTYPE) TRUE;           /* First module */
    for(;;)                             /* Loop to process file */
    {
        snMac = 1;                      /* Initialize counter */
        grMac = 1;                      /* Initialize */
        extMac = 1;                     /* Initialize counter */
        lnameMac = 1;                   /* Initialize counter */
        typMac = 1;                     /* Initialize counter */
        vfNewOMF = FALSE;               /* Assume old OMF */
        DEBUGVALUE(gsnMac);             /* Debug info */
        DEBUGVALUE(ggrMac);             /* Debug info */
#if OXOUT OR OIAPX286
        lfa = ftell(bsInput);           /* Save initial file position */
        fread(&xhdr,1,CBRUN,bsInput);   /* Read x.out header */
        if(xhdr.x_magic == X_MAGIC)     /* If magic number found */
        {
#if OXOUT
            if((xhdr.x_cpu & XC_CPU) != XC_8086) InvalidObject();
                                        /* Bad if not 8086 */
#else
            xhdr.x_cpu &= XC_CPU;       /* Get CPU specification */
            if(xhdr.x_cpu != XC_286 && xhdr.x_cpu != XC_8086) InvalidObject();
                                        /* Bad if not 286 or 8086 */
#endif
            if(xhdr.x_relsym != (XR_R86REL | XR_S86REL)) InvalidObject();
                                        /* Check symbol table type */
            if((xhdr.x_renv & XE_VERS) != xever) InvalidObject();
                                        /* Check Xenix version */
        }
        else
            fseek(bsInput,lfa,0);       /* Else return to start */
#endif /* OXOUT OR OIAPX286 */
#if OVERLAYS
        if(fOverlays)                   /* If there are overlays */
            iovFile = ((APROPFILEPTR) vrpropFile)->af_iov;
                                        /* Save overlay number for file */
        else
            iovFile = 0;                /* File contains part of root */
#endif
        fFirstRec = (FTYPE) TRUE;       /* Looking at first record */
        fModEnd = FALSE;                /* Not at module's end */
        fP2Start = FALSE;               /* No p2start record yet */
#if SYMDEB
        cSegCode = 0;                   /* No code segments yet */
#endif
        while(!fModEnd)                 /* Loop to process object module */
        {
            rect = (WORD) getc(bsInput);/* Read record type */
            if(fFirstRec)               /* If first record */
            {
                if(rect != THEADR && rect != LHEADR)
                {                       /* If not header */
                    if(fFirstMod) break;/* Error if first module */
                    return;             /* Else return */
                }
                fFirstRec = FALSE;      /* Not first record any more */
            }
            else if (IsBadRec(rect)) break;
                                        /* Break if invalid object */

            cbRec = WSGets();           /* Read record length */
            lfaLast += cbRec + 3;       /* Update current file pos. */

#if ALIGN_REC
            if (bsInput->_cnt >= cbRec)
            {
                pbRec = bsInput->_ptr;
                bsInput->_ptr += cbRec;
                bsInput->_cnt -= cbRec;
            }
            else
            {
                if (cbRec > sizeof(recbuf))
                {
                    // error -- record too large [rm]
                    InvalidObject();
                }

                // read record into contiguous buffer
                fread(recbuf,1,cbRec,bsInput);
                pbRec = recbuf;
            }
#endif

            DEBUGVALUE(rect);           /* Debug info */
            DEBUGVALUE(cbRec);          /* Debug info */
            switch(TYPEOF(rect))        /* Switch on record type */
            {
#if TCE
                case  FIXUPP:
                    if(fTCE)
                        FixRc1();
                    else
                        SkipBytes((WORD) (cbRec - 1));   /* Skip to checksum byte */
                    break;
#endif

                case TYPDEF:
                    TypRc1();
                    break;

                case COMDEF:
                case LCOMDEF:
                    ComDf1();
                    break;

                case SEGDEF:
                    SegRc1();
                    break;

                case THEADR:
                    ModRc1();
                    break;

                case COMENT:
                    ComRc1();
                    break;

                case LHEADR:
                    ModRc1();
                    break;

                case GRPDEF:
                    GrpRc1();
                    break;

                case EXTDEF:
                case LEXTDEF:
                case CEXTDEF:
                    ExtRc1();
                    break;

                case LNAMES:
                case LLNAMES:
                    LNmRc1((WORD) (TYPEOF(rect) == LLNAMES));
                    break;

                case PUBDEF:
                case LPUBDEF:
                    PubRc1();
                    break;

                case MODEND:
#if OVERLAYS
                    if(fOverlays) EndRc1();
                    else
#endif
                    SkipBytes((WORD) (cbRec - 1));   /* Skip to checksum byte */
                    fModEnd = (FTYPE) TRUE; /* Stop processing module */
                    break;

                case COMDAT:
                    ComDatRc1();
                    break;

                case ALIAS:
                    AliasRc1();
                    break;

                default:
                    if (rect == EOF)
                        InvalidObject();
                    SkipBytes((WORD) (cbRec - 1));   /* Skip to checksum byte */
                    break;
            }
            if(cbRec != 1) break;       /* If record length bad */
            Gets();                     /* Eat the checksum byte */
        }
        if(!fModEnd)
        {
            ChkInput();                 /* First check for I/O problems */
            InvalidObject();            /* Invalid module */
        }
        ++modkey;                       /* For local symbols */
#if SYMDEB
        if (fSymdeb)
        {
            apropFile = (APROPFILEPTR) FetchSym(vrpropFile, TRUE);
            if (apropFile->af_cvInfo || apropFile->af_Src)
                ++ObjDebTotal;          /* Count the .OBJ with CV info */
        }
#endif
        if(extMac > extMax)             /* Possibly set new extMax */
            extMax = extMac;
        if(fLibraryFile || fP2Start) return;
        fFirstMod = FALSE;              /* Not first module */
    }
}

#pragma check_stack(off)