windows-nt/Source/XPSP1/NT/sdktools/link16/newstr.c
2020-09-26 16:20:57 +08:00

569 lines
20 KiB
C

/* SCCSID = %W% %E% */
/*
* Copyright Microsoft Corporation, 1983-1987
*
* This Module contains Proprietary Information of Microsoft
* Corporation and should be treated as Confidential.
*/
/****************************************************************
* *
* NEWSTR.C *
* *
* Routines concerning filenames, strings. *
* *
****************************************************************/
#include <minlit.h> /* Types, constants, macros */
#include <bndtrn.h> /* More of the same */
#include <bndrel.h> /* More of the same */
#include <lnkio.h> /* Linker I/O definitions */
#include <lnkmsg.h> /* Error messages */
#include <extern.h> /* External declarations */
#include <undname.h>
/*
* LOCAL FUNCTION PROTOTYPES
*/
LOCAL unsigned short NEAR Find(unsigned char *s1,
unsigned char b,
unsigned short n);
LOCAL void NEAR DelimParts(unsigned char *psb,
unsigned short *pi1,
unsigned short *pi2,
unsigned short *pi3);
/****************************************************************
* *
* Find: *
* *
* This function takes as its arguments a byte pointer s1, and *
* a BYTE b, and a WORD n. It scans at most n bytes of s1 *
* looking for an occurrence of b. If it finds one, it *
* returns its offset from the beginning of s1, and if it does *
* not, it returns the value INIL. *
* *
****************************************************************/
LOCAL WORD NEAR Find(s1,b,n) /* Find matching byte */
REGISTER BYTE *s1; /* Pointer to a byte string */
BYTE b; /* Search target */
WORD n; /* Length of s1 */
{
REGISTER WORD i; /* Counter */
i = 0; /* Initialize */
#if ECS
if (b < 0x40) /* b cannot be part of ECS */
{
#endif
while(n--) /* While not at end of string */
{
if(*s1++ == b) return(i); /* If match found, return position */
++i; /* Increment counter */
}
return(INIL); /* No match */
#if ECS
}
#endif
#if ECS || defined(_MBCS)
/* We have to worry about ECS */
while(n--)
{
if(*s1++ == b) return(i);
++i;
if (IsLeadByte(s1[-1])) /* If we were on a lead byte */
{ /* Advance an extra byte */
s1++;
i++;
n--;
}
}
return(INIL); /* No match */
#endif /* ECS */
}
WORD IFind(sb,b)
BYTE *sb; /* Pointer to length-prefixed string */
BYTE b; /* Search target */
{
return(Find(&sb[1],b,B2W(sb[0]))); /* Call Find() to do the work */
}
/****************************************************************
* *
* BreakLine: *
* *
* This function takes as its arguments an SBTYPE, a pointer *
* to a function, and a character used as a delimiter. It *
* It parses the SBTYPE, applying the given function to every *
* substring delimited by the given delimiter. The function *
* does not return a meaningful value. *
* *
****************************************************************/
void BreakLine(psb,pfunc,sepchar)
BYTE *psb; /* String to parse */
void (*pfunc)(BYTE *);/* Function pointer */
char sepchar; /* Delimiter */
{
SBTYPE substr; /* Substring */
REGISTER WORD ibeg; /* Index variable */
REGISTER WORD ilen; /* Substring length */
ibeg = 1; /* Initialize */
while(ibeg <= B2W(psb[0])) /* While not at end of string */
{
ilen = Find(&psb[ibeg],sepchar,(WORD)(B2W(psb[0]) - ibeg + 1));
/* Get index of sepchar in string */
if(ilen == INIL) ilen = B2W(psb[0]) - ibeg + 1;
/* Len is all that's left if no sep */
memcpy(&substr[1],&psb[ibeg],ilen);
/* Copy substring into substr */
substr[0] = (BYTE) ilen; /* Store the length */
ibeg += ilen + 1; /* Skip over substring and delimiter */
(*pfunc)(substr); /* Call the specified function */
}
}
#pragma check_stack(on)
/****************************************************************
* *
* UpdateFileParts: *
* *
* "Inherit file pieces from a master template and specify *
* missing Update. Inherit four pieces: disk drive, path, *
* file name, extension." *
* *
* Inputs: psbOld pointer to "old sb that specifies *
* pieces of a file name." *
* psbUpdate pointer to "new pieces." *
* *
* Output: psbOld "updated to reflect missing *
* update." *
* *
****************************************************************/
void UpdateFileParts(psbOld,psbUpdate)
BYTE *psbOld; /* Name to be updated */
BYTE *psbUpdate; /* The update */
{
char oldDrive[_MAX_DRIVE];
char oldDir[_MAX_DIR];
char oldFname[_MAX_FNAME];
char oldExt[_MAX_EXT];
char updDrive[_MAX_DRIVE];
char updDir[_MAX_DIR];
char updFname[_MAX_FNAME];
char updExt[_MAX_EXT];
char *newDrive;
char *newDir;
char *newFname;
char *newExt;
char newPath[_MAX_PATH];
int newPathLen;
psbOld[psbOld[0]+1] = '\0';
_splitpath(&psbOld[1], oldDrive, oldDir, oldFname, oldExt);
psbUpdate[psbUpdate[0]+1] = '\0';
_splitpath(&psbUpdate[1], updDrive, updDir, updFname, updExt);
// Select components of the updated file path
if (updDrive[0] != '\0')
newDrive = updDrive;
else
newDrive = oldDrive;
if ((updDir[0] != '\0') && !(updDir[0] == '/' && updDir[1] == '\0'))
newDir = updDir; /* This above is a fix for bug # 46 */
else
newDir = oldDir;
// If newDir points to UNC name then forget about drive spec
if ((newDir[0] == '\\') && (newDir[1] == '\\'))
newDrive = NULL;
if (updFname[0] != '\0')
newFname = updFname;
else
newFname = oldFname;
if (updExt[0] != '\0')
newExt = updExt;
else
newExt = oldExt;
_makepath(newPath, newDrive, newDir, newFname, newExt);
newPathLen = strlen(newPath);
if (newPathLen > SBLEN - 1)
newPathLen = SBLEN - 1;
memcpy(&psbOld[1], newPath, newPathLen);
psbOld[0] = (BYTE) newPathLen;
if (newPathLen < SBLEN - 1)
psbOld[newPathLen + 1] = '\0';
else
{
psbOld[SBLEN - 1] = '\0';
OutWarn(ER_fntoolong, psbOld + 1);
fflush(stdout);
}
}
#pragma check_stack(off)
#if OVERLAYS OR SYMDEB
/*
* StripDrivePath (sb)
*
* Strip drive and path from a filename.
* Return pointer to new name, minus drive and path (if any).
*/
BYTE *StripDrivePath(sb)
BYTE *sb; /* Length-prefixed filename */
{
StripPath(sb); /* Strip path from name */
if (sb[2] != ':') /* If there is no drive */
return(sb); /* return it as is */
sb[2] = (BYTE) ((sb[0]) - 2); /* Adjust length byte, move it */
return(&sb[2]); /* Return minus drive */
}
#endif
/****************************************************************
* *
* SbCompare: *
* *
* Compares two length-prefixed strings. Returns true if they *
* match. *
* *
* NOTE: When comparison is case-insensitive note that letters *
* will match regardless of case, but, in addition, '{' will *
* match '[', '|' will match '\', '}' will match ']', and *
* '~' will match '^'. *
* *
* NOTE: This routine does not know about DBCS. *
* *
****************************************************************/
WORD SbCompare(ps1,ps2,fncs)
REGISTER BYTE *ps1; /* Pointer to symbol */
REGISTER BYTE *ps2; /* Pointer to symbol */
WORD fncs; /* True if not case-sensitive */
{
WORD length; /* No. of char.s to compare */
if(*ps1 != *ps2) return(FALSE); /* Lengths must match */
length = B2W(*ps1); /* Get length */
if (!fncs) /* If case-sensitive */
{ /* Simple string comparison */
while (length && (*++ps1 == *++ps2))
length--;
return(length ? FALSE : TRUE); /* Success iff nothing left */
}
while(length--)
{
if(*++ps1 == *++ps2) continue; /* Bytes match */
if((*ps1 & 0137) != (*ps2 & 0137)) return(FALSE);
}
return(TRUE); /* They match */
}
#if OSEGEXE
/****************************************************************
* *
* SbUcase: *
* *
* Force a length-prefixed string to upper case. *
* Does not check for punctuation characters. *
* *
****************************************************************/
void SbUcase(sb)
REGISTER BYTE *sb; /* Length-prefixed string */
{
REGISTER int length;
#ifdef _MBCS
sb[B2W(sb[0])+1] = '\0';
_mbsupr (sb + 1);
#else
/* Loop through symbol, changing lower to upper case. */
for(length = B2W(*sb++); length > 0; --length, ++sb)
{
#if ECS
/* If lead byte character, skip two bytes */
if(IsLeadByte(*sb))
{
--length;
++sb;
continue;
}
#endif
if(*sb >= 'a' && *sb <= 'z')
*sb -= 'a' - 'A';
}
#endif
}
#endif
/*
* SbSuffix:
*
* Tell if one length-prefixed string is a suffix of another.
*/
FTYPE SbSuffix(sb,sbSuf,fIgnoreCase)
REGISTER BYTE *sb; /* String */
REGISTER BYTE *sbSuf; /* Suffix */
WORD fIgnoreCase; /* True if case is to be ignored */
{
WORD suflen; /* Suffix length */
/* Get suffix length. If longer than string, return false. */
suflen = B2W(sbSuf[0]);
if(suflen > B2W(sb[0])) return(FALSE);
/*
* Point to end of suffix and end of string. Loop backwards
* until mismatch or end of suffix.
*/
sbSuf = &sbSuf[suflen];
sb = &sb[B2W(sb[0])];
while(suflen--)
{
if(!fIgnoreCase)
{
if(*sb-- != *sbSuf--) return(FALSE);
}
else if((*sb-- | 0x20) != (*sbSuf-- | 0x20)) return(FALSE);
}
return((FTYPE) TRUE);
}
#if NEWSYM
#if !defined( M_I386 ) && !defined( _WIN32 )
/*** GetFarSb - copy a far length-prefixed string
*
* Purpose:
* Copy a far length-prefixed string into a near static buffer.
* Terminate with null byte.
* Return a pointer to the the buffer.
*
* Input:
* psb - pointer to the far string
*
* Output:
* Pointer to the near buffer.
*
* Exceptions:
* None.
*
* Notes:
* Don't call this function twice in the row to get two far strings,
* because the second call will overwite the first string.
*
*************************************************************************/
char *GetFarSb(BYTE FAR *lpsb)
{
static BYTE sb[SBLEN+1]; /* 1 extra for the null byte */
sb[0] = lpsb[0];
FMEMCPY((BYTE FAR *) &sb[1], &lpsb[1], B2W(lpsb[0]));
if (sb[0] + 1 < sizeof(sb))
sb[sb[0] + 1] = 0; /* Some routines expect a terminating 0 */
else
sb[SBLEN] = 0;
return(sb);
}
#endif
#endif
/****************************************************************
* *
* ProcObject: *
* *
* This function takes as its argument a pointer to a length- *
* prefixed string containing the name of an object file. It *
* processes that file name. It does not return a meaningful *
* value. *
* *
****************************************************************/
void ProcObject(psbObj)/* Process object file name */
REGISTER BYTE *psbObj; /* Object file name */
{
SBTYPE sbFile; /* File name */
#if OVERLAYS
FTYPE frparen; /* True if trailing paren found */
FTYPE flparen; /* True if leading paren found */
#endif
#if CMDMSDOS
BYTE sbExt[5];
#endif
#if OVERLAYS
if(psbObj[B2W(psbObj[0])] == ')') /* If trailing parenthesis found */
{
frparen = (FTYPE) TRUE; /* Set flag true */
--psbObj[0]; /* Delete parenthesis */
}
else frparen = FALSE; /* Else set flag false */
if(psbObj[0] && psbObj[1] == '(') /* If leading parenthesis found */
{
flparen = (FTYPE) TRUE; /* Set flag true */
psbObj[1] = (BYTE) (psbObj[0] - 1);/* Delete parenthesis */
++psbObj;
}
else flparen = FALSE; /* Else set flag false */
#endif
#if CMDMSDOS
PeelFlags(psbObj); /* Process flags, if any */
#if OVERLAYS
if(psbObj[B2W(psbObj[0])] == ')') /* If trailing parenthesis found */
{
if(frparen) Fatal(ER_nstrpar);
/* Cannot nest parentheses */
frparen = (FTYPE) TRUE; /* Set flag true */
--psbObj[0]; /* Delete parenthesis */
}
#endif
#endif
#if OVERLAYS
if(flparen) /* If leading parenthesis */
{
if(fInOverlay) Fatal(ER_nstlpar);
/* Check if in overlay already */
fInOverlay = (FTYPE) TRUE; /* Set flag */
fOverlays = (FTYPE) TRUE; /* Set flag */
}
#endif
if(psbObj[0]) /* If object name length not zero */
{
#if DEBUG /* If debugging on */
fprintf(stderr," Object "); /* Message */
OutSb(stderr,psbObj); /* File name */
NEWLINE(stderr); /* Newline */
#endif /* End debugging code */
#if CMDMSDOS
memcpy(sbFile,sbDotObj,5); /* Put extension in sbFile */
UpdateFileParts(sbFile,psbObj); /* Add extension to name */
#endif
#if CMDXENIX
memcpy(sbFile,psbObj,B2W(psbObj[0]) + 1);
/* Leave name unchanged */
#endif
#if CMDMSDOS
/* If file has extension ".LIB" then save it as a library
* from which all modules will be extracted.
*/
sbExt[0] = 4;
memcpy(sbExt+1,&sbFile[B2W(sbFile[0])-3],4);
if (SbCompare(sbExt, sbDotLib, TRUE))
{
if(ifhLibMac >= IFHLIBMAX) Fatal(ER_libmax);
/* Mark name pointer nil so library won't be searched. */
mpifhrhte[ifhLibMac] = RHTENIL;
SaveInput(sbFile,0L,ifhLibMac++,(WORD)(fInOverlay? iovMac: 0));
}
else
#endif
SaveInput(sbFile,0L,(WORD) FHNIL,(WORD)(fInOverlay? iovMac: 0));
/* Save input file name and address */
}
#if OVERLAYS
if(frparen) /* If trailing parenthesis */
{
if(!fInOverlay) Fatal(ER_unmrpar);
/* Check parentheses */
fInOverlay = FALSE; /* No longer specifying overlay */
if(++iovMac > IOVMAX) Fatal(ER_ovlmax);
/* Increment overlay counter */
}
#endif
}
/*
* fPathChr (ch)
*
* Tells whether or not a given character is a path character.
*
*/
FTYPE fPathChr(ch)
char ch;
{
#if OSXENIX
if (ch == '/')
#else
if (ch == '/' || ch == '\\')
#endif
return((FTYPE) TRUE);
return(FALSE);
}
/*** UndecorateSb - undecorate name
*
* Purpose:
* Undecorate length prefixed name.
*
* Input:
* sbSrc - length prefixed decorated name
* sbDst - length prefixed undecorated name
* cbDst - size of sbDst
*
* Output:
* If undecoration is successfull the sbDst contains undecorated
* C++ name, else the sbSrc is copied to the sbDst.
*
* Exceptions:
* None.
*
* Notes:
* None.
*
*************************************************************************/
void UndecorateSb(char FAR *sbSrc, char FAR *sbDst, unsigned cbDst)
{
char FAR *pUndecor;
unsigned len;
// Make sure that decorated string is zero-terminated
if (sbSrc[0] < sizeof(SBTYPE))
sbSrc[sbSrc[0] + 1] = '\0';
else
sbSrc[sizeof(SBTYPE) - 1] = '\0';
pUndecor = __unDName(NULL, (pcchar_t) &sbSrc[1], 0, &malloc, &free, 0);
if (pUndecor == NULL)
{
// Undecorator failed
FMEMCPY(sbDst, sbSrc, sbSrc[0] + 1);
}
else
{
// Add length to the undecorated name
len = FSTRLEN(pUndecor);
len = cbDst - 2 >= len ? len : cbDst - 2;
FMEMCPY(&sbDst[1], pUndecor, len);
sbDst[0] = (BYTE) len;
sbDst[len + 1] = '\0';
FFREE(pUndecor);
}
}