Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

666 lines
16 KiB

/*** INLINE.C - contains routines used to handle processing of in-line files **
*
* Copyright (c) 1989-1990, Microsoft Corporation. All rights reserved.
*
* Purpose:
* This module contains the in-line file handling routines of NMAKE.
*
* Revision History:
* 15-Nov-1993 JdR Major speed improvements
* 15-Oct-1993 HV Use tchar.h instead of mbstring.h directly, change STR*() to _ftcs*()
* 01-Jun-1993 HV Use UngetTxtChr() instead of ungetc()
* 10-May-1993 HV Add include file mbstring.h
* Change the str* functions to STR*
* 02-Feb-1990 SB change fopen() to FILEOPEN()
* 03-Jan-1990 SB removed unitiallized variable
* 04-Dec-1989 SB Removed to unreferenced variables in makeInlineFiles()
* 01-Dec-1989 SB Changed realloc() to REALLOC()
* 22-Nov-1989 SB Changed free() to FREE()
* 07-Nov-1989 SB Length of action word not evaluated correct for multiple
* inline files for the same command
* 06-Nov-1989 SB allow macros in action word for inline files
* 24-Sep-1989 SB added processInline(), createInline()
* 20-Sep-1989 SB Created from routines previously scattered in the sources.
*
* Notes:
* 1> This file contains '#ifdef NOESC' to segregate text which uses ESCH, the
* NMAKE escape character.
* 2> Sections with 'NOTE:' inside comments marks important/incomplete items.
*
*******************************************************************************/
// NOTE: Function headers yet to be completed; other comments are incomplete
/* Include Files */
#include "nmake.h"
#include "nmmsg.h"
#include "proto.h"
#include "globals.h"
#include "grammar.h"
/* L O C A L Function Prototypes */
LOCAL void NEAR processEschIn(char *);
// NOTE: This may go soon (use nextInlineFile ?)
LOCAL void NEAR parseInlineFileList(char *);
// NOTE: The next one has to go soon
LOCAL void NEAR appendScript(SCRIPTLIST**,SCRIPTLIST*);
LOCAL void NEAR delInlineSymbol(char*);
LOCAL char * NEAR nextInlineFile(char **);
#ifdef DEAD_CODE
LOCAL BOOL NEAR duplicateInline(char *);
#endif
// NOTE: Probably needs a new name
LOCAL void NEAR replaceLtLt(char **, char *);
LOCAL void NEAR createInline(FILE *, char **);
LOCAL char * NEAR getLine(char *, int);
/* E X T E R N Function Prototypes */
// NOTE: delScriptFiles() from nmake.c not yet brought in here
extern FILE * NEAR createDosTmp(char *);
/* G L O B A L Function Prototypes */
char * NEAR makeInlineFiles(char *, char **, char **);
BOOL NEAR processInline(char *, char **, STRINGLIST **);
/*** makeInlineFiles - creates memory images for in-line files *****************
*
* Scope:
* Global.
*
* Purpose:
* This is the function that handles dynamic in-line files
*
* Input:
* s - Input command line string after first << (pts to char Buffer)
*
* Output:
* Returns ...
*
* Errors/Warnings:
* SYNTAX_UNEXPECTED_TOKEN - The makefile cannot end without the in-line file
* ending.
* CANT_READ_FILE - When the makefile is unreadable.
* SYNTAX_KEEP_INLINE_FILE - An inline file should end
* OUT_OF_MEMORY - On failing to extend in-memory in-line file.
*
* Assumes:
* Modifies Globals:
* Uses Globals:
* file - global stream
* line - lexer's line count
*
* Notes:
* Usage notes and other important notes
*
*******************************************************************************/
char * NEAR
makeInlineFiles(s, begin, end)
char *s;
char **begin;
char **end;
{
char rgchBuf[MAXBUF];
char *t;
unsigned size;
BOOL fPastCmd = FALSE; // If seen line past Cmd line
//used when rgchBuf is insuff for in-memory-inline file
char *szTmpBuf = NULL;
_ftcscpy(rgchBuf, "<<"); // to help parseInlineFileList
if (!getLine(rgchBuf+2,MAXBUF - 2)) {
if (feof(file))
makeError(line, SYNTAX_UNEXPECTED_TOKEN, "EOF");
makeError(line, CANT_READ_FILE);
}
parseInlineFileList(rgchBuf);
for (;scriptFileList;scriptFileList = scriptFileList->next)
for (;;) {
for (t = rgchBuf;;) {
*s++ = *t++;
if (s == *end) {
if (!szTmpBuf) { /* Increase size of s */
szTmpBuf = allocate(MAXBUF<<1);
_ftcsncpy(szTmpBuf,*begin,MAXBUF);
s = szTmpBuf + MAXBUF;
size = MAXBUF << 1;
*end = szTmpBuf + size;
}
else {
if ((size + MAXBUF < size) /* overflow error */
|| !(szTmpBuf = REALLOC(szTmpBuf,size+MAXBUF)))
makeError(line, MACRO_TOO_LONG);
s = szTmpBuf + size;
size += MAXBUF;
*end = szTmpBuf + size;
}
*begin = szTmpBuf;
}
if (!*t)
break;
}
if (fPastCmd && rgchBuf[0] == '<' && rgchBuf[1] == '<') {
//We don't care about action specified here; could be a macro
if (scriptFileList->next) {
if (!getLine(rgchBuf, MAXBUF)) {
#ifdef INLINE
if (!fgets(rgchBuf,MAXBUF)) {
#endif
if (feof(file))
makeError(line,SYNTAX_UNEXPECTED_TOKEN,"EOF");
makeError(line,CANT_READ_FILE);
}
}
break;
}
fPastCmd = TRUE;
if (!getLine(rgchBuf,MAXBUF)) {
#ifdef INLINE
if (!fgets(rgchBuf,MAXBUF,file)) {
#endif
if (feof(file))
makeError(line,SYNTAX_UNEXPECTED_TOKEN,"EOF");
makeError(line,CANT_READ_FILE);
}
}
*s = '\0';
return(s);
}
/*** processEschIn - Handles Esch characters in Script File lines **************
*
* Scope:
* Global.
*
* Purpose:
* Inline file lines are handled for escape characters. If a line contains an
* escaped newline then append the next line to it.
*
* Input:
* buf - the command line to be processed for ESCH characters
*
* Output:
*
* Errors/Warnings:
* SYNTAX_UNEXPECTED_TOKEN - The makefile cannot end without the in-line file
* ending.
* CANT_READ_FILE - When the makefile is unreadable.
*
* Assumes:
* If the newline is escaped the newline is last char in 'pGlobalbuf'. Safe
* to do so because we got 'pGlobalBuf' via fgets(). ????
*
* Modifies Globals:
* line - if newline was Escaped update line
* file - the makefile being processed
* buf - gets next line appended if newline was Escaped (indirectly)
*
* Uses Globals:
* buf - Indirectly
*
* Notes:
*
*******************************************************************************/
#ifndef NOESCH
LOCAL void NEAR
processEschIn(pGlobalBuf)
char *pGlobalBuf;
{
char *p, *q;
p = pGlobalBuf;
while (p = _ftcschr(p, '\n')) {
if (p[-1] == ESCH) {
++p;
if (!(q = fgets(p, MAXBUF - (p - pGlobalBuf), file))) {
if (feof(file))
makeError(line, SYNTAX_UNEXPECTED_TOKEN, "EOF");
makeError(line, CANT_READ_FILE);
}
line++;
}
else break;
}
}
#endif
/*** parseInlineFileList - Parses file list and makes list of Inline files *****
*
* Scope:
* Global.
*
* Purpose:
* To handle multiple inline files, the names of the files are to be stored
* in a list. This function creates the list by parsing the command file
*
* Input:
* buf - the line to be parsed
*
* Output:
*
* Errors/Warnings:
*
* Assumes:
*
* Modifies Globals:
* scriptFileList -- the list of script files.
*
* Uses Globals:
*
* Notes:
*
**********************************************************************/
void NEAR
parseInlineFileList(buf)
char *buf;
{
SCRIPTLIST *new;
char *token;
processEschIn(buf);
token = nextInlineFile(&buf); //next inline file
for (;;) {
if (!token) break;
new = makeNewScriptListElement();
new->sFile = makeString(token);
appendScript(&scriptFileList, new);
token = nextInlineFile(&buf); //next inline file
}
}
/*** appendScript -- appends an element to the tail of a scriptlist ****
*
* Purpose:
* Traverse to the end of the list and append element there.
*
* Input:
* list -- the list to append to
* element -- the element inserted
*
* Modifies:
* the global list
*
***************************************************************************/
void NEAR
appendScript(list, element)
SCRIPTLIST **list;
SCRIPTLIST *element;
{
for (; *list; list = &(*list)->next);
*list = element;
}
char tok[MAXNAME];
#define NAME_CHAR(c) (c) != ' ' && (c) != '>' && (c) != '<' && \
(c) != '^' && (c) != ',' && (c) != '\t' && \
(c) != '\n'
/*** nextInlineFile - gets next Inline file name from command line *************
*
* Scope:
* Local.
*
* Purpose:
* The command line syntax is complex. This function returns the next Inline
* file in the command line part passed to it. As a side effect it changes the
* pointer to just after this inline file name.
*
* Input:
* str - address of the part of command line under consideration.
*
* Output:
* Returns the next inline filename.
*
* Errors/Warnings:
*
* Assumes:
*
* Modifies Globals:
* Global - How and why modified
*
* Uses Globals:
* tok - the address of this static array is returned.
*
* Notes:
*
*******************************************************************************/
LOCAL char * NEAR
nextInlineFile(str)
char **str;
{
char *t = tok,
*pStr = *str;
BOOL fFound = FALSE; // '<<' not found
while (!fFound)
if (!(pStr = _ftcschr(pStr, '<')))
return(NULL);
else if (*++pStr == '<')
fFound = TRUE;
//Since '<<' has been found we definitely have another Inline File
pStr++;
while (*pStr && NAME_CHAR(*pStr)) {
if (*pStr == '$' && pStr[1] == '(') {
*t = '$';
*++t = '(';
while (*++pStr != '\n' && *pStr != ')') {
*t++ = *pStr;
}
if (*pStr == '\n')
break;
}
else {
*t = *pStr;
++t; ++pStr;
}
}
*t = '\0';
*str = pStr;
return(tok);
}
/*** duplicateInline -- check if inline filename is already present ************
*
* Scope:
* Local.
*
* Purpose:
* Checks if an inline filename has been used or not
*
* Input:
* name - the name to check for
*
* Output:
* Returns ... TRUE if it is a duplicate inline file and FALSE if not.
*
* Errors/Warnings:
*
* Assumes:
*
* Modifies Globals:
*
* Uses Globals:
* inlineFileList - The global list of inline files
*
* Notes:
*
*******************************************************************************/
#ifdef DEAD_CODE
BOOL NEAR
duplicateInline(name)
char *name;
{
BOOL fFound = FALSE;
STRINGLIST *pList = inlineFileList;
for (; pList && !fFound; pList = pList->next) {
if (!_ftcsnicmp(name, pList->text, _ftcslen(pList->text)))
fFound = TRUE;
}
return(fFound);
}
#endif
/*** processInline - Brief description of the function *************************
*
* Scope:
* Global.
*
* Purpose:
* What does the function do?
*
* Input:
* parameter - description
*
* Output:
* Returns ... TRUE if cmdline returned is expanded
*
* Errors/Warnings:
* error/warning - Why?
*
* Assumes:
* Whatever it assumes
*
* Modifies Globals:
* Global - How and why modified
*
* Uses Globals:
* Global - How and why used
*
* Notes:
* Usage notes and other important notes
*
*******************************************************************************/
BOOL NEAR
processInline(
char *szCmd,
char **szCmdLine,
STRINGLIST **pMacroList
) {
char *szInline, *szUnexpInline; // Inline name, unexpanded
char *pCmdLine; // The executable line
FILE *infile; // The inline file
char *begInBlock, *inBlock, *pInBlock; // inline block
char szTmp[MAXNAME];
STRINGLIST *new;
int iKeywordLen;
if (begInBlock = _ftcschr(szCmd, '\n')) {
*begInBlock = '\0';
*szCmdLine = expandMacros(szCmd, pMacroList);
*begInBlock = '\n';
begInBlock++;
//if not expanded, allocate a copy
if (*szCmdLine == szCmd)
*szCmdLine = makeString(szCmd);
}
else {
*szCmdLine = makeString(szCmd);
return(FALSE);
}
pCmdLine = *szCmdLine;
//expand macros in the inline file ...
pInBlock = inBlock = expandMacros(begInBlock, pMacroList);
while (szUnexpInline = nextInlineFile(&pCmdLine)) {
BOOL fKeep = FALSE; // default is NOKEEP
char *newline;
// CAVIAR 3410 -- the inline filename has already been expaned
// by the time we get here... we just need to dup the name
// so that it is preserved long enough to delete it later... [rm]
//
// szInline = removeMacros(szUnexpInline);
szInline = makeString(szUnexpInline);
if (!*szInline) {
char *nmTmp;
if ((nmTmp = getenv("TMP")) != NULL && *nmTmp) {
assert(_ftcslen(nmTmp) <= MAXNAME);
_ftcsncpy(szTmp, nmTmp, MAXNAME);
}
else
szTmp[0] = '\0';
if (!(infile = createDosTmp(szTmp)))
makeError(line, CANT_MAKE_INLINE, szTmp);
replaceLtLt(szCmdLine, szTmp);
FREE(szInline);
szInline = makeString(szTmp);
}
else if (!(infile = FILEOPEN(szInline, "w")))
makeError(line, CANT_MAKE_INLINE, szInline);
else
delInlineSymbol(*szCmdLine);
pCmdLine = *szCmdLine; //Because szCmdLine changed
createInline(infile, &pInBlock);
//Add handling of KEEP and NOKEEP here
//iKeywordLen is length of word after << on that line
newline = _ftcschr(pInBlock , '\n');
iKeywordLen = newline ? newline - pInBlock : _ftcslen(pInBlock);
if (iKeywordLen > 3 && !_ftcsnicmp(pInBlock, "keep", 4)) {
pInBlock +=4;
fKeep = (BOOL)TRUE;
}
else if (iKeywordLen > 5 && !_ftcsnicmp(pInBlock, "nokeep", 6))
pInBlock += 6;
else if (iKeywordLen)
makeError(line, SYNTAX_KEEP_INLINE_FILE);
if (*pInBlock == '\n')
pInBlock++;
fclose(infile);
//Add the file to list to be deleted; except for "KEEP"
if (!fKeep) {
new = makeNewStrListElement();
new->text = makeString(szInline);
appendItem(&delList, new);
}
FREE(szInline);
}
if (inBlock != begInBlock)
FREE(inBlock);
return(TRUE);
}
void NEAR
replaceLtLt(source, str)
char **source;
char *str;
{
char *szBuf;
char *p, *q;
// Don't subtract two for the << and forget to add 1 for the null termination.
szBuf = _alloca(_ftcslen(*source) - 1 + _ftcslen(str));
for (p = *source, q = szBuf;;++p,++q)
if (*p != '<')
*q = *p;
else if (*(p+1) != '<') {
*q = '<';
}
else {
*q = '\0';
_ftcscat(_ftcscat(szBuf, str), p+2);
*source = (char *)REALLOC(*source, _ftcslen(szBuf) + 1);
_ftcscpy(*source, szBuf);
break;
}
}
void NEAR
createInline(file, szString)
FILE *file;
char **szString;
{
char *t, *u;
while (t = _ftcschr(*szString, '\n'))
if (!_ftcsncmp(*szString, "<<", 2)) {
*szString += 2;
break;
}
else {
for (u = *szString; u <= t; u++)
fputc(*u, file);
*szString = u;
}
if (!t && !_ftcsncmp(*szString, "<<", 2))
*szString += 2;
}
LOCAL void NEAR
delInlineSymbol(s)
char *s;
{
char *p = _ftcschr(s, '<');
while (p[1] != '<')
p = _ftcschr(p+1, '<');
// "<<" found
_ftcscpy(p, p+2);
}
/*** getLine - get next line processing NMAKE conditionals enroute ***********
*
* Scope:
* Local
*
* Purpose:
* This function handles directives in inline files. This function gets the
* next line of input ... managing conditionals on the way.
*
* Input:
* pchLine - pointer to buffer where line is copied
* n - size of buffer
*
* Output:
* Returns ... NULL, on EOF
* ... non-zero on success
*
* Errors/Warnings:
* Assumes:
* Modifies Globals:
* Uses Globals:
* line - lexer's line count
* colZero - if starting from colZero, needed by lgetc()
*
* Notes:
* Similar to fgets() without stream
*
* Implementation Notes:
* lgetc() handles directives while getting the next character. It handles
* directives when the global colZero is TRUE.
*
*****************************************************************************/
LOCAL char * NEAR
getLine(
char *pchLine,
int n
) {
char *end = pchLine + n;
int c;
while (c = lgetc()) {
switch (c) {
case EOF:
*pchLine = '\0';
return(NULL);
default:
*pchLine++ = (char)c;
break;
}
if (pchLine == end) {
pchLine[-1] = '\0';
UngetTxtChr(c, file);
return(pchLine);
}
else if (c == '\n') {
colZero = TRUE;
++line;
*pchLine = '\0';
return(pchLine);
}
else
colZero = FALSE; // the last character was not a '\n' and we
// are not at the beginning of the file
}
}