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.
 
 
 
 
 
 

1170 lines
22 KiB

/* Setup Instatllation Program
* (C) Copyright 1987 by Microsoft
* Written By Steven Zeck
*
* This module contains all the command excutors.
*************************************************************************/
#include "core.h"
#include <process.h>
#include <fcntl.h>
#include <memory.h>
#include <string.h>
#include <crtapi.h>
/* cls - clear the screen
*
* Inputs
* optional :a XX - screen attributes
* optional title bar
* Returns
*
****************************************************************************/
void doCls ()
{
if ((tokenPeek = getoken()) == opTT && *tokenVal == ':'){
tokenPeek = 0;
getoken();
if (*tokenVal == 'a')
defCrtAttr = nextTokenVal();
else
synError("Syntax error: %s", tokenVal);
}
if (getoken() == strTT)
strcpy(pSTCur->title, tokenVal);
fillCrt(1, 1, cCrtLineMax, 80, defCrtAttr, ' ');
curCrtLine = 1;
if (*pSTCur->title) {
centerOut(1, pSTCur->title);
curCrtLine += 2;
}
}
/* doEcho - echo a line to the screen tty fashion
*
* Inputs
* Returns
*
****************************************************************************/
void doEcho ()
{
char buffT[LINE_MAX*2];
if ((tokenPeek = getoken()) == opTT) {
tokenPeek = 0;
switch(*tokenVal) {
case '@':
curCrtLine = nextTokenVal();
break;
}
}
getText(buffT);
lineOut(buffT);
}
/* dialog - Get a line from the user
*
* Inputs
* type of dialog box
* variable to place answer and get initial value
* optional caption
*
****************************************************************************/
void doDialog ()
{
enum { /* dialog types */
simpleDT,
simplePathDT,
yesNoDT,
listboxDT
};
int typeDT = simpleDT;
SY *pSY;
int column = 1;
getoken();
if (tokenIs("simple"))
;
else if (tokenIs("simplePath"))
typeDT = simplePathDT;
else if (tokenIs("yesNo"))
typeDT = yesNoDT;
else if (tokenIs("listbox"))
typeDT = listboxDT;
else
synError("Expecting dialog type: %s", tokenVal);
getoken(); /* skip , */
switch(typeDT) {
case yesNoDT:
case simpleDT:
case simplePathDT:
getoken();
if (!(pSY = lookup(tokenVal))) {
pSY = newSY(tokenVal);
pSY->type = intSYT;
}
if (getoken() != eolTT) {
pSZ pPrompt;
lineOut(pPrompt = nextTokenStr());
curCrtLine--;
column = strlen(pPrompt)+1;
}
if (typeDT == yesNoDT) {
if (pSY->type != intSYT)
synError("Must be numeric for YES/NO dialog: %s", pSY->name);
textOut(curCrtLine, column, (pSY->v.val)? "Yes ": "No ");
getYesNo:
switch(RpcGetch()) {
case 'y':
case 'Y':
pSY->v.val = 1;
break;
case 'N':
case 'n':
pSY->v.val = 0;
break;
case '\r':
break;
default:
outStat("Enter Y for Yes, N for No");
moveTo(curCrtLine, column);
goto getYesNo;
}
textOut(curCrtLine++, column, (pSY->v.val)? "Yes": "No ");
outStat("");
}
else FOREVER {
getInput(curCrtLine, column, pSY);
if (typeDT == simplePathDT) {
if (! (fileAttrFet(pSY->v.pVal) & (ATTR_NOTF | ATTR_DIR))){
outStat("%s isn't a valid path, reenter", pSY->v.pVal);
continue;
}
}
curCrtLine++;
break;
}
break;
case listboxDT:
{
typedef struct {
char *pValue;
} LISTBOX;
#define ListMax 25
LISTBOX aList[ListMax];
int listMax = 0;
unsigned int listIndex = 0;
int listWidth;
unsigned int oListLeft, oListRight, oListTop, oListBottem;
int oT;
char *pListValues, *pT, c;
pSZ title;
SY *pSYindex = NIL;
// Get the title for the list box and compute size
title = nextTokenStr();
listWidth = strlen(title);
curCrtLine++;
centerOut(curCrtLine++, title);
getoken(); /* skip , */
// Get a copy of list box items and parse into seperate items
pListValues = newStr(nextTokenStr());
for (pT = pListValues; *pT; listMax++) {
while (*pT == ';') pT++; // handle multiple ;;
aList[listMax].pValue = pT;
oT = 0;
while (*pT && *pT != ';'){
oT++;
pT++;
}
if (oT > listWidth)
listWidth = oT;
if (*pT)
*pT++ = NIL;
}
getoken(); /* skip , */
getoken();
// get result variable, create if needed
if (!(pSY = lookup(tokenVal))) {
pSY = newSY(tokenVal);
pSY->type = charSYT;
}
// process optional listbox index
getoken(); /* skip , */
if (getoken() != eolTT) {
if (!(pSYindex = lookup(tokenVal))) {
pSYindex = newSY(tokenVal);
pSYindex->type = intSYT;
}
listIndex = pSYindex->v.val;
if (listIndex > listMax)
terminate("list index(%d) bigger the size(%d)", listIndex, listMax);
}
// now all the variables are collected, draw the list box outline
oListLeft = (80 - listWidth-2)/2;
oListRight = oListLeft + listWidth + 2;
oListTop = curCrtLine;
oListBottem = oListTop + listMax + 1;
curCrtLine = oListBottem+1;
// first the top & bottem
fillCrt(oListTop, oListLeft, oListTop, oListRight, defCrtAttr, 0xc4);
fillCrt(oListBottem, oListLeft, oListBottem, oListRight, defCrtAttr, 0xc4);
// then the end corners
charOut(oListTop, oListLeft, 0xda);
charOut(oListTop, oListRight, 0xbf);
charOut(oListBottem, oListLeft, 0xc0);
charOut(oListBottem, oListRight, 0xd9);
// finally the ends and the values themselves
for (oT = oListTop+1; oT < oListBottem; oT++) {
charOut(oT, oListLeft, 0xb3);
charOut(oT, oListRight, 0xb3);
textOut(oT, oListLeft+1, aList[oT-oListTop-1].pValue);
}
textOut(oListBottem, 1, "");
// Now run the selection of the list box
goto firstList;
while((c = RpcGetch()) != '\r') {
// deselect the old item
attrOut(listIndex+oListTop+1, oListLeft+1, listWidth, defCrtAttr);
if (c == 0x50)
listIndex++;
else if (c == 0x48)
if (listIndex-- == 0)
listIndex = listMax-1;
listIndex %= listMax;
firstList:
attrOut(listIndex+oListTop+1, oListLeft+1, listWidth, (char) ~defCrtAttr);
}
// assign the return values
pSY->v.pVal = newStr(aList[listIndex].pValue);
if (pSYindex)
pSYindex->v.val = listIndex;
free(pListValues);
}
break;
}
}
/* doSet - assign expression to a variable
*
* Inputs
* Returns
*
****************************************************************************/
void doSet ()
{
register SY *pSY;
pSZ pT;
if (getoken() != labelTT)
terminate("Set expected: identifier");
if (!(pSY = lookup(tokenVal)))
pSY = newSY(tokenVal);
if (getoken() != opTT || *tokenVal != '=')
terminate("Set expected: =");
if (pSY->type == charSYT)
free(pSY->v.pVal);
assignNextToken(pSY);
if (getoken() == opTT) {
if (pSY->type != charSYT)
synError("Must be string type for operator");
if (*tokenVal == '&') {
pT = nextTokenStr();
pSY->v.pVal = (pSZ) realloc(pSY->v.pVal, strlen(pSY->v.pVal) + strlen(pT) + 1);
strcat(pSY->v.pVal, pT);
return;
}
else if (*tokenVal != ':')
synError("Unknow string operator %s", tokenVal);
getoken();
switch(*tokenVal) {
case 'd': /* get the drive from a string */
if (pSY->v.pVal[1] == ':')
pSY->v.pVal[2] = NIL;
else
pSY->v.pVal[0] = NIL;
break;
case 'f': /* get the drive free space for a drive */
pT = pSY->v.pVal;
pSY->type = intSYT;
pSY->v.val = freeSpaceFet(*pT);
free(pT);
break;
}
}
}
/* if - process an if statment
*
* Inputs
* Returns
*
****************************************************************************/
void doIf ()
{
Bool fCondition;
if(!pSTCur->fInFalse)
fCondition = evalCondition();
else
{
getoken(); // skip (
while (!(getoken() == opTT && *tokenVal == ')'))
if (!tokenCur)
synError("Missing )");
}
if (getoken() == labelTT && tokenIs("then")) {
if (pSTCur->fInFalse)
return;
/* run a single line if statement */
if (fCondition)
dispatcher(NIL);
return;
}
if (pSTCur->fInFalse) { /* push context in false confitional */
runFile(TRUE);
if (pKYCur == PELSEKY)
runFile(TRUE);
return;
}
/* run a multi line conditional, first do the part after the IF
* then the ELSE part */
runFile((Bool) !fCondition);
if (pKYCur == PELSEKY)
runFile(fCondition);
}
/* evalCondition - evalutate a predict enclosed in ( )
*
* Inputs
* Expression at current line
* Returns
*
****************************************************************************/
Bool evalCondition()
{
SY rhsSY, *pLhsSY;
UINT operator;
int fRet, valRight, attr;
pSZ pFile;
Bool fNot = FALSE;
fRet = FALSE;
if (getoken() != opTT || *tokenVal != '(')
synError("Expecting (");
if (getoken() != labelTT)
synError("Left side must be variable: %s", tokenVal);
if (tokenIs("not")) {
fNot = TRUE;
if (getoken() != labelTT)
synError("Left side must be variable: %s", tokenVal);
}
operator = 0;
if (tokenIs("exist"))
operator = 1;
else if (tokenIs("okdirect"))
operator = 2;
else if (tokenIs("def")) {
if (getoken() != labelTT)
synError("def operator expecting label: %s", tokenVal);
fRet = lookup(tokenVal) != NIL;
goto Done;
}
if (operator) {
if (!(pFile = nextTokenStr()))
return(FALSE);
attr = fileAttrFet(pFile);
if (operator == 1 ){
if (!(attr & ATTR_NOTF))
fRet++;
}
else if ((attr & (ATTR_NOTF|ATTR_DIR)))
fRet++;
goto Done;
}
if (! (pLhsSY = lookup(tokenVal)))
synError("Label not defined: %s", tokenVal);
if (getoken() != opTT )
synError("Expecting predict");
if (isOperator(*pLineCur))
operator = *tokenVal << 8 | *pLineCur++;
else
operator = *tokenVal;
assignNextToken(&rhsSY);
if (pLhsSY->type == intSYT) {
/* do a type conversion from char to int */
if (rhsSY.type == charSYT)
valRight = atoi(rhsSY.v.pVal);
else
valRight = rhsSY.v.val;
switch(operator) {
case '>':
fRet = pLhsSY->v.val > valRight;
break;
case '<':
fRet = pLhsSY->v.val < valRight;
break;
case '!'<<8 | '=':
fRet = pLhsSY->v.val != valRight;
break;
case '='<<8 | '=':
fRet = pLhsSY->v.val == valRight;
break;
case '>'<<8 | '=':
fRet = pLhsSY->v.val >= valRight;
break;
case '<'<<8 | '=':
fRet = pLhsSY->v.val <= valRight;
break;
default:
synError("Unknow operator: %c", operator);
}
}
else {
/* do a type conversion from int to char */
if (rhsSY.type == intSYT) {
RpcItoa(rhsSY.v.val, tokenVal, 10);
fRet = RpcStrcmpi(pLhsSY->v.pVal, tokenVal);
}
else
fRet = RpcStrcmpi(pLhsSY->v.pVal, rhsSY.v.pVal);
switch(operator) {
case '>':
fRet = fRet > 0;
break;
case '<':
fRet = fRet < 0;
break;
case '!'<<8 | '=':
break;
case '='<<8 | '=':
fRet = !fRet;
break;
case '>'<<8 | '=':
fRet = fRet >= 0;
break;
case '<'<<8 | '=':
fRet = fRet <= 0;
break;
default:
synError("Unknow operator: %c", operator);
}
free(rhsSY.v.pVal);
}
Done:
if (getoken() != opTT || *tokenVal != ')')
synError("Expecting )");
return ((fNot)? !fRet: fRet);
}
/* doExit - exit script with optional status
*
* Inputs
* Optional exit code
* Returns
* Modifies "status" variable
*
****************************************************************************/
void doExit ()
{
pSTCur->pBuffCur = pSTCur->pBuff + pSTCur->cbFile;
if ((tokenPeek = getoken()) != eolTT)
*pStatus = nextTokenVal();
}
/* goto - goto a label
*
* Inputs
* label to goto
* Returns
* new line position
*
****************************************************************************/
void doGoto ()
{
if (getoken() != labelTT) {
synError("Expecting label");
return;
}
/* just do a sequentail search from the beginning of the file */
pSTCur->pBuffCur = pSTCur->pBuff;
pSTCur->lineCur = 0;
while(getline()) {
if (*pLineCur == ':' &&
memcmp(pLineCur+1, tokenVal, cbToken) == 0 &&
!isAlpha(pLineCur[cbToken+1]))
longjmp(pSTCur->rootLevel, 1);
}
synError("Couldn't find label: %s", tokenVal);
}
/* doCopy - copy files from distinstation to target
*
* Inputs
* List of files to copy
* optional destination
*
* Several features directory control features are built into this command.
* The variable volID is used to make sure the users has the correct floppy
* disk in drive A:. The variable copyPath is where the files are copied
* to if there isn't destination. Both wild cards and directories as sources
* are supported.
****************************************************************************/
typedef struct FL_s { /* file list structure */
struct FL_s *pNextFL; /* pointer to next file structure */
pSZ fName; /* fully qualified path name */
int cbSubPath; /* part of the path to throw away on target */
} FL;
FL *pFLRoot, *pFL, *pFLCur;
int cbSubPath; /* path prefix to throw away during create */
expandFile(pFileCur) // process a single file
pSZ pFileCur;
{
UINT attr, cbCopyDrive;
pSZ pT; char * pT2;
FILEFILE FileBuff;
char buffT[TOKEN_MAX];
Bool fWildCard = FALSE;
/* collect the file name into a buffer and note if there is a wild
* card characters in the name */
newDrive:
if (!cbSubPath) {
cbCopyDrive = strlen( strcpy(buffT, pCopyDrive->v.pVal) );
if (buffT[cbCopyDrive-1] != '\\')
*(int *)&buffT[cbCopyDrive++] = '\\';
for (pT = buffT + cbCopyDrive, pT2 = pFileCur; isFile(*pT2);) {
if (*pT2 == '*' || *pT2 == '?')
fWildCard++;
*pT++ = *pT2++;
}
*pT = NIL;
/* check for drive/path name, if so don't prefix default drive name */
pT = buffT;
if (buffT[cbCopyDrive+2] == ':' ||
buffT[cbCopyDrive] == '\\' || buffT[cbCopyDrive] == '.')
pT += cbCopyDrive;
}
else
pT = strcpy(buffT, pFileCur);
if (!fWildCard) { /* check for directory entry */
if ((attr = fileAttrFet(pT)) & ATTR_DIR) {
strcat(pT, "\\*.*");
fWildCard++;
}
else if (attr & ATTR_NOTF) {
/* ask the user to change disks and try again */
strcpy(buffT, pFileCur);
changeDisk(pT);
strcpy(pFileCur, buffT);
goto newDrive;
}
}
if (!cbSubPath)
cbSubPath = strrchr(pT, '\\') - pT + 1;
// if the file is a wild card or directory, expand that file name
if (fWildCard) {
/* go through an accumulate all the files names */
if (getFristFile(pT, &FileBuff)) {
do {
// ignore . and .. directorys
if (strrchr(pT, '\\')[1] == '.')
continue;
expandFile(pT);
} while(getNextFile(pT, &FileBuff));
}
}
else {
// add the file to the linked list
pFL = (FL *) memory(sizeof(FL));
pFL->fName = newStr(buffT);
pFL->cbSubPath = cbSubPath;
if (!pFLRoot)
pFLRoot = pFL;
else
pFLCur->pNextFL = pFL;
pFLCur = pFL;
}
}
void doCopy ()
{
pSZ pFiles;
pSZ pT, pFileCur;
UINT attr;
char buffT[TOKEN_MAX], buffDir[TOKEN_MAX];
char oneDir[200];
pSZ pOneDir;
if (!(pFiles = nextTokenStr()))
return;
pFLRoot = pFL = NIL;
/* First, go through and build up a list of files that need coping */
for (pFileCur = pFiles; *pFileCur; ) {
while(isSpace(*pFileCur))
pFileCur++;
cbSubPath = 0;
expandFile(pFileCur);
while(isFile(*pFileCur))
pFileCur++;
}
/* get the target distination, one of:
* - second argument
* - value of "cPath"
* - current directory
*/
pFiles = NIL;
if ((tokenPeek = getoken()) != eolTT)
pFiles = nextTokenStr();
else
if (lookup("cPath") && pSYCur->type == charSYT)
pFiles = pSYCur->v.pVal;
if (pFiles) {
strcpy(buffDir, pFiles);
if (buffDir[strlen(buffDir)-1] != '\\')
strcat(buffDir, "\\");
}
else
buffDir[0] = NIL;
/* All the files have been turned into full path names, now
* go through and do tha actual copy operations */
for (pFL = pFLRoot; pFL; pFL = pFL->pNextFL) {
/* create the target path name, which is the directory target,
/* plus the source name minus the path prefix */
strcat (strcpy(buffT, buffDir), pFL->fName + pFL->cbSubPath);
/* walk the directory path to the source name, creating any
* non existant directory entries. */
pT = buffT;
pOneDir = oneDir;
if (*pT == '\\') // allow path without drive
goto NoDriveInPath;
goto FirstDir;
while (*pT == '\\') {
attr = fileAttrFet(oneDir);
if (attr & ATTR_NOTF) {
outStat("Creating directory %s", buffDir);
if (RpcMkdir(oneDir))
terminate("Couldn't make directory: %s", oneDir);
}
else if (!(attr & ATTR_DIR)) {
terminate("Target exists and isn't a directory: %s\n", oneDir);
}
NoDriveInPath:
*pOneDir++ = '\\';
pT++;
FirstDir:
while(*pT && (*pT != '\\' || pT[-1] == ':'))
*pOneDir++ = *pT++;
*pOneDir = NIL;
}
copyFile(pFL->fName, buffT);
free(pFL->fName);
free(pFL);
}
}
/* doCopyTo - copy a single file to a new name, with no path processing
*
****************************************************************************/
void doCopyTo()
{
char buffT[TOKEN_MAX];
strcpy(buffT, nextTokenStr());
copyFile(buffT,nextTokenStr());
}
/* appendFile - append one or more lines to a file
*
* Inputs
* fileName to modifiy
* values to insert
* optional search string for insertion point
*
****************************************************************************/
void doAppendFile ()
{
char fileName[TOKEN_MAX];
char fileNameBak[TOKEN_MAX];
pSZ valueString;
pSZ searchString = NIL;
int cbSearch;
int cbFileName;
FARB pBuffCur, pT2;
UINT cbRead;
Bool fAppend;
int fNotFound = FALSE;
int fCreate = FALSE;
int fReplace = FALSE;
int fhFrom, fhTo;
pSZ pT;
strcpy(fileName, nextTokenStr()); // get file name
getoken(); // skip ,
// run the replacement string through printf to process the escapes
valueString = newStr(nextTokenStr()); // get strings to append
if (getoken() != eolTT) {
if ((tokenPeek = getoken()) == labelTT &&
tokenIs("Create")) {
fCreate = TRUE;
}
else {
searchString = nextTokenStr(); // optional search string
fAppend = FALSE;
// if the search string begins with a $, this indicates the append option
if (searchString[0] == '$') {
fAppend = TRUE;
searchString++;
}
// if the search string begins with a ^, this indicates the replace option
if (searchString[0] == '^') {
fReplace = TRUE;
searchString++;
}
cbSearch = strlen(searchString);
fNotFound = TRUE;
}
}
// create the name of the backup file
cbFileName = strlen( strcpy(fileNameBak, fileName));
for (pT = fileNameBak + cbFileName;
*pT != '.' && *pT != '\\' && pT > fileNameBak; pT--) ;
// handle file name with no extension
if (*pT != '.')
pT = fileNameBak + cbFileName;
strcpy(pT, ".$$$");
// now, delete any existing file name with .bak and rename the
// exiting one to this name
RpcUnlink(fileNameBak);
if (!fCreate) {
if (rename(fileName, fileNameBak))
terminate("can't rename %s to %s", fileName, fileNameBak);
fhFrom = openFile(fileNameBak, O_RDONLY | O_BINARY);
}
fhTo = openFile(fileName, O_CREAT | O_TRUNC| O_WRONLY | O_BINARY);
// copy the old file to new file until the end of file is found
// or the insertion point is located
while (!fCreate && (cbRead = readFar(fhFrom, pCopyBuff, COPYBUF_MAX*2))) {
pBuffCur = pCopyBuff;
if (searchString) {
// we stop 512 bytes short of a full read to avoid buffer
// boundary cases, the last 512 of the file is read again
if (cbRead > COPYBUF_MAX*2 - 512) {
cbRead -= 512;
RpcLseek(fhFrom, -512L, 1);
}
// look for a string to match
while (pBuffCur < pCopyBuff+cbRead) {
// do a case insensitive search, allowing any # of spaces
// to match any number in the target string
for (pT = searchString, pT2 = pBuffCur;
*pT == ((*pT2 >= 'A' && *pT2 <= 'Z')? (*pT2 | 0x20): *pT2);) {
if (*pT == ' ') {
while (*pT == ' ' && *pT) pT++;
while (*pT2 == ' ') pT2++;
}
else {
pT++;
pT2++;
}
if (*pT == NIL) {
fNotFound = FALSE;
// skip to the end of the line for the append option
pBuffCur = pT2;
if (fAppend || fReplace) {
while (*pT2 != '\r')
pT2++;
}
if (!fReplace)
pBuffCur = pT2;
goto found;
}
}
pBuffCur++;
}
}
writeFar(fhTo, pCopyBuff, cbRead);
}
pBuffCur = pCopyBuff;
found:
// the insertion point has been found. Output the values to the file
if (!fCreate)
writeFar(fhTo, pCopyBuff, pBuffCur - pCopyBuff);
if (fReplace && !fNotFound)
pBuffCur = pT2;
if (!fNotFound)
writeFar(fhTo, valueString, strlen(valueString));
if (!fCreate)
writeFar(fhTo, pBuffCur, cbRead - (pBuffCur - pCopyBuff));
// append the rest of the file
if (!fCreate)
while ((cbRead = readFar(fhFrom, pCopyBuff, COPYBUF_MAX)))
writeFar(fhTo, pCopyBuff, cbRead);
if (!fCreate)
RpcClose(fhFrom);
RpcClose(fhTo);
RpcUnlink(fileNameBak);
free(valueString);
*pStatus = fNotFound;
}
/* md - make a dirctory
*
****************************************************************************/
void doMd ()
{
pSZ pDir;
pDir = nextTokenStr();
if (fileAttrFet(pDir) & ATTR_NOTF) {
if (RpcMkdir(pDir))
terminate("Couldn't make directory: %s", pDir);
}
}
/* cd - change to a dirctory or Dir
*
****************************************************************************/
void doCd ()
{
pSZ pDir;
pDir = nextTokenStr();
if (pDir[1] == ':' && pDir[2] == NIL)
cdDrive(pDir[0]);
else if (RpcChdir(pDir))
terminate("Couldn't change to directory: %s", pDir);
}
/* doExec - exec a program
*
* Inputs
* Program name, followed by arguments
* Returns
* Sets the exit variable to return status of program
*
****************************************************************************/
void doExec ()
{
#ifdef EXEC
int stat;
pSZ pProgram;
char argBuff[LINE_MAX*2];
char pgmBuff[TOKEN_MAX];
pProgram = nextTokenStr();
strcpy(pgmBuff, pProgram);
getText(argBuff);
outStat("Running %s %s", pgmBuff, argBuff);
moveTo(curCrtLine, 1);
stat = spawnlp(P_WAIT, pgmBuff, pgmBuff, argBuff, NIL);
if (stat == -1 ) /* map -1 to something our limited if can handle */
stat = 1000;
*pStatus = stat;
#endif
}
/* doCall - call another script file
*
* Inputs
* Returns
*
****************************************************************************/
void doCall ()
{
runScript(nextTokenStr());
}