|
|
/*
* Copyright Microsoft Corporation, 1983-1989 * * This Module contains Proprietary Information of Microsoft * Corporation and should be treated as Confidential. */ /****************************************************************
* * * FLAG PROCESSOR MODULE * * * ****************************************************************/
#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 */
#if OIAPX286
#include <xenfmt.h> /* x.out definitions */
#endif
#include <extern.h> /* External declarations */
#include <newexe.h> /* DOS & 286 .EXE format structure def.s */
#if EXE386
#include <exe386.h> /* 386 .EXE format structure def.s */
#endif
#include <process.h>
extern FTYPE fNoExtDic; /* Not searching extended dictionary */
LOCAL BYTE *osbSwitch; /* Switch pointer */ LOCAL MSGTYPE SwitchErr; /* Switch error number */
/*
* FUNCTION PROTOTYPES */
#if TIMINGS
LOCAL void NEAR SwShowTiming(void); #endif // TIMINGS
#if PCODE
LOCAL void NEAR SwPCode(void); #endif
LOCAL void NEAR SwAlign(void); LOCAL void NEAR SwBatch(void); #if ODOS3EXE
LOCAL void NEAR SwBinary(void); #endif
LOCAL void NEAR SwCase(void); LOCAL void NEAR SwCParMax(void); LOCAL void NEAR SwDelexe(void); LOCAL void NEAR SwDosExtend(void); LOCAL void NEAR SwDosseg(void); LOCAL void NEAR SwDSAlloc(void); LOCAL void NEAR SwDynamic(void); LOCAL void NEAR SwIdef(void); LOCAL void NEAR SwOldOvl(void); LOCAL void NEAR SwExePack(void); LOCAL void NEAR SwFarCall(void); #if EXE386
LOCAL void NEAR SwHeader(void); #endif
#if NOT WIN_3
LOCAL void NEAR SwHelp(void); LOCAL void NEAR SwShortHelp(void); #endif
LOCAL void NEAR SwHigh(void); #if ILINK
LOCAL void NEAR SwIncremental(void); #endif
LOCAL void NEAR SwInfo(void); LOCAL void NEAR SwIntNo(void); #if (OSEGEXE AND defined(LEGO)) OR EXE386
LOCAL void NEAR SwKeepFixups(void); #endif
#if EXE386
LOCAL void NEAR SwKeepVSize(void); #endif
LOCAL void NEAR SwLineNos(void); LOCAL void NEAR SwMap(void); #if O68K
LOCAL void NEAR SwMac(void); #endif /* O68K */
#if WIN_NT
LOCAL void NEAR SwMemAlign(void); #endif
#if NOT EXE386
LOCAL void NEAR SwNewFiles(void); #endif
LOCAL void NEAR SwNoDefLib(void); LOCAL void NEAR SwNoExtDic(void); LOCAL void NEAR SwNoFarCall(void); LOCAL void NEAR SwNoGrp(void); LOCAL void NEAR SwNologo(); LOCAL void NEAR SwNonulls(void); LOCAL void NEAR SwNoPack(void); LOCAL void NEAR SwNoUseReal(void); LOCAL void NEAR SwPack(void); LOCAL void NEAR SwPackData(void); LOCAL void NEAR SwPackFunctions(void); LOCAL void NEAR SwNoPackFunctions(void); LOCAL void NEAR SwPadCode(void); LOCAL void NEAR SwPadData(void); LOCAL void NEAR SwPause(void); LOCAL void NEAR SwPmType(void); LOCAL void NEAR SwQuicklib(void); LOCAL void NEAR SwSegments(void); LOCAL void NEAR SwStack(void); LOCAL void NEAR SwSymdeb(void); LOCAL void NEAR SwWarnFixup(void); #if DOSEXTENDER
LOCAL void NEAR SwRunReal(void); #endif
#if QCLINK
LOCAL void NEAR SwZ1(void); #endif
#if QCLINK OR Z2_ON
LOCAL void NEAR SwZ2 (void); #endif
#if QCLINK
LOCAL void NEAR SwZincr(void); #endif
LOCAL int NEAR ParseNo(unsigned long *pResult); LOCAL int NEAR ParseStr(char *pResult); LOCAL void NEAR BadFlag(unsigned char *psb, MSGTYPE errnum); LOCAL int NEAR FPrefix(unsigned char *psb1,unsigned char *psb2);
/*
* ParseNo : Parse switch number * * Return value: * 1 result stored in pointer * 0 no switch given * -1 error */ LOCAL int NEAR ParseNo(pResult) unsigned long *pResult; { REGISTER char *s; /* String pointer */ REGISTER WORD ch; /* A character */ WORD strlen; /* String length */ WORD base = 10; /* Base to read constant in */ DWORD oldval;
oldval = *pResult = 0L; /* Initialize */ strlen = IFind(osbSwitch,':'); /* Look for a colon in the string */ if(strlen != INIL && strlen < (WORD) (B2W(osbSwitch[0]) - 1)) { /* If switch form valid */ s = &osbSwitch[strlen + 2]; /* Set pointer past colon */ strlen = B2W(osbSwitch[0]) - strlen - 1; /* Get length of string left */ if(*s == '0') /* If string starts with 0 */ { if(strlen > 1 && ((WORD) s[1] & 0137) == 'X') { /* If string starts with "0x" */ base = 16; /* Change base to hexadecimal */ ++s; /* Skip over "0" */ --strlen; /* Decrement length */ } else base = 8; /* Else change to octal */ ++s; /* Skip "0" (or "x") */ --strlen; /* Decrement length */ } while(strlen--) /* While not at end of string */ { ch = B2W(*s++); /* Get character */ if(ch >= '0' && ch <= '9') ch -= (WORD) '0'; /* Remove offset */ else if(ch >= 'A' && ch < 'A' + base - 10) ch -= (WORD) 'A' - 10; /* Remove offset */ else if(ch >= 'a' && ch < 'a' + base - 10) ch -= (WORD) 'a' - 10; /* Remove offset */ else /* Invalid character */ { SwitchErr = ER_swbadnum; return(-1); /* Error */ } if((*pResult *= base) < oldval) { SwitchErr = ER_swbadnum; return(-1); /* Error */ } *pResult += ch; oldval = *pResult; } return(1); /* Number is present */ } else return(0); /* No number present */ }
/*
* ParseStr : Parse switch string * * Return value: * 1 result stored in string * 0 no switch string given */
LOCAL int NEAR ParseStr(pResult) char *pResult; /* Length prefixed result */ { REGISTER char *s; /* String pointer */ WORD strlen; /* String length */
*pResult = '\0'; /* Initialize */ strlen = IFind(osbSwitch,':'); /* Look for a colon in the string */ if(strlen != INIL && strlen < (WORD) (B2W(osbSwitch[0]) - 1)) { /* If switch form valid */ s = &osbSwitch[strlen + 2]; /* Set pointer past colon */ strlen = B2W(osbSwitch[0]) - strlen - 1; /* Get length of string left */ *pResult++ = (char) strlen; /* Store length */
while(strlen--) /* While not at end of string */ { *pResult++ = (char) (*s++); /* Get character */ } return(1); /* String is present */ } else return(0); /* No stringr present */ }
#if PCODE
LOCAL void NEAR SwPCode(void) {
SBTYPE SwString;
fNewExe = (FTYPE) TRUE; fMPC = (FTYPE) TRUE;
if (ParseStr(SwString)) { if(SwString[1] == 'n' || SwString[1] == 'N') // /PCODE:NOMPC
{ fIgnoreMpcRun = (FTYPE) TRUE; fMPC = (FTYPE) FALSE; } } } #endif
/***************************************************************/ /* Options common to all versions regardless of output format */
LOCAL void NEAR SwCase() { fIgnoreCase = (FTYPE) ~IGNORECASE; /* Toggle default case sensitivity */ }
LOCAL void NEAR SwLineNos() /* Line numbers requested */ { vfLineNos = (FTYPE) TRUE; /* Set flag */ }
#if LOCALSYMS
LOCAL void NEAR SwLocals() /* Local symbols requested */ { fLocals = (FTYPE) TRUE; /* Set flag */ } #endif
#pragma check_stack(on)
LOCAL void NEAR SwMap() /* Link map requested */ { SBTYPE SwString; int rc;
vfMap = (FTYPE) TRUE; // Set flag
if ((rc = ParseStr(SwString)) <= 0) // Done if no num or error
return;
// The optional parameter following /MAP was originally intended
// to tell the linker how much to space to allocate for sorting
// more public symbols than the stack-based limit. Since we now
// dyamically allocate as much space as possible for sorting,
// the parameter is no longer necessary and its value is ignored.
// However, the side effect of suppressing the "sorted by name"
// list is retained.
if (SwString[1] == 'A' || SwString[1] == 'a') fListAddrOnly = (FTYPE) TRUE; // /MAP:ADDRESS
else if (SwString[1] == 'F' || SwString[1] == 'f') fFullMap = (FTYPE) TRUE; // /MAP:FULL or /MAP:full
}
LOCAL void NEAR SwNoDefLib() /* Do not search default library */ { SBTYPE SwString; SBTYPE LibName;
if (ParseStr(SwString)) { vfNoDefaultLibrarySearch = FALSE; /* Clear flag - selective library search */ strcpy(LibName, sbDotLib); UpdateFileParts(LibName, SwString); EnterName(LibName,ATTRSKIPLIB,TRUE); } else vfNoDefaultLibrarySearch = (FTYPE) TRUE; /* Set flag */ }
#pragma check_stack(off)
LOCAL void NEAR SwNologo() { // if fNoprompt is already set then either
// a) /BATCH was specified, in which case /NOLOGO is redundant
// b) BATCH was in _MSC_IDE_FLAGS in which case fNoEchoLrf has not been
// set, and we want to suppress echoing of the response file
// (see CAVIAR 2378 [rm])
if (fNoprompt) fNoEchoLrf = TRUE; /* Do not echo response file */
fNoBanner = TRUE; /* Do not display banner */ }
LOCAL void NEAR SwBatch() /* Do not prompt for files */ { fNoEchoLrf = (FTYPE) TRUE; /* Do not echo response file */ fNoprompt = (FTYPE) TRUE; /* Do not prompt */ fPauseRun = FALSE; /* Disable /PAUSE */ fNoBanner = (FTYPE) TRUE; /* Do not display banner */ }
#if ODOS3EXE
LOCAL void NEAR SwBinary() /* Produce .COM file */ { fBinary = (FTYPE) TRUE; SwNonulls(); /* No nulls */ fFarCallTrans = (FTYPE) TRUE; /* Far call translation */ packLim = LXIVK - 36; /* Default limit is 64K - 36 */ fPackSet = (FTYPE) TRUE; /* Remember packLim was set */ } #endif
#if SYMDEB
LOCAL void NEAR SwSymdeb() /* Symbolic debugging */ { SBTYPE SwString;
fSymdeb = (FTYPE) TRUE; if (ParseStr(SwString)) { fCVpack = (FTYPE) (SwString[1] == 'c' || SwString[1] == 'C'); } } #endif
#if PERFORMANCE
LOCAL void NEAR SwVMPerf() /* Report on VM performance */ { fPerformance = (FTYPE) TRUE; /* Set flag */ } #endif
#if OSMSDOS
LOCAL void NEAR SwPause() /* Pause before writing executable */ { fPauseRun = (FTYPE) TRUE; /* Set flag */ fNoprompt = FALSE; /* Disable /NOPROMPT */ } #endif
LOCAL void NEAR SwStack() /* Set stack segment size */ { unsigned long num; int rc;
if((rc = ParseNo(&num)) < 0) /* Quit if error */ return; #if EXE386
if(!rc || num > CBMAXSEG32 - 4L) #else
if(!rc || num > LXIVK - 2L) #endif
SwitchErr = ER_swstack; else #if EXE386
cbStack = num; #else
cbStack = (WORD) num; #endif
}
LOCAL void NEAR SwSegments() /* Set maximum number of segments */ { unsigned long nsegs; /* Number of segments */ int rc;
if((rc = ParseNo(&nsegs)) <= 0) /* Quit if error or no argument */ return; if(nsegs > (long) GSNMAX) SwitchErr = ER_swseglim; else { if ((nsegs + 3L) > GSNMAX) gsnMax = GSNMAX; else gsnMax = (SNTYPE) nsegs; /* Else set limit */ } }
#if EXE386
LOCAL void NEAR SwMemAlign(void)/* Set memory object alignment factor */ { long align; /* Alignment size in bytes */ int rc;
if ((rc = ParseNo(&align)) < 0) /* Quit if error */ return; if (rc && align >= 1) { /* If value in legal range */ for (objAlign = 32; objAlign != 0; --objAlign) { /* Loop to find log of align */ if ((1L << objAlign) & align) break; /* Break when high bit found */ } if ((1L << objAlign) == align) return; /* Align must be power of two */ } OutWarn(ER_alnbad); /* Output warning message */ objAlign = DFOBJALIGN; /* Use default value */ } #endif
#if NOT EXE386
LOCAL void NEAR SwNewFiles(void) { vFlagsOthers |= NENEWFILES; /* Set flag */ } #endif
#if FDEBUG
LOCAL void NEAR SwInfo() /* Turn on runtime debugging */ { fDebug = (FTYPE) TRUE; /* Set flag */ } #endif
#if LIBMSDOS
LOCAL void NEAR SwNoExtDic() /* Don't search extended dictionary */ { fNoExtDic = (FTYPE) TRUE; } #endif
/***************************************************************/ /* Options for segmented executable format. */
#if OSEGEXE
LOCAL void NEAR SwAlign() /* Set segment alignment factor */ { long align; /* Alignment size in byutes */ int rc;
if((rc = ParseNo(&align)) < 0) /* Quit if error */ return; if(rc && align >= 1 && align <= 32768L) { /* If value in legal range */ for(fileAlign = 16; fileAlign != 0; --fileAlign) { /* Loop to find log of align */ if((1L << fileAlign) & align) break; /* Break when high bit found */ } if((1L << fileAlign) == align) return; /* Align must be power of two */ } OutWarn(ER_alnbad); /* Output warning message */ fileAlign = DFSAALIGN; /* Use default value */ } #pragma check_stack(on)
#if OUT_EXP
LOCAL void NEAR SwIdef(void) /* Dump exports to a text file */ { SBTYPE SwString; int rc;
if ((rc = ParseStr(SwString)) <= 0) // Done if no string or error
{ bufExportsFileName[0] = '.'; // Use the default file name
return; } strcpy(bufExportsFileName, SwString); } #endif
#if NOT EXE386
LOCAL void NEAR SwPmType() /* /PMTYPE:<type> */ { SBTYPE SwString;
if (ParseStr(SwString)) { if (FPrefix("\002PM", SwString)) vFlags |= NEWINAPI; else if (FPrefix("\003VIO", SwString)) vFlags |= NEWINCOMPAT; else if (FPrefix("\005NOVIO", SwString)) vFlags |= NENOTWINCOMPAT; else OutWarn(ER_badpmtype, &osbSwitch[1]); } else OutWarn(ER_badpmtype, &osbSwitch[1]); } #endif
#pragma check_stack(off)
LOCAL void NEAR SwWarnFixup() { fWarnFixup = (FTYPE) TRUE; }
#if O68K
LOCAL void NEAR SwMac() /* Target is a Macintosh */ { SBTYPE SwString;
f68k = fTBigEndian = fNewExe = (FTYPE) TRUE; iMacType = (BYTE) (ParseStr(SwString) && FPrefix("\011SWAPPABLE", SwString) ? MAC_SWAP : MAC_NOSWAP);
/* If we are packing code to the default value, change the default. */ if (fPackSet && packLim == LXIVK - 36) packLim = LXIVK / 2; } #endif /* O68K */
#endif /* OSEGEXE */
/***************************************************************/ /* Options shared by DOS3 and segmented exe formats. */
#if OEXE
/*
* HACK ALERT !!!!!!!!!!!!!!! * Function SetDosseg is used to hide local call to SwDosseg(). * This function is called from ComRc1 (in NEWTP1.C). * */ void SetDosseg(void) { SwDosseg(); }
LOCAL void NEAR SwDosseg() /* DOS Segment ordering switch given */ { static FTYPE FirstTimeCalled = (FTYPE) TRUE; /* If true create symbols _edata */ /* and _end */
fSegOrder = (FTYPE) TRUE; /* Set switch */ if (FirstTimeCalled && vfPass1) { MkPubSym((BYTE *) "\006_edata",0,0,(RATYPE)0); MkPubSym((BYTE *) "\007__edata",0,0,(RATYPE)0); MkPubSym((BYTE *) "\004_end",0,0,(RATYPE)0); MkPubSym((BYTE *) "\005__end",0,0,(RATYPE)0); FirstTimeCalled = FALSE; #if ODOS3EXE
if (cparMaxAlloc == 0) cparMaxAlloc = 0xFFFF; /* Turn off /HIGH */ vfDSAlloc = FALSE; /* Turn off DS Allocation */ #endif
} }
#if ODOS3EXE
LOCAL void NEAR SwDosExtend(void) { long mode; // Extender mode
int rc;
if ((rc = ParseNo(&mode)) < 0) // Quit if error
return;
if (rc) dosExtMode = (WORD) mode; fDOSExtended = (FTYPE) TRUE; } #endif
#if TIMINGS
LOCAL void NEAR SwShowTiming(void) { extern int fShowTiming;
fShowTiming = TRUE; } #endif // TIMINGS
#if USE_REAL
LOCAL void NEAR SwNoUseReal(void) { fSwNoUseReal = TRUE; } #endif
#if FEXEPACK
LOCAL void NEAR SwExePack() /* Set exepack switch */ { #if QBLIB
/* If /QUICKLIB given, issue fatal error. */ if(fQlib) Fatal(ER_swqe); #endif
#if ODOS3EXE
if (cparMaxAlloc == 0) OutWarn(ER_loadhi); else #endif
fExePack = (FTYPE) TRUE; } #endif
LOCAL void NEAR SwNonulls () { extern FTYPE fNoNulls;
/*
* /NONULLSDOSSEG: just like /DOSSEG except do not insert * 16 null bytes in _TEXT. */ SwDosseg(); fNoNulls = (FTYPE) TRUE; }
LOCAL void NEAR SwNoFarCall() /* Disable far call optimization */ { fFarCallTrans = FALSE; }
void NEAR SwNoPack() /* Disable code packing */ { fPackSet = (FTYPE) TRUE; /* Remember packLim was set */ packLim = 0L; }
LOCAL void NEAR SwPack() /* Pack code segments */ { int rc;
fPackSet = (FTYPE) TRUE; /* Remember packLim was set */ if((rc = ParseNo(&packLim)) < 0) /* Quit if error */ return; if(!rc) #if EXE386
packLim = CBMAXSEG32; /* Default limit is 4Gb */ #else
#if O68K
packLim = iMacType != MAC_NONE ? LXIVK / 2 : LXIVK - 36; /* Default limit is 32K or 64K - 36 */ #else
packLim = LXIVK - 36; /* Default limit is 64K - 36 */ #endif
else if(packLim > LXIVK) /* If limit set too high */ SwitchErr = ER_swpack; else if(packLim > LXIVK - 36) OutWarn(ER_pckval); #endif
}
LOCAL void NEAR SwPackData() /* Pack data segments */ { int rc;
fPackData = (FTYPE) TRUE; if((rc = ParseNo(&DataPackLim)) < 0)/* Quit if error */ return; if(!rc) #if EXE386
DataPackLim = CBMAXSEG32; /* Default limit is 4Gb */ #else
DataPackLim = LXIVK; /* Default limit is 64K */ else if(DataPackLim > LXIVK) /* If limit set too high */ SwitchErr = ER_swpack; #endif
}
LOCAL void NEAR SwNoPackFunctions()// DO NOT eliminate uncalled COMDATs
{ fPackFunctions = (FTYPE) FALSE; }
LOCAL void NEAR SwPackFunctions()// DO eliminate uncalled COMDATs
{ #if TCE
SBTYPE SwString; int rc; #endif
fPackFunctions = (FTYPE) TRUE; #if TCE
if ((rc = ParseStr(SwString)) <= 0) // Done if no num or error
return; if (SwString[1] == 'M' || SwString[1] == 'm') { fTCE = (FTYPE) TRUE; // /PACKF:MAX = perform TCE
fprintf(stdout, "\r\nTCE is active. "); } #endif
}
LOCAL void NEAR SwFarCall() /* Enable far call optimization */ { fFarCallTrans = (FTYPE) TRUE; } #endif /* OEXE */
#if DOSEXTENDER
LOCAL void NEAR SwRunReal(void) { OutWarn(ER_rnotfirst); } #endif
/***************************************************************/ /* Options for DOS3 exe format. */
#if ODOS3EXE
LOCAL void NEAR SwDSAlloc() /* DS allocation requested */ { if(!fSegOrder) vfDSAlloc = (FTYPE) TRUE; /* Set flag if not overridden */ }
#if OVERLAYS
LOCAL void NEAR SwDynamic(void) { unsigned long cThunks; int rc;
if ((rc = ParseNo(&cThunks)) < 0) return; /* Bad argument */ fDynamic = (FTYPE) TRUE; fFarCallTrans = (FTYPE) TRUE; fPackSet = (FTYPE) TRUE; packLim = LXIVK - 36; /* Default limit is 64K - 36 */ if (!rc) cThunks = 256; else if (cThunks > LXIVK / OVLTHUNKSIZE) { char buf[17]; cThunks = LXIVK / OVLTHUNKSIZE; OutWarn(ER_arginvalid, "DYNAMIC", _itoa((WORD)cThunks, buf, 10));
}
ovlThunkMax = (WORD) cThunks; }
LOCAL void NEAR SwOldOvl(void) { fOldOverlay = (FTYPE) TRUE; fDynamic = (FTYPE) FALSE; }
#endif
LOCAL void NEAR SwHigh() /* Load high */ { if(!fSegOrder) { #if FEXEPACK
if (fExePack == (FTYPE) TRUE) { OutWarn(ER_loadhi); fExePack = FALSE; } #endif
cparMaxAlloc = 0; /* Dirty trick! */ } }
#if OVERLAYS
LOCAL void NEAR SwIntNo() { unsigned long intno; int rc;
if((rc = ParseNo(&intno)) < 0) /* Quit if error */ return; if(rc == 0 || intno > 255) /* If no number or num exceeds 255 */ SwitchErr = ER_swovl; else vintno = (BYTE) intno; /* Else store interrupt number */ } #endif
LOCAL void NEAR SwCParMax() { unsigned long cparmax; int rc;
if((rc = ParseNo(&cparmax)) < 0) /* Quit if error */ return; if(rc == 0 || cparmax > 0xffffL) /* If no number or num exceeds ffff */ SwitchErr = ER_swcpar; else cparMaxAlloc = (WORD) cparmax; /* Else store cparMaxAlloc */ }
LOCAL void NEAR SwNoGrp() { fNoGrpAssoc = (FTYPE) TRUE; /* Don't associate publics w/ groups */ } #endif /* ODOS3EXE */
/***************************************************************/ /* Options for ILINK-version */
#if ILINK
LOCAL void NEAR SwIncremental() /* Incremental linking support */ { //fIncremental = (FTYPE) !fZincr;
fIncremental = (FTYPE) FALSE; //INCR support dropped in 5.30.30
} #endif
LOCAL void NEAR SwPadCode() /* Code padding */ { long num; int rc;
if((rc = ParseNo(&num)) < 0) return; /* PADCODE:xxx option specifies code padding size */ if(rc) { if(num < 0 || num > 0x8000) SwitchErr = ER_swbadnum; else cbPadCode = (WORD) num; } }
LOCAL void NEAR SwPadData() /* Data padding */ { long num; int rc;
if((rc = ParseNo(&num)) < 0) return; /* PADDATA:xxx option specifies data padding size */ if(rc) { if(num < 0 || num > 0x8000) SwitchErr = ER_swbadnum; else cbPadData = (WORD) num; } }
/***************************************************************/ /* Switches for segmented x.out format */
#if OIAPX286
LOCAL void NEAR SwAbsolute () { if(!cbStack) ParseNo(&absAddr); }
LOCAL void NEAR SwNoPack() /* Disable code packing */ { fPack = FALSE; }
LOCAL void NEAR SwTextbias () { long num;
if(ParseNo(&num) > 0) stBias = num; }
LOCAL void NEAR SwDatabias () { long num;
if(ParseNo(&num) > 0) stDataBias = num; }
LOCAL void NEAR SwPagesize () { long num;
if(ParseNo(&num) > 0) cblkPage = num >> 9; }
LOCAL void NEAR SwTextrbase () { long num;
if(ParseNo(&num) > 0) rbaseText = num; }
LOCAL void NEAR SwDatarbase () { long num;
if(ParseNo(&num) > 0) rbaseData = num; }
LOCAL void NEAR SwVmod () { long num;
if(ParseNo(&num) <= 0) return; switch(num) { case 0: xevmod = XE_VMOD; break; case 1: xevmod = XE_EXEC | XE_VMOD; break; default: SwitchErr = ER_swbadnum; } } #endif /* OIAPX286 */
#if OXOUT OR OIAPX286
LOCAL void NEAR SwNosymbols () { fSymbol = FALSE; }
LOCAL void NEAR SwMixed () { fMixed = (FTYPE) TRUE; }
LOCAL void NEAR SwLarge () { fLarge = (FTYPE) TRUE; SwMedium(); }
LOCAL void NEAR SwMedium() { fMedium = (FTYPE) TRUE; /* Medium model */ fIandD = (FTYPE) TRUE; /* Separate code and data */ }
LOCAL void NEAR SwPure() { fIandD = (FTYPE) TRUE; /* Separate code and data */ } #endif /* OXOUT OR OIAPX286 */
/* Options for linker profiling */ #if LNKPROF
char fP1stop = FALSE; /* Stop after pass 1 */ LOCAL void NEAR SwPass1() { fP1stop = (FTYPE) TRUE; } #endif /* LNKPROF */
/* Special options */ #if QBLIB
LOCAL void NEAR SwQuicklib() /* Create a QB userlibrary */ { #if FEXEPACK
/* If /EXEPACK given, issue fatal error. */ if(fExePack) Fatal(ER_swqe); #endif
fQlib = (FTYPE) TRUE; SwDosseg(); /* /QUICKLIB forces /DOSSEG */ fNoExtDic = (FTYPE) TRUE; /* /QUICKLIB forces /NOEXTDICTIONARY */ } #endif
#if (QCLINK) AND NOT EXE386
typedef int (cdecl far * FARFPTYPE)(int, ...);/* Far function pointer type */ extern FARFPTYPE far *pfQTab; /* Table of addresses */
#pragma check_stack(on)
/*
* PromptQC : output a prompt to the QC prompt routine * * Call pfQTab[1] with parameters described below. * Returns: * always TRUE * * QCPrompt : display a message with a prompt * * void far QCPrompt (type, msg1, msg2, msg3, pResponse) * short type; /* type of message, as follows:
* 0 = undefined * 1 = edit field required (e.g. file name) * 2 = wait for some action * all other values undefined * Any of the following fields may be NULL: * char far *msg1; /* 1st message (error)
* char far *msg2; /* 2nd message (file name)
* char far *msg3; /* 3rd message (prompt text)
* char far *pResponse; /* Pointer to buffer in which to
* * store response. */ int cdecl PromptQC (sbNew,msg,msgparm,pmt,pmtparm) BYTE *sbNew; /* Buffer for response */ MSGTYPE msg; /* Error message */ int msgparm; /* Message parameter */ MSGTYPE pmt; /* Prompt */ int pmtparm; /* Prompt parameter */ { int type; SBTYPE message; SBTYPE prompt;
if(sbNew != NULL) type = 1; else type = 2; sprintf(message,GetMsg(msg),msgparm); sprintf(prompt,GetMsg(pmt),pmtparm); /* Return value of 1 means interrupt. */ if((*pfQTab[1])(type,(char far *) message,0L,(char far *)prompt, (char far *) sbNew) == 1) UserKill(); return(TRUE); }
#pragma check_stack(off)
/*
* CputcQC : console character output routine for QC */ void CputcQC (ch) int ch; { }
/*
* CputsQC : console string output routine for QC */ void CputsQC (str) char *str; { }
/*
* SwZ1 : process /Z1:address * * /Z1 is a special undocumented switch for QC. It contains * the address of a table of routines to use for console I/O. */
LOCAL void NEAR SwZ1 (void) /* Get address for message I/O */ { long num; extern FARFPTYPE far *pfQTab; /* Table of addresses */
if(ParseNo(&num) <= 0) return; pfQTab = (FARFPTYPE far *) num; pfPrompt = PromptQC; fNoprompt = FALSE; /* Disable /NOPROMPT */ fNoBanner = (FTYPE) TRUE; pfCputc = CputcQC; pfCputs = CputsQC; fZ1 = (FTYPE) TRUE; } /*
* /Zincr is a special undocumented switch for QC. It is required * for "ILINK-breaking" errors. If ILINK encounters one of these errors, * it ivokes the linker w /ZINCR which override /INCR. */
LOCAL void NEAR SwZincr(void) { fZincr = (FTYPE) TRUE; } #endif
#if Z2_ON OR (QCLINK AND NOT EXE386)
/*
* SwZ2 : process /Z2 * * /Z2 is another special undocumented switch for QC. * It causes deletion of responce file passed to the linker. */
LOCAL void NEAR SwZ2 (void) { fZ2 = (FTYPE) TRUE; }
#endif
/* Structure for table of linker options */ struct option { char *sbSwitch; /* length-prefixed switch string */ #ifdef M68000
int (*proc)(); /* pointer to switch function */ #else
void (NEAR *proc)(); /* pointer to switch function */ #endif
};
/* Table of linker options */ LOCAL struct option switchTab[] = { #if NOT WIN_3
{ "\01?", SwShortHelp }, #endif
#if OIAPX286
{ "\017ABSOLUTEADDRESS", SwAbsolute }, #endif
#if OSEGEXE AND NOT QCLINK
{ "\011ALIGNMENT", SwAlign }, #endif
{ "\005BATCH", SwBatch }, #if LNKPROF
{ "\007BUFSIZE", SwBufsize }, #endif
#if SYMDEB
{ "\010CODEVIEW", SwSymdeb }, #endif
#if ODOS3EXE
{ "\014CPARMAXALLOC", SwCParMax }, #endif
#if OIAPX286
{ "\010DATABIAS", SwDatabias }, { "\011DATARBASE", SwDatarbase }, #endif
#if ODOS3EXE
{ "\013DOSEXTENDER", SwDosExtend }, #endif
#if OEXE
{ "\006DOSSEG", SwDosseg }, #endif
#if ODOS3EXE
{ "\012DSALLOCATE", SwDSAlloc }, #if OVERLAYS
{ "\007DYNAMIC", SwDynamic }, #endif
#endif
#if FEXEPACK
{ "\007EXEPACK", SwExePack }, #endif
#if OEXE
{ "\022FARCALLTRANSLATION", SwFarCall }, #endif
#if EXE386
{ "\006HEADER", SwHeader }, #endif
#if NOT WIN_3
{ "\004HELP", #if C8_IDE
SwShortHelp }, #else
SwHelp }, #endif
#endif
#if ODOS3EXE
{ "\004HIGH", SwHigh }, #endif
#if NOT IGNORECASE
{ "\012IGNORECASE", SwCase }, #endif
#if EXE386
{ "\016IMAGEALIGNMENT", SwMemAlign }, #endif
#if ILINK AND NOT IBM_LINK
{ "\013INCREMENTAL", SwIncremental }, #endif
#if FDEBUG
{ "\013INFORMATION", SwInfo }, #endif
#if OSEGEXE AND OUT_EXP
{ "\004IDEF", SwIdef }, #endif
#if (OSEGEXE AND defined(LEGO)) OR EXE386
{ "\012KEEPFIXUPS", SwKeepFixups }, #endif
#if EXE386
{ "\012KEEPVSIZE", SwKeepVSize }, #endif
#if OIAPX286
{ "\005LARGE", SwLarge }, #endif
{ "\013LINENUMBERS", SwLineNos }, #if LOCALSYMS
{ "\014LOCALSYMBOLS", SwLocals }, #endif
#if O68K
{ "\011MACINTOSH", SwMac }, #endif /* O68K */
{ "\003MAP", SwMap }, #if OXOUT OR OIAPX286
{ "\006MEDIUM", SwMedium }, { "\005MIXED", SwMixed }, #endif
#if NOT EXE386
{ "\010KNOWEAS", SwNewFiles }, #endif
{ "\026NODEFAULTLIBRARYSEARCH", SwNoDefLib }, #if LIBMSDOS
{ "\017NOEXTDICTIONARY", SwNoExtDic }, #endif
#if OEXE
{ "\024NOFARCALLTRANSLATION", SwNoFarCall }, #endif
#if ODOS3EXE
{ "\022NOGROUPASSOCIATION", SwNoGrp }, #endif
#if IGNORECASE
{ "\014NOIGNORECASE", SwCase }, #endif
#if TIMINGS
{ "\002BT", SwShowTiming }, #endif // TIMINGS
{ "\006NOLOGO", SwNologo }, { "\015NONULLSDOSSEG", SwNonulls }, { "\012NOPACKCODE", SwNoPack }, { "\017NOPACKFUNCTIONS", SwNoPackFunctions }, #if OXOUT OR OIAPX286
{ "\011NOSYMBOLS", SwNosymbols }, #endif
#if USE_REAL
{ "\011NOFREEMEM", SwNoUseReal }, #endif
#if OVERLAYS
{ "\012OLDOVERLAY", SwOldOvl }, #endif
{ "\007ONERROR", SwDelexe }, #if OVERLAYS
{ "\020OVERLAYINTERRUPT", SwIntNo }, #endif
{ "\010PACKCODE", SwPack }, { "\010PACKDATA", SwPackData }, { "\015PACKFUNCTIONS", SwPackFunctions }, #if ILINK AND NOT IBM_LINK
{ "\007PADCODE", SwPadCode }, { "\007PADDATA", SwPadData }, #endif
#if OIAPX286
{ "\010PAGESIZE", SwPagesize }, #endif
#if OSMSDOS
{ "\005PAUSE", SwPause }, #endif
#if LNKPROF
{ "\005PASS1", SwPass1 }, #endif
#if PCODE
{ "\005PCODE", SwPCode }, #endif
#if OSEGEXE AND NOT (QCLINK OR EXE386)
{ "\006PMTYPE", SwPmType }, #endif
#if OXOUT OR OIAPX286
{ "\004PURE", SwPure }, #endif
#if QBLIB
{ "\014QUICKLIBRARY", SwQuicklib }, #endif
#if DOSEXTENDER AND NOT WIN_NT
{ "\001r", SwRunReal }, #endif
{ "\010SEGMENTS", SwSegments }, { "\005STACK", SwStack }, #if OIAPX286
{ "010TEXTBIAS", SwTextbias }, { "\011TEXTRBASE", SwTextrbase }, #endif
#if ODOS3EXE
{ "\004TINY", SwBinary }, #endif
#if PERFORMANCE
{ "\030VIRTUALMEMORYPERFORMANCE", SwVMPerf }, #endif
#if OIAPX286
{ "\004VMOD", SwVmod }, #endif
#if OSEGEXE AND NOT QCLINK
{ "\011WARNFIXUP", SwWarnFixup }, #endif
#if OSEGEXE AND NOT EXE386 AND QCLINK
{ "\002Z1", SwZ1 }, #endif
#if Z2_ON OR QCLINK
{ "\002Z2", SwZ2 }, #endif
#if QCLINK
{ "\005ZINCR", SwZincr }, #endif
{ NULL, 0} };
#if QCLINK
#define SWSTOP &switchTab[(sizeof(switchTab)/sizeof(struct option)) - 5]
#else
#if EXE386
#define SWSTOP &switchTab[(sizeof(switchTab)/sizeof(struct option)) - 2]
#else
#define SWSTOP &switchTab[(sizeof(switchTab)/sizeof(struct option)) - 2]
#endif
#endif
#define FIELDLENGTH 28
#if NOT WIN_3
LOCAL void NEAR SwShortHelp() /* Print valid switches */ { struct option *pTab; /* Option table pointer */ int toggle = 1; int n;
#if CMDMSDOS
/* Maybe display banner here, in case /NOLOGO seen first. */
DisplayBanner(); #endif
fputs(GetMsg(P_usage1),stdout); fputs(GetMsg(P_usage2),stdout); fputs(GetMsg(P_usage3),stdout); fputs(GetMsg(P_switches),stdout); NEWLINE(stdout); for(pTab = switchTab; pTab < SWSTOP; ++pTab) { // Don't display undocumented swiches
if (pTab->proc == &SwNewFiles) { continue; } if (pTab->proc == &SwDosExtend) { continue; } #ifdef LEGO
#if OSEGEXE
if (pTab->proc == &SwKeepFixups) continue; #endif
#endif /* LEGO */
fputs(" /",stdout); fwrite(&pTab->sbSwitch[1],1,B2W(pTab->sbSwitch[0]),stdout); /* Output switches in two columns */ if(toggle ^= 1) NEWLINE(stdout); else for(n = FIELDLENGTH - B2W(pTab->sbSwitch[0]); n > 0; --n) fputc(' ',stdout); } NEWLINE(stdout); fflush(stdout); #if USE_REAL
RealMemExit(); #endif
exit(0); } #endif
LOCAL void NEAR SwDelexe() // Supress .EXE generation if errors occur
{ SBTYPE SwString; int rc;
vfMap = (FTYPE) TRUE; // Set flag
if ((rc = ParseStr(SwString)) == 0) // NOEXE not present
{ OutWarn(ER_opnoarg, "ONERROR"); return; }
if (SwString[1] == 'N' || SwString[1] == 'n') { fDelexe = TRUE; // ONERROR:NOEXE
} else { // ONERROR:????
OutWarn(ER_opnoarg, "ONERROR"); return; } }
#if (OSEGEXE AND defined(LEGO)) OR EXE386
LOCAL void NEAR SwKeepFixups(void) { fKeepFixups = (FTYPE) TRUE; }
#endif
#if EXE386
LOCAL void NEAR SwHeader() // Set executable header size
{ int rc; DWORD newSize;
if ((rc = ParseNo(&newSize)) < 0) // Quit if error
return; if (rc) hdrSize = ((newSize << 10) + 0xffffL) & ~0xffffL; }
LOCAL void NEAR SwKeepVSize(void) { fKeepVSize = (FTYPE) TRUE; }
#endif
#if NOT WIN_3
LOCAL void NEAR SwHelp() /* Print valid switches */ { intptr_t exitCode; char *pszPath; char *pszQH; char *pszHELPFILES; char FAR *lpch; char *pch; int len;
// Try to use QuickHelp - this is tricky; We have stubbed the
// C run-time environment setup, so spawnlp has no way of
// searching the path. Here we first add the path to C run-time
// environemt table and then invoke spawnlp.
if (lpszPath) { // Recreate C run-time PATH variable
len = FSTRLEN(lpszPath); if ((pszPath = calloc(len + 6, sizeof(char))) != NULL) { strcpy(pszPath, "PATH="); for (lpch = lpszPath, pch = pszPath + 5; len > 0; len--) *pch++ = *lpch++; _putenv(pszPath); } } if (lpszQH) { // Recreate C run-time QH variable
len = FSTRLEN(lpszQH); if ((pszQH = calloc(len + 4, sizeof(char))) != NULL) { strcpy(pszQH, "QH="); for (lpch = lpszQH, pch = pszQH + 3; len > 0; len--) *pch++ = *lpch++; _putenv(pszQH); } } if (lpszHELPFILES) { // Recreate C run-time HELPFILES variable
len = FSTRLEN(lpszHELPFILES); if ((pszHELPFILES = calloc(len + 12, sizeof(char))) != NULL) { strcpy(pszHELPFILES, "HELPFILES="); for (lpch = lpszHELPFILES, pch = pszHELPFILES + 10; len > 0; len--) *pch++ = *lpch++; _putenv(pszHELPFILES); } } #if USE_REAL
RealMemExit(); #endif
exitCode = _spawnlp(P_WAIT, "QH.EXE", "qh", "/u link.exe", NULL); if (exitCode < 0 || exitCode == 3) SwShortHelp(); exit(0); } #endif
/****************************************************************
* * * BadFlag: * * * * This function takes as its argument a pointer to a length- * * prefixed string containing an invalid switch. It goes * * through the customary contortions of dying with grace. * * * ****************************************************************/
LOCAL void NEAR BadFlag(psb,errnum) BYTE *psb; /* Pointer to the bad switch */ MSGTYPE errnum; /* Error number */ { psb[B2W(psb[0]) + 1] = '\0'; /* Null-terminate it */ Fatal(errnum,psb + 1); }
/****************************************************************
* * * FPrefix: * * * * This function takes as its arguments two pointers to * * length-prefixed strings. It returns true if the second is * * a prefix of the first. * * * ****************************************************************/
LOCAL int NEAR FPrefix(psb1,psb2) BYTE *psb1; /* Pointer to first string */ BYTE *psb2; /* Pointer to second string */ { REGISTER WORD len; /* Length of string 2 */
if((len = B2W(psb2[0])) > B2W(psb1[0])) return(FALSE); /* String 2 cannot be longer */ while(len) /* Compare the strings */ { if(UPPER(psb2[len]) != UPPER(psb1[len])) return(FALSE); /* Check for mismatch */ --len; /* Decrement index */ } return(TRUE); /* 2 is a prefix of 1 */ }
/****************************************************************
* * * ProcFlag: * * * * This function takes as its argument a length-prefixed * * string containing a single '/-type' flag. It processes it, * * but does not return a meaningful value. * * * ****************************************************************/
void ProcFlag(psb) /* Process a flag */ BYTE *psb; /* Pointer to flag string */ { struct option *pTab; /* Pointer to option table */ struct option *pTabMatch; /* Pointer to matching entry */ WORD ich3; /* Index */ WORD ich4; /* Index */
pTabMatch = NULL; /* Not found */ if((ich3 = IFind(psb,':')) == INIL) ich3 = B2W(psb[0]); /* Get index to colon */ ich4 = B2W(psb[0]); /* Save the original length */ psb[0] = (BYTE) ich3; /* Set new length */ for(pTab = switchTab; pTab->sbSwitch; pTab++) { /* Loop thru switch table */ if(FPrefix(pTab->sbSwitch,psb)) { /* If we've identified the switch */ if(pTabMatch) /* If there was a previous match */ BadFlag(psb,ER_swambig);/* Ambiguous switch */ pTabMatch = pTab; /* Save the match */ } } if(!pTabMatch) /* If no match found */ { psb[psb[0]+1] = '\0'; OutWarn(ER_swunrecw,&psb[1]); /* Unrecognized switch */ return; } psb[0] = (BYTE) ich4; /* Restore original length */ osbSwitch = psb; /* Pass the switch implicitly */ SwitchErr = 0; /* Assume no error */ (*pTabMatch->proc)(); /* Invoke the processing procedure */ if(SwitchErr) BadFlag(psb,SwitchErr); /* Check for errors */ }
#pragma check_stack(on)
/****************************************************************
* * * PeelFlags: * * * * This function takes as its argument a pointer to a length- * * prefixed string of bytes. It "peels/processes all '/-type' * * switches." It does not return a meaningful value. * * * ****************************************************************/
void PeelFlags(psb) /* Peel/process flags */ BYTE *psb; /* Pointer to a byte string */ { REGISTER WORD ich; /* Index */ SBTYPE sbFlags; /* The flags */
if((ich = IFind(psb,CHSWITCH)) != INIL) { /* If a switch found */ memcpy(&sbFlags[1],&psb[ich + 2],B2W(psb[0]) - ich - 1); /* Move flags to flag buffer */ sbFlags[0] = (BYTE) ((psb[0]) - ich - 1); /* Set the length of flags */ while(psb[ich] == ' ' && ich) --ich; /* Delete trailing spaces */ psb[0] = (BYTE) ich; /* Reset length of input line */ ich = sbFlags[0]; while((sbFlags[ich] == ' ' || sbFlags[ich] == ';' || sbFlags[ich] == ',' ) && ich) --ich; /* Delete unwanted characters */ sbFlags[0] = (BYTE) ich; BreakLine(sbFlags,ProcFlag,CHSWITCH); /* Process the switch */ } }
#pragma check_stack(off)
|