home *** CD-ROM | disk | FTP | other *** search
- //
- /* */
- /* cmd.c */
- /* */
- /* command.com Top Level Driver */
- /* */
- /* Copyright (c) 2000 */
- /* Pasquale J. Villani */
- /* All Rights Reserved */
- /* */
- /* */
- /* CMD32 is free software; you can redistribute it and/or */
- /* modify it under the terms of the GNU General Public License */
- /* as published by the Free Software Foundation; either version */
- /* 2, or (at your option) any later version. */
- /* */
- /* CMD32 is distributed in the hope that it will be useful, but */
- /* WITHOUT ANY WARRANTY; without even the implied warranty of */
- /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */
- /* the GNU General Public License for more details. */
- /* */
- /* You should have received a copy of the GNU General Public */
- /* License along with CMD32; see the file COPYING. If not, */
- /* write to the Free Software Foundation, 675 Mass Ave, */
- /* Cambridge, MA 02139, USA. */
- //
-
-
- // $Logfile$
-
- /* $Log$
- * $EndLog$ */
-
- #include <windows.h>
- #include <stdarg.h>
- #include <stdlib.h>
- #include <ctype.h>
- #define MAIN
- #include "globals.h"
- #include "proto.h"
-
- #ifdef VERSION_STRINGS
- static BYTE *RcsId = "$Header$";
- #endif
-
- #define SIZE 4096
-
- struct table
- {
- BYTE *str;
- int (*func)(INT, BYTE **);
- };
-
- static BOOL
- bCFlag;
-
- struct table *lookup(struct table *, BYTE *);
- VOID err_report(INT);
- VOID put_prompt(BYTE *);
- VOID Redirect(BYTE *, BYTE *, BYTE *, BOOL *);
- VOID RestoreIO(HANDLE, HANDLE);
- static BOOL MatchCommand(BYTE *pszPattern, BYTE *pszCmd, BOOL *pbBatch);
-
- BOOL ExecCmd(INT argc, BYTE *argv[]);
- BOOL CmdExit(INT argc, BYTE *argv[]);
- BOOL cd(INT argc, BYTE *argv[]);
- BOOL cmd_date(INT argc, BYTE *argv[]);
- BOOL cmd_time(INT argc, BYTE *argv[]);
- BOOL copy(INT argc, BYTE *argv[]);
- BOOL del(INT argc, BYTE *argv[]);
- BOOL dir(INT argc, BYTE *argv[]);
- BOOL echo_bat(INT argc, BYTE *argv[]);
- BOOL echo_dot_bat(INT argc, BYTE *argv[]);
- BOOL mkdir(INT argc, BYTE *argv[]);
- BOOL ren(INT argc, BYTE *argv[]);
- BOOL rmdir(INT argc, BYTE *argv[]);
- BOOL type(INT argc, BYTE *argv[]);
- BOOL ver(INT argc, BYTE *argv[]);
- BOOL Prompt(INT argc, BYTE *argv[]);
- BOOL cmd_path(INT argc, BYTE *argv[]);
- BOOL set_bat(INT argc, BYTE *argv[]);
- BOOL rem_bat(INT argc, BYTE *argv[]);
-
- INT GetDrive(void);
-
- // External commands
-
- struct table commands[] =
- {
- {"cd", cd},
- {"copy", copy},
- {"date", cmd_date},
- {"del", del},
- {"dir", dir},
- {"echo", echo_bat},
- {"echo.", echo_dot_bat},
- {"echo+", echo_dot_bat},
- {"echo\"", echo_dot_bat},
- {"echo/", echo_dot_bat},
- {"echo[", echo_dot_bat},
- {"echo]", echo_dot_bat},
- {"echo:", echo_dot_bat},
- {"exit", CmdExit},
- {"md", mkdir},
- {"mkdir", mkdir},
- {"path", cmd_path},
- {"prompt", Prompt},
- {"rem", rem_bat},
- {"ren", ren},
- {"rmdir", rmdir},
- {"rd", rmdir},
- {"set", set_bat},
- {"time", cmd_time},
- {"type", type},
- {"ver", ver},
- {"", ExecCmd}
- };
-
- WORD printf (CONST BYTE *fmt, ...);
-
- static INT argc;
- static BYTE *argv[NPARAMS];
-
- static BOOL cflag = FALSE, bootup = FALSE;
-
- INT
- main(INT argc, BYTE *argv[])
- {
- BYTE szPath[SIZE] = "";
- DWORD nRead;
- BYTE *cmd_tail;
-
- /* First, establish stdin and stdout */
- hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
- hStdin = GetStdHandle(STD_INPUT_HANDLE);
- hStderr = GetStdHandle(STD_ERROR_HANDLE);
- if(hStdin == INVALID_HANDLE_VALUE
- || hStdout == INVALID_HANDLE_VALUE
- || hStderr == INVALID_HANDLE_VALUE)
- return 0;
-
- /* Initialize our program */
- hInput = hStdin;
- hOutput = hStdout;
- bCFlag = FALSE;
- echo_FLAG = FALSE;
- batch_FLAG = FALSE;
- strcpy(szDfltPrompt, "$p$g ");
- strcpy(szDfltPath, "");
- hHeap = GetProcessHeap();
- if(!hHeap)
- {
- return 1;
- }
- cmd_tail = GetCommandLine();
-
- /* Check what PROMPT is set in env to over ride default */
- nRead = GetEnvironmentVariable("PROMPT", szPrompt, sizeof(szPrompt));
- if(!nRead)
- {
- strcpy(szPrompt, szDfltPrompt);
- }
-
-
- /* Check what PATH is set in env to over ride default */
- pszPath = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, SIZE);
- nRead = GetEnvironmentVariable("PATH", szPath, SIZE);
- if(nRead)
- {
- strcpy(pszPath, szPath);
- }
- else
- {
- strcpy(pszPath, szDfltPath);
- }
-
- /* Main body for code. Either read from Stdin and execute */
- /* commands or simply execute just once if -c specified. */
- if(!cflag)
- {
- /* Announce our version */
- printf(ANNOUNCE, copyright);
- printf("\n\n");
-
- FOREVER
- {
- default_drive = GetDrive();
- put_prompt(szPrompt);
- if(!ReadFile(hStdin, szCmdLine, MAX_CMDLINE, &nRead, 0))
- continue;
- do_command(nRead);
- }
- }
- else
- {
- BYTE FAR *p;
-
- default_drive = GetDrive();
- for(p = cmd_tail; *p != '\r'; p++)
- {
- if(*p == '/' && (*(p + 1) == 'c' || *(p + 1) == 'C'))
- break;
- }
- p += 2;
- strncpy(szCmdLine, p, 0x7f);
- for(nRead = 0; *p != '\r'; nRead++, p++)
- ;
- ++nRead;
- do_command(nRead);
- }
- return 0;
- }
-
-
- VOID Redirect(BYTE *pszCmdLine,
- BYTE *pszInput, BYTE *pszOutput,
- BOOL *pbAppendMode)
- {
- BYTE
- szLocalBuffer[MAX_CMDLINE],
- *pszLine, *pszDest = pszCmdLine;
- SECURITY_ATTRIBUTES saAttr;
-
- // First - create an image, since we'll be copying back into
- // the original buffer.
- strcpy(szLocalBuffer, pszCmdLine);
-
- // Initialize the destination names for later use.
- *pszInput = *pszOutput = '\0';
-
- // Next, start looking for redirect symbols.
- pszLine = skipwh(szLocalBuffer);
- while(*pszLine != '\0')
- {
- switch(*pszLine)
- {
- case '<':
- pszLine = scan(++pszLine, pszInput);
- break;
-
- case '>':
- if(*(pszLine + 1) == '>')
- {
- ++pszLine;
- *pbAppendMode = TRUE;
- }
- else
- {
- *pbAppendMode = FALSE;
- }
- pszLine = scan(++pszLine, pszOutput);
- break;
-
- default:
- *pszDest++ = *pszLine++;
- break;
- }
- }
- *pszDest = '\0';
-
- // Set the bInheritHandle flag so file handles are inherited.
- saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
- saAttr.bInheritHandle = TRUE;
- saAttr.lpSecurityDescriptor = NULL;
-
- // Now that we have the requested redirection, time
- // to perform it on the users behalh.
- if(*pszInput)
- {
- hInput = CreateFile(
- pszInput, // pointer to name of the file
- GENERIC_READ, // access (read-write) mode
- FILE_SHARE_READ, // share mode
- &saAttr, // pointer to security attributes
- OPEN_EXISTING, // how to open
- FILE_ATTRIBUTE_NORMAL, // file attributes
- 0); // handle to file with attributes to copy
- if(hInput == INVALID_HANDLE_VALUE)
- {
- hInput = hStdin;
- }
- else
- {
- SetStdHandle(STD_INPUT_HANDLE, hInput);
- }
- }
- if(*pszOutput)
- {
- hOutput = CreateFile(
- pszOutput, // create output file
- GENERIC_WRITE, // open for writing
- 0, // do not share
- NULL, // no security
- CREATE_ALWAYS, // overwrite existing
- FILE_ATTRIBUTE_NORMAL | // normal file
- FILE_FLAG_OVERLAPPED, // asynchronous I/O
- NULL); // no attr. template
- if(hOutput == INVALID_HANDLE_VALUE)
- {
- hOutput = hStdout;
- }
- else
- {
- SetStdHandle(STD_OUTPUT_HANDLE, hOutput);
- }
- }
- }
-
-
-
-
- VOID do_command(INT nRead)
- {
- BYTE *pszLine;
- struct table *pTable;
- INT nIndex = 0;
- BOOL IORedirected = FALSE;
- BYTE szInput[MAX_CMDLINE], szOutput[MAX_CMDLINE];
- BOOL bAppendMode;
-
- // If nothing to do, just return
- if(nRead <= 0)
- return;
-
- // Initialize local variables
- szCmdLine[nRead] = '\0';
- bAppendMode = FALSE;
-
- // Parse for command line redirection.
- Redirect(szCmdLine, szInput, szOutput, &bAppendMode);
- IORedirected = (*szInput != '\0' || *szOutput != '\0');
-
- // Now parse for local command arguments.
- for(argc = 0; argc < 16; argc++)
- {
- argv[argc] = (BYTE *)0;
- args[argc][0] = '\0';
- }
- pszLine = scanspl(szCmdLine, args[0], '/');
-
- if(args[0][0] == '@')
- {
- at_FLAG = TRUE;
- nIndex++;
- }
- else
- at_FLAG = FALSE;
-
- // If preceeded by a @, swallow it, it was taken care of
- // elsewhere. Also, change case so that our command verb is
- // case insensitive.
- while(args[0][nIndex] != '\0')
- {
-
- if(at_FLAG)
- args[0][nIndex-1] = tolower(args[0][nIndex]);
- else
- args[0][nIndex] = tolower(args[0][nIndex]);
- nIndex++;
- }
- if(at_FLAG)
- args[0][nIndex-1] = '\0';
-
- argv[0] = args[0];
- // this kludge is for a win32 wart emulation (see ExecCmd)
- tail = skipwh(pszLine);
-
- for(argc = 1; argc < NPARAMS; argc++)
- {
- pszLine = scan(pszLine, args[argc]);
- if(*args[argc] == '\0')
- break;
- else
- argv[argc] = args[argc];
- }
-
- if(*argv[0] != '\0')
- {
- /* Look for just a drive change command, and execute */
- /* it if found. */
- if(argv[0][1] == ':' && argv[0][2] == '\0')
- {
- BYTE c = argv[0][0];
-
- if(c >= 'a' && c <= 'z')
- c = c - 'a' + 'A';
- if(c >= 'A' && c <= 'Z')
- default_drive = (c - 'A');
- }
-
- /* It may be a help command request. */
- else if( (argc > 1) &&
- (argv[1][0] == switchchar) &&
- (argv[1][1] == '?'))
- {
- strcpy(tail, " ");
- strcat(tail, argv[0]);
- strcat(tail, "\r\n");
- argc = 2;
- argv[1] = argv[0];
- argv[0] = "help";
- argv[2] = 0;
- ExecCmd(argc, argv);
- if(IORedirected)
- RestoreIO(hStdin, hStdout);
- }
- /* do a normal command execution */
- else
- {
- #ifdef DEBUG
- printf("Looking up %s\n", argv[0]);
- #endif
- pTable = lookup(commands, argv[0]);
- (*(pTable -> func))(argc, argv);
- if(IORedirected)
- RestoreIO(hStdin, hStdout);
- }
- }
- }
-
-
- BOOL Prompt(INT argc, BYTE *argv[])
- {
- BYTE *p;
- BYTE *cmd = "PROMPT";
-
- if(argc == 1)
- {
- strcpy(szPrompt, dflt_pr_string);
- SetEnvironmentVariable(cmd, szPrompt);
- }
- else
- {
- /* Trim trailing newline */
- for(p = tail; (*p != '\r') && (*p != '\n'); p++)
- ;
- *p = '\0';
-
- /* should be scopy(argv[1], &pr_string[1]); but to */
- /* emulate an MS-DOS wart, is */
- strcpy(szPrompt, tail);
-
- /* Now set the environment variable for all children to */
- /* see. */
- SetEnvironmentVariable(cmd, szPrompt);
- }
- return TRUE;
- }
-
-
- struct table *lookup(p, token)
- struct table *p;
- BYTE *token;
- {
- while(*(p -> str) != '\0')
- {
- if(strcmp(p -> str, token) == 0)
- break;
- else
- ++p;
- }
- return p;
- }
-
-
- VOID RestoreIO(HANDLE hDupStdin, HANDLE hDupStdout)
- {
- // After process creation, restore the saved STDIN and STDOUT.
- if (!SetStdHandle(STD_INPUT_HANDLE, hDupStdin))
- error_message(CANNOT_RESTORE);
-
- if (!SetStdHandle(STD_OUTPUT_HANDLE, hDupStdout))
- error_message(CANNOT_RESTORE);
- if(hOutput != hStdout)
- {
- CloseHandle(hOutput);
- hOutput = hDupStdout;
- }
- if(hInput != hStdin)
- {
- CloseHandle(hInput);
- hInput = hDupStdin;
- }
- }
-
-
- static BOOL MatchCommand(BYTE *pszPattern, BYTE *pszCmd, BOOL *pbBatch)
- {
- WORD nIdx;
- BYTE szPattern[SIZE];
- WIN32_FIND_DATA dmp;
- HANDLE hDir;
- struct _Ext
- {
- BYTE *pszExt;
- BOOL bBatch;
- };
- #define NUMEXT 3
- static struct _Ext exTable[NUMEXT] =
- {
- {".bat", TRUE},
- {".exe", FALSE},
- {".com", FALSE}
- };
-
- // First, see if we already have a desired extension. If so, try finding it.
- for(nIdx = 0; nIdx < NUMEXT; nIdx++)
- {
- if((strlen(pszPattern) >4)
- && (!_stricmp(&pszPattern[strlen(pszPattern)-4], exTable[nIdx].pszExt)))
- {
- if((hDir = FindFirstFile((LPCTSTR)pszPattern, (LPWIN32_FIND_DATA)&dmp))
- != INVALID_HANDLE_VALUE)
- {
- if(pszCmd)
- {
- strcpy(pszCmd, pszPattern);
- }
- CloseHandle(hDir);
- return TRUE;
- }
- else
- {
- return FALSE;
- }
- }
- }
-
- // OK, we need to check, in order, for the command.
- for(nIdx = 0; nIdx < NUMEXT; nIdx++)
- {
- strcpy(szPattern, pszPattern);
- strcat(szPattern, exTable[nIdx].pszExt);
- if((hDir = FindFirstFile((LPCTSTR)szPattern, (LPWIN32_FIND_DATA)&dmp))
- != INVALID_HANDLE_VALUE)
- {
- if(pszCmd)
- {
- strcpy(pszCmd, szPattern);
- }
- CloseHandle(hDir);
- return TRUE;
- }
- }
-
- // Didn't find it, return an error.
- return FALSE;
- }
-
-
- BOOL ExecCmd(INT argc, BYTE *argv[])
- {
- PROCESS_INFORMATION piProcInfo;
- SECURITY_ATTRIBUTES saAttr;
- BOOL bRetVal, bFound = FALSE, bBatch = FALSE;
- STARTUPINFO siStartInfo;
- WORD nIdx;
- BYTE szChildCmdLine[MAX_CMDLINE];
- BYTE szPath[SIZE] = "", *pszPath, *pszTerm;
- DWORD nRead;
-
- // See if there's a PATH spec out there somewhere. If not, use the default.
- nRead = GetEnvironmentVariable("PATH", szPath, SIZE);
- if(!nRead)
- {
- strcpy(szPath, szDfltPath);
- }
-
-
- // Go through and search the path. Loop through the path looking
- // for the command. Look in the current directory
- // first. If it matches a local file, copy in actual file name.
- if(MatchCommand(argv[0], szChildCmdLine, &bBatch))
- {
- bFound = TRUE;
- }
- else
- {
- for(pszPath = szPath, pszTerm = szPath; *pszTerm ; pszPath = pszTerm)
- {
- // Isolate a path component to search
- while(*pszTerm && (*pszTerm != ';'))
- {
- ++pszTerm;
- }
- if(*pszTerm == ';')
- {
- *pszTerm = '\0';
- ++pszTerm;
- }
-
- strcpy(szChildCmdLine, pszPath);
- strcat(szChildCmdLine, "\\");
- strcat(szChildCmdLine, argv[0]);
- if(MatchCommand(szChildCmdLine, 0, &bBatch))
- {
- bFound = TRUE;
- break;
- }
- }
- }
-
- // Did we find it? If not, report an error and return
- if(!bFound)
- {
- error_message(FILE_NOT_FOUND);
- return FALSE;
- }
-
- // Build a command line to execute
- for(nIdx = 1; nIdx < argc; ++nIdx)
- {
- strcat(szChildCmdLine, " ");
- strcat(szChildCmdLine, argv[nIdx]);
- }
-
- // Set the bInheritHandle flag so file handles are inherited.
- saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
- saAttr.bInheritHandle = TRUE;
- saAttr.lpSecurityDescriptor = NULL;
-
- // Set up members of STARTUPINFO structure.
- ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
- siStartInfo.cb = sizeof(STARTUPINFO); // Create the child process.
-
- // The following is somewhat inetersting. We don't specify a module
- // name because of NT stream operating systems. These require a
- // null as the module in order to execute 16-bit programs.
- // Yet another Microsoft "design feature."
- bRetVal = CreateProcess(NULL,
- szChildCmdLine, // command line
- &saAttr, // process security attributes
- NULL, // primary thread security attributes
- TRUE, // handles are inherited
- 0, // creation flags
- NULL, // use parent's environment
- NULL, // use parent's current directory
- &siStartInfo, // STARTUPINFO pointer
- &piProcInfo); // receives PROCESS_INFORMATION
-
- // Wait for the process to exit, if we didn't have an error
- if(bRetVal)
- {
- WaitForSingleObject(piProcInfo.hProcess, INFINITE);
- }
- else
- {
- error_message(EXEC_ERR);
- }
-
- return bRetVal;
- }
-
-
- BOOL CmdExit(INT argc, BYTE FAR *argv[])
- {
- #ifdef DEBUG
- printf("Entered CmdExit\n");
- #endif
- /* If no values passed, return errorvalue = 0 */
- if(argc == 1)
- ExitProcess(0);
-
- /* otherwise return what the user asked for */
- else
- {
- INT nRetVal;
- static BYTE szNums[] = "0123456789";
- BYTE *pszNum;
-
- for(nRetVal = 0, pszNum = argv[1]; isdigit(*pszNum); pszNum++)
- {
- INT j;
-
- for(j = 0; j < 10; j++)
- if(szNums[j] == *pszNum)
- break;
- nRetVal += j;
- }
- ExitProcess(nRetVal);
- }
- return TRUE;
- }
-
-
-
- INT GetDrive(void)
- {
- BYTE directory[NAMEMAX];
-
- GetCurrentDirectory(NAMEMAX, directory);
- return (directory[0] - 'A');
-
- }
-
-
- /* Win32 adaptation of printf generic output routine */
- void HandleChar(BYTE **pszChar, INT cChar)
- {
- BYTE szBuffer[2];
- DWORD cWritten;
-
- if(pszChar && *pszChar != 0)
- {
- *(*pszChar)++ = cChar;
- **pszChar = '\0';
- }
- else
- {
- szBuffer[0] = cChar;
- szBuffer[1] = '\0';
- WriteFile(hOutput, szBuffer, 1, &cWritten, NULL);
- }
- }
-
-
-