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.
 
 
 
 
 
 

349 lines
11 KiB

/*** COMMAND.C - NMAKE 'command line' handling routines ************************
*
* Copyright (c) 1988-1990, Microsoft Corporation. All rights reserved.
*
* Purpose:
* Module contains routines to handle NMAKE 'command line' syntax. NMAKE can be
* optionally called by using the syntax 'NMAKE @commandfile'. This allows more
* flexibility and preents a way of getting around DOS's 128-byte limit on the
* length of a command line. Additionally, it saves keystrokes for frequently
* run commands for NMAKE.
*
* Revision History:
* 15-Nov-1993 JR Major speed improvements
* 15-Oct-1993 HV Use tchar.h instead of mbstring.h directly, change STR*() to _ftcs*()
* 10-May-1993 HV Add include file mbstring.h
* Change the str* functions to STR*
* 14-Aug-1992 SS CAVIAR 2735: handle quoted macro values in command files
* 02-Feb-1990 SB Replace fopen() by FILEOPEN
* 01-Dec-1989 SB Changed realloc() to REALLOC()
* 22-Nov-1989 SB Changed free() to FREE()
* 17-Aug-1989 SB Add error check to closing file
* 05-Apr-1989 SB made func calls NEAR to put all funcs into 1 module
* 20-Oct-1988 SB Notes added to readCommandFile()
* 17-Aug-1988 RB Clean up.
*
*******************************************************************************/
#include "nmake.h"
#include "nmmsg.h"
#include "proto.h"
#include "globals.h"
#include "grammar.h"
LOCAL void NEAR addArgument(char*,unsigned,char***);
LOCAL void NEAR processLine(char*,unsigned*,char***);
LOCAL void NEAR tokenizeLine(char*,unsigned*,char***);
/* ----------------------------------------------------------------------------
* readCommandFile()
*
* arguments: name pointer to name of command file to read
*
* actions: opens command file
* reads in lines and calls processLine() to
* break them into tokens and to build
* an argument vector (a la argv[])
* calls parseCommandLine() recursively to process
* the accumulated "command line" arguments
* frees space used by the arg vector
*
* modifies: makeFiles in main() by modifying contents of parameter
* list
* makeTargets in main() by modifying contents of targets
* parameter
* buf global buffer
*
* notes: function is not ANSI portable because it uses fopen()
* with "rt" type and text mode is a Microsoft extension
*
*/
void NEAR
readCommandFile(name)
char *name;
{
char *s, /* buffer */
**vector; /* local versions of */
unsigned count = 0, /* arg vector, count */
n;
if (!(file = FILEOPEN(name,"rt")))
makeError(0,CANT_OPEN_FILE,name);
vector = NULL; /* no args yet */
while (fgets(buf,MAXBUF,file)) {
n = _ftcslen(buf);
/* if we didn't get the whole line, OR
* the line ended with a backSlash
*/
if ((n == MAXBUF-1 && buf[n-1] != '\n')
|| (buf[n-1] == '\n' && buf[n-2] == '\\')) {
if (buf[n-2] == '\\') {
//Replace \n by \0 and \\ by a space; Also reset length
buf[n-1] = '\0';
buf[n-2] = ' ';
n--;
}
s = makeString(buf);
getRestOfLine(&s,&n);
}
else s = buf;
processLine(s,&count,&vector); /* separate into args */
if (s != buf) FREE(s);
}
if (fclose(file) == EOF)
makeError(0, ERROR_CLOSING_FILE, name);
parseCommandLine(count,vector); /* evaluate the args */
while (count--) /* free the arg vector*/
if(vector[count]) FREE(vector[count]); /* NULL entries mean */
FREE(vector); /* that the space the*/
} /* entry used to pt */
/* to is still in use*/
/* ----------------------------------------------------------------------------
* getRestOfLine()
*
* arguments: s pointer to readCommandFile()'s buffer
* holding line so far
* n pointer to readCommandFile()'s count of
* the chars in *s
*
* actions: keeps reading in text until it sees a newline
* or the end of file
* reallocs space for the old buffer plus the
* contents of the new buffer each time
* appends new buffer's text to existing text
*
* modifies: s readCommandFile()'s text buffer by realloc'ing
* more space for incoming text
* n readCommandFile()'s count of bytes in s
* buf global buffer
*/
void NEAR
getRestOfLine(s,n)
char *s[];
unsigned *n;
{
unsigned temp;
char *t;
t = buf;
while ((*s)[*n-1] != '\n') { /* get rest of line */
if (!fgets(t,MAXBUF,file))
break; /* we hit EOF */
temp = _ftcslen(t);
if (t[temp-2] == '\\' && t[temp-1] == '\n') {
//Replace \n by \0 and \\ by a space; Also reset length
t[temp-1] = '\0';
t[temp-2] = ' ';
}
temp = *n;
*n += _ftcslen(t);
*s = REALLOC(*s,*n+1); /* + 1 for NULL byte */
if (!*s)
makeError(line, MACRO_TOO_LONG);
_ftcscpy(*s+temp,t);
}
}
/* ----------------------------------------------------------------------------
* processLine()
*
* arguments: s pointer to readCommandFile()'s buffer
* holding "command line" to be processed
* count pointer to readCommandFile()'s count of
* "command line" arguments seen so far
* vector pointer to readCommandFile()'s vector of
* pointers to character strings
*
* actions: if the line to be broken into "command line arguments"
* contains '"'
* breaks all the text before '"' into tokens
* delimited by whitespace (which get put in
* vector[] by tokenizeLine())
* finds the closing '"' and treats the quoted string
* as a single token, adding it to the vector
* recurses on the tail of the line (to check for
* other quoted strings)
* else breaks all text in line into tokens delimited
* by whitespace
*
* modifies: vector readCommandFile()'s vector of pointers to
* "command line argument" strings (by modifying
* the contents of the parameter pointer, vector)
* count readCommandFile()'s count of the arguments in
* the vector (by modifying the contents of the
* parameter pointer, count)
*/
LOCAL void NEAR
processLine(s,count,vector)
char *s;
unsigned *count;
char **vector[];
{
char *t;
char *u;
unsigned m;
unsigned n;
BOOL allocFlag = FALSE;
if (!(t = _ftcschr(s,'"'))) /* no quoted strings, */
tokenizeLine(s,count,vector); /* just standard fare*/
else {
/* There are two kinds of situations in which quotes can occur:
1. "FOO = bar baz"
2. FOO="bar baz"
*/
if ((t == s) || (*(t-1) != '=')) // Case 1 above
{ /* if line contains */
*t++ = '\0'; /* quoted macrodef */
tokenizeLine(s,count,vector); /* get tokens before "*/
}
else // Case 2 above
{
*t-- = ' ';
for (u = t; u > s; --u) // find the beginning of the macro name
if (*u == ' ' || *u == '\t' || *u == '\n')
break;
if (u != s)
{
*u++ = '\0';
tokenizeLine(s, count, vector);
}
t = u;
}
n = _ftcslen(t);
for (u = t; *u; ++u) { /* look for closing " */
if (*u == '"') { /* need " and not "" */
if (*(u+1) == '"') {
_ftcscpy(u,u+1);
continue;
}
*u++ = '\0'; /* terminate macrodef */
addArgument(t,*count,vector); /* treat as one arg */
++*count;
processLine(u+1,count,vector); /* recurse on rest of */
break; /* line */
} /* TAIL RECURSION -- */
if ((*u == '\\') /* eliminate later? */
&& WHITESPACE(*(u-1))
&& (*(u+1) == '\n')) { /* \n always last char*/
/***
*u++ = ' '; * \\n becomes a space*
***/
*u = '\0'; /* 2 chars go to 1 */
m = (n = n-2); /* adjust length count*/
if (!allocFlag) {
allocFlag = TRUE;
t = makeString(t);
}
getRestOfLine(&t,&n); /* get some more text */
/**
u = t + m - 1; * reset u & continue *
**/
u = t + m ; /* reset u & continue */
} /* looping */
}
if (u == t + n) /* if at end of line */
makeError(0,SYNTAX_NO_QUOTE); /* and no ", error */
if (allocFlag) FREE(t);
}
}
/* ----------------------------------------------------------------------------
* tokenizeLine()
*
* arguments: s pointer to readCommandFile()'s buffer
* holding "command line" to be tokenized
* count pointer to readCommandFile()'s count of
* "command line" arguments seen so far
* vector pointer to readCommandFile()'s vector of
* pointers to character strings
*
* actions: breaks the line in s into tokens (command line
* arguments) delimited by whitespace
* adds each token to the argument vector
* adjusts the argument counter
*
* modifies: vector readCommandFile()'s vector of pointers to
* "command line argument" strings (by modifying
* the contents of the parameter pointer, vector)
* count readCommandFile()'s count of the arguments in
* the vector (by modifying the contents of the
* parameter pointer, count)
*
* If the user ever wants '@' to be part of an argument in a command file,
* he has to enclose that argument in quotation marks.
*/
LOCAL void NEAR
tokenizeLine(s,count,vector) /* gets args delimited*/
char *s; /* by whitespace and */
unsigned *count; /* constructs an arg */
char **vector[]; /* vector */
{
char *t;
if (t = _ftcschr(s,'\\'))
if (WHITESPACE(*(t-1)) && (*(t+1) == '\n'))
*t = '\0';
for (t = _ftcstok(s," \t\n"); t; t = _ftcstok(NULL," \t\n")) {
if (*t == '@') {
makeError(0,SYNTAX_CMDFILE,t+1);
break; /* should we keep on */
} /* parsing here? */
addArgument(t,*count,vector);
++*count;
}
}
/* ----------------------------------------------------------------------------
* addArgument()
*
* arguments: s pointer to text of argument to be added
* to the "command line argument" vector
* count pointer to readCommandFile()'s count of
* "command line" arguments seen so far
* vector pointer to readCommandFile()'s vector of
* pointers to character strings
*
* actions: allocates space in the vector for the new argument
* allocates space for argument string
* makes vector entry point to argument string
*
* modifies: vector readCommandFile()'s vector of pointers to
* "command line argument" strings (by modifying
* the contents of the parameter pointer, vector)
* (count gets incremented by caller)
*
* To keep from fragmenting memory by doing many realloc() calls for very
* small amounts of space, we get memory in small chunks and use that until
* it is depleted, then we get another chunk . . . .
*/
LOCAL void NEAR
addArgument(s,count,vector) /* puts s in vector */
char *s;
unsigned count;
char **vector[];
{
if (!(*vector))
*vector = (char**) allocate(CHUNKSIZE*sizeof(char*));
else if (!(count % CHUNKSIZE)) {
*vector = (char**) REALLOC(*vector,(count+CHUNKSIZE)*sizeof(char*));
if (!*vector) makeError(0,OUT_OF_MEMORY);
}
(*vector)[count] = makeString(s);
}