/* SCCSID = %W% %E% */
/*
*       Copyright Microsoft Corporation, 1983-1987
*
*       This Module contains Proprietary Information of Microsoft
*       Corporation and should be treated as Confidential.
*/

/* Various tools, e.g. environment for libs. */

    /****************************************************************
    *                                                               *
    *                           NEWPAR.C                            *
    *                                                               *
    ****************************************************************/

#include                <minlit.h>      /* Types and constants */
#include                <bndtrn.h>      /* Types and constants */
#include                <bndrel.h>      /* Types and constants */
#include                <lnkio.h>       /* Linker I/O definitions */
#include                <lnkmsg.h>      /* Error messages */
#include                <extern.h>      /* External declarations */

/*
 *  LOCAL FUNCTION PROTOTYPES
 */

LOCAL WORD NEAR TrailChar(unsigned char *psb,unsigned char b);



/*
 * SaveInput - save an input object module in the list if it's not
 *      already there
 *
 * RETURNS
 *      TRUE if module was saved
 *      FALSE if module was not saved
 */

WORD                    SaveInput(psbFile,lfa,ifh,iov)
BYTE                    *psbFile;       /* File name */
LFATYPE                 lfa;            /* File address */
WORD                    ifh;            /* Library number */
WORD                    iov;            /* Overlay number */
{
    APROPFILEPTR        papropFile;
    RBTYPE              rpropFilePrev;
#if OSXENIX
    FTYPE               fSave;
#endif
#if BIGSYM
    SBTYPE              sbFile;         /* Buffer to hold psbFile */
#endif

#if DEBUG                               /* If debugging on */
    fprintf(stderr,"File ");            /* Message */
    OutSb(stderr,psbFile);              /* File name */
    NEWLINE(stderr);                    /* Newline */
#endif                                  /* End debugging code */
    DEBUGVALUE(lfa);                    /* Debug info */
    DEBUGVALUE(ifh);                    /* Debug info */
    DEBUGVALUE(iov);                    /* Debug info */
#if OSMSDOS
    if(SbCompare(psbFile, (BYTE *) "\006VM.TMP", TRUE))
    {                                   /* If name given is VM.TMP */
        OutWarn(ER_vmtmp);
        return(FALSE);
    }
#endif
#if OSXENIX
    fSave = fIgnoreCase;
    fIgnoreCase = FALSE;
#endif
#if BIGSYM
    /* PsbFile is pointing to a VM buffer which may get flushed out
     * before PropSymLookup finds a match, in a very big symbol table.
     * So we copy it to a stack buffer first.
     */
    memcpy(sbFile,psbFile,B2W(psbFile[0]) + 1);
    psbFile = sbFile;
#endif
    papropFile = (APROPFILEPTR ) PropSymLookup(psbFile,ATTRFIL,TRUE);
#if OSXENIX
    fIgnoreCase = fSave;
#endif
    if(!vfCreated)
    {
        for(;;)
        {
            /* "If we have a library and we've seen this module before,
            *  ignore it."
            */
            DEBUGVALUE(papropFile->af_attr);
            if(papropFile->af_attr == ATTRNIL) break;
            DEBUGVALUE(papropFile->af_ifh);
            DEBUGVALUE(papropFile->af_lfa);
            if(papropFile->af_attr == ATTRFIL &&
              papropFile->af_ifh != FHNIL && papropFile->af_ifh == (char) ifh &&
              papropFile->af_lfa == lfa)
              return(FALSE);
            papropFile = (APROPFILEPTR ) FetchSym(papropFile->af_next,FALSE);
        }
        papropFile = (APROPFILEPTR ) PropAdd(vrhte,ATTRFIL);
    }
    /* Save virt address of 1st object.  If library with lfa = 0, it's
     * a load-library so consider it an object.
     */
    if(rhteFirstObject == RHTENIL && (ifh == FHNIL || lfa == 0))
        rhteFirstObject = vrhte;
                                        /* Save virt addr of 1st object */
#if ILINK
    /* allocate a module number for all modules */
    if (papropFile->af_imod == IMODNIL)
        papropFile->af_imod = ++imodCur; /* allocate a module number */
    papropFile->af_cont = 0;
    papropFile->af_ientOnt = 0;
#endif
    papropFile->af_rMod = 0;
    papropFile->af_lfa = lfa;
    papropFile->af_ifh = (char) ifh;
    papropFile->af_iov = (IOVTYPE) iov;
    papropFile->af_publics = 0L;
#if SYMDEB
    papropFile->af_cvInfo = NULL;
    papropFile->af_cCodeSeg = 0;
    papropFile->af_Code = NULL;
    papropFile->af_CodeLast = NULL;
    papropFile->af_publics = NULL;
    papropFile->af_Src = NULL;
    papropFile->af_SrcLast = NULL;
#endif
    papropFile->af_ComDat = 0L;
    papropFile->af_ComDatLast = 0L;
    rpropFilePrev = vrpropTailFile;
    vrpropTailFile = vrprop;
    if(!rprop1stFile) rprop1stFile = vrpropTailFile;
    else
    {
        papropFile = (APROPFILEPTR ) FetchSym(rpropFilePrev,TRUE);
        papropFile->af_FNxt = vrpropTailFile;
    }
    return(TRUE);
}

#if CMDMSDOS
/*
 *  TrailChar (pb, b)
 *
 *  Tells whether the final character of a length-prefixed string
 *  equals the single-byte character b.  Knows about ECS.
 *
 */

LOCAL WORD NEAR         TrailChar(psb,b)
REGISTER BYTE           *psb;           /* Pointer to length-prefixed string */
BYTE                    b;              /* Byte being tested for */
{
    REGISTER unsigned char
                        *pLast;         /* Pointer to last byte */

    pLast = (unsigned char *)&psb[B2W(psb[0])];
                                        /* Set pointer to last byte */

#ifdef _MBCS
    if (!IsLeadByte(pLast[-1]))
#elif ECS
    if (b <  0x40 || !IsLeadByte(pLast[-1]))
                                        /* b cannot be part of an ECS char */
#endif
        return(*pLast == b ? TRUE : FALSE);
#if ECS || defined(_MBCS)
    psb++;                              /* Skip length byte */
        /* In the following, psb is kept on a known character boundary */
    while (psb < pLast)
        if (IsLeadByte(*psb++))         /* If valid lead byte */
            psb++;                      /* Advance an extra byte */
    if (psb == pLast)                   /* If pLast on a char boundary */
        return(*pLast == b ? TRUE : FALSE);
    return(FALSE);                      /* pLast is 2nd byte of ECS char */
#endif /* ECS */
}
#endif /* OSMSDOS  OR CMDMSDOS */

#if CMDMSDOS
#if OSXENIX
#define fPath(s)        (IFind(s,CHPATH) != INIL)
#else
#define fPath(s)        (IFind(s,'\\') != INIL || IFind(s,'/') != INIL)
#endif

#pragma check_stack(on)

void NEAR               AddLibPath(i)   /* Add paths to library names */
WORD                    i;              /* Index */
{
    AHTEPTR             ahte;           /* Pointer to hash table entry */
    WORD                j;              /* Index */
    SBTYPE              sbLib;          /* Library name */
    SBTYPE              sbTmp;          /* Temporary library name */

    /* Don't do anything if name is nil */
    if(mpifhrhte[i] == RHTENIL)
        return;
    ahte = (AHTEPTR ) FetchSym(mpifhrhte[i],FALSE);
                                        /* Fetch library name */
#if OSMSDOS
    if(IFind(GetFarSb(ahte->cch),':') == INIL && !fPath(GetFarSb(ahte->cch)))
#else
    if(!fPath(GetFarSb(ahte->cch)))
#endif
    {                                   /* If there is no path on the name */
        memcpy(sbLib,GetFarSb(ahte->cch),B2W(ahte->cch[0]) + 1);
                                        /* Copy the name */
        sbLib[B2W(sbLib[0]) + 1] = '\0';/* Null-terminate the name */
        if(_access(&sbLib[1],0))         /* If file not in current directory */
        {
            for(j = 0; j < cLibPaths; ++j)
            {                           /* Look through default paths */
                memcpy(sbTmp,sbLib,B2W(sbLib[0]) + 1);
                                        /* Copy library name */
                ahte = (AHTEPTR ) FetchSym(rgLibPath[j],FALSE);
                                        /* Fetch a default path */
                UpdateFileParts(sbTmp,GetFarSb(ahte->cch));
                                        /* Apply file name */
                sbTmp[B2W(sbTmp[0]) + 1] = '\0';
                                        /* Null-terminate the name */
                if(!_access(&sbTmp[1],0))/* If the library exists */
                {
                    PropSymLookup(sbTmp,ATTRFIL,TRUE);
                                        /* Add to symbol table */
                    mpifhrhte[i] = vrhte;
                                        /* Make table entry */
                    break;              /* Exit the loop */
                }
            }
        }
    }
}

void NEAR               LibEnv()        /* Process LIB= environment variable */
{
    SBTYPE              sbPath;         /* Library search path */
    char FAR            *lpch;          /* Pointer to buffer */
    REGISTER BYTE       *sb;            /* Pointer to string */
    WORD                i;              /* Index */
#if OSMSDOS AND NOT CLIBSTD
    BYTE                buffer[512];    /* Environment value buffer */
    FTYPE               genv();         /* Get environment variable value */
#endif

#if OSMSDOS AND NOT CLIBSTD
    if(genv("LIB",buffer))              /* If variable set */
    {
        pb = buffer;                    /* Initialize */
#else
    if(lpszLIB != NULL)                 /* If variable set */
    {
#endif
        lpch = lpszLIB;
        sb = sbPath;                    /* Initialize */
        do                              /* Loop through environment value */
        {
            if(*lpch == ';' || *lpch == '\0')
            {                           /* If end of path specification */
                if(sb > sbPath)         /* If specification not empty */
                {
                    sbPath[0] = (BYTE)(sb - sbPath);
                                        /* Set length of path string */
                    if (*sb != ':' && !TrailChar(sbPath, CHPATH))
                    {                   /* Add path char if none */
                        *++sb = CHPATH;
                        sbPath[0]++;    /* Increment length */
                    }
                    AddLibrary(sbPath); /* Add path to list of defaults */
                    sb = sbPath;        /* Reset pointer */
                }
            }
            else
            {
                 *++sb = *lpch;         /* Else copy character to path */

                 // The names in linker are limited to 255 chars
                 // Check for length overflow
                 if (sb >= sbPath + sizeof(sbPath) - 1)
                 {
                    sbPath[sizeof(sbPath) - 1] = '\0';
                    OutError(ER_badlibpath, sbPath);
                    sb = sbPath;
                 }
            }
        }
        while(*lpch++ != '\0');         /* Loop until end of string */
    }
    for(i = 0; i < ifhLibMac; ++i) AddLibPath(i);
                                        /* Fix libraries from command line */
}
#endif /* #if (OSMSDOS OR OSXENIX) AND CMDMSDOS */

    /****************************************************************
    *                                                               *
    *  AddLibrary:                                                  *
    *                                                               *
    *  Add a library to the search list.  Check for duplicates and  *
    *  for too many libraries.                                      *
    *                                                               *
    ****************************************************************/

#if CMDMSDOS
void                    AddLibrary(psbName)
BYTE                    *psbName;       /* Name of library to add */
{
    AHTEPTR             ahteLib;        /* Pointer to hash table entry */
    SBTYPE              sbLib;          /* Library name */
#if OSMSDOS
    SBTYPE              sbCmp2;         /* Second name for comparison */
    SBTYPE              sbCmp1;         /* First name for comparison */
#endif
    WORD                i;              /* Index variable */

    /*
     * NOTE: It is assumed in this function that
     * psbName is not a pointer to a virtual memory
     * buffer, i.e., one may not pass a pointer
     * returned by FetchSym(), PropSymLookup(), etc.,
     * as the argument to this function.
     */
    if(!fDrivePass) PeelFlags(psbName); /* Process any flags */
    if(psbName[0])                      /* If name not null */
    {
#if OSMSDOS
        if(psbName[B2W(psbName[0])] == ':' || TrailChar(psbName, CHPATH))
#else
        if(TrailChar(psbName, CHPATH))
#endif
        {                             /* If path spec only */
            /*
             * Add an entry to the list of default paths.
             */
            if(cLibPaths >= IFHLIBMAX) return;
                                        /* Only so many paths allowed */
            if(PropSymLookup(psbName,ATTRNIL,FALSE) != PROPNIL) return;
                                        /* No duplicates allowed */
            PropSymLookup(psbName,ATTRNIL,TRUE);
                                        /* Install in symbol table */
            rgLibPath[cLibPaths++] = vrhte;
                                        /* Save virtual address */
            return;                     /* And return */
        }
#if OSMSDOS
        memcpy(sbCmp1,sbDotLib,5);      /* Default .LIB extension */
        UpdateFileParts(sbCmp1,psbName);/* Add extension to name */
        memcpy(sbLib,sbCmp1,B2W(sbCmp1[0]) + 1);
                                        /* Copy back name plus extension */
        UpdateFileParts(sbCmp1,(BYTE *) "\003A:\\");
                                        /* Force drive and path to "A:\" */
        for(i = 0; i < ifhLibMac; ++i)  /* Look at libraries in list now */
        {
            if(mpifhrhte[i] == RHTENIL) /* Skip if NIL */
                continue;
            ahteLib = (AHTEPTR ) FetchSym(mpifhrhte[i],FALSE);
                                        /* Fetch name */
            memcpy(sbCmp2,GetFarSb(ahteLib->cch),B2W(ahteLib->cch[0]) + 1);
                                        /* Copy it */
            UpdateFileParts(sbCmp2,(BYTE *) "\003A:\\");
                                        /* Force drive and path to "A:\" */
            if(SbCompare(sbCmp1,sbCmp2,TRUE)) return;
                                        /* Return if names match */
        }
        if(ifhLibMac >= IFHLIBMAX) Fatal(ER_libmax);
                                        /* Check for too many libraries */
        PropSymLookup(sbLib,ATTRFIL,TRUE);
                                        /* Add to symbol table */
#else
        memcpy(sbLib,sbDotLib,5);         /* Default .LIB extension */
        UpdateFileParts(sbLib,psbName); /* Add file name */
        if(PropSymLookup(sbLib,ATTRFIL,FALSE) != PROPNIL) return;
                                        /* Do not allow multiple definitions */
        if(ifhLibMac >= IFHLIBMAX) Fatal(ER_libmax);
                                        /* Check for too many libraries */
        PropSymLookup(sbLib,ATTRFIL,TRUE);
                                        /* Add to symbol table */
#endif /* #if OSMSDOS ... #else ... */
        mpifhrhte[ifhLibMac] = vrhte;   /* Make table entry */
        if(fDrivePass) AddLibPath(ifhLibMac);
                                        /* Fix library from object module */
        ++ifhLibMac;                    /* Increment counter */
    }
}
#pragma check_stack(off)

#endif /* CMDMSDOS */

#if CMDXENIX
void                    AddLibrary(psbName)
BYTE                    *psbName;       /* Name of library to add */
{
    SBTYPE              sbLib;          /* Library name */

    if(psbName[0])                      /* If name not null */
    {
        memcpy(sbLib,psbName,B2W(psbName[0]) + 1);
                                        /* Copy the library name */
        if(PropSymLookup(sbLib,ATTRFIL,FALSE) != PROPNIL) return;
                                        /* No duplicates allowed */
        if(ifhLibMac >= IFHLIBMAX) Fatal(ER_libmax);
                                        /* Check for too many libraries */
        PropSymLookup(sbLib,ATTRFIL,TRUE);
                                        /* Add to symbol table */
        mpifhrhte[ifhLibMac] = vrhte;   /* Make table entry */
        ++ifhLibMac;                    /* Increment counter */
    }
}
#endif /* CMDXENIX */