From 9f7f2c0f7228aade69336551db6496ad5a21672b Mon Sep 17 00:00:00 2001 From: Rex Jolliff Date: Sat, 20 Mar 1999 20:28:42 +0000 Subject: [PATCH] Added Eric Kohl's port of freedos command svn path=/trunk/; revision=324 --- reactos/apps/utils/cmd/alias.c | 327 +++++++ reactos/apps/utils/cmd/attrib.c | 352 ++++++++ reactos/apps/utils/cmd/batch.c | 462 ++++++++++ reactos/apps/utils/cmd/batch.h | 39 + reactos/apps/utils/cmd/beep.c | 56 ++ reactos/apps/utils/cmd/bugs.txt | 15 + reactos/apps/utils/cmd/call.c | 93 ++ reactos/apps/utils/cmd/chcp.c | 90 ++ reactos/apps/utils/cmd/chcp.h | 8 + reactos/apps/utils/cmd/cls.c | 67 ++ reactos/apps/utils/cmd/cmd.c | 1066 ++++++++++++++++++++--- reactos/apps/utils/cmd/cmd.h | 300 +++++++ reactos/apps/utils/cmd/cmdinput.c | 412 +++++++++ reactos/apps/utils/cmd/cmdtable.c | 241 ++++++ reactos/apps/utils/cmd/color.c | 102 +++ reactos/apps/utils/cmd/config.h | 86 ++ reactos/apps/utils/cmd/console.c | 273 ++++++ reactos/apps/utils/cmd/copy.c | 733 ++++++++++++++++ reactos/apps/utils/cmd/date.c | 298 +++++++ reactos/apps/utils/cmd/del.c | 271 ++++++ reactos/apps/utils/cmd/dir.c | 1225 +++++++++++++++++++++++++++ reactos/apps/utils/cmd/dirstack.c | 183 ++++ reactos/apps/utils/cmd/echo.c | 59 ++ reactos/apps/utils/cmd/error.c | 177 ++++ reactos/apps/utils/cmd/filecomp.c | 253 ++++++ reactos/apps/utils/cmd/files.txt | 56 ++ reactos/apps/utils/cmd/for.c | 135 +++ reactos/apps/utils/cmd/goto.c | 110 +++ reactos/apps/utils/cmd/history.c | 126 +++ reactos/apps/utils/cmd/history.txt | 345 ++++++++ reactos/apps/utils/cmd/if.c | 157 ++++ reactos/apps/utils/cmd/internal.c | 485 +++++++++++ reactos/apps/utils/cmd/label.c | 121 +++ reactos/apps/utils/cmd/license.txt | 342 ++++++++ reactos/apps/utils/cmd/locale.c | 118 +++ reactos/apps/utils/cmd/makefile | 25 +- reactos/apps/utils/cmd/makefile.lcc | 194 +++++ reactos/apps/utils/cmd/misc.c | 296 +++++++ reactos/apps/utils/cmd/move.c | 267 ++++++ reactos/apps/utils/cmd/path.c | 88 ++ reactos/apps/utils/cmd/pause.c | 68 ++ reactos/apps/utils/cmd/prompt.c | 237 ++++++ reactos/apps/utils/cmd/readme.txt | 101 +++ reactos/apps/utils/cmd/redir.c | 218 +++++ reactos/apps/utils/cmd/ren.c | 72 ++ reactos/apps/utils/cmd/set.c | 127 +++ reactos/apps/utils/cmd/shift.c | 72 ++ reactos/apps/utils/cmd/time.c | 253 ++++++ reactos/apps/utils/cmd/todo.txt | 21 + reactos/apps/utils/cmd/type.c | 96 +++ reactos/apps/utils/cmd/ver.c | 139 +++ reactos/apps/utils/cmd/verify.c | 59 ++ reactos/apps/utils/cmd/vol.c | 101 +++ reactos/apps/utils/cmd/where.c | 161 ++++ reactos/apps/utils/cmd/wishlist.txt | 15 + rosapps/cmd/alias.c | 327 +++++++ rosapps/cmd/attrib.c | 352 ++++++++ rosapps/cmd/batch.c | 462 ++++++++++ rosapps/cmd/batch.h | 39 + rosapps/cmd/beep.c | 56 ++ rosapps/cmd/bugs.txt | 15 + rosapps/cmd/call.c | 93 ++ rosapps/cmd/chcp.c | 90 ++ rosapps/cmd/chcp.h | 8 + rosapps/cmd/cls.c | 67 ++ rosapps/cmd/cmd.c | 1066 ++++++++++++++++++++--- rosapps/cmd/cmd.h | 300 +++++++ rosapps/cmd/cmdinput.c | 412 +++++++++ rosapps/cmd/cmdtable.c | 241 ++++++ rosapps/cmd/color.c | 102 +++ rosapps/cmd/config.h | 86 ++ rosapps/cmd/console.c | 273 ++++++ rosapps/cmd/copy.c | 733 ++++++++++++++++ rosapps/cmd/date.c | 298 +++++++ rosapps/cmd/del.c | 271 ++++++ rosapps/cmd/dir.c | 1225 +++++++++++++++++++++++++++ rosapps/cmd/dirstack.c | 183 ++++ rosapps/cmd/echo.c | 59 ++ rosapps/cmd/error.c | 177 ++++ rosapps/cmd/filecomp.c | 253 ++++++ rosapps/cmd/files.txt | 56 ++ rosapps/cmd/for.c | 135 +++ rosapps/cmd/goto.c | 110 +++ rosapps/cmd/history.c | 126 +++ rosapps/cmd/history.txt | 345 ++++++++ rosapps/cmd/if.c | 157 ++++ rosapps/cmd/internal.c | 485 +++++++++++ rosapps/cmd/label.c | 121 +++ rosapps/cmd/license.txt | 342 ++++++++ rosapps/cmd/locale.c | 118 +++ rosapps/cmd/makefile | 25 +- rosapps/cmd/makefile.lcc | 194 +++++ rosapps/cmd/misc.c | 296 +++++++ rosapps/cmd/move.c | 267 ++++++ rosapps/cmd/path.c | 88 ++ rosapps/cmd/pause.c | 68 ++ rosapps/cmd/prompt.c | 237 ++++++ rosapps/cmd/readme.txt | 101 +++ rosapps/cmd/redir.c | 218 +++++ rosapps/cmd/ren.c | 72 ++ rosapps/cmd/set.c | 127 +++ rosapps/cmd/shift.c | 72 ++ rosapps/cmd/time.c | 253 ++++++ rosapps/cmd/todo.txt | 21 + rosapps/cmd/type.c | 96 +++ rosapps/cmd/ver.c | 139 +++ rosapps/cmd/verify.c | 59 ++ rosapps/cmd/vol.c | 101 +++ rosapps/cmd/where.c | 161 ++++ rosapps/cmd/wishlist.txt | 15 + 110 files changed, 23334 insertions(+), 252 deletions(-) create mode 100644 reactos/apps/utils/cmd/alias.c create mode 100644 reactos/apps/utils/cmd/attrib.c create mode 100644 reactos/apps/utils/cmd/batch.c create mode 100644 reactos/apps/utils/cmd/batch.h create mode 100644 reactos/apps/utils/cmd/beep.c create mode 100644 reactos/apps/utils/cmd/bugs.txt create mode 100644 reactos/apps/utils/cmd/call.c create mode 100644 reactos/apps/utils/cmd/chcp.c create mode 100644 reactos/apps/utils/cmd/chcp.h create mode 100644 reactos/apps/utils/cmd/cls.c create mode 100644 reactos/apps/utils/cmd/cmd.h create mode 100644 reactos/apps/utils/cmd/cmdinput.c create mode 100644 reactos/apps/utils/cmd/cmdtable.c create mode 100644 reactos/apps/utils/cmd/color.c create mode 100644 reactos/apps/utils/cmd/config.h create mode 100644 reactos/apps/utils/cmd/console.c create mode 100644 reactos/apps/utils/cmd/copy.c create mode 100644 reactos/apps/utils/cmd/date.c create mode 100644 reactos/apps/utils/cmd/del.c create mode 100644 reactos/apps/utils/cmd/dir.c create mode 100644 reactos/apps/utils/cmd/dirstack.c create mode 100644 reactos/apps/utils/cmd/echo.c create mode 100644 reactos/apps/utils/cmd/error.c create mode 100644 reactos/apps/utils/cmd/filecomp.c create mode 100644 reactos/apps/utils/cmd/files.txt create mode 100644 reactos/apps/utils/cmd/for.c create mode 100644 reactos/apps/utils/cmd/goto.c create mode 100644 reactos/apps/utils/cmd/history.c create mode 100644 reactos/apps/utils/cmd/history.txt create mode 100644 reactos/apps/utils/cmd/if.c create mode 100644 reactos/apps/utils/cmd/internal.c create mode 100644 reactos/apps/utils/cmd/label.c create mode 100644 reactos/apps/utils/cmd/license.txt create mode 100644 reactos/apps/utils/cmd/locale.c create mode 100644 reactos/apps/utils/cmd/makefile.lcc create mode 100644 reactos/apps/utils/cmd/misc.c create mode 100644 reactos/apps/utils/cmd/move.c create mode 100644 reactos/apps/utils/cmd/path.c create mode 100644 reactos/apps/utils/cmd/pause.c create mode 100644 reactos/apps/utils/cmd/prompt.c create mode 100644 reactos/apps/utils/cmd/readme.txt create mode 100644 reactos/apps/utils/cmd/redir.c create mode 100644 reactos/apps/utils/cmd/ren.c create mode 100644 reactos/apps/utils/cmd/set.c create mode 100644 reactos/apps/utils/cmd/shift.c create mode 100644 reactos/apps/utils/cmd/time.c create mode 100644 reactos/apps/utils/cmd/todo.txt create mode 100644 reactos/apps/utils/cmd/type.c create mode 100644 reactos/apps/utils/cmd/ver.c create mode 100644 reactos/apps/utils/cmd/verify.c create mode 100644 reactos/apps/utils/cmd/vol.c create mode 100644 reactos/apps/utils/cmd/where.c create mode 100644 reactos/apps/utils/cmd/wishlist.txt create mode 100644 rosapps/cmd/alias.c create mode 100644 rosapps/cmd/attrib.c create mode 100644 rosapps/cmd/batch.c create mode 100644 rosapps/cmd/batch.h create mode 100644 rosapps/cmd/beep.c create mode 100644 rosapps/cmd/bugs.txt create mode 100644 rosapps/cmd/call.c create mode 100644 rosapps/cmd/chcp.c create mode 100644 rosapps/cmd/chcp.h create mode 100644 rosapps/cmd/cls.c create mode 100644 rosapps/cmd/cmd.h create mode 100644 rosapps/cmd/cmdinput.c create mode 100644 rosapps/cmd/cmdtable.c create mode 100644 rosapps/cmd/color.c create mode 100644 rosapps/cmd/config.h create mode 100644 rosapps/cmd/console.c create mode 100644 rosapps/cmd/copy.c create mode 100644 rosapps/cmd/date.c create mode 100644 rosapps/cmd/del.c create mode 100644 rosapps/cmd/dir.c create mode 100644 rosapps/cmd/dirstack.c create mode 100644 rosapps/cmd/echo.c create mode 100644 rosapps/cmd/error.c create mode 100644 rosapps/cmd/filecomp.c create mode 100644 rosapps/cmd/files.txt create mode 100644 rosapps/cmd/for.c create mode 100644 rosapps/cmd/goto.c create mode 100644 rosapps/cmd/history.c create mode 100644 rosapps/cmd/history.txt create mode 100644 rosapps/cmd/if.c create mode 100644 rosapps/cmd/internal.c create mode 100644 rosapps/cmd/label.c create mode 100644 rosapps/cmd/license.txt create mode 100644 rosapps/cmd/locale.c create mode 100644 rosapps/cmd/makefile.lcc create mode 100644 rosapps/cmd/misc.c create mode 100644 rosapps/cmd/move.c create mode 100644 rosapps/cmd/path.c create mode 100644 rosapps/cmd/pause.c create mode 100644 rosapps/cmd/prompt.c create mode 100644 rosapps/cmd/readme.txt create mode 100644 rosapps/cmd/redir.c create mode 100644 rosapps/cmd/ren.c create mode 100644 rosapps/cmd/set.c create mode 100644 rosapps/cmd/shift.c create mode 100644 rosapps/cmd/time.c create mode 100644 rosapps/cmd/todo.txt create mode 100644 rosapps/cmd/type.c create mode 100644 rosapps/cmd/ver.c create mode 100644 rosapps/cmd/verify.c create mode 100644 rosapps/cmd/vol.c create mode 100644 rosapps/cmd/where.c create mode 100644 rosapps/cmd/wishlist.txt diff --git a/reactos/apps/utils/cmd/alias.c b/reactos/apps/utils/cmd/alias.c new file mode 100644 index 00000000000..ac0a9149d09 --- /dev/null +++ b/reactos/apps/utils/cmd/alias.c @@ -0,0 +1,327 @@ +/* + * ALIAS.C - alias administration module. + * + * + * History: + * + * 02/02/1996 (Oliver Mueller) + * started. + * + * 02/03/1996 (Oliver Mueller) + * Added sorting algorithm and case sensitive substitution by using + * partstrupr(). + * + * 27 Jul 1998 John P. Price + * added config.h include + * added ifdef's to disable aliases + * + * 09-Dec-1998 (Eric Kohl ) + * Fixed crash when removing an alias in DeleteAlias(). + * Added help text ("/?"). + * + * 14-Jan-1998 (Eric Kohl ) + * Clean up and Unicode safe! + * + * 24-Jan-1998 (Eric Kohl ) + * Redirection safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef FEATURE_ALIASES + +#include +#include +#include +#include +#include + +#include "cmd.h" + + +typedef struct tagALIAS +{ + struct tagALIAS *next; + LPTSTR lpName; + LPTSTR lpSubst; + WORD wUsed; +} ALIAS, *LPALIAS; + + +static LPALIAS lpFirst = NULL; +static LPALIAS lpLast = NULL; +static WORD wUsed = 0; + + +/* module internal functions */ +/* strlwr only for first word in string */ +static VOID +partstrlwr (LPTSTR str) +{ + LPTSTR c = str; + while (*c && !_istspace (*c)) + { + *c = _totlower (*c); + c++; + } +} + + +static VOID +PrintAlias (VOID) +{ + LPALIAS ptr = lpFirst; + while (ptr) + { + ConOutPrintf (_T("%s=%s\n"), ptr->lpName, ptr->lpSubst); + ptr = ptr->next; + } +} + + +static VOID +DeleteAlias (LPTSTR pszName) +{ + LPALIAS ptr = lpFirst; + LPALIAS prev = NULL; + + while (ptr) + { + if (!_tcsicmp (ptr->lpName, pszName)) + { + if (prev) + prev->next = ptr->next; + else + lpFirst = ptr->next; + free (ptr->lpName); + free (ptr->lpSubst); + free (ptr); + return; + } + prev = ptr; + ptr = ptr->next; + } +} + + +static INT +AddAlias (LPTSTR name, LPTSTR subst) +{ + LPALIAS ptr = lpFirst; + LPALIAS prev, entry; + LPTSTR s; + + while (ptr) + { + if (!_tcsicmp (ptr->lpName, name)) + { + s = (LPTSTR)malloc ((_tcslen (subst) + 1)*sizeof(TCHAR)); + if (!s) + { + error_out_of_memory (); + return 1; + } + + free (ptr->lpSubst); + ptr->lpSubst = s; + _tcscpy (ptr->lpSubst, subst); + return 0; + } + ptr = ptr->next; + } + + ptr = (LPALIAS)malloc (sizeof (ALIAS)); + if (!ptr) + return 1; + + ptr->next = 0; + + ptr->lpName = (LPTSTR)malloc ((_tcslen (name) + 1)*sizeof(TCHAR)); + if (!ptr->lpName) + { + error_out_of_memory (); + free (ptr); + return 1; + } + _tcscpy (ptr->lpName, name); + + ptr->lpSubst = (LPTSTR)malloc ((_tcslen (subst) + 1)*sizeof(TCHAR)); + if (!ptr->lpSubst) + { + error_out_of_memory (); + free (ptr->lpName); + free (ptr); + return 1; + } + _tcscpy (ptr->lpSubst, subst); + + /* it's necessary for recursive substitution */ + partstrlwr (ptr->lpSubst); + + ptr->wUsed = 0; + + /* Alias table must be sorted! + * Here a little example: + * command line = "ls -c" + * If the entries are + * ls=dir + * ls -c=ls /w + * command line will be expanded to "dir -c" which is not correct. + * If the entries are sortet as + * ls -c=ls /w + * ls=dir + * it will be expanded to "dir /w" which is a valid DOS command. + */ + entry = lpFirst; + prev = 0; + while (entry) + { + if (_tcsicmp (ptr->lpName, entry->lpName) > 0) + { + if (prev) + { + prev->next = ptr; + ptr->next = entry; + } + else + { + ptr->next = entry; + lpFirst = ptr; + } + return 0; + } + prev = entry; + entry = entry->next; + } + + /* The new entry is the smallest (or the first) and must be + * added to the end of the list. + */ + if (!lpFirst) + lpFirst = ptr; + else + lpLast->next = ptr; + lpLast = ptr; + + return 0; +} + + +/* specified routines */ +VOID ExpandAlias (LPTSTR cmd, INT maxlen) +{ + unsigned n = 0, + m, + i, + len; + short d = 1; + LPALIAS ptr = lpFirst; + + wUsed++; + if (wUsed == 0) + { + while (ptr) + ptr->wUsed = 0; + ptr = lpFirst; + wUsed = 1; + } + + /* skipping white spaces */ + while (_istspace (cmd[n])) + n++; + + partstrlwr (&cmd[n]); + + if (!_tcsncmp (&cmd[n], _T("NOALIAS"), 7) && + (_istspace (cmd[n + 7]) || cmd[n + 7] == _T('\0'))) + { + memmove (cmd, &cmd[n + 7], (_tcslen (&cmd[n + 7]) + 1) * sizeof (TCHAR)); + return; + } + + /* substitution loop */ + while (d) + { + d = 0; + while (ptr) + { + len = _tcslen (ptr->lpName); + if (!_tcsncmp (&cmd[n], ptr->lpName, len) && + (_istspace (cmd[n + len]) || cmd[n + len] == _T('\0')) && + ptr->wUsed != wUsed) + { + m = _tcslen (ptr->lpSubst); + if ((int)(_tcslen (cmd) - len + m - n) > maxlen) + { + ConErrPrintf (_T("Command line too long after alias expansion!\n")); + /* the parser won't cause any problems with an empty line */ + cmd[0] = _T('\0'); + } + else + { + memmove (&cmd[m], &cmd[n + len], (_tcslen(&cmd[n + len]) + 1) * sizeof (TCHAR)); + for (i = 0; i < m; i++) + cmd[i] = ptr->lpSubst[i]; + ptr->wUsed = wUsed; + /* whitespaces are removed! */ + n = 0; + d = 1; + } + } + ptr = ptr->next; + } + } +} + + +INT cmd_alias (LPTSTR cmd, LPTSTR param) +{ + LPTSTR ptr; + INT n = 0; + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Sets, removes or shows aliases.\n" + "\n" + "ALIAS [alias=[command]]\n" + "\n" + " alias Name for an alias.\n" + " command Text to be substituted for an alias.\n" + "\n" +// "For example:\n" + "To list all aliases:\n" + " ALIAS\n\n" + "To set a new or replace an existing alias:\n" + " ALIAS da=dir a:\n\n" + "To remove an alias from the alias list:\n" + " ALIAS da=" +// "Type ALIAS without a parameter to display the alias list.\n" + )); + return 0; + } + + if (param[0] == _T('\0')) + { + PrintAlias (); + return 0; + } + + /* error if no '=' found */ + if ((ptr = _tcschr (param, _T('='))) == 0) + return -1; + + /* Split rest into name and substitute */ + *ptr++ = _T('\0'); + + partstrlwr (param); + + if (ptr[0] == _T('\0')) + DeleteAlias (param); + else + n = AddAlias (param, ptr); + + return n; +} +#endif diff --git a/reactos/apps/utils/cmd/attrib.c b/reactos/apps/utils/cmd/attrib.c new file mode 100644 index 00000000000..65a2c316731 --- /dev/null +++ b/reactos/apps/utils/cmd/attrib.c @@ -0,0 +1,352 @@ +/* + * ATTRIB.C - attrib internal command. + * + * + * History: + * + * 04-Dec-1998 (Eric Kohl ) + * started + * + * 09-Dec-1998 (Eric Kohl ) + * implementation works, except recursion ("attrib /s"). + * + * 05-Jan-1999 (Eric Kohl ) + * major rewrite. + * fixed recursion ("attrib /s"). + * started directory support ("attrib /s /d"). + * updated help text. + * + * 14-Jan-1999 (Eric Kohl ) + * Unicode ready! + * + * 19-Jan-1999 (Eric Kohl ) + * Redirection ready! + * + * 21-Jan-1999 (Eric Kohl ) + * Added check for invalid filenames. + * + * 23-Jan-1999 (Eric Kohl ) + * Added handling of multiple filenames. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_ATTRIB + +#include +#include +#include + +#include "cmd.h" + + +static VOID +PrintAttribute (LPTSTR pszPath, LPTSTR pszFile, BOOL bRecurse) +{ + WIN32_FIND_DATA findData; + HANDLE hFind; + TCHAR szFullName[MAX_PATH]; + LPTSTR pszFileName; + + /* prepare full file name buffer */ + _tcscpy (szFullName, pszPath); + pszFileName = szFullName + _tcslen (szFullName); + + /* display all subdirectories */ + if (bRecurse) + { + /* append file name */ + _tcscpy (pszFileName, pszFile); + + hFind = FindFirstFile (szFullName, &findData); + if (hFind == INVALID_HANDLE_VALUE) + { + ErrorMessage (GetLastError (), pszFile); + return; + } + + do + { + if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + continue; + + if (!_tcscmp (findData.cFileName, _T(".")) || + !_tcscmp (findData.cFileName, _T(".."))) + continue; + + _tcscpy (pszFileName, findData.cFileName); + _tcscat (pszFileName, _T("\\")); + PrintAttribute (szFullName, pszFile, bRecurse); + } + while (FindNextFile (hFind, &findData)); + FindClose (hFind); + } + + /* append file name */ + _tcscpy (pszFileName, pszFile); + + /* display current directory */ + hFind = FindFirstFile (szFullName, &findData); + if (hFind == INVALID_HANDLE_VALUE) + { + ErrorMessage (GetLastError (), pszFile); + return; + } + + do + { + if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + continue; + + _tcscpy (pszFileName, findData.cFileName); + + ConOutPrintf (_T("%c %c%c%c %s\n"), + (findData.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) ? _T('A') : _T(' '), + (findData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) ? _T('S') : _T(' '), + (findData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? _T('H') : _T(' '), + (findData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? _T('R') : _T(' '), + szFullName); + } + while (FindNextFile (hFind, &findData)); + FindClose (hFind); +} + + +static VOID +ChangeAttribute (LPTSTR pszPath, LPTSTR pszFile, DWORD dwMask, + DWORD dwAttrib, BOOL bRecurse, BOOL bDirectories) +{ + WIN32_FIND_DATA findData; + HANDLE hFind; + DWORD dwAttribute; + TCHAR szFullName[MAX_PATH]; + LPTSTR pszFileName; + + /* prepare full file name buffer */ + _tcscpy (szFullName, pszPath); + pszFileName = szFullName + _tcslen (szFullName); + + /* change all subdirectories */ + if (bRecurse) + { + /* append file name */ + _tcscpy (pszFileName, _T("*.*")); + + hFind = FindFirstFile (szFullName, &findData); + if (hFind == INVALID_HANDLE_VALUE) + { + ErrorMessage (GetLastError (), pszFile); + return; + } + + do + { + if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if (!_tcscmp (findData.cFileName, _T(".")) || + !_tcscmp (findData.cFileName, _T(".."))) + continue; + + _tcscpy (pszFileName, findData.cFileName); + _tcscat (pszFileName, _T("\\")); + + ChangeAttribute (szFullName, pszFile, dwMask, + dwAttrib, bRecurse, bDirectories); + } + } + while (FindNextFile (hFind, &findData)); + FindClose (hFind); + } + + /* append file name */ + _tcscpy (pszFileName, pszFile); + + hFind = FindFirstFile (szFullName, &findData); + if (hFind == INVALID_HANDLE_VALUE) + { + ErrorMessage (GetLastError (), pszFile); + return; + } + + do + { + if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + continue; + + _tcscpy (pszFileName, findData.cFileName); + + dwAttribute = GetFileAttributes (szFullName); + + if (dwAttribute != 0xFFFFFFFF) + { + dwAttribute = (dwAttribute & ~dwMask) | dwAttrib; + SetFileAttributes (szFullName, dwAttribute); + } + } + while (FindNextFile (hFind, &findData)); + FindClose (hFind); +} + + +INT cmd_attrib (LPTSTR cmd, LPTSTR param) +{ + LPTSTR *arg; + INT argc, i; + TCHAR szPath[MAX_PATH]; + TCHAR szFileName [MAX_PATH]; + BOOL bRecurse = FALSE; + BOOL bDirectories = FALSE; + DWORD dwAttrib = 0; + DWORD dwMask = 0; + + /* initialize strings */ + szPath[0] = _T('\0'); + szFileName[0] = _T('\0'); + + /* print help */ + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Displays or changes file attributes.\n\n" + "ATTRIB [+R | -R] [+A | -A] [+S | -S] [+H | -H] file ...\n" + " [/S [/D]]\n\n" + " + Sets an attribute\n" + " - Clears an attribute\n" + " R Read-only file attribute\n" + " A Archive file attribute\n" + " S System file attribute\n" + " H Hidden file attribute\n" + " /S Processes matching files in the current directory\n" + " and all subdirectories\n" + " /D Processes direcories as well\n\n" + "Type ATTRIB without a parameter to display the attributes of all files.")); + return 0; + } + + /* build parameter array */ + arg = split (param, &argc); + + /* check for options */ + for (i = 0; i < argc; i++) + { + if (_tcsicmp (arg[i], _T("/s")) == 0) + bRecurse = TRUE; + else if (_tcsicmp (arg[i], _T("/d")) == 0) + bDirectories = TRUE; + } + + /* create attributes and mask */ + for (i = 0; i < argc; i++) + { + if (*arg[i] == _T('+')) + { + if (_tcslen (arg[i]) != 2) + { + error_invalid_parameter_format (arg[i]); + freep (arg); + return -1; + } + + switch ((TCHAR)_totupper (arg[i][1])) + { + case _T('A'): + dwMask |= FILE_ATTRIBUTE_ARCHIVE; + dwAttrib |= FILE_ATTRIBUTE_ARCHIVE; + break; + + case _T('H'): + dwMask |= FILE_ATTRIBUTE_HIDDEN; + dwAttrib |= FILE_ATTRIBUTE_HIDDEN; + break; + + case _T('R'): + dwMask |= FILE_ATTRIBUTE_READONLY; + dwAttrib |= FILE_ATTRIBUTE_READONLY; + break; + + case _T('S'): + dwMask |= FILE_ATTRIBUTE_SYSTEM; + dwAttrib |= FILE_ATTRIBUTE_SYSTEM; + break; + + default: + error_invalid_parameter_format (arg[i]); + freep (arg); + return -1; + } + } + else if (*arg[i] == _T('-')) + { + if (_tcslen (arg[i]) != 2) + { + error_invalid_parameter_format (arg[i]); + freep (arg); + return -1; + } + + switch ((TCHAR)_totupper (arg[i][1])) + { + case _T('A'): + dwMask |= FILE_ATTRIBUTE_ARCHIVE; + dwAttrib &= ~FILE_ATTRIBUTE_ARCHIVE; + break; + + case _T('H'): + dwMask |= FILE_ATTRIBUTE_HIDDEN; + dwAttrib &= ~FILE_ATTRIBUTE_HIDDEN; + break; + + case _T('R'): + dwMask |= FILE_ATTRIBUTE_READONLY; + dwAttrib &= ~FILE_ATTRIBUTE_READONLY; + break; + + case _T('S'): + dwMask |= FILE_ATTRIBUTE_SYSTEM; + dwAttrib &= ~FILE_ATTRIBUTE_SYSTEM; + break; + + default: + error_invalid_parameter_format (arg[i]); + freep (arg); + return -1; + } + } + } + + if (argc == 0) + { + GetCurrentDirectory (MAX_PATH, szPath); + _tcscat (szPath, _T("\\")); + _tcscpy (szFileName, _T("*.*")); + PrintAttribute (szPath, szFileName, bRecurse); + } + else + { + /* get full file name */ + for (i = 0; i < argc; i++) + { + if ((*arg[i] != _T('+')) && (*arg[i] != _T('-')) && (*arg[i] != _T('/'))) + { + LPTSTR p; + GetFullPathName (arg[i], MAX_PATH, szPath, NULL); + p = _tcsrchr (szPath, _T('\\')) + 1; + _tcscpy (szFileName, p); + *p = _T('\0'); + + if (dwMask == 0) + PrintAttribute (szPath, szFileName, bRecurse); + else + ChangeAttribute (szPath, szFileName, dwMask, + dwAttrib, bRecurse, bDirectories); + } + } + } + + freep (arg); + + return 0; +} + +#endif /* INCLUDE_CMD_ATTRIB */ diff --git a/reactos/apps/utils/cmd/batch.c b/reactos/apps/utils/cmd/batch.c new file mode 100644 index 00000000000..b1ea5be8903 --- /dev/null +++ b/reactos/apps/utils/cmd/batch.c @@ -0,0 +1,462 @@ +/* + * BATCH.C - batch file processor for CMD.EXE. + * + * + * History: + * + * ??/??/?? (Evan Jeffrey) + * started. + * + * 15 Jul 1995 (Tim Norman) + * modes and bugfixes. + * + * 08 Aug 1995 (Matt Rains) + * i have cleaned up the source code. changes now bring this + * source into guidelines for recommended programming practice. + * + * i have added some constants to help making changes easier. + * + * 29 Jan 1996 (Steffan Kaiser) + * made a few cosmetic changes + * + * 05 Feb 1996 (Tim Norman) + * changed to comply with new first/rest calling scheme + * + * 14 Jun 1997 (Steffen Kaiser) + * bug fixes. added error level expansion %?. ctrl-break handling + * + * 16 Jul 1998 (Hans B Pufal) + * Totally reorganised in conjunction with COMMAND.C (cf) to + * implement proper BATCH file nesting and other improvements. + * + * 16 Jul 1998 (John P Price ) + * Seperated commands into individual files. + * + * 19 Jul 1998 (Hans B Pufal) [HBP_001] + * Preserve state of echo flag across batch calls. + * + * 19 Jul 1998 (Hans B Pufal) [HBP_002] + * Implementation of FOR command + * + * 20-Jul-1998 (John P Price ) + * added error checking after malloc calls + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 02-Aug-1998 (Hans B Pufal) [HBP_003] + * Fixed bug in ECHO flag restoration at exit from batch file + * + * 26-Jan-1999 (Eric Kohl ) + * Replaced CRT io functions by Win32 io functions. + * Unicode safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include +#include + +#include "cmd.h" +#include "batch.h" + + +/* The stack of current batch contexts. + * NULL when no batch is active + */ +LPBATCH_CONTEXT bc = NULL; + +BOOL bEcho = TRUE; /* The echo flag */ + + + +/* Buffer for reading Batch file lines */ +TCHAR textline[BATCH_BUFFSIZE]; + + +/* + * Returns a pointer to the n'th parameter of the current batch file. + * If no such parameter exists returns pointer to empty string. + * If no batch file is current, returns NULL + * + */ + +LPTSTR FindArg (INT n) +{ + LPTSTR pp; + +#ifdef _DEBUG + DebugPrintf ("FindArg: (%d)\n", n); +#endif + + if (bc == NULL) + return NULL; + + n += bc->shiftlevel; + pp = bc->params; + + /* Step up the strings till we reach the end */ + /* or the one we want */ + while (*pp && n--) + pp += _tcslen (pp) + 1; + + return pp; +} + + +/* HBP_002 { FOR command support */ +/* + * Batch_params builds a parameter list in newlay allocated memory. + * The parameters consist of null terminated strings with a final + * NULL character signalling the end of the parameters. + * +*/ + +LPTSTR BatchParams (LPTSTR s1, LPTSTR s2) +{ + LPTSTR dp = (LPTSTR)malloc ((_tcslen(s1) + _tcslen(s2) + 3) * sizeof (TCHAR)); + + /* JPP 20-Jul-1998 added error checking */ + if (dp == NULL) + { + error_out_of_memory(); + return NULL; + } + + if (s1 && *s1) + { + s1 = stpcpy (dp, s1); + *s1++ = _T('\0'); + } + else + s1 = dp; + + while (*s2) + { + if (_istspace (*s2) || _tcschr (_T(",;"), *s2)) + { + *s1++ = _T('\0'); + s2++; + while (*s2 && _tcschr (_T(" ,;"), *s2)) + s2++; + continue; + } + + if ((*s2 == _T('"')) || (*s2 == _T('\''))) + { + TCHAR st = *s2; + + do + *s1++ = *s2++; + while (*s2 && (*s2 != st)); + } + + *s1++ = *s2++; + } + + *s1++ = _T('\0'); + *s1 = _T('\0'); + + return dp; +} + +/* HBP_002 } */ + + +/* + * If a batch file is current, exits it, freeing the context block and + * chaining back to the previous one. + * + * If no new batch context is found, sets ECHO back ON. + * + * If the parameter is non-null or not empty, it is printed as an exit + * message + */ + +VOID ExitBatch (LPTSTR msg) +{ +#ifdef _DEBUG + DebugPrintf ("ExitBatch: (\'%s\')\n", msg); +#endif + + if (bc) + { + LPBATCH_CONTEXT t = bc; + + if (bc->hBatchFile) + { + CloseHandle (bc->hBatchFile); + bc->hBatchFile = INVALID_HANDLE_VALUE; + } + + if (bc->params) + free(bc->params); + +/* HBP_002 { FOR command support */ + + if (bc->forproto) + free(bc->forproto); + + if (bc->ffind) + free(bc->ffind); + +/* HBP_002 } */ + +/* HBP_003 { fix echo restore */ + /* Preserve echo state across batch calls */ + bEcho = bc->bEcho; + +/* HBP_003 fix echo restore } */ + + bc = bc->prev; + free(t); + } + +/* HBP_001 } */ + + if (msg && *msg) + ConOutPrintf ("%s\n", msg); +} + + +/* + * Start batch file execution + * + * The firstword parameter is the full filename of the batch file. + * + */ + +BOOL Batch (LPTSTR fullname, LPTSTR firstword, LPTSTR param) +{ + HANDLE hFile; + + hFile = CreateFile (fullname, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | + FILE_FLAG_SEQUENTIAL_SCAN, NULL); + +#ifdef _DEBUG + DebugPrintf ("Batch: (\'%s\', \'%s\', \'%s\') hFile = %x\n", + fullname, firstword, param, hFile); +#endif + + if (hFile == INVALID_HANDLE_VALUE) + { + ConErrPrintf (_T("Error opening batch file\n")); + return FALSE; + } + +/* HBP_002 { FOR command support */ + + /* Kill any and all FOR contexts */ + while (bc && bc->forvar) + ExitBatch (NULL); + +/* HBP_002 } */ + + if (bc == NULL) + { + /* No curent batch file, create a new context */ + LPBATCH_CONTEXT n = (LPBATCH_CONTEXT)malloc (sizeof(BATCH_CONTEXT)); + + if (n == NULL) + { + /* JPP 20-Jul-1998 added error checking */ + error_out_of_memory (); + return FALSE; + } + + n->prev = bc; + bc = n; + } + else if (bc->hBatchFile != INVALID_HANDLE_VALUE) + { + /* Then we are transferring to another batch */ + CloseHandle (bc->hBatchFile); + bc->hBatchFile = INVALID_HANDLE_VALUE; + free (bc->params); + } + + bc->hBatchFile = hFile; + bc->bEcho = bEcho; /* Preserve echo across batch calls [HBP_001] */ + bc->shiftlevel = 0; + + /* HBP_002 { FOR command support */ + bc->ffind = NULL; + bc->forvar = _T('\0'); + bc->forproto = NULL; + bc->params = BatchParams (firstword, param); + /* HBP_002 } */ + + return TRUE; +} + + +/* + * Read and return the next executable line form the current batch file + * + * If no batch file is current or no further executable lines are found + * return NULL. + * + * Here we also look out for FOR bcontext structures which trigger the + * FOR expansion code. + * + * Set eflag to 0 if line is not to be echoed else 1 + */ + +LPTSTR ReadBatchLine (LPBOOL bLocalEcho) +{ + HANDLE hFind = INVALID_HANDLE_VALUE; + LPTSTR first; + LPTSTR ip; + + /* No batch */ + if (bc == NULL) + return NULL; + +#ifdef _DEBUG + DebugPrintf ("ReadBatchLine ()\n"); +#endif + + while (1) + { + /* User halt */ + if (CheckCtrlBreak (BREAK_BATCHFILE)) + { + while (bc) + ExitBatch (NULL); + return NULL; + } + + /* HBP_002 { FOR command support */ + /* No batch */ + if (bc == NULL) + return NULL; + + /* If its a FOR context... */ + if (bc->forvar) + { + LPTSTR sp = bc->forproto; /* pointer to prototype command */ + LPTSTR dp = textline; /* Place to expand protoype */ + LPTSTR fv = FindArg (0); /* Next list element */ + + /* End of list so... */ + if ((fv == NULL) || (*fv == _T('\0'))) + { + /* just exit this context */ + ExitBatch (NULL); + continue; + } + + if (_tcscspn (fv, _T("?*")) == _tcslen (fv)) + { + /* element is wild file */ + bc->shiftlevel++; /* No use it and shift list */ + } + else + { + /* Wild file spec, find first (or next) file name */ + if (bc->ffind) + { + /* First already done so do next */ + fv = FindNextFile (hFind, bc->ffind) ? bc->ffind->cFileName : NULL; + } + else + { + /* For first find, allocate a find first block */ + if ((bc->ffind = (LPWIN32_FIND_DATA)malloc (sizeof (WIN32_FIND_DATA))) == NULL) + { + error_out_of_memory(); /* JPP 20-Jul-1998 added error checking */ + return NULL; + } + + hFind = FindFirstFile (fv, bc->ffind); + fv = !(hFind==INVALID_HANDLE_VALUE) ? bc->ffind->cFileName : NULL; + } + + if (fv == NULL) + { + /* Null indicates no more files.. */ + free (bc->ffind); /* free the buffer */ + bc->ffind = NULL; + bc->shiftlevel++; /* On to next list element */ + continue; + } + } + + /* At this point, fv points to parameter string */ + while (*sp) + { + if ((*sp == _T('%')) && (*(sp + 1) == bc->forvar)) + { + /* replace % var */ + dp = stpcpy (dp, fv); + sp += 2; + } + else + { + /* Else just copy */ + *dp++ = *sp++; + } + } + + *dp = _T('\0'); + + *bLocalEcho = bEcho; + + return textline; + } + + /* HBP_002 } */ + + if (!FileGetString (bc->hBatchFile, textline, sizeof (textline))) + { +#ifdef _DEBUG + DebugPrintf (_T("ReadBatchLine(): Reached EOF!\n")); +#endif + /* End of file.... */ + ExitBatch (NULL); + + if (bc == NULL) + return NULL; + + continue; + } + +#ifdef _DEBUG + DebugPrintf (_T("ReadBatchLine(): textline: \'%s\'\n"), textline); +#endif + + /* Strip leading spaces and trailing space/control chars */ + for (first = textline; _istspace (*first); first++) + ; + + for (ip = first + _tcslen (first) - 1; _istspace (*ip) || _istcntrl (*ip); ip--) + ; + + *++ip = _T('\0'); + + /* ignore labels and empty lines */ + if (*first == _T(':') || *first == 0) + continue; + + if (*first == _T('@')) + { + /* don't echo this line */ + do + first++; + while (_istspace (*first)); + + *bLocalEcho = 0; + } + else + *bLocalEcho = bEcho; + + break; + } + + return first; +} diff --git a/reactos/apps/utils/cmd/batch.h b/reactos/apps/utils/cmd/batch.h new file mode 100644 index 00000000000..11324e38c61 --- /dev/null +++ b/reactos/apps/utils/cmd/batch.h @@ -0,0 +1,39 @@ +/* + * BATCH.H - A structure to preserve the context of a batch file + * + * + */ + + +typedef struct tagBATCHCONTEXT +{ + struct tagBATCHCONTEXT *prev; + LPWIN32_FIND_DATA ffind; + HANDLE hBatchFile; + LPTSTR forproto; + LPTSTR params; + INT shiftlevel; + BOOL bEcho; /* Preserve echo flag across batch calls [HBP_001] */ + TCHAR forvar; +} BATCH_CONTEXT, *LPBATCH_CONTEXT; + +/* HBP_002 } */ + + +/* The stack of current batch contexts. + * NULL when no batch is active + */ +extern LPBATCH_CONTEXT bc; + +extern BOOL bEcho; /* The echo flag */ + +#define BATCH_BUFFSIZE 2048 + +extern TCHAR textline[BATCH_BUFFSIZE]; /* Buffer for reading Batch file lines */ + + +LPTSTR FindArg (INT); +LPTSTR BatchParams (LPTSTR, LPTSTR); +VOID ExitBatch (LPTSTR); +BOOL Batch (LPTSTR, LPTSTR, LPTSTR); +LPTSTR ReadBatchLine (LPBOOL); diff --git a/reactos/apps/utils/cmd/beep.c b/reactos/apps/utils/cmd/beep.c new file mode 100644 index 00000000000..9f9834c5775 --- /dev/null +++ b/reactos/apps/utils/cmd/beep.c @@ -0,0 +1,56 @@ +/* + * BEEP.C - beep internal command. + * + * + * History: + * + * 16 Jul 1998 (Hans B Pufal) + * started. + * + * 16 Jul 1998 (John P Price) + * Separated commands into individual files. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 14-Jan-1999 (Eric Kohl ) + * Added help text ("beep /?"). + * Unicode ready! + * + * 20-Jan-1999 (Eric Kohl ) + * Redirection ready! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_BEEP + +#include +#include +#include + +#include "cmd.h" +#include "batch.h" + + +INT cmd_beep (LPTSTR cmd, LPTSTR param) +{ + if (_tcsncmp (param, _T("/?"), 2) == 0) + { + ConOutPuts (_T("Beep the speaker.\n\nBEEP")); + return 0; + } + +#if 0 + /* check if run in batch mode */ + if (bc == NULL) + return 1; +#endif + + MessageBeep (-1); + + return 0; +} +#endif diff --git a/reactos/apps/utils/cmd/bugs.txt b/reactos/apps/utils/cmd/bugs.txt new file mode 100644 index 00000000000..2cfa275c5a0 --- /dev/null +++ b/reactos/apps/utils/cmd/bugs.txt @@ -0,0 +1,15 @@ + **** Please report bugs to ekohl@abo.rhein-zeitung.de! **** + +Known bugs in CMD version 0.0.4 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +o let set work with or without the '=' sign. People like it that way. + (I don't know, if I should really fix this?) + +o command.com ignores control-c and control-break, which makes it difficult + to quit typing a long file, among other things + +o "alias v = dir" doesn't work because of the spaces. + + + **** Please report bugs to ekohl@abo.rhein-zeitung.de! **** diff --git a/reactos/apps/utils/cmd/call.c b/reactos/apps/utils/cmd/call.c new file mode 100644 index 00000000000..db5dd630217 --- /dev/null +++ b/reactos/apps/utils/cmd/call.c @@ -0,0 +1,93 @@ +/* + * CALL.C - call internal batch command. + * + * + * History: + * + * 16 Jul 1998 (Hans B Pufal) + * started. + * + * 16 Jul 1998 (John P Price) + * Seperated commands into individual files. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 04-Aug-1998 (Hans B Pufal) + * added lines to initialize for pointers (HBP004) This fixed the + * lock-up that happened sometimes when calling a batch file from + * another batch file. + * + * 07-Jan-1999 (Eric Kohl ) + * Added help text ("call /?") and cleaned up. + * + * 20-Jan-1999 (Eric Kohl ) + * Unicode and redirection safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include +#include + +#include "cmd.h" +#include "batch.h" + + +/* + * Perform CALL command. + * + * Allocate a new batch context and add it to the current chain. + * Call parsecommandline passing in our param string + * If No batch file was opened then remove our newly allocted + * context block. + */ + +INT cmd_call (LPTSTR cmd, LPTSTR param) +{ + LPBATCH_CONTEXT n = NULL; + +#ifdef _DEBUG + DebugPrintf ("cmd_call: (\'%s\',\'%s\')\n", cmd, param); +#endif + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Calls one batch program from another.\n\n" + "CALL [drive:][path]filename [batch-parameter]\n\n" + " batch-parameter Specifies any command-line information required by the\n" + " batch program.")); + return 0; + } + + n = (LPBATCH_CONTEXT)malloc (sizeof (BATCH_CONTEXT)); + + if (n == NULL) + { + error_out_of_memory (); + return 1; + } + + n->prev = bc; + bc = n; + + bc->hBatchFile = INVALID_HANDLE_VALUE; + bc->params = NULL; + bc->shiftlevel = 0; + bc->forvar = 0; /* HBP004 */ + bc->forproto = NULL; /* HBP004 */ + + ParseCommandLine (param); + + /* Wasn't a batch file so remove conext */ + if (bc->hBatchFile == INVALID_HANDLE_VALUE) + { + bc = bc->prev; + free (n); + } + + return 0; +} diff --git a/reactos/apps/utils/cmd/chcp.c b/reactos/apps/utils/cmd/chcp.c new file mode 100644 index 00000000000..6831e576906 --- /dev/null +++ b/reactos/apps/utils/cmd/chcp.c @@ -0,0 +1,90 @@ +/* + * CHCP.C - chcp internal command. + * + * + * History: + * + * 23-Dec-1998 (Eric Kohl ) + * Started. + * + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_CHCP + +#include +#include +#include + +#include "cmd.h" +#include "chcp.h" + + +INT CommandChcp (LPTSTR cmd, LPTSTR param) +{ + LPTSTR *arg; + INT args; + + /* print help */ + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Displays or sets the active code page number.\n\n" + "CHCP [nnn]\n\n" + " nnn Specifies the active code page number.\n\n" + "Type CHCP without a parameter to display the active code page number.")); + return 0; + } + + /* get parameters */ + arg = split (param, &args); + + if (args == 0) + { + /* display active code page number */ + ConOutPrintf ("Active code page: %u\n", GetConsoleCP ()); + } + else if (args >= 2) + { + /* too many parameters */ + ConErrPrintf ("Invalid parameter format - %s\n", param); + } + else + { + /* set active code page number */ + + UINT uOldCodePage; + UINT uNewCodePage; + + /* save old code page */ + uOldCodePage = GetConsoleCP (); + + uNewCodePage = (UINT)_ttoi (arg[0]); + + if (uNewCodePage == 0) + { + ConErrPrintf ("Parameter format incorrect - %s\n", arg[0]); + + } + else + { + if (!SetConsoleCP (uNewCodePage)) + { + ConErrPrintf ("Invalid code page\n"); + } + else + { + SetConsoleOutputCP (uNewCodePage); + InitLocale (); + } + } + } + + freep (arg); + + return 0; +} + +#endif /* INCLUDE_CMD_CHCP */ \ No newline at end of file diff --git a/reactos/apps/utils/cmd/chcp.h b/reactos/apps/utils/cmd/chcp.h new file mode 100644 index 00000000000..11ff568dc59 --- /dev/null +++ b/reactos/apps/utils/cmd/chcp.h @@ -0,0 +1,8 @@ +/* prototypes for CHCP.C */ + + +#ifdef INCLUDE_CMD_CHCP + +INT CommandChcp (LPTSTR, LPTSTR); + +#endif \ No newline at end of file diff --git a/reactos/apps/utils/cmd/cls.c b/reactos/apps/utils/cmd/cls.c new file mode 100644 index 00000000000..2e27fcc0246 --- /dev/null +++ b/reactos/apps/utils/cmd/cls.c @@ -0,0 +1,67 @@ +/* + * CLS.C - clear screen internal command. + * + * + * History: + * + * 07/27/1998 (John P. Price) + * started. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 04-Dec-1998 (Eric Kohl ) + * Changed to Win32 console app. + * + * 08-Dec-1998 (Eric Kohl ) + * Added help text ("/?"). + * + * 14-Jan-1998 (Eric Kohl ) + * Unicode ready! + * + * 20-Jan-1998 (Eric Kohl ) + * Redirection ready! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_CLS + +#include +#include +#include + +#include "cmd.h" + + +INT cmd_cls (LPTSTR cmd, LPTSTR param) +{ + DWORD dwWritten; + CONSOLE_SCREEN_BUFFER_INFO csbi; + COORD coPos; + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Clears the screen.\n\nCLS")); + return 0; + } + + GetConsoleScreenBufferInfo (hOut, &csbi); + + coPos.X = 0; + coPos.Y = 0; + FillConsoleOutputAttribute (hOut, wColor, + (csbi.dwSize.X)*(csbi.dwSize.Y), + coPos, &dwWritten); + FillConsoleOutputCharacter (hOut, _T(' '), + (csbi.dwSize.X)*(csbi.dwSize.Y), + coPos, &dwWritten); + SetConsoleCursorPosition (hOut, coPos); + + bIgnoreEcho = TRUE; + + return 0; +} +#endif diff --git a/reactos/apps/utils/cmd/cmd.c b/reactos/apps/utils/cmd/cmd.c index 22211f73308..2841c33dec0 100644 --- a/reactos/apps/utils/cmd/cmd.c +++ b/reactos/apps/utils/cmd/cmd.c @@ -1,158 +1,980 @@ -#include +/* + * CMD.C - command-line interface. + * + * + * History: + * + * 17 Jun 1994 (Tim Norman) + * started. + * + * 08 Aug 1995 (Matt Rains) + * I have cleaned up the source code. changes now bring this source + * into guidelines for recommended programming practice. + * + * A added the the standard FreeDOS GNU licence test to the + * initialize() function. + * + * Started to replace puts() with printf(). this will help + * standardize output. please follow my lead. + * + * I have added some constants to help making changes easier. + * + * 15 Dec 1995 (Tim Norman) + * major rewrite of the code to make it more efficient and add + * redirection support (finally!) + * + * 06 Jan 1996 (Tim Norman) + * finished adding redirection support! Changed to use our own + * exec code (MUCH thanks to Svante Frey!!) + * + * 29 Jan 1996 (Tim Norman) + * added support for CHDIR, RMDIR, MKDIR, and ERASE, as per + * suggestion of Steffan Kaiser + * + * changed "file not found" error message to "bad command or + * filename" thanks to Dustin Norman for noticing that confusing + * message! + * + * changed the format to call internal commands (again) so that if + * they want to split their commands, they can do it themselves + * (none of the internal functions so far need that much power, anyway) + * + * 27 Aug 1996 (Tim Norman) + * added in support for Oliver Mueller's ALIAS command + * + * 14 Jun 1997 (Steffan Kaiser) + * added ctrl-break handling and error level + * + * 16 Jun 1998 (Rob Lake) + * Runs command.com if /P is specified in command line. Command.com + * also stays permanent. If /C is in the command line, starts the + * program next in the line. + * + * 21 Jun 1998 (Rob Lake) + * Fixed up /C so that arguments for the program + * + * 08-Jul-1998 (John P. Price) + * Now sets COMSPEC environment variable + * misc clean up and optimization + * added date and time commands + * changed to using spawnl instead of exec. exec does not copy the + * environment to the child process! + * + * 14 Jul 1998 (Hans B Pufal) + * Reorganised source to be more efficient and to more closely + * follow MS-DOS conventions. (eg %..% environment variable + * replacement works form command line as well as batch file. + * + * New organisation also properly support nested batch files. + * + * New command table structure is half way towards providing a + * system in which COMMAND will find out what internal commands + * are loaded + * + * 24 Jul 1998 (Hans B Pufal) [HBP_003] + * Fixed return value when called with /C option + * + * 27 Jul 1998 John P. Price + * added config.h include + * + * 28 Jul 1998 John P. Price + * added showcmds function to show commands and options available + * + * 07-Aug-1998 (John P Price ) + * Fixed carrage return output to better match MSDOS with echo + * on or off. (marked with "JPP 19980708") + * + * 07-Dec-1998 (Eric Kohl ) + * First ReactOS release. + * Extended length of commandline buffers to 512. + * + * 13-Dec-1998 (Eric Kohl ) + * Added COMSPEC environment variable. + * Added "/t" support (color) on cmd command line. + * + * 07-Jan-1999 (Eric Kohl ) + * Added help text ("cmd /?"). + * + * 25-Jan-1999 (Eric Kohl ) + * Unicode and redirection safe! + * Fixed redirections and piping. + * Piping is based on temporary files, but basic support + * for anonymous pipes already exists. + * + * 27-Jan-1999 (Eric Kohl ) + * Replaced spawnl() by CreateProcess(). + */ + +// #define WIN32_LEAN_AND_MEAN + +#include "config.h" + #include +// #include +#include +#include -HANDLE stdin; -HANDLE stdout; +#include "cmd.h" +#include "batch.h" -void Console_puts(char* str) +#define CMDLINE_LENGTH 512 + + +BOOL bExit = FALSE; /* indicates EXIT was typed */ +BOOL bCanExit = TRUE; /* indicates if this shell is exitable */ +BOOL bCtrlBreak = FALSE; /* Ctrl-Break or Ctrl-C hit */ +BOOL bIgnoreEcho = FALSE; /* Ignore 'newline' before 'cls' */ +INT errorlevel = 0; /* Errorlevel of last launched external program */ +OSVERSIONINFO osvi; +HANDLE hIn; +HANDLE hOut; + +#ifdef INCLUDE_CMD_COLOR +WORD wColor = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN; /* current color */ +WORD wDefColor = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN; /* default color */ +#endif + + +extern COMMAND cmds[]; /* The internal command table */ + + +/* + * is character a delimeter when used on first word? + * + */ + +static BOOL IsDelimiter (TCHAR c) { - ULONG nchar; - - WriteConsole(stdout, - str, - strlen(str), - &nchar, - NULL); + return (c == _T('/') || c == _T('=') || c == _T('\0') || _istspace (c)); } -void Console_printf(char* fmt, ...) -{ - char buffer[255]; - va_list vargs; - va_start(vargs,fmt); - vsprintf(buffer,fmt,vargs); - Console_puts(buffer); - va_end(vargs); +/* + * This command (in first) was not found in the command table + * + * first - first word on command line + * rest - rest of command line + */ + +static VOID +Execute (LPTSTR first, LPTSTR rest) +{ + TCHAR szFullName[MAX_PATH]; + + /* check for a drive change */ + if (!_tcscmp (first + 1, _T(":")) && _istalpha (*first)) + { + TCHAR szPath[MAX_PATH]; + + _tcscpy (szPath, _T("A:")); + szPath[0] = _totupper (*first); + SetCurrentDirectory (szPath); + GetCurrentDirectory (MAX_PATH, szPath); + if (szPath[0] != (TCHAR)_totupper (*first)) + ConErrPuts (INVALIDDRIVE); + + return; + } + + /* get the PATH environment variable and parse it */ + /* search the PATH environment variable for the binary */ + find_which (first, szFullName); + + if (szFullName[0] == _T('\0')) + { + error_bad_command (); + return; + } + + /* check if this is a .BAT or .CMD file */ + if (!_tcsicmp (_tcsrchr (szFullName, _T('.')), _T(".bat")) || + !_tcsicmp (_tcsrchr (szFullName, _T('.')), _T(".cmd"))) + { +#ifdef _DEBUG + DebugPrintf ("[BATCH: %s %s]\n", szFullName, rest); +#endif + Batch (szFullName, first, rest); + } + else + { + /* exec the program */ + TCHAR szFullCmdLine [1024]; + PROCESS_INFORMATION prci; + STARTUPINFO stui; + DWORD dwError = 0; + +#ifdef _DEBUG + DebugPrintf ("[EXEC: %s %s]\n", szFullName, rest); +#endif + /* build command line for CreateProcess() */ + _tcscpy (szFullCmdLine, szFullName); + _tcscat (szFullCmdLine, " "); + _tcscat (szFullCmdLine, rest); + + /* fill startup info */ + memset (&stui, 0, sizeof (STARTUPINFO)); + stui.cb = sizeof (STARTUPINFO); + stui.dwFlags = STARTF_USESHOWWINDOW; + stui.wShowWindow = SW_SHOWDEFAULT; + + if (CreateProcess (NULL, szFullCmdLine, NULL, NULL, FALSE, + 0, NULL, NULL, &stui, &prci)) + { + WaitForSingleObject (prci.hProcess, INFINITE); + GetExitCodeProcess (prci.hProcess, &errorlevel); + CloseHandle (prci.hThread); + CloseHandle (prci.hProcess); + } + else + { + ErrorMessage (GetLastError (), + "Error executing CreateProcess()!!\n"); + } + } } -void Console_getline(PCH Prompt, PCH Output, DWORD OutputLength) + +/* + * look through the internal commands and determine whether or not this + * command is one of them. If it is, call the command. If not, call + * execute to run it as an external program. + * + * line - the command line of the program to run + * + */ + +static VOID +DoCommand (LPTSTR line) { - char ch; - DWORD nbytes; + TCHAR com[MAX_PATH]; /* the first word in the command */ + LPTSTR cp = com; + LPTSTR cstart; + LPTSTR rest = line; /* pointer to the rest of the command line */ + INT cl; + LPCOMMAND cmdptr; - Console_puts(Prompt); + /* Skip over initial white space */ + while (isspace (*rest)) + rest++; - ReadConsole(stdin, - Output, - OutputLength, - &nbytes, - NULL); - Output[nbytes-2]=0; + cstart = rest; + + /* Anything to do ? */ + if (*rest) + { + /* Copy over 1st word as lower case */ + while (!IsDelimiter (*rest)) + *cp++ = _totlower (*rest++); + + /* Terminate first word */ + *cp = _T('\0'); + + /* Skip over whitespace to rest of line */ + while (_istspace (*rest)) + rest++; + + /* Scan internal command table */ + for (cmdptr = cmds;; cmdptr++) + { + /* If end of table execute ext cmd */ + if (cmdptr->name == NULL) + { + Execute (com, rest); + break; + } + + if (!_tcscmp (com, cmdptr->name)) + { + cmdptr->func (com, rest); + break; + } + + /* The following code handles the case of commands like CD which + * are recognised even when the command name and parameter are + * not space separated. + * + * e.g dir.. + * cd\freda + */ + + /* Get length of command name */ + cl = _tcslen (cmdptr->name); + + if ((cmdptr->flags & CMD_SPECIAL) && + (!_tcsncmp (cmdptr->name, com, cl)) && + (_tcschr (_T("\\.-"), *(com + cl)))) + { + /* OK its one of the specials...*/ + + /* Terminate first word properly */ + com[cl] = _T('\0'); + + /* Call with new rest */ + cmdptr->func (com, cstart + cl); + break; + } + } + } } -void func_cd(char* s) + +/* + * process the command line and execute the appropriate functions + * full input/output redirection and piping are supported + */ + +VOID ParseCommandLine (LPTSTR s) { - Console_printf("Changing directory to %s\n",s); - if (!SetCurrentDirectory(s)) - { - Console_puts("Failed to change to directory\n"); - } +#ifdef FEATURE_REDIRECTION + TCHAR in[CMDLINE_LENGTH] = ""; + TCHAR out[CMDLINE_LENGTH] = ""; + TCHAR err[CMDLINE_LENGTH] = ""; + TCHAR szTempPath[MAX_PATH] = _T(".\\"); + TCHAR szFileName[2][MAX_PATH] = {"", ""}; + HANDLE hFile[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}; + LPTSTR t = NULL; + INT num = 0; + INT nRedirFlags = 0; + + HANDLE hOldConIn; + HANDLE hOldConOut; + HANDLE hOldConErr; +#endif /* FEATURE_REDIRECTION */ + +#ifdef _DEBUG + DebugPrintf ("ParseCommandLine: (\'%s\')]\n", s); +#endif /* _DEBUG */ + +#ifdef FEATURE_ALIASES + /* expand all aliases */ + ExpandAlias (s, CMDLINE_LENGTH); +#endif /* FEATURE_ALIAS */ + +#ifdef FEATURE_REDIRECTION + /* find the temp path to store temporary files */ + GetTempPath (MAX_PATH, szTempPath); + if (szTempPath[_tcslen (szTempPath) - 1] != _T('\\')) + _tcscat (szTempPath, _T("\\")); + + /* get the redirections from the command line */ + num = GetRedirection (s, in, out, err, &nRedirFlags); + + /* more efficient, but do we really need to do this? */ + for (t = in; _istspace (*t); t++) + ; + _tcscpy (in, t); + + for (t = out; _istspace (*t); t++) + ; + _tcscpy (out, t); + + for (t = err; _istspace (*t); t++) + ; + _tcscpy (err, t); + + /* Set up the initial conditions ... */ + /* preserve STDIN, STDOUT and STDERR handles */ + hOldConIn = GetStdHandle (STD_INPUT_HANDLE); + hOldConOut = GetStdHandle (STD_OUTPUT_HANDLE); + hOldConErr = GetStdHandle (STD_ERROR_HANDLE); + + /* redirect STDIN */ + if (in[0]) + { + HANDLE hFile; + + hFile = CreateFile (in, GENERIC_READ, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + ConErrPrintf ("Can't redirect input from file %s\n", in); + return; + } + + if (!SetStdHandle (STD_INPUT_HANDLE, hFile)) + { + ConErrPrintf ("Can't redirect input from file %s\n", in); + return; + } +#ifdef _DEBUG + DebugPrintf (_T("Input redirected from: %s\n"), in); +#endif + } + + /* Now do all but the last pipe command */ + *szFileName[0] = '\0'; + hFile[0] = INVALID_HANDLE_VALUE; + + while (num-- > 1) + { + /* Create unique temporary file name */ + GetTempFileName (szTempPath, "CMD", 0, szFileName[1]); + + /* Set current stdout to temporary file */ + hFile[1] = CreateFile (szFileName[1], GENERIC_WRITE, 0, NULL, + TRUNCATE_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL); + SetStdHandle (STD_OUTPUT_HANDLE, hFile[1]); + + DoCommand (s); + + /* close stdout file */ + SetStdHandle (STD_OUTPUT_HANDLE, hOldConOut); + if ((hFile[1] != INVALID_HANDLE_VALUE) && (hFile[1] != hOldConOut)) + { + CloseHandle (hFile[1]); + hFile[1] = INVALID_HANDLE_VALUE; + } + + /* close old stdin file */ + SetStdHandle (STD_INPUT_HANDLE, hOldConIn); + if ((hFile[0] != INVALID_HANDLE_VALUE) && (hFile[0] != hOldConIn)) + { + /* delete old stdin file, if it is a real file */ + CloseHandle (hFile[0]); + hFile[0] = INVALID_HANDLE_VALUE; + DeleteFile (szFileName[0]); + *szFileName[0] = _T('\0'); + } + + /* copy stdout file name to stdin file name */ + _tcscpy (szFileName[0], szFileName[1]); + *szFileName[1] = _T('\0'); + + /* open new stdin file */ + hFile[0] = CreateFile (szFileName[0], GENERIC_READ, 0, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL); + SetStdHandle (STD_INPUT_HANDLE, hFile[0]); + + s = s + _tcslen (s) + 1; + } + + /* Now set up the end conditions... */ + /* redirect STDOUT */ + if (out[0]) + { + /* Final output to here */ + HANDLE hFile; + + hFile = CreateFile (out, GENERIC_WRITE, 0, NULL, + (nRedirFlags & OUTPUT_APPEND) ? OPEN_ALWAYS : CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + ConErrPrintf ("Can't redirect to file %s\n", out); + return; + } + + if (!SetStdHandle (STD_OUTPUT_HANDLE, hFile)) + { + ConErrPrintf ("Can't redirect to file %s\n", out); + return; + } + + if (nRedirFlags & OUTPUT_APPEND) + { + LONG lHighPos = 0; + + if (GetFileType (hFile) == FILE_TYPE_DISK) + SetFilePointer (hFile, 0, &lHighPos, FILE_END); + } +#ifdef _DEBUG + DebugPrintf (_T("Output redirected to: %s\n"), out); +#endif + } + else if (hOldConOut != INVALID_HANDLE_VALUE) + { + /* Restore original stdout */ + HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE); + SetStdHandle (STD_OUTPUT_HANDLE, hOldConOut); + if (hOldConOut != hOut) + CloseHandle (hOut); + hOldConOut = INVALID_HANDLE_VALUE; + } + + /* redirect STDERR */ + if (err[0]) + { + /* Final output to here */ + HANDLE hFile; + + if (!_tcscmp (err, out)) + { +#ifdef _DEBUG + DebugPrintf (_T("Stdout and stderr will use the same file!!\n")); +#endif + DuplicateHandle (GetCurrentProcess (), GetStdHandle (STD_OUTPUT_HANDLE), GetCurrentProcess (), + &hFile, 0, TRUE, DUPLICATE_SAME_ACCESS); + } + else + { + hFile = + CreateFile (err, GENERIC_WRITE, 0, NULL, + (nRedirFlags & ERROR_APPEND) ? OPEN_ALWAYS : CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + ConErrPrintf ("Can't redirect to file %s\n", err); + return; + } + } + if (!SetStdHandle (STD_ERROR_HANDLE, hFile)) + { + ConErrPrintf ("Can't redirect to file %s\n", err); + return; + } + + if (nRedirFlags & ERROR_APPEND) + { + LONG lHighPos = 0; + + if (GetFileType (hFile) == FILE_TYPE_DISK) + SetFilePointer (hFile, 0, &lHighPos, FILE_END); + } +#ifdef _DEBUG + DebugPrintf (_T("Error redirected to: %s\n"), err); +#endif + } + else if (hOldConErr != INVALID_HANDLE_VALUE) + { + /* Restore original stderr */ + HANDLE hErr = GetStdHandle (STD_ERROR_HANDLE); + SetStdHandle (STD_ERROR_HANDLE, hOldConErr); + if (hOldConErr != hErr) + CloseHandle (hErr); + hOldConErr = INVALID_HANDLE_VALUE; + } +#endif + + /* process final command */ + DoCommand (s); + +#ifdef FEATURE_REDIRECTION + /* close old stdin file */ +#if 0 /* buggy implementation */ + SetStdHandle (STD_INPUT_HANDLE, hOldConIn); + if ((hFile[0] != INVALID_HANDLE_VALUE) && + (hFile[0] != hOldConIn)) + { + /* delete old stdin file, if it is a real file */ + CloseHandle (hFile[0]); + hFile[0] = INVALID_HANDLE_VALUE; + DeleteFile (szFileName[0]); + *szFileName[0] = _T('\0'); + } + + /* Restore original STDIN */ + if (hOldConIn != INVALID_HANDLE_VALUE) + { + HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE); + SetStdHandle (STD_INPUT_HANDLE, hOldConIn); + if (hOldConIn != hIn) + CloseHandle (hIn); + hOldConIn = INVALID_HANDLE_VALUE; + } + else + { +#ifdef _DEBUG + DebugPrintf (_T("Can't restore STDIN! Is invalid!!\n"), out); +#endif + } +#endif /* buggy implementation */ + + + if (hOldConIn != INVALID_HANDLE_VALUE) + { + HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE); + SetStdHandle (STD_INPUT_HANDLE, hOldConIn); + if (hIn == INVALID_HANDLE_VALUE) + { +#ifdef _DEBUG + DebugPrintf (_T("Previous STDIN is invalid!!\n")); +#endif + } + else + { + if (GetFileType (hIn) == FILE_TYPE_DISK) + { + if (hFile[0] == hIn) + { + CloseHandle (hFile[0]); + hFile[0] = INVALID_HANDLE_VALUE; + DeleteFile (szFileName[0]); + *szFileName[0] = _T('\0'); + } + else + { +#ifdef _DEBUG + DebugPrintf (_T("hFile[0] and hIn dont match!!!\n")); +#endif + + } + } + } + } + + + /* Restore original STDOUT */ + if (hOldConOut != INVALID_HANDLE_VALUE) + { + HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE); + SetStdHandle (STD_OUTPUT_HANDLE, hOldConOut); + if (hOldConOut != hOut) + CloseHandle (hOut); + hOldConOut = INVALID_HANDLE_VALUE; + } + + /* Restore original STDERR */ + if (hOldConErr != INVALID_HANDLE_VALUE) + { + HANDLE hErr = GetStdHandle (STD_ERROR_HANDLE); + SetStdHandle (STD_ERROR_HANDLE, hOldConErr); + if (hOldConErr != hErr) + CloseHandle (hErr); + hOldConErr = INVALID_HANDLE_VALUE; + } +#endif /* FEATURE_REDIRECTION */ } -void func_dir(char* s) + +/* + * do the prompt/input/process loop + * + */ + +static INT +ProcessInput (BOOL bFlag) { - HANDLE shandle; - WIN32_FIND_DATA FindData; + TCHAR commandline[CMDLINE_LENGTH]; + TCHAR readline[CMDLINE_LENGTH]; + LPTSTR tp; + LPTSTR ip; + LPTSTR cp; - shandle = FindFirstFile("*.*",&FindData); + /* JPP 19980807 - changed name so not to conflict with echo global */ + BOOL bEchoThisLine; - if (shandle==INVALID_HANDLE_VALUE) - { - return; - } - do - { - Console_printf("Scanning %s\n",FindData.cFileName); - } while(FindNextFile(shandle,&FindData)); -} + do + { + /* if no batch input then... */ + if (!(ip = ReadBatchLine (&bEchoThisLine))) + { + if (bFlag) + return 0; -int is_builtin(char* name, char* args) -{ - if (strcmp(name,"dir")==0) - { - func_dir(args); - return(1); - } - if (strcmp(name,"cd")==0) - { - func_cd(args); - return(1); - } - return(0); -} + ReadCommand (readline, CMDLINE_LENGTH); + ip = readline; + bEchoThisLine = FALSE; + } -int process_command(char* str) -{ - char* name; - char* args; - PROCESS_INFORMATION pi; - STARTUPINFO si; - char process_arg[255]; + cp = commandline; + while (*ip) + { + if (*ip == _T('%')) + { + switch (*++ip) + { + case _T('%'): + *cp++ = *ip++; + break; - if (strcmp(str,"exit")==0) - { - return(1); - } + case _T('0'): + case _T('1'): + case _T('2'): + case _T('3'): + case _T('4'): + case _T('5'): + case _T('6'): + case _T('7'): + case _T('8'): + case _T('9'): + if (tp = FindArg (*ip - _T('0'))) + { + cp = stpcpy (cp, tp); + ip++; + } + else + *cp++ = _T('%'); + break; - name = strtok(str," \t"); - args = strtok(NULL,""); + case _T('?'): + cp += wsprintf (cp, _T("%u"), errorlevel); + ip++; + break; - if (is_builtin(name,args)) - { - return(0); - } - memset(&si,0,sizeof(STARTUPINFO)); - si.cb=sizeof(STARTUPINFO); - si.lpTitle=strdup(name); + default: + if (tp = _tcschr (ip, _T('%'))) + { + char evar[512]; + *tp = _T('\0'); - strcpy(process_arg,name); - strcat(process_arg," "); - if(args!=NULL) - { - strcat(process_arg,args); - } - Console_printf("name '%s' process_arg '%s'\n",name,process_arg); - if (!CreateProcess(NULL,process_arg,NULL,NULL,FALSE, - CREATE_NEW_CONSOLE, - NULL,NULL,&si,&pi)) - { - Console_printf("Failed to execute process\n"); - } - return(0); -} + /* FIXME: This is just a quick hack!! */ + /* Do a proper memory allocation!! */ + if (GetEnvironmentVariable (ip, evar, 512)) + cp = stpcpy (cp, evar); -void build_prompt(char* prompt) -{ - int len; + ip = tp + 1; + } + break; + } + continue; + } - len = GetCurrentDirectory(255,prompt); - strcat(prompt,">"); -} + if (_istcntrl (*ip)) + *ip = _T(' '); + *cp++ = *ip++; + } -void command_loop() -{ - char line[255]; - char prompt[255]; - int do_exit = 0; + *cp = _T('\0'); - while (!do_exit) - { - build_prompt(prompt); - Console_getline(prompt,line,255); - Console_printf("Processing command '%s'\n",line); - do_exit = process_command(line); - } -} + /* strip trailing spaces */ + while ((--cp >= commandline) && _istspace (*cp)) + ; -int STDCALL WinMain (HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow) -{ - AllocConsole(); - stdin = GetStdHandle(STD_INPUT_HANDLE); - stdout = GetStdHandle(STD_OUTPUT_HANDLE); + *(cp + 1) = _T('\0'); - command_loop(); + /* JPP 19980807 */ + /* Echo batch file line */ + if (bEchoThisLine) + { + PrintPrompt (); + ConOutPuts (commandline); + } + + if (*commandline) + { + ParseCommandLine (commandline); + if (bEcho && !bIgnoreEcho) + ConOutChar ('\n'); + bIgnoreEcho = FALSE; + } + } + while (!bCanExit || !bExit); return 0; } + + +/* + * control-break handler. + */ +BOOL BreakHandler (DWORD dwCtrlType) +{ + if ((dwCtrlType == CTRL_C_EVENT) || + (dwCtrlType == CTRL_BREAK_EVENT)) + { + bCtrlBreak = TRUE; /* indicate the break condition */ + return TRUE; + } + return FALSE; +} + + +/* + * show commands and options that are available. + * + */ +static VOID +ShowCommands (VOID) +{ + LPCOMMAND cmdptr; + INT y; + + ConOutPrintf (_T("\nInternal commands available:\n")); + y = 0; + cmdptr = cmds; + while (cmdptr->name) + { + if (++y == 8) + { + ConOutPuts (cmdptr->name); + y = 0; + } + else + ConOutPrintf (_T("%-10s"), cmdptr->name); + + cmdptr++; + } + + if (y != 0) + ConOutChar ('\n'); + + /* print feature list */ + ConOutPuts ("\nFeatures available:"); +#ifdef FEATURE_ALIASES + ConOutPuts (" [aliases]"); +#endif +#ifdef FEATURE_HISTORY + ConOutPuts (" [history]"); +#endif +#ifdef FEATURE_UNIX_FILENAME_COMPLETION + ConOutPuts (" [unix filename completion]"); +#endif +#ifdef FEATURE_DIRECTORY_STACK + ConOutPuts (" [directory stack]"); +#endif +#ifdef FEATURE_REDIRECTION + ConOutPuts (" [redirections and piping]"); +#endif + ConOutChar ('\n'); +} + + +/* + * set up global initializations and process parameters + * + * argc - number of parameters to command.com + * argv - command-line parameters + * + */ +static VOID Initialize (int argc, char *argv[]) +{ + INT i; + + /* Added by Rob Lake 06/16/98. This enables the command.com + * to run the autoexec.bat at startup */ + +#ifdef _DEBUG + INT x; + + DebugPrintf ("[command args:\n"); + for (x = 0; x < argc; x++) + { + DebugPrintf ("%d. %s\n", x, argv[x]); + } + DebugPrintf ("]\n"); +#endif + + /* get version information */ + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx (&osvi); + + InitLocale (); + + /* get default input and output console handles */ + hOut = GetStdHandle (STD_OUTPUT_HANDLE); + hIn = GetStdHandle (STD_INPUT_HANDLE); + +#ifdef INCLUDE_CMD_CHDIR + InitLastPath (); +#endif + + if (argc >= 2) + { + if (!_tcsncmp (argv[1], _T("/?"), 2)) + { + ConOutPuts (_T("Starts a new instance of the ReactOS command line interpreter\n\n" + "CMD [/P][/C]...\n\n" + " /P ...\n" + " /C ...")); + ExitProcess (0); + } + else + { + for (i = 1; i < argc; i++) + { + if (!_tcsicmp (argv[i], _T("/p"))) + { + if (!IsValidFileName (_T("\\autoexec.bat"))) + { +#ifdef INCLUDE_CMD_DATE + cmd_date ("", ""); +#endif +#ifdef INCLUDE_CMD_TIME + cmd_time ("", ""); +#endif + } + else + ParseCommandLine ("\\autoexec.bat"); + bCanExit = FALSE; + } + else if (!_tcsicmp (argv[i], _T("/c"))) + { + /* This just runs a program and exits, RL: 06/16,21/98 */ + char commandline[CMDLINE_LENGTH]; + ++i; + strcpy(commandline, argv[i]); + while (argv[++i]) + { + strcat(commandline, " "); + strcat(commandline, argv[i]); + } + + ParseCommandLine(commandline); + + /* HBP_003 { Fix return value when /C used }*/ + ExitProcess (ProcessInput (TRUE)); + } + +#ifdef INCLUDE_CMD_COLOR + else if (!_tcsnicmp (argv[i], _T("/t:"), 3)) + { + /* process /t (color) argument */ + wDefColor = (WORD)strtoul (&argv[i][3], NULL, 16); + wColor = wDefColor; + } +#endif + } + } + } + +#ifdef FEATURE_DIR_STACK + /* initialize directory stack */ + InitDirectoryStack (); +#endif + +#ifdef INCLUDE_CMD_COLOR + /* set default colors */ + SetScreenColor (wColor); +#endif + + ShortVersion (); + ShowCommands (); + + /* Set COMSPEC environment variable */ + SetEnvironmentVariable (_T("COMSPEC"), argv[0]); + + /* add ctrl handler */ + SetConsoleCtrlHandler (NULL, TRUE); +} + + +static VOID Cleanup (VOID) +{ + +#ifdef FEATURE_DIECTORY_STACK + /* destroy directory stack */ + DestroyDirectoryStack (); +#endif + +#ifdef INCLUDE_CMD_CHDIR + FreeLastPath (); +#endif + + /* remove ctrl handler */ +// SetConsoleCtrlHandler ((PHANDLER_ROUTINE)&BreakHandler, FALSE); +} + + +/* + * main function + */ +int main (int argc, char *argv[]) +{ + INT nExitCode; + + AllocConsole (); + SetFileApisToOEM (); + + /* check switches on command-line */ + Initialize (argc, argv); + + /* call prompt routine */ + nExitCode = ProcessInput (FALSE); + + /* do the cleanup */ + Cleanup (); + FreeConsole (); + + return nExitCode; +} diff --git a/reactos/apps/utils/cmd/cmd.h b/reactos/apps/utils/cmd/cmd.h new file mode 100644 index 00000000000..e34fffedb1d --- /dev/null +++ b/reactos/apps/utils/cmd/cmd.h @@ -0,0 +1,300 @@ +/* + * CMD.H - header file for the modules in CMD.EXE + * + * + * History: + * + * 7-15-95 Tim Norman + * started + * + * 06/29/98 (Rob Lake) + * Moved error messages in here + * + * 07/12/98 (Rob Lake) + * Moved more error messages here + * + * 30-Jul-1998 (John P Price ) + * Added compile date to version + */ + +// #define WIN32_LEAN_AND_MEAN + +#include +// #include + +#define SHELLVER "version 0.0.4 [" __DATE__"]" + +#define BREAK_BATCHFILE 1 +#define BREAK_OUTOFBATCH 2 +#define BREAK_INPUT 3 +#define BREAK_IGNORE 4 + +/* define some error messages */ +#define NOENVERR "ERROR: no environment" +#define INVALIDDRIVE "ERROR: invalid drive" +#define INVALIDFUNCTION "ERROR: invalid function" +#define ACCESSDENIED "ERROR: access denied" +#define BADENVIROMENT "ERROR: bad enviroment" +#define BADFORMAT "ERROR: bad format" +#define ERROR_E2BIG "ERROR: Argument list too long" +#define ERROR_EINVAL "ERROR: Invalid argument" + +#define SHELLINFO "ReactOS Command Line Interface" +#define USAGE "usage" + + +#define D_ON "on" +#define D_OFF "off" + + + +/* prototypes for CMD.C */ +extern HANDLE hOut; +extern HANDLE hIn; +extern WORD wColor; +extern WORD wDefColor; +extern BOOL bCtrlBreak; +extern BOOL bIgnoreEcho; +extern BOOL bExit; +extern int errorlevel; +extern SHORT maxx; +extern SHORT maxy; +extern OSVERSIONINFO osvi; + + +// VOID Execute (char *, char *); +void command(char *); +VOID ParseCommandLine (LPTSTR); +int c_brk(void); + + + + +/* prototypes for ALIAS.C */ +VOID ExpandAlias (char *, int); +INT cmd_alias (LPTSTR, LPTSTR); + + +/* prototyped for ATTRIB.C */ +INT cmd_attrib (LPTSTR, LPTSTR); + + +/* prototypes for CLS.C */ +INT cmd_cls (LPTSTR, LPTSTR); + + +/* prototypes for CMDINPUT.C */ +VOID ReadCommand (LPTSTR, INT); + + +/* prototypes for CMDTABLE.C */ +#define CMD_SPECIAL 1 +#define CMD_BATCHONLY 2 + +typedef struct tagCOMMAND +{ + LPTSTR name; + INT flags; + INT (*func) (LPTSTR, LPTSTR); +} COMMAND, *LPCOMMAND; + + +/* prototypes for COLOR.C */ +VOID SetScreenColor (WORD); +INT cmd_color (LPTSTR, LPTSTR); + + +/* prototypes for CONSOLE.C */ +#ifdef _DEBUG +VOID DebugPrintf (LPTSTR, ...); +#endif /* _DEBUG */ + +VOID ConInDummy (VOID); +VOID ConInKey (PINPUT_RECORD); + +VOID ConInString (LPTSTR, DWORD); + + +VOID ConOutChar (TCHAR); +VOID ConOutPuts (LPTSTR); +VOID ConOutPrintf (LPTSTR, ...); +VOID ConErrChar (TCHAR); +VOID ConErrPuts (LPTSTR); +VOID ConErrPrintf (LPTSTR, ...); + + +SHORT wherex (VOID); +SHORT wherey (VOID); +VOID goxy (SHORT, SHORT); + +VOID GetScreenSize (PSHORT, PSHORT); +VOID SetCursorType (BOOL, BOOL); + + +/* prototypes for COPY.C */ +INT cmd_copy (LPTSTR, LPTSTR); + + +/* prototypes for DATE.C */ +INT cmd_date (LPTSTR, LPTSTR); + + +/* prototypes for DEL.C */ +INT cmd_del (LPTSTR, LPTSTR); + + +/* prototypes for DIR.C */ +//int incline(int *line, unsigned flags); +INT cmd_dir (LPTSTR, LPTSTR); + + +/* prototypes for DIRSTACK.C */ +VOID InitDirectoryStack (VOID); +VOID DestroyDirectoryStack (VOID); +INT GetDirectoryStackDepth (VOID); +INT cmd_pushd (LPTSTR, LPTSTR); +INT cmd_popd (LPTSTR, LPTSTR); + + +/* Prototypes for ERROR.C */ +VOID ErrorMessage (DWORD, LPTSTR, ...); + +VOID error_no_pipe (VOID); +VOID error_bad_command (VOID); +VOID error_invalid_drive (VOID); +VOID error_req_param_missing (VOID); +VOID error_sfile_not_found (LPTSTR); +VOID error_file_not_found (VOID); +VOID error_path_not_found (VOID); +VOID error_too_many_parameters (LPTSTR); +VOID error_invalid_switch (TCHAR); +VOID error_invalid_parameter_format (LPTSTR); +VOID error_out_of_memory (VOID); +VOID error_syntax (LPTSTR); + +VOID msg_pause (VOID); + + +/* prototypes for FILECOMP.C */ +#ifdef FEATURE_UNIX_FILENAME_COMPLETION +VOID CompleteFilename (LPTSTR, INT); +INT ShowCompletionMatches (LPTSTR, INT); +#endif +#ifdef FEATURE_4NT_FILENAME_COMPLETION +#endif + + +/* prototypes for HISTORY.C */ +#ifdef FEATURE_HISTORY +VOID History (INT, LPTSTR); +#endif + + +/* prototypes for INTERNAL.C */ +VOID InitLastPath (VOID); +VOID FreeLastPath (VOID); +int cmd_chdir(char *, char *); +int cmd_mkdir(char *, char *); +int cmd_rmdir(char *, char *); +int internal_exit(char *, char *); +int cmd_rem(char *, char *); +int cmd_showcommands(char *, char *); + + +/* prototyped for LABEL.C */ +INT cmd_label (LPTSTR, LPTSTR); + + +/* prototypes for LOCALE.C */ +extern TCHAR cDateSeparator; +extern INT nDateFormat; +extern TCHAR cTimeSeparator; +extern INT nTimeFormat; +extern TCHAR aszDayNames[7][8]; +extern TCHAR cThousandSeparator; +extern TCHAR cDecimalSeparator; +extern INT nNumberGroups; + +VOID InitLocale (VOID); + + +/* Prototypes for MISC.C */ +TCHAR cgetchar (VOID); +BOOL CheckCtrlBreak (INT); +LPTSTR *split (LPTSTR, LPINT); +VOID freep (LPTSTR *); +LPTSTR stpcpy (LPTSTR, LPTSTR); +BOOL IsValidPathName (LPCTSTR); +BOOL IsValidFileName (LPCTSTR); +BOOL FileGetString (HANDLE, LPTSTR, INT); + + +/* prototypes for MOVE.C */ +INT cmd_move (LPTSTR, LPTSTR); + + +/* prototypes from PATH.C */ +INT cmd_path (LPTSTR, LPTSTR); + + +/* prototypes from PROMPT.C */ +VOID PrintPrompt (VOID); +INT cmd_prompt (LPTSTR, LPTSTR); + + +/* prototypes for REDIR.C */ +#define INPUT_REDIRECTION 1 +#define OUTPUT_REDIRECTION 2 +#define OUTPUT_APPEND 4 +#define ERROR_REDIRECTION 8 +#define ERROR_APPEND 16 +INT GetRedirection (LPTSTR, LPTSTR, LPTSTR, LPTSTR, LPINT); + + +/* prototypes for REN.C */ +INT cmd_rename (LPTSTR, LPTSTR); + + +/* prototypes for SET.C */ +INT cmd_set (LPTSTR, LPTSTR); + + +/* prototypes for TIME.C */ +INT cmd_time (LPTSTR, LPTSTR); + + +/* prototypes for TYPE.C */ +INT cmd_type (LPTSTR, LPTSTR); + + +/* prototypes for VER.C */ +VOID ShortVersion (VOID); +INT cmd_ver (LPTSTR, LPTSTR); + + +/* prototypes for VERIFY.C */ +INT cmd_verify (LPTSTR, LPTSTR); + + +/* prototypes for VOL.C */ +INT cmd_vol (LPTSTR, LPTSTR); + + +/* prototypes for WHERE.C */ +BOOL find_which (LPCTSTR, LPTSTR); + + + + +/* The MSDOS Batch Commands [MS-DOS 5.0 User's Guide and Reference p359] */ +int cmd_call(char *, char *); +int cmd_echo(char *, char *); +int cmd_for(char *, char *); +int cmd_goto(char *, char *); +int cmd_if(char *, char *); +int cmd_pause(char *, char *); +int cmd_shift(char *, char *); + +int cmd_beep(char *, char *); + + diff --git a/reactos/apps/utils/cmd/cmdinput.c b/reactos/apps/utils/cmd/cmdinput.c new file mode 100644 index 00000000000..6ac5302529d --- /dev/null +++ b/reactos/apps/utils/cmd/cmdinput.c @@ -0,0 +1,412 @@ +/* + * CMDINPUT.C - handles command input (tab completion, history, etc.). + * + * + * History: + * + * 01/14/95 (Tim Norman) + * started. + * + * 08/08/95 (Matt Rains) + * i have cleaned up the source code. changes now bring this source + * into guidelines for recommended programming practice. + * i have added some constants to help making changes easier. + * + * 12/12/95 (Tim Norman) + * added findxy() function to get max x/y coordinates to display + * correctly on larger screens + * + * 12/14/95 (Tim Norman) + * fixed the Tab completion code that Matt Rains broke by moving local + * variables to a more global scope and forgetting to initialize them + * when needed + * + * 8/1/96 (Tim Norman) + * fixed a bug in tab completion that caused filenames at the beginning + * of the command-line to have their first letter truncated + * + * 9/1/96 (Tim Norman) + * fixed a silly bug using printf instead of fputs, where typing "%i" + * confused printf :) + * + * 6/14/97 (Steffan Kaiser) + * ctrl-break checking + * + * 6/7/97 (Marc Desrochers) + * recoded everything! now properly adjusts when text font is changed. + * removed findxy(), reposition(), and reprint(), as these functions + * were inefficient. added goxy() function as gotoxy() was buggy when + * the screen font was changed. the printf() problem with %i on the + * command line was fixed by doing printf("%s",str) instead of + * printf(str). Don't ask how I find em just be glad I do :) + * + * 7/12/97 (Tim Norman) + * Note: above changes pre-empted Steffan's ctrl-break checking. + * + * 7/7/97 (Marc Desrochers) + * rewrote a new findxy() because the new dir() used it. This + * findxy() simply returns the values of *maxx *maxy. In the + * future, please use the pointers, they will always be correct + * since they point to BIOS values. + * + * 7/8/97 (Marc Desrochers) + * once again removed findxy(), moved the *maxx, *maxy pointers + * global and included them as externs in command.h. Also added + * insert/overstrike capability + * + * 7/13/97 (Tim Norman) + * added different cursor appearance for insert/overstrike mode + * + * 7/13/97 (Tim Norman) + * changed my code to use _setcursortype until I can figure out why + * my code is crashing on some machines. It doesn't crash on mine :) + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 28-Jul-1998 (John P Price ) + * put ifdef's around filename completion code. + * + * 30-Jul-1998 (John P Price ) + * moved filename completion code to filecomp.c + * made second TAB display list of filename matches + * + * 31-Jul-1998 (John P Price ) + * Fixed bug where if you typed something, then hit HOME, then tried + * to type something else in insert mode, it crashed. + * + * 07-Aug-1998 (John P Price ) + * Fixed carrage return output to better match MSDOS with echo + * on or off.(marked with "JPP 19980708") + * + * 13-Dec-1998 (Eric Kohl ) + * Added insert/overwrite cursor. + * + * 25-Jan-1998 (Eric Kohl ) + * Replaced CRT io functions by Win32 console io functions. + * This can handle - for 4NT filename completion. + * Unicode and redirection safe! + * + * 04-Feb-1999 (Eric Kohl ) + * Fixed input bug. A "line feed" character remined in the keyboard + * input queue when you pressed . This sometimes caused + * some very strange effects. + * Fixed some command line editing annoyances. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include + +#include "cmd.h" +#include "batch.h" + + + +SHORT maxx; +SHORT maxy; + +/* + * global command line insert/overwrite flag + */ +static BOOL bInsert = TRUE; + + +static VOID +ClearCommandLine (LPTSTR str, INT maxlen, SHORT orgx, SHORT orgy) +{ + INT count; + + goxy (orgx, orgy); + for (count = 0; count < (INT)_tcslen (str); count++) + ConOutChar (_T(' ')); + _tcsnset (str, _T('\0'), maxlen); + goxy (orgx, orgy); +} + + +/* read in a command line */ +VOID ReadCommand (LPTSTR str, INT maxlen) +{ + SHORT orgx; /* origin x/y */ + SHORT orgy; + SHORT curx; + SHORT cury; + INT count; + INT current = 0; + INT charcount = 0; + INPUT_RECORD ir; + WORD wLastKey = 0; + TCHAR ch; + + /* get screen size */ + GetScreenSize (&maxx, &maxy); + + /* JPP 19980807 - if echo off, don't print prompt */ + if (bEcho) + PrintPrompt(); + + orgx = wherex (); + orgy = wherey (); + + memset (str, 0, maxlen * sizeof (TCHAR)); + + SetCursorType (bInsert, TRUE); + + do + { + ConInKey (&ir); + + switch (ir.Event.KeyEvent.wVirtualKeyCode) + { + case VK_BACK: + /* - delete character to left of cursor */ + if (current > 0 && charcount > 0) + { + if (current == charcount) + { + /* if at end of line */ + str[current - 1] = _T('\0'); + if (wherex () != 0) + { + ConOutPrintf ("\b \b"); + } + else + { + goxy ((SHORT)(maxx - 1), (SHORT)(wherey () - 1)); + ConOutChar (_T(' ')); + goxy ((SHORT)(maxx - 1), (SHORT)(wherey () - 1)); + } + } + else + { + for (count = current - 1; count < charcount; count++) + str[count] = str[count + 1]; + if (wherex () != 0) + goxy ((SHORT)(wherex () - 1), wherey ()); + else + goxy ((SHORT)(maxx - 1), (SHORT)(wherey () - 1)); + curx = wherex (); + cury = wherey (); + ConOutPrintf (_T("%s "), &str[current - 1]); + goxy (curx, cury); + } + charcount--; + current--; + } + break; + + case VK_INSERT: + /* toggle insert/overstrike mode */ + bInsert ^= TRUE; + SetCursorType (bInsert, TRUE); + break; + + case VK_DELETE: + /* delete character under cursor */ + if (current != charcount && charcount > 0) + { + for (count = current; count < charcount; count++) + str[count] = str[count + 1]; + charcount--; + curx = wherex (); + cury = wherey (); + ConOutPrintf (_T("%s "), &str[current]); + goxy (curx, cury); + } + break; + + case VK_HOME: + /* goto beginning of string */ + if (current != 0) + { + goxy (orgx, orgy); + current = 0; + } + break; + + case VK_END: + /* goto end of string */ + if (current != charcount) + { + goxy (orgx, orgy); + ConOutPrintf (_T("%s"), str); + current = charcount; + } + break; + + case VK_TAB: +#ifdef FEATURE_UNIX_FILENAME_COMPLETION + /* expand current file name */ + if (current == charcount) // only works at end of line + { + if (wLastKey != VK_TAB) + { + // if first TAB, complete filename + CompleteFilename (str, charcount); + charcount = _tcslen (str); + current = charcount; + + goxy(orgx, orgy); + ConOutPrintf (_T("%s"), str); + if ((_tcslen (str) > (USHORT)(maxx - orgx)) && (orgy == maxy + 1)) + orgy--; + } + else + { + //if second TAB, list matches + if (ShowCompletionMatches (str, charcount)) + { + PrintPrompt (); + orgx = wherex (); + orgy = wherey (); + ConOutPrintf (_T("%s"), str); + } + } + } + else + { + MessageBeep (-1); + } +#endif +#ifdef FEATURE_4NT_FILENAME_COMPLETION + /* this is not implemented yet */ + if (ir.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) + { + /* get previous match */ + + } + else + { + /* get next match */ + + } +#endif + break; + + case VK_RETURN: + /* end input, return to main */ +#ifdef FEATURE_HISTORY + /* add to the history */ + if (str[0]) + History (0, str); +#endif + ConInDummy (); + ConOutChar (_T('\n')); + break; + + case VK_ESCAPE: + /* clear str Make this callable! */ + ClearCommandLine (str, maxlen, orgx, orgy); + current = charcount = 0; + break; + + case VK_UP: +#ifdef FEATURE_HISTORY + /* get previous command from buffer */ + ClearCommandLine (str, maxlen, orgx, orgy); + History (-1, str); + current = charcount = _tcslen (str); + ConOutPrintf (_T("%s"), str); +#endif + break; + + case VK_DOWN: +#ifdef FEATURE_HISTORY + /* get next command from buffer */ + ClearCommandLine (str, maxlen, orgx, orgy); + History (1, str); + current = charcount = _tcslen (str); + ConOutPrintf (_T("%s"), str); +#endif + break; + + case VK_LEFT: + /* move cursor left */ + if (current > 0) + { + current--; + if (wherex () == 0) + goxy ((SHORT)(maxx - 1), (SHORT)(wherey () - 1)); + else + goxy ((SHORT)(wherex () - 1), wherey ()); + } + else + { +// Beep (440, 100); + MessageBeep (-1); + } + break; + + case VK_RIGHT: + /* move cursor right */ + if (current != charcount) + { + current++; + if (wherex () == maxx - 1) + goxy (0, (SHORT)(wherey () + 1)); + else + goxy ((SHORT)(wherex () + 1), wherey ()); + } + break; + + default: +#ifdef _UNICODE + ch = ir.Event.KeyEvent.uChar.UnicodeChar; +#else + ch = ir.Event.KeyEvent.uChar.AsciiChar; +#endif + if ((ch >= 32 && ch <= 255) && (charcount != (maxlen - 2))) + { + /* insert character into string... */ + if (bInsert && current != charcount) + { + for (count = charcount; count > current; count--) + str[count] = str[count - 1]; + str[current++] = ch; + if (wherex () == maxx - 1) + { + curx = 0; + cury = wherey () + 1; + } + else + { + curx = wherex () + 1; + cury = wherey (); + } + ConOutPrintf (_T("%s"), &str[current - 1]); + if ((_tcslen (str) > (USHORT)(maxx - orgx)) && (orgy == maxy + 1)) + cury--; + goxy (curx, cury); + charcount++; + } + else + { + if (current == charcount) + charcount++; + str[current++] = ch; + ConOutChar (ch); + } + if ((_tcslen (str) > (USHORT)(maxx - orgx)) && (orgy == maxy + 1)) + orgy--; + } +#if 0 + else + { +// Beep (440, 100); + MessageBeep (-1); + } +#endif + break; + + } + wLastKey = ir.Event.KeyEvent.wVirtualKeyCode; + } + while (ir.Event.KeyEvent.wVirtualKeyCode != VK_RETURN); + + SetCursorType (bInsert, TRUE); +} diff --git a/reactos/apps/utils/cmd/cmdtable.c b/reactos/apps/utils/cmd/cmdtable.c new file mode 100644 index 00000000000..f2d8339dfce --- /dev/null +++ b/reactos/apps/utils/cmd/cmdtable.c @@ -0,0 +1,241 @@ +/* + * CMDTABLE.C - table of internal commands. + * + * + * History: + * + * 16 Jul 1998 (Hans B Pufal) + * started. + * New file to keep the internal command table. I plan on + * getting rid of the table real soon now and replacing it + * with a dynamic mechnism. + * + * 27 Jul 1998 John P. Price + * added config.h include + * + * 21-Jan-1999 (Eric Kohl ) + * Unicode ready! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include + +#include "cmd.h" + +#include "chcp.h" + + +/* a list of all the internal commands, associating their command names */ +/* to the functions to process them */ + +/* Lines marked + * + * $$ are external commands + * !! internal commands which are not yet implemented + * ** special FREEDOS specific implementation + */ + +COMMAND cmds[] = +{ + {_T("?"), 0, cmd_showcommands}, + +#ifdef FEATURE_ALIASES + {_T("alias"), 0, cmd_alias}, +#endif + +#ifdef INCLUDE_CMD_ATTRIB + {_T("attrib"), 0, cmd_attrib}, +#endif + +#ifdef INCLUDE_CMD_BEEP + {_T("beep"), 0, cmd_beep}, +#endif + +/* + {_T("break"), 0, cmd_break}, +*/ + + {_T("call"), CMD_BATCHONLY, cmd_call}, + +#ifdef INCLUDE_CMD_CHDIR + {_T("cd"), CMD_SPECIAL, cmd_chdir}, + {_T("chdir"), CMD_SPECIAL, cmd_chdir}, +#endif + +#ifdef INCLUDE_CMD_CHCP + {_T("chcp"), 0, CommandChcp}, +#endif + +#ifdef INCLUDE_CMD_CLS + {_T("cls"), 0, cmd_cls}, +#endif + +#ifdef INCLUDE_CMD_COLOR + {_T("color"), 0, cmd_color}, +#endif + +#ifdef INCLUDE_CMD_COPY + {_T("copy"), 0, cmd_copy}, +#endif + +/* +#define INCLUDE_CMD_CTTY + {_T("ctty"), 0, cmd_ctty}, +#endif +*/ + +#ifdef INCLUDE_CMD_DATE + {_T("date"), 0, cmd_date}, +#endif + +#ifdef INCLUDE_CMD_DEL + {_T("del"), 0, cmd_del}, + {_T("delete"), 0, cmd_del}, +#endif + +#ifdef INCLUDE_CMD_DIR + {_T("dir"), CMD_SPECIAL, cmd_dir}, +#endif + + {_T("echo"), 0, cmd_echo}, + +#ifdef INCLUDE_CMD_DEL + {_T("erase"), 0, cmd_del}, +#endif + + {_T("exit"), 0, internal_exit}, + + {_T("for"), 0, cmd_for}, + + {_T("goto"), CMD_BATCHONLY, cmd_goto}, + + {_T("if"), 0, cmd_if}, + +#ifdef INCLUDE_CMD_LABEL + {_T("label"), 0, cmd_label}, +#endif + +#ifdef INCLUDE_CMD_MKDIR + {_T("md"), CMD_SPECIAL, cmd_mkdir}, + {_T("mkdir"), CMD_SPECIAL, cmd_mkdir}, +#endif + +#ifdef INCLUDE_CMD_MOVE + {_T("move"), 0, cmd_move}, +#endif + +#ifdef INCLUDE_CMD_PATH + {_T("path"), 0, cmd_path}, +#endif + +#ifdef INCLUDE_CMD_PAUSE + {_T("pause"), 0, cmd_pause}, +#endif + +#ifdef FEATURE_DIRECTORY_STACK + {_T("popd"), 0, cmd_popd}, +#endif + +#ifdef INCLUDE_CMD_PROMPT + {_T("prompt"), 0, cmd_prompt}, +#endif + +#ifdef FEATURE_DIRECTORY_STACK + {_T("pushd"), 0, cmd_pushd}, +#endif + +#ifdef INCLUDE_CMD_RMDIR + {_T("rd"), CMD_SPECIAL, cmd_rmdir}, +#endif + +#ifdef INCLUDE_CMD_REM + {_T("rem"), 0, cmd_rem}, +#endif + +#ifdef INCLUDE_CMD_RENAME + {_T("ren"), 0, cmd_rename}, + {_T("rename"), 0, cmd_rename}, +#endif + +#ifdef INCLUDE_CMD_RMDIR + {_T("rmdir"), CMD_SPECIAL, cmd_rmdir}, +#endif + +#ifdef INCLUDE_CMD_SET + {_T("set"), 0, cmd_set}, +#endif + + {_T("shift"), CMD_BATCHONLY, cmd_shift}, + +#ifdef INCLUDE_CMD_TIME + {_T("time"), 0, cmd_time}, +#endif + +#ifdef INCLUDE_CMD_TYPE + {_T("type"), 0, cmd_type}, +#endif + +#ifdef INCLUDE_CMD_VER + {_T("ver"), 0, cmd_ver}, +#endif + +#ifdef INCLUDE_CMD_VERIFY + {_T("verify"), 0, cmd_verify}, +#endif + +#ifdef INCLUDE_CMD_VOL + {_T("vol"), 0, cmd_vol}, +#endif + + {NULL, 0, NULL} +}; + +/* append, $$ */ +/* assign, $$ */ +/* attrib, ** */ +/* backup, $$ */ +/* chkdsk, $$ */ +/* comp, $$ */ +/* debug, $$ */ +/* diskcomp, $$ */ +/* diskcopy, $$ */ +/* doskey, ** */ +/* dosshell, $$ */ +/* edit, $$ */ +/* edlin, $$ */ +/* emm386, $$ */ +/* exe2bin, $$ */ +/* expand, $$ */ +/* fastopen, $$ */ +/* fc, $$ */ +/* fdisk, $$ */ +/* find, $$ */ +/* format, $$ */ +/* graftabl, $$ */ +/* graphics, $$ */ +/* help, $$ */ +/* join, $$ */ +/* keyb, $$ */ +/* mem, $$ */ +/* mirror, $$ */ +/* mode, $$ */ +/* more, $$ */ +/* nlsfunc, $$ */ +/* print, $$ */ +/* qbasic, $$ */ +/* recover, $$ */ +/* replace, $$ */ +/* restore, $$ */ +/* setver, $$ */ +/* share, $$ */ +/* sort, $$ */ +/* subst, $$ */ +/* sys, $$ */ +/* tree, $$ */ +/* undelete, $$ */ +/* unformat, $$ */ +/* xcopy, $$ */ diff --git a/reactos/apps/utils/cmd/color.c b/reactos/apps/utils/cmd/color.c new file mode 100644 index 00000000000..f5d086704db --- /dev/null +++ b/reactos/apps/utils/cmd/color.c @@ -0,0 +1,102 @@ +/* + * COLOR.C - color internal command. + * + * + * History: + * + * 13-Dec-1998 (Eric Kohl ) + * Started. + * + * 19-Jan-1999 (Eric Kohl ) + * Unicode ready! + * + * 20-Jan-1999 (Eric Kohl ) + * Redirection ready! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_COLOR +#include +#include +#include +#include + +#include "cmd.h" + + +VOID SetScreenColor (WORD wColor) +{ + DWORD dwWritten; + CONSOLE_SCREEN_BUFFER_INFO csbi; + COORD coPos; + + GetConsoleScreenBufferInfo (hOut, &csbi); + + coPos.X = 0; + coPos.Y = 0; + FillConsoleOutputAttribute (hOut, wColor, + (csbi.dwSize.X)*(csbi.dwSize.Y), + coPos, &dwWritten); + SetConsoleTextAttribute (hOut, wColor); +} + + +/* + * color + * + * internal dir command + */ +INT cmd_color (LPTSTR first, LPTSTR rest) +{ + if (_tcsncmp (rest, _T("/?"), 2) == 0) + { + ConOutPuts (_T("Sets the default foreground and background colors.\n\n" + "COLOR [attr]\n\n" + " attr Specifies color attribute of console output\n\n" + "Color attributes are specified by TWO hex digits -- the first\n" + "corresponds to the background; the second to the foreground. Each digit\n" + "can be one of the following:\n")); + + ConOutPuts (_T(" 0 = Black 8 = Gray\n" + " 1 = Blue 9 = Light Blue\n" + " 2 = Green A = Light Green\n" + " 3 = Aqua B = Light Aqua\n" + " 4 = Red C = Light Red\n" + " 5 = Purple D = Light Purple\n" + " 6 = Yellow E = Light Yellow\n" + " 7 = White F = Bright White\n")); + return 0; + } + + if (rest[0] == _T('\0')) + { + /* set default color */ + wColor = wDefColor; + SetScreenColor (wColor); + return 0; + } + + if (_tcslen (rest) != 2) + { + ConErrPuts (_T("parameter error!")); + return 1; + } + + wColor = (WORD)_tcstoul (rest, NULL, 16); + + if ((wColor & 0xF) == (wColor &0xF0) >> 4) + { + ConErrPuts (_T("same colors error!")); + return 1; + } + + /* set color */ + SetScreenColor (wColor); + + return 0; +} + +#endif diff --git a/reactos/apps/utils/cmd/config.h b/reactos/apps/utils/cmd/config.h new file mode 100644 index 00000000000..1e214e276e4 --- /dev/null +++ b/reactos/apps/utils/cmd/config.h @@ -0,0 +1,86 @@ +/* + * CONFIG.H - Used to configure what will be compiled into the shell. + * + * + * History: + * + * 27 Jul 1998 - John P. Price + * started. + * + */ + + +/* JPP 20 Jul 1998 - define DEBUG to add debugging code */ +/*#define DEBUG */ + + +/* Define to enable the alias command, and aliases.*/ +#define FEATURE_ALIASES + + +/* Define to enable history */ +#define FEATURE_HISTORY + + +/* Define one of these to enable filename completion */ +#define FEATURE_UNIX_FILENAME_COMPLETION +/* #define FEATURE_4NT_FILENAME_COMPLETION */ + + +/* Define to enable the directory stack */ +#define FEATURE_DIRECTORY_STACK + + +/* Define to activate redirections and piping */ +#define FEATURE_REDIRECTION + + +/* Define one of these to select the used locale. */ +/* (date and time formats etc.) used in DATE, TIME */ +/* DIR and PROMPT. */ +#define LOCALE_WINDOWS /* System locale */ +/* #define LOCALE_GERMAN */ /* German locale */ +/* #define LOCALE_DEFAULT */ /* United States locale */ + + +#define INCLUDE_CMD_ATTRIB +//#define INCLUDE_CMD_BREAK +#define INCLUDE_CMD_CHCP +#define INCLUDE_CMD_CHDIR +#define INCLUDE_CMD_CLS +#define INCLUDE_CMD_COLOR +#define INCLUDE_CMD_COPY +//#define INCLUDE_CMD_CTTY +#define INCLUDE_CMD_DATE +#define INCLUDE_CMD_DEL +#define INCLUDE_CMD_DIR +#define INCLUDE_CMD_LABEL +#define INCLUDE_CMD_MKDIR +#define INCLUDE_CMD_MOVE +#define INCLUDE_CMD_PATH +#define INCLUDE_CMD_PROMPT +#define INCLUDE_CMD_RMDIR +#define INCLUDE_CMD_RENAME +#define INCLUDE_CMD_SET +#define INCLUDE_CMD_TIME +#define INCLUDE_CMD_TYPE +#define INCLUDE_CMD_VER +#define INCLUDE_CMD_REM +#define INCLUDE_CMD_PAUSE +#define INCLUDE_CMD_BEEP +#define INCLUDE_CMD_VERIFY +#define INCLUDE_CMD_VOL + +/* +command that do not have a define: + +exit +call +echo +goto +for +if +shift + +*/ + diff --git a/reactos/apps/utils/cmd/console.c b/reactos/apps/utils/cmd/console.c new file mode 100644 index 00000000000..c740f2a2ed7 --- /dev/null +++ b/reactos/apps/utils/cmd/console.c @@ -0,0 +1,273 @@ +/* + * CONSOLE.C - console input/output functions. + * + * + * History: + * + * 20-Jan-1999 (Eric Kohl ) + * started + */ + + + +#define WIN32_LEAN_AND_MEAN + +#include +#include + +#include "cmd.h" + + + +/* internal variables for paged output */ +SHORT sLineCount; +SHORT sMaxLines; +BOOL bPageable; + + + +#ifdef _DEBUG +VOID DebugPrintf (LPTSTR szFormat, ...) +{ + TCHAR szOut[512]; + va_list arg_ptr; + + va_start (arg_ptr, szFormat); + wvsprintf (szOut, szFormat, arg_ptr); + va_end (arg_ptr); + + OutputDebugString (szOut); +} +#endif /* _DEBUG */ + + +VOID ConInDummy (VOID) +{ + HANDLE hInput = GetStdHandle (STD_INPUT_HANDLE); + INPUT_RECORD dummy; + DWORD dwRead; + +#ifdef _DEBUG + if (hInput == INVALID_HANDLE_VALUE) + DebugPrintf ("Invalid input handle!!!\n"); +#endif + + ReadConsoleInput (hInput, &dummy, 1, &dwRead); +} + + +VOID ConInKey (PINPUT_RECORD lpBuffer) +{ + HANDLE hInput = GetStdHandle (STD_INPUT_HANDLE); + DWORD dwRead; + +#ifdef _DEBUG + if (hInput == INVALID_HANDLE_VALUE) + DebugPrintf ("Invalid input handle!!!\n"); +#endif + + do + { + WaitForSingleObject (hInput, INFINITE); + ReadConsoleInput (hInput, lpBuffer, 1, &dwRead); + if ((lpBuffer->EventType == KEY_EVENT) && + (lpBuffer->Event.KeyEvent.bKeyDown == TRUE)) + break; + } + while (TRUE); +} + + + +VOID ConInString (LPTSTR lpInput, DWORD dwLength) +{ + DWORD dwOldMode; + DWORD dwRead; + HANDLE hFile; + + LPTSTR p; + DWORD i; + + ZeroMemory (lpInput, dwLength * sizeof(TCHAR)); + hFile = GetStdHandle (STD_INPUT_HANDLE); + GetConsoleMode (hFile, &dwOldMode); + + SetConsoleMode (hFile, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT); + + ReadFile (hFile, lpInput, dwLength, &dwRead, NULL); + + p = lpInput; + for (i = 0; i < dwRead; i++, p++) + { + if (*p == _T('\x0d')) + { + *p = _T('\0'); + break; + } + } + + SetConsoleMode (hFile, dwOldMode); +} + + +VOID ConOutChar (TCHAR c) +{ + DWORD dwWritten; + + WriteFile (GetStdHandle (STD_OUTPUT_HANDLE), &c, 1, &dwWritten, NULL); +} + + +VOID ConOutPuts (LPTSTR szText) +{ + DWORD dwWritten; + + WriteFile (GetStdHandle (STD_OUTPUT_HANDLE), szText, _tcslen(szText), &dwWritten, NULL); + WriteFile (GetStdHandle (STD_OUTPUT_HANDLE), "\x0a\x0d", 2, &dwWritten, NULL); +} + + +VOID ConOutPrintf (LPTSTR szFormat, ...) +{ + DWORD dwWritten; + TCHAR szOut[256]; + va_list arg_ptr; + + va_start (arg_ptr, szFormat); + wvsprintf (szOut, szFormat, arg_ptr); + va_end (arg_ptr); + + WriteFile (GetStdHandle (STD_OUTPUT_HANDLE), szOut, _tcslen(szOut), &dwWritten, NULL); +} + + +VOID ConErrChar (TCHAR c) +{ + DWORD dwWritten; + + WriteFile (GetStdHandle (STD_ERROR_HANDLE), &c, 1, &dwWritten, NULL); +} + + +VOID ConErrPuts (LPTSTR szText) +{ + DWORD dwWritten; + + WriteFile (GetStdHandle (STD_ERROR_HANDLE), szText, _tcslen(szText), &dwWritten, NULL); + WriteFile (GetStdHandle (STD_ERROR_HANDLE), "\x0a\x0d", 2, &dwWritten, NULL); +} + + +VOID ConErrPrintf (LPTSTR szFormat, ...) +{ + DWORD dwWritten; + TCHAR szOut[4096]; + va_list arg_ptr; + + va_start (arg_ptr, szFormat); + wvsprintf (szOut, szFormat, arg_ptr); + va_end (arg_ptr); + + WriteFile (GetStdHandle (STD_ERROR_HANDLE), szOut, _tcslen(szOut), &dwWritten, NULL); +} + + + + +/* + * goxy -- move the cursor on the screen. + */ +VOID goxy (SHORT x, SHORT y) +{ + COORD coPos; + + coPos.X = x; + coPos.Y = y; + SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), coPos); +} + + +SHORT wherex (VOID) +{ + CONSOLE_SCREEN_BUFFER_INFO csbi; + + GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &csbi); + + return csbi.dwCursorPosition.X; +} + + +SHORT wherey (VOID) +{ + CONSOLE_SCREEN_BUFFER_INFO csbi; + + GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &csbi); + + return csbi.dwCursorPosition.Y; +} + + +VOID GetScreenSize (PSHORT maxx, PSHORT maxy) +{ + CONSOLE_SCREEN_BUFFER_INFO csbi; + + GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &csbi); + + if (maxx) + *maxx = csbi.dwSize.X; + if (maxy) + *maxy = csbi.dwSize.Y; +} + + +VOID SetCursorType (BOOL bInsert, BOOL bVisible) +{ + CONSOLE_CURSOR_INFO cci; + + cci.dwSize = bInsert ? 10 : 100; + cci.bVisible = bVisible; + + SetConsoleCursorInfo (GetStdHandle (STD_OUTPUT_HANDLE), &cci); +} + + + +VOID InitializePageOut (VOID) +{ + sLineCount = 0; + + if (GetFileType (GetStdHandle (STD_OUTPUT_HANDLE)) == FILE_TYPE_CHAR) + { + bPageable = TRUE; + GetScreenSize (NULL, &sMaxLines); + } + else + { + bPageable = FALSE; + } +} + + +VOID TerminatePageOut (VOID) +{ + + +} + + + +int LinePageOut (LPTSTR szLine) +{ + ConOutPuts (szLine); + + if (bPageable) + { + sLineCount++; + if (sLineCount >= sMaxLines) + { + sLineCount = 0; + cmd_pause ("", ""); + } + } + return 0; +} diff --git a/reactos/apps/utils/cmd/copy.c b/reactos/apps/utils/cmd/copy.c new file mode 100644 index 00000000000..16b561727d0 --- /dev/null +++ b/reactos/apps/utils/cmd/copy.c @@ -0,0 +1,733 @@ +/* + * COPY.C -- copy internal command. + * + * + * History: + * + * 01-Aug-98 (Rob Lake z63rrl@morgan.ucs.mun.ca) + * started + * + * 13-Aug-1998 (John P. Price) + * fixed memory leak problem in copy function. + * fixed copy function so it would work with wildcards in the source + * + * 13-Dec-1998 (Eric Kohl ) + * Added COPY command to CMD. + * + * 26-Jan-1998 (Eric Kohl ) + * Replaced CRT io functions by Win32 io functions. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_COPY + +#include +#include +#include +#include +#include + +#include "cmd.h" + + +#define VERIFY 1 /* VERIFY Switch */ +#define BINARY 2 /* File is to be copied as BINARY */ +#define ASCII 4 /* File is to be copied as ASCII */ +#define PROMPT 8 /* Prompt before overwriting files */ +#define NPROMPT 16 /* Do not prompt before overwriting files */ +#define HELP 32 /* Help was asked for */ +#define SOURCE 128 /* File is a source */ + + +typedef struct tagFILES +{ + struct tagFILES *next; + TCHAR szFile[MAX_PATH]; + DWORD dwFlag; /* BINARY -xor- ASCII */ +} FILES, *LPFILES; + + +static BOOL DoSwitches (LPTSTR, LPDWORD); +static BOOL AddFile (LPFILES, char *, int *, int *, unsigned *); +static BOOL AddFiles (LPFILES, char *, int *, int *, int *, unsigned *); +static BOOL GetDestination (LPFILES, LPFILES); +static INT ParseCommand (LPFILES, int, char **, LPDWORD); +static VOID DeleteFileList (LPFILES); +static INT Overwrite (LPTSTR); + + + +static BOOL IsDirectory (LPTSTR fn) +{ + if (!IsValidFileName (fn)) + return FALSE; + return (GetFileAttributes (fn) & FILE_ATTRIBUTE_DIRECTORY); +} + + +static BOOL DoSwitches (LPTSTR arg, LPDWORD lpdwFlags) +{ + if (!_tcsicmp (arg, _T("/-Y"))) + { + *lpdwFlags |= PROMPT; + *lpdwFlags &= ~NPROMPT; + return TRUE; + } + else if (_tcslen (arg) > 2) + { + error_too_many_parameters (""); + return FALSE; + } + + switch (_totupper (arg[1])) + { + case _T('V'): + *lpdwFlags |= VERIFY; + break; + + case _T('A'): + *lpdwFlags |= ASCII; + *lpdwFlags &= ~BINARY; + break; + + case _T('B'): + *lpdwFlags |= BINARY; + *lpdwFlags &= ~ASCII; + break; + + case _T('Y'): + *lpdwFlags &= ~PROMPT; + *lpdwFlags |= NPROMPT; + break; + + default: + error_invalid_switch (arg[1]); + return FALSE; + } + return TRUE; +} + + +static BOOL +AddFile (LPFILES f, char *arg, int *source, int *dest, unsigned *flags) +{ + if (*dest) + { + error_too_many_parameters (""); + return FALSE; + } + if (*source) + { + *dest = 1; + f->dwFlag = 0; + } + else + { + *source = 1; + f->dwFlag = SOURCE; + } + _tcscpy(f->szFile, arg); + f->dwFlag |= *flags & ASCII ? ASCII : BINARY; + if ((f->next = (LPFILES)malloc (sizeof (FILES))) == NULL) + { + error_out_of_memory (); + return FALSE; + } + f = f->next; + f->dwFlag = 0; + f->next = NULL; + return TRUE; +} + + +static BOOL +AddFiles (LPFILES f, char *arg, int *source, int *dest, + int *count, unsigned *flags) +{ + char t[128]; + int j; + int k; + + if (*dest) + { + error_too_many_parameters (""); + return FALSE; + } + + j = 0; + k = 0; + + while (arg[j] == _T('+')) + j++; + + while (arg[j] != _T('\0')) + { + t[k] = arg[j++]; + if (t[k] == '+' || arg[j] == _T('\0')) + { + if (!k) + continue; + if (arg[j] == _T('\0') && t[k] != _T('+')) + k++; + t[k] = _T('\0'); + *count += 1; + _tcscpy (f->szFile, t); + *source = 1; + if (*flags & ASCII) + f->dwFlag |= *flags | SOURCE | ASCII; + else + f->dwFlag |= *flags | BINARY | SOURCE; + + if ((f->next = (LPFILES)malloc (sizeof (FILES))) == NULL) + { + error_out_of_memory (); + return FALSE; + } + f = f->next; + f->next = NULL; + k = 0; + f->dwFlag = 0; + continue; + } + k++; + } + + if (arg[--j] == _T('+')) + *source = 0; + + return 1; +} + + +static BOOL GetDestination (LPFILES f, LPFILES dest) +{ + LPFILES p; + LPFILES start = f; + + while (f->next != NULL) + { + p = f; + f = f->next; + } + + f = p; + + if ((f->dwFlag & SOURCE) == 0) + { + free (p->next); + p->next = NULL; + _tcscpy (dest->szFile, f->szFile); + dest->dwFlag = f->dwFlag; + dest->next = NULL; + f = start; + return TRUE; + } + + return FALSE; +} + + +static INT +ParseCommand (LPFILES f, int argc, char **arg, LPDWORD lpdwFlags) +{ + INT i; + INT dest; + INT source; + INT count; + + dest = 0; + source = 0; + count = 0; + + for (i = 0; i < argc; i++) + { + if (arg[i][0] == _T('/')) + { + if (!DoSwitches (arg[i], lpdwFlags)) + return -1; + } + else + { + if (!_tcscmp(arg[i], _T("+"))) + source = 0; + else if (!_tcschr(arg[i], _T('+')) && source) + { + if (!AddFile(f, arg[i], &source, &dest, lpdwFlags)) + return -1; + f = f->next; + count++; + } + else + { + if (!AddFiles(f, arg[i], &source, &dest, &count, lpdwFlags)) + return -1; + while (f->next != NULL) + f = f->next; + } + } + } +#ifdef _DEBUG + DebugPrintf ("ParseCommand: flags has %s\n", + *lpdwFlags & ASCII ? "ASCII" : "BINARY"); +#endif + return count; +} + + +static VOID DeleteFileList (LPFILES f) +{ + LPFILES temp; + + while (f != NULL) + { + temp = f; + f = f->next; + free (temp); + } +} + + +static INT +Overwrite (LPTSTR fn) +{ + TCHAR inp[10]; + LPTSTR p; + + ConOutPrintf (_T("Overwrite %s (Yes/No/All)? "), fn); + ConInString (inp, 10); + + _tcsupr (inp); + for (p = inp; _istspace (*p); p++) + ; + + if (*p != _T('Y') && *p != _T('A')) + return 0; + if (*p == _T('A')) + return 2; + + return 1; +} + + +#define BUFF_SIZE 16384 /* 16k = max buffer size */ + + +int copy (LPTSTR source, LPTSTR dest, int append, LPDWORD lpdwFlags) +{ + FILETIME srctime; + HANDLE hFileSrc; + HANDLE hFileDest; + LPBYTE buffer; + DWORD dwAttrib; + DWORD dwRead; + DWORD dwWritten; + DWORD i; + BOOL bEof = FALSE; + +#ifdef _DEBUG + DebugPrintf ("checking mode\n"); +#endif + + dwAttrib = GetFileAttributes (source); + + hFileSrc = CreateFile (source, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, 0, NULL); + if (hFileSrc == INVALID_HANDLE_VALUE) + { + ConErrPrintf (_T("Error: Cannot open source - %s!\n"), source); + return 0; + } + +#ifdef _DEBUG + DebugPrintf (_T("getting time\n")); +#endif + + GetFileTime (hFileSrc, &srctime, NULL, NULL); + +#ifdef _DEBUG + DebugPrintf (_T("copy: flags has %s\n"), + *lpdwFlags & ASCII ? "ASCII" : "BINARY"); +#endif + + if (!IsValidFileName (dest)) + { +#ifdef _DEBUG + DebugPrintf (_T("opening/creating\n")); +#endif + hFileDest = + CreateFile (dest, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + } + else if (!append) + { + if (!_tcscmp (dest, source)) + { + ConErrPrintf (_T("Error: Can't copy onto itself!\n")); + CloseHandle (hFileSrc); + return 0; + } + +#ifdef _DEBUG + DebugPrintf (_T("SetFileAttributes (%s, FILE_ATTRIBUTE_NORMAL);\n"), dest); +#endif + SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL); + +#ifdef _DEBUG + DebugPrintf (_T("DeleteFile (%s);\n"), dest); +#endif + DeleteFile (dest); + + hFileDest = + CreateFile (dest, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + } + else + { + LONG lFilePosHigh = 0; + + if (!_tcscmp (dest, source)) + { + CloseHandle (hFileSrc); + return 0; + } + +#ifdef _DEBUG + DebugPrintf (_T("opening/appending\n")); +#endif + hFileDest = + CreateFile (dest, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + SetFilePointer (hFileDest, 0, &lFilePosHigh,FILE_END); + } + + if (hFileDest == INVALID_HANDLE_VALUE) + { + CloseHandle (hFileSrc); + error_path_not_found (); + return 0; + } + + buffer = (LPBYTE)malloc (BUFF_SIZE); + if (buffer == NULL) + { + CloseHandle (hFileDest); + CloseHandle (hFileSrc); + error_out_of_memory (); + return 0; + } + + ConOutPuts (source); + + do + { + ReadFile (hFileSrc, buffer, BUFF_SIZE, &dwRead, NULL); + if (*lpdwFlags & ASCII) + { + for (i = 0; i < dwRead; i++) + { + if (((LPTSTR)buffer)[i] == 0x1A) + { + bEof = TRUE; + break; + } + } + dwRead = i; + } + + if (dwRead == 0) + break; + + WriteFile (hFileDest, buffer, dwRead, &dwWritten, NULL); + if (dwWritten != dwRead) + { + ConErrPrintf (_T("Error writing destination!\n")); + free (buffer); + CloseHandle (hFileDest); + CloseHandle (hFileSrc); + return 0; + } + } + while (dwRead && !bEof); + +#ifdef _DEBUG + DebugPrintf (_T("setting time\n")); +#endif + SetFileTime (hFileDest, &srctime, NULL, NULL); + + if (*lpdwFlags & ASCII) + { + ((LPTSTR)buffer)[0] = 0x1A; + ((LPTSTR)buffer)[1] = _T('\0'); +#ifdef _DEBUG + DebugPrintf (_T("appending ^Z\n")); +#endif + WriteFile (hFileDest, buffer, sizeof(TCHAR), &dwWritten, NULL); + } + + free (buffer); + CloseHandle (hFileDest); + CloseHandle (hFileSrc); + +#ifdef _DEBUG + DebugPrintf (_T("setting mode\n")); +#endif + SetFileAttributes (dest, dwAttrib); + + return 1; +} + + +int setup_copy (LPFILES sources, char **p, BOOL bMultiple, + char *drive_d, char *dir_d, char *file_d, + char *ext_d, int *append, LPDWORD lpdwFlags) +{ + WIN32_FIND_DATA find; + + char drive_s[_MAX_DRIVE], + dir_s[_MAX_DIR], + file_s[_MAX_FNAME], + ext_s[_MAX_EXT]; + char from_merge[_MAX_PATH]; + + LPTSTR real_source; + LPTSTR real_dest; + + INT nCopied = 0; + BOOL bAll = FALSE; + BOOL bDone; + HANDLE hFind; + + + real_source = (LPTSTR)malloc (MAX_PATH); + real_dest = (LPTSTR)malloc (MAX_PATH); + + if (!real_source || !real_dest) + { + error_out_of_memory (); + DeleteFileList (sources); + free (real_source); + free (real_dest); + freep (p); + return 0; + } + + while (sources->next != NULL) + { + _splitpath (sources->szFile, drive_s, dir_s, file_s, ext_s); + hFind = FindFirstFile (sources->szFile, &find); + if (hFind == INVALID_HANDLE_VALUE) + { + error_file_not_found(); + DeleteFileList (sources); + freep(p); + free(real_source); + free(real_dest); + return 0; + } + + do + { + if (find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + goto next; + + _makepath(from_merge, drive_d, dir_d, file_d, ext_d); + if (from_merge[_tcslen(from_merge) - 1] == _T('\\')) + from_merge[_tcslen(from_merge) - 1] = 0; + + if (IsDirectory (from_merge)) + { + bMultiple = FALSE; + _tcscat (from_merge, _T("\\")); + _tcscat (from_merge, find.cFileName); + } + else + bMultiple = TRUE; + + _tcscpy (real_dest, from_merge); + _makepath (real_source, drive_s, dir_s, find.cFileName, NULL); + +#ifdef _DEBUG + DebugPrintf (_T("copying %s -> %s (%sappending%s)\n"), + real_source, real_dest, + *append ? "" : "not ", + sources->dwFlag & ASCII ? ", ASCII" : ", BINARY"); +#endif + + if (IsValidFileName (real_dest) && !bAll) + { + int over = Overwrite (real_dest); + if (over == 2) + bAll = TRUE; + else if (over == 0) + goto next; + else if (bMultiple) + bAll = TRUE; + } + if (copy (real_source, real_dest, *append, lpdwFlags)) + nCopied++; + next: + bDone = FindNextFile (hFind, &find); + + if (bMultiple) + *append = 1; + } + while (bDone); + + FindClose (hFind); + sources = sources->next; + + } + free (real_source); + free (real_dest); + + return nCopied; +} + + +INT cmd_copy (LPTSTR first, LPTSTR rest) +{ + char **p; + char drive_d[_MAX_DRIVE], + dir_d[_MAX_DIR], + file_d[_MAX_FNAME], + ext_d[_MAX_EXT]; + + int argc, + append, + files, + copied; + + LPFILES sources; + FILES dest; + LPFILES start; + BOOL bMultiple; + BOOL bWildcards; + BOOL bDestFound; + DWORD dwFlags = 0; + + if (!_tcsncmp (rest, _T("/?"), 2)) + { + ConOutPuts (_T("Copies one or more files to another location.\n" + "\n" + "COPY [/V][/Y|/-Y][/A|/B] source [/A|/B]\n" + " [+ source [/A|/B] [+ ...]] [destination [/A|/B]]\n" + "\n" + " source Specifies the file or files to be copied.\n" + " /A Indicates an ASCII text file.\n" + " /B Indicates a binary file.\n" + " destination Specifies the directory and/or filename for the new file(s).\n" + " /V Verifies that new files are written correctly.\n" + " /Y Suppresses prompting to confirm you want to overwrite an\n" + " existing destination file.\n" + " /-Y Causes prompting to confirm you want to overwrite an\n" + " existing destination file.\n" + "\n" + "The switch /Y may be present in the COPYCMD environment variable.\n" + "...")); + return 1; + } + + p = split (rest, &argc); + + if (argc == 0) + { + error_req_param_missing (); + return 0; + } + + sources = (LPFILES)malloc (sizeof (FILES)); + if (!sources) + { + error_out_of_memory (); + return 0; + } + sources->next = NULL; + sources->dwFlag = 0; + + if ((files = ParseCommand (sources, argc, p, &dwFlags)) == -1) + { + DeleteFileList (sources); + freep (p); + return 0; + } + else if (files == 0) + { + error_req_param_missing(); + DeleteFileList (sources); + freep (p); + return 0; + } + start = sources; + + bDestFound = GetDestination (sources, &dest); + if (bDestFound) + { + _splitpath (dest.szFile, drive_d, dir_d, file_d, ext_d); + if (IsDirectory (dest.szFile)) + { + _tcscat (dir_d, file_d); + _tcscat (dir_d, ext_d); + file_d[0] = _T('\0'); + ext_d[0] = _T('\0'); + } + } + + if (_tcschr (dest.szFile, _T('*')) || _tcschr (dest.szFile, _T('?'))) + bWildcards = TRUE; + else + bWildcards = FALSE; + + if (strchr(rest, '+')) + bMultiple = TRUE; + else + bMultiple = FALSE; + + append = 0; + copied = 0; + + if (bDestFound && !bWildcards) + { + copied = setup_copy (sources, p, bMultiple, drive_d, dir_d, file_d, ext_d, &append, &dwFlags); + } + else if (bDestFound && bWildcards) + { + ConErrPrintf (_T("Error: Not implemented yet!\n")); + DeleteFileList (sources); + freep (p); + return 0; + } + else if (!bDestFound && !bMultiple) + { + _splitpath (sources->szFile, drive_d, dir_d, file_d, ext_d); + if (IsDirectory (sources->szFile)) + { + _tcscat (dir_d, file_d); + _tcscat (dir_d, ext_d); + file_d[0] = _T('\0'); + ext_d[0] = _T('\0'); + } + copied = setup_copy (sources, p, FALSE, "", "", file_d, ext_d, &append, &dwFlags); + } + else + { + _splitpath(sources->szFile, drive_d, dir_d, file_d, ext_d); + if (IsDirectory (sources->szFile)) + { + _tcscat (dir_d, file_d); + _tcscat (dir_d, ext_d); + file_d[0] = _T('\0'); + ext_d[0] = _T('\0'); + } + + ConOutPuts (sources->szFile); + append = 1; + copied = setup_copy (sources->next, p, bMultiple, drive_d, dir_d, file_d, ext_d, &append, &dwFlags) + 1; + } + + DeleteFileList (start); + freep (p); + ConOutPrintf (_T(" %d file(s) copied\n"), copied); + + return 1; +} +#endif /* INCLUDE_CMD_COPY */ diff --git a/reactos/apps/utils/cmd/date.c b/reactos/apps/utils/cmd/date.c new file mode 100644 index 00000000000..e2712366d85 --- /dev/null +++ b/reactos/apps/utils/cmd/date.c @@ -0,0 +1,298 @@ +/* + * DATE.C - date internal command. + * + * + * History: + * + * 08 Jul 1998 (John P. Price) + * started. + * + * 20 Jul 1998 (John P. Price) + * corrected number of days for December from 30 to 31. + * (Thanx to Steffen Kaiser for bug report) + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 29-Jul-1998 (Rob Lake) + * fixed stand-alone mode. + * Added Pacific C compatible dos_getdate functions + * + * 09-Jan-1999 (Eric Kohl ) + * Added locale support + * + * 23-Jan-1999 (Eric Kohl ) + * Unicode and redirection safe! + * + * 04-Feb-1999 (Eric Kohl ) + * Fixed date input bug. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_DATE + +#include +#include +#include +#include + +#include "cmd.h" + + +static WORD awMonths[2][13] = +{ + {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} +}; + + +static VOID +PrintDate (VOID) +{ +#if 0 + SYSTEMTIME st; + + GetLocalTime (&st); + + switch (nDateFormat) + { + case 0: /* mmddyy */ + default: + ConOutPrintf (_T("Current date is: %s %02d%c%02d%c%04d\n"), + aszDayNames[st.wDayOfWeek], st.wMonth, cDateSeparator, st.wDay, cDateSeparator, st.wYear); + break; + + case 1: /* ddmmyy */ + ConOutPrintf (_T("Current date is: %s %02d%c%02d%c%04d\n"), + aszDayNames[st.wDayOfWeek], st.wDay, cDateSeparator, st.wMonth, cDateSeparator, st.wYear); + break; + + case 2: /* yymmdd */ + ConOutPrintf (_T("Current date is: %s %04d%c%02d%c%02d\n"), + aszDayNames[st.wDayOfWeek], st.wYear, cDateSeparator, st.wMonth, cDateSeparator, st.wDay); + break; + } +#endif + TCHAR szDate[32]; + + GetDateFormat (LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, + szDate, sizeof (szDate)); + ConOutPrintf (_T("Current date is: %s\n"), szDate); +} + + +static VOID +PrintDateString (VOID) +{ + switch (nDateFormat) + { + case 0: /* mmddyy */ + default: + ConOutPrintf (_T("Enter new date (mm%cdd%cyyyy): "), + cDateSeparator, cDateSeparator); + break; + + case 1: /* ddmmyy */ + ConOutPrintf (_T("Enter new date (dd%cmm%cyyyy): "), + cDateSeparator, cDateSeparator); + break; + + case 2: /* yymmdd */ + ConOutPrintf (_T("Enter new date (yyyy%cmm%cdd): "), + cDateSeparator, cDateSeparator); + break; + } +} + + +static BOOL +ReadNumber (LPTSTR *s, LPWORD lpwValue) +{ + if (_istdigit (**s)) + { + while (_istdigit (**s)) + { + *lpwValue = *lpwValue * 10 + **s - _T('0'); + (*s)++; + } + return TRUE; + } + return FALSE; +} + + +static BOOL +ReadSeparator (LPTSTR *s) +{ + if (**s == _T('/') || **s == _T('-') || **s == cDateSeparator) + { + (*s)++; + return TRUE; + } + return FALSE; +} + + +static BOOL +ParseDate (LPTSTR s) +{ + SYSTEMTIME d; + unsigned char leap; + LPTSTR p = s; + + if (!*s) + return TRUE; + + GetLocalTime (&d); + + d.wYear = 0; + d.wDay = 0; + d.wMonth = 0; + + switch (nDateFormat) + { + case 0: /* mmddyy */ + default: + if (!ReadNumber (&p, &d.wMonth)) + return FALSE; + if (!ReadSeparator (&p)) + return FALSE; + if (!ReadNumber (&p, &d.wDay)) + return FALSE; + if (!ReadSeparator (&p)) + return FALSE; + if (!ReadNumber (&p, &d.wYear)) + return FALSE; + break; + + case 1: /* ddmmyy */ + if (!ReadNumber (&p, &d.wDay)) + return FALSE; + if (!ReadSeparator (&p)) + return FALSE; + if (!ReadNumber (&p, &d.wMonth)) + return FALSE; + if (!ReadSeparator (&p)) + return FALSE; + if (!ReadNumber (&p, &d.wYear)) + return FALSE; + break; + + case 2: /* yymmdd */ + if (!ReadNumber (&p, &d.wYear)) + return FALSE; + if (!ReadSeparator (&p)) + return FALSE; + if (!ReadNumber (&p, &d.wMonth)) + return FALSE; + if (!ReadSeparator (&p)) + return FALSE; + if (!ReadNumber (&p, &d.wDay)) + return FALSE; + break; + } + + /* if only entered two digits: + /* assume 2000's if value less than 80 */ + /* assume 1900's if value greater or equal 80 */ + if (d.wYear <= 99) + { + if (d.wYear >= 80) + d.wYear = 1900 + d.wYear; + else + d.wYear = 2000 + d.wYear; + } + + leap = (!(d.wYear % 4) && (d.wYear % 100)) || !(d.wYear % 400); + + if ((d.wMonth >= 1 && d.wMonth <= 12) && + (d.wDay >= 1 && d.wDay <= awMonths[leap][d.wMonth]) && + (d.wYear >= 1980 && d.wYear <= 2099)) + { + SetLocalTime (&d); + return TRUE; + } + + return FALSE; +} + + +INT cmd_date (LPTSTR cmd, LPTSTR param) +{ + LPTSTR *arg; + INT argc; + INT i; + BOOL bPrompt = TRUE; + INT nDateString = -1; + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Displays or sets the date.\n\n" + "DATE [/T][date]\n\n" + " /T display only\n\n" + "Type DATE without parameters to display the current date setting and\n" + "a prompt for a new one. Press ENTER to keep the same date.")); + return 0; + } + + /* build parameter array */ + arg = split (param, &argc); + + /* check for options */ + for (i = 0; i < argc; i++) + { + if (_tcsicmp (arg[i], _T("/t")) == 0) + bPrompt = FALSE; + if ((*arg[i] != _T('/')) && (nDateString == -1)) + nDateString = i; + } + + if (nDateString == -1) + PrintDate (); + + if (!bPrompt) + { + freep (arg); + return 0; + } + + if (nDateString == -1) + { + while (TRUE) /* forever loop */ + { + TCHAR s[40]; + + PrintDateString (); + ConInString (s, 40); +#ifdef _DEBUG + DebugPrintf ("\'%s\'\n", s); +#endif + while (*s && s[_tcslen (s) - 1] < ' ') + s[_tcslen (s) - 1] = '\0'; + if (ParseDate (s)) + { + freep (arg); + return 0; + } + ConErrPuts ("Invalid date."); + } + } + else + { + if (ParseDate (arg[nDateString])) + { + freep (arg); + return 0; + } + ConErrPuts ("Invalid date."); + } + + freep (arg); + + return 0; +} +#endif + diff --git a/reactos/apps/utils/cmd/del.c b/reactos/apps/utils/cmd/del.c new file mode 100644 index 00000000000..c249670c472 --- /dev/null +++ b/reactos/apps/utils/cmd/del.c @@ -0,0 +1,271 @@ +/* + * DEL.C - del internal command. + * + * + * History: + * + * 06/29/98 (Rob Lake rlake@cs.mun.ca) + * rewrote del to support wildcards + * added my name to the contributors + * + * 07/13/98 (Rob Lake) + * fixed bug that caused del not to delete file with out + * attribute. moved set, del, ren, and ver to there own files + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 09-Dec-1998 (Eric Kohl ) + * Fixed command line parsing bugs. + * + * 21-Jan-1999 (Eric Kohl ) + * Started major rewrite using a new structure. + * + * 03-Jan-1999 (Eric Kohl ) + * First working version. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_DEL + +#include +#include +#include +#include + +#include "cmd.h" + + +#define PROMPT_NO 0 +#define PROMPT_YES 1 +#define PROMPT_ALL 2 +#define PROMPT_BREAK 3 + + +static BOOL ConfirmDeleteAll (VOID) +{ + TCHAR inp[10]; + LPTSTR p; + + ConOutPrintf ("All files in directory will be deleted!\n" + "Are you sure (Y/N)? "); + ConInString (inp, 10); + + _tcsupr (inp); + for (p = inp; _istspace (*p); p++) + ; + + if (*p == _T('Y')) + return PROMPT_YES; + else if (*p == _T('N')) + return PROMPT_NO; + +#if 0 + if (*p == _T('A')) + return PROMPT_ALL; + else if (*p == _T('\03')) + return PROMPT_BREAK; +#endif + + return PROMPT_NO; +} + + +static INT Prompt (LPTSTR str) +{ + TCHAR inp[10]; + LPTSTR p; + + ConOutPrintf (_T("Delete %s (Yes/No)? "), str); + ConInString (inp, 10); + + _tcsupr (inp); + for (p = inp; _istspace (*p); p++) + ; + + if (*p == _T('Y')) + return PROMPT_YES; + else if (*p == _T('N')) + return PROMPT_NO; + +#if 0 + if (*p == _T('A')) + return PROMPT_ALL; + else if (*p == _T('\03')) + return PROMPT_BREAK; +#endif +} + + + +INT cmd_del (LPTSTR cmd, LPTSTR param) +{ + LPTSTR *arg = NULL; + INT args; + INT i; + INT nEvalArgs = 0; /* nunber of evaluated arguments */ + BOOL bNothing = FALSE; + BOOL bQuiet = FALSE; + BOOL bPrompt = FALSE; + + HANDLE hFile; + WIN32_FIND_DATA f; +// DWORD dwAttributes; + + + if (!_tcsncmp (param, _T("/?"), 2)) + { +/* + ConOutPuts (_T("Deletes one or more files.\n\n" + "DEL [drive:][path]filename [/P]\n" + "DELETE [drive:][path]filename [/P]\n" + "ERASE [drive:][path]filename [/P]\n\n" + " [drive:][path]filename Specifies the file(s) to delete. Specify multiple\n" + " files by using wildcards.\n" + " /P Prompts for confirmation before deleting each file.")); +*/ + + ConOutPuts (_T("Deletes one or more files.\n" + "\n" + "DEL [/N /P /Q] file ...\n" + "DELETE [/N /P /Q] file ...\n" + "ERASE [/N /P /Q] file ...\n" + "\n" + " file Specifies the file(s) to delete.\n" + "\n" + " /N Nothing.\n" + " /P Prompts for confirmation before deleting each file.\n" + " (Not implemented yet!)\n" + " /Q Quiet." + )); + + return 0; + } + + arg = split (param, &args); + + if (args > 0) + { + /* check for options anywhere in command line */ + for (i = 0; i < args; i++) + { + if (*arg[i] == _T('/')) + { + if (_tcslen (arg[i]) >= 2) + { + switch (_totupper (arg[i][1])) + { + case _T('N'): + bNothing = TRUE; + break; + + case _T('P'): + bPrompt = TRUE; + break; + + case _T('Q'): + bQuiet = TRUE; + break; + } + + } + + nEvalArgs++; + } + } + + /* there are only options on the command line --> error!!! */ + if (args == nEvalArgs) + { + error_req_param_missing (); + freep (arg); + return 1; + } + + /* check for filenames anywhere in command line */ + for (i = 0; i < args; i++) + { + if (!_tcscmp (arg[i], _T("*")) || + !_tcscmp (arg[i], _T("*.*"))) + { + if (!ConfirmDeleteAll ()) + break; + + } + + if (*arg[i] != _T('/')) + { +#ifdef _DEBUG + ConErrPrintf ("File: %s\n", arg[i]); +#endif + + if (_tcschr (arg[i], _T('*')) || _tcschr (arg[i], _T('?'))) + { + /* wildcards in filespec */ +#ifdef _DEBUG + ConErrPrintf ("Wildcards!\n\n"); +#endif + + hFile = FindFirstFile (arg[i], &f); + if (hFile == INVALID_HANDLE_VALUE) + { + error_file_not_found (); + freep (arg); + return 0; + } + + do + { + if (!_tcscmp (f.cFileName, _T(".")) || + !_tcscmp (f.cFileName, _T(".."))) + continue; + +#ifdef _DEBUG + ConErrPrintf ("Delete file: %s\n", f.cFileName); +#endif + + if (!bNothing) + { + if (!DeleteFile (f.cFileName)) + ErrorMessage (GetLastError(), _T("")); + } + + + } + while (FindNextFile (hFile, &f)); + FindClose (hFile); + } + else + { + /* no wildcards in filespec */ +#ifdef _DEBUG + ConErrPrintf ("No Wildcards!\n"); + ConErrPrintf ("Delete file: %s\n", arg[i]); +#endif + + if (!bNothing) + { + if (!DeleteFile (arg[i])) + ErrorMessage (GetLastError(), _T("")); + } + } + } + } + } + else + { + /* only command given */ + error_req_param_missing (); + freep (arg); + return 1; + } + + freep (arg); + + return 0; +} + +#endif diff --git a/reactos/apps/utils/cmd/dir.c b/reactos/apps/utils/cmd/dir.c new file mode 100644 index 00000000000..c56d8470bb3 --- /dev/null +++ b/reactos/apps/utils/cmd/dir.c @@ -0,0 +1,1225 @@ +/* + * DIR.C - dir internal command. + * + * + * History: + * + * 01/29/97 (Tim Norman) + * started. + * + * 06/13/97 (Tim Norman) + * Fixed code. + * + * 07/12/97 (Tim Norman) + * Fixed bug that caused the root directory to be unlistable + * + * 07/12/97 (Marc Desrochers) + * Changed to use maxx, maxy instead of findxy() + * + * 06/08/98 (Rob Lake) + * Added compatibility for /w in dir + * + * 06/09/98 (Rob Lake) + * Compatibility for dir/s started + * Tested that program finds directories off root fine + * + * 06/10/98 (Rob Lake) + * do_recurse saves the cwd and also stores it in Root + * build_tree adds the cwd to the beginning of its' entries + * Program runs fine, added print_tree -- works fine.. as EXE, + * program won't work properly as COM. + * + * 06/11/98 (Rob Lake) + * Found problem that caused COM not to work + * + * 06/12/98 (Rob Lake) + * debugged... + * added free mem routine + * + * 06/13/98 (Rob Lake) + * debugged the free mem routine + * debugged whole thing some more + * Notes: + * ReadDir stores Root name and _Read_Dir does the hard work + * PrintDir prints Root and _Print_Dir does the hard work + * KillDir kills Root _after_ _Kill_Dir does the hard work + * Integrated program into DIR.C(this file) and made some same + * changes throughout + * + * 06/14/98 (Rob Lake) + * Cleaned up code a bit, added comments + * + * 06/16/98 (Rob Lake) + * Added error checking to my previously added routines + * + * 06/17/98 (Rob Lake) + * Rewrote recursive functions, again! Most other recursive + * functions are now obsolete -- ReadDir, PrintDir, _Print_Dir, + * KillDir and _Kill_Dir. do_recurse does what PrintDir did + * and _Read_Dir did what it did before along with what _Print_Dir + * did. Makes /s a lot faster! + * Reports 2 more files/dirs that MS-DOS actually reports + * when used in root directory(is this because dir defaults + * to look for read only files?) + * Added support for /b, /a and /l + * Made error message similar to DOS error messages + * Added help screen + * + * 06/20/98 (Rob Lake) + * Added check for /-(switch) to turn off previously defined + * switches. + * Added ability to check for DIRCMD in environment and + * process it + * + * 06/21/98 (Rob Lake) + * Fixed up /B + * Now can dir *.ext/X, no spaces! + * + * 06/29/98 (Rob Lake) + * error message now found in command.h + * + * 07/08/1998 (John P. Price) + * removed extra returns; closer to MSDOS + * fixed wide display so that an extra return is not displayed + * when there is five filenames in the last line. + * + * 07/12/98 (Rob Lake) + * Changed error messages + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * + * 04-Dec-1998 (Eric Kohl ) + * Converted source code to Win32, except recursive dir ("dir /s"). + * + * 10-Dec-1998 (Eric Kohl ) + * Fixed recursive dir ("dir /s"). + * + * 14-Dec-1998 (Eric Kohl ) + * Converted to Win32 directory functions and + * fixed some output bugs. There are still some more ;) + * + * 10-Jan-1999 (Eric Kohl ) + * Added "/N" and "/4" options, "/O" is a dummy. + * Added locale support. + * + * 20-Jan-1999 (Eric Kohl ) + * Redirection safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_DIR +#include +#include +#include +#include +#include + +#include + +#include "cmd.h" + + +/* useful macro */ +#define MEM_ERR error_out_of_memory(); return 1; + + +/* flag definitions */ +/* Changed hex to decimal, hex wouldn't work + * if > 8, Rob Lake 06/17/98. + */ +enum +{ + DIR_RECURSE = 0x0001, + DIR_PAGE = 0x0002, + DIR_WIDE = 0x0004, /* Rob Lake */ + DIR_BARE = 0x0008, /* Rob Lake */ + DIR_ALL = 0x0010, /* Rob Lake */ + DIR_LWR = 0x0020, /* Rob Lake */ + DIR_SORT = 0x0040, /* /O sort */ + DIR_NEW = 0x0080, /* /N new style */ + DIR_FOUR = 0x0100 /* /4 four digit year */ +}; + + +/* Globally save the # of dirs, files and bytes, + * probabaly later pass them to functions. Rob Lake */ +long recurse_dir_cnt; +long recurse_file_cnt; +ULARGE_INTEGER recurse_bytes; + + +/* + * help + * + * displays help screen for dir + * Rob Lake + */ +static VOID Help (VOID) +{ +#if 1 + ConOutPuts (_T("Displays a list of files and subdirectories in a directory.\n" + "\n" + "DIR [drive:][path][filename] [/A] [/B] [/L] [/N] [/S] [/P] [/W] [/4]\n" + "\n" + " [drive:][path][filename]\n" + " Specifies drive, directory, and/or files to list.\n" + "\n" + " /A Displays files with HIDDEN SYSTEM attributes\n" + " default is ARCHIVE and READ ONLY\n" + " /B Uses bare format (no heading information or summary).\n" + " /L Uses lowercase.\n" + " /N New long list format where filenames are on the far right.\n" + " /S Displays files in specified directory and all subdirectories\n" + " /P Pauses after each screen full\n" + " /W Prints in wide format\n" + " /4 Display four digit years.\n" + "\n" + "Switches may be present in the DIRCMD environment variable. Use\n" + "of the - (hyphen) can turn off defined swtiches. Ex. /-W would\n" + "turn off printing in wide format.\n" + )); +#endif +#if 0 + InitializePageOut (); + LinePageOut (_T("Displays a list of files and subdirectories in a directory.")); + LinePageOut (_T("")); + LinePageOut (_T("DIR [drive:][path][filename] [/A] [/B] [/L] [/N] [/S] [/P] [/W] [/4]")); + LinePageOut (_T("")); + LinePageOut (_T(" [drive:][path][filename]")); + LinePageOut (_T(" Specifies drive, directory, and/or files to list.")); + LinePageOut (_T("")); + LinePageOut (_T(" /A Displays files with HIDDEN SYSTEM attributes")); + LinePageOut (_T(" default is ARCHIVE and READ ONLY")); + LinePageOut (_T(" /B Uses bare format (no heading information or summary).")); + LinePageOut (_T(" /L Uses lowercase.")); + LinePageOut (_T(" /N New long list format where filenames are on the far right.")); + LinePageOut (_T(" /S Displays files in specified directory and all subdirectories")); + LinePageOut (_T(" /P Pauses after each screen full")); + LinePageOut (_T(" /W Prints in wide format")); + LinePageOut (_T(" /4 Display four digit years.")); + LinePageOut (_T("")); + LinePageOut (_T("Switches may be present in the DIRCMD environment variable. Use")); + LinePageOut (_T("of the - (hyphen) can turn off defined swtiches. Ex. /-W would")); + LinePageOut (_T("turn off printing in wide format.")); + TerminatePageOut (); +#endif +} + + +/* + * dir_read_param + * + * read the parameters from the command line + */ +static BOOL +DirReadParam (char *line, char **param, LPDWORD lpFlags) +{ + int slash = 0; + + if (!line) + return TRUE; + + *param = NULL; + + /* scan the command line, processing switches */ + while (*line) + { + /* process switch */ + if (*line == _T('/') || slash) + { + if (!slash) + line++; + slash = 0; + if (*line == _T('-')) + { + line++; + if (_totupper (*line) == _T('S')) + *lpFlags &= ~DIR_RECURSE; + else if (_totupper (*line) == _T('P')) + *lpFlags &= ~DIR_PAGE; + else if (_totupper (*line) == _T('W')) + *lpFlags &= ~DIR_WIDE; + else if (_totupper (*line) == _T('B')) + *lpFlags &= ~DIR_BARE; + else if (_totupper (*line) == _T('A')) + *lpFlags &= ~DIR_ALL; + else if (_totupper (*line) == _T('L')) + *lpFlags &= ~DIR_LWR; + else if (_totupper (*line) == _T('N')) + *lpFlags &= ~DIR_NEW; + else if (_totupper (*line) == _T('O')) + *lpFlags &= ~DIR_SORT; + else if (_totupper (*line) == _T('4')) + *lpFlags &= ~DIR_FOUR; + else + { + error_invalid_switch ((TCHAR)_totupper (*line)); + return FALSE; + } + line++; + continue; + } + else + { + if (_totupper (*line) == _T('S')) + *lpFlags |= DIR_RECURSE; + else if (_toupper (*line) == _T('P')) + *lpFlags |= DIR_PAGE; + else if (_totupper (*line) == _T('W')) + *lpFlags |= DIR_WIDE; + else if (_totupper (*line) == _T('B')) + *lpFlags |= DIR_BARE; + else if (_totupper (*line) == _T('A')) + *lpFlags |= DIR_ALL; + else if (_totupper (*line) == _T('L')) + *lpFlags |= DIR_LWR; + else if (_totupper (*line) == _T('N')) + *lpFlags |= DIR_NEW; + else if (_totupper (*line) == _T('O')) + *lpFlags |= DIR_SORT; + else if (_totupper (*line) == _T('4')) + *lpFlags |= DIR_FOUR; + else if (*line == _T('?')) + { + Help(); + return FALSE; + } + else + { + error_invalid_switch ((TCHAR)_totupper (*line)); + return FALSE; + } + line++; + continue; + } + } + + /* process parameter */ + if (!_istspace (*line)) + { + if (*param) + { + error_too_many_parameters (*param); + return FALSE; + } + + *param = line; + + /* skip to end of line or next whitespace or next / */ + while (*line && !_istspace (*line) && *line != _T('/')) + line++; + + /* if end of line, return */ + if (!*line) + return TRUE; + + /* if parameter, remember to process it later */ + if (*line == _T('/')) + slash = 1; + + *line++ = 0; + continue; + } + + line++; + } + + if (slash) + { + error_invalid_switch ((TCHAR)_totupper (*line)); + return FALSE; + } + + return TRUE; +} + + +/* + * extend_file + * + * extend the filespec, possibly adding wildcards + */ +void extend_file (char **file) +{ + LPTSTR tmp; + + if (!*file) + return; + + /* if no file spec, change to "*.*" */ + if (!**file) + { + free (*file); + *file = _tcsdup (_T("*.*")); + return; + } + + /* if starts with . add * in front */ + if (**file == _T('.')) + { + tmp = malloc ((_tcslen (*file) + 2) * sizeof(TCHAR)); + if (tmp) + { + *tmp = _T('*'); + _tcscpy (&tmp[1], *file); + } + free (*file); + *file = tmp; + return; + } + + /* if no . add .* */ + if (!_tcschr (*file, _T('.'))) + { + tmp = malloc ((_tcslen (*file) + 3) * sizeof(TCHAR)); + if (tmp) + { + _tcscpy (tmp, *file); + _tcscat (tmp, _T(".*")); + } + free (*file); + *file = tmp; + return; + } +} + + +/* + * dir_parse_pathspec + * + * split the pathspec into drive, directory, and filespec + */ +static int +DirParsePathspec (char *pathspec, int *drive, char **dir, char **file) +{ + TCHAR orig_dir[MAX_PATH]; + LPTSTR start; + LPTSTR tmp; + INT i; + INT wildcards = 0; + + + /* get the drive and change to it */ + if (pathspec[1] == _T(':')) + { + *drive = _totupper (pathspec[0]) - _T('@'); + start = pathspec + 2; + _chdrive (*drive); + } + else + { + *drive = _getdrive (); + start = pathspec; + } + + GetCurrentDirectory (MAX_PATH, orig_dir); + + /* check for wildcards */ + for (i = 0; pathspec[i]; i++) + if (pathspec[i] == _T('*') || pathspec[i] == _T('?')) + wildcards = 1; + + /* check if this spec is a directory */ + if (!wildcards) + { + if (chdir(pathspec) == 0) + { + *file = _tcsdup (_T("*.*")); + if (!*file) + { + MEM_ERR + } + + tmp = getcwd (NULL, MAX_PATH); + if (!tmp) + { + free (*file); + chdir (orig_dir); + MEM_ERR + } + + *dir = _tcsdup (&tmp[2]); + free (tmp); + if (!*dir) + { + free (*file); + chdir (orig_dir); + MEM_ERR + } + + chdir (orig_dir); + return 0; + } + } + + /* find the file spec */ + tmp = _tcsrchr (start, _T('\\')); + + /* if no path is specified */ + if (!tmp) + { + *file = _tcsdup (start); + extend_file (file); + if (!*file) + { + MEM_ERR + } + + tmp = getcwd (NULL, _MAX_PATH); + if (!tmp) + { + free (*file); + chdir (orig_dir); + MEM_ERR + } + *dir = _tcsdup (&tmp[2]); + free(tmp); + if (!*dir) + { + free (*file); + chdir (orig_dir); + MEM_ERR + } + + return 0; + } + + /* get the filename */ + *file = _tcsdup (tmp + 1); + extend_file (file); + if (!*file) + { + MEM_ERR + } + + *tmp = 0; + + /* change to this directory and get its full name */ + if (chdir (start) < 0) + { + error_path_not_found (); + *tmp = _T('\\'); + free (*file); + chdir (orig_dir); + return 1; + } + + tmp = getcwd (NULL, _MAX_PATH); + if (!tmp) + { + free (*file); + MEM_ERR + } + *dir = _tcsdup (&tmp[2]); + free(tmp); + if (!*dir) + { + free(*file); + MEM_ERR + } + + *tmp = _T('\\'); + + chdir(orig_dir); + return 0; +} + + +/* + * pause + * + * pause until a key is pressed + */ +static INT +Pause (VOID) +{ + cmd_pause ("", ""); + + return 0; +} + + +/* + * incline + * + * increment our line if paginating, display message at end of screen + */ +static INT +incline (int *line, DWORD dwFlags) +{ + if (!(dwFlags & DIR_PAGE)) + return 0; + + (*line)++; + + if (*line >= (int)maxy - 2) + { + *line = 0; + return Pause (); + } + + return 0; +} + + +/* + * PrintDirectoryHeader + * + * print the header for the dir command + */ +static BOOL +PrintDirectoryHeader (int drive, int *line, DWORD dwFlags) +{ + TCHAR szRootName[] = _T("A:\\"); + TCHAR szVolName[80]; + DWORD dwSerialNr; + + if (dwFlags & DIR_BARE) + return TRUE; + + /* get the media ID of the drive */ + szRootName[0] = drive + _T('@'); + if (!GetVolumeInformation (szRootName, szVolName, 80, &dwSerialNr, + NULL, NULL, NULL, 0)) + { + error_invalid_drive(); + return FALSE; + } + + /* print drive info */ + ConOutPrintf (_T(" Volume in drive %c"), szRootName[0]); + + if (szVolName[0] != _T('\0')) + ConOutPrintf (_T(" is %s\n"), szVolName); + else + ConOutPrintf (_T(" has no label\n")); + + if (incline (line, dwFlags) != 0) + return FALSE; + + /* print the volume serial number if the return was successful */ + ConOutPrintf (_T(" Volume Serial Number is %04X-%04X\n"), + HIWORD(dwSerialNr), LOWORD(dwSerialNr)); + if (incline (line, dwFlags) != 0) + return FALSE; + + return TRUE; +} + + +/* + * convert + * + * insert commas into a number + */ +static INT +ConvertLong (LONG num, LPTSTR des, INT len) +{ + TCHAR temp[32]; + INT c = 0; + INT n = 0; + + if (num == 0) + { + des[0] = _T('0'); + des[1] = _T('\0'); + n = 1; + } + else + { + temp[31] = 0; + while (num > 0) + { + if (((c + 1) % (nNumberGroups + 1)) == 0) + temp[30 - c++] = cThousandSeparator; + temp[30 - c++] = (TCHAR)(num % 10) + _T('0'); + num /= 10; + } + + for (n = 0; n <= c; n++) + des[n] = temp[31 - c + n]; + } + + return n; +} + + +static INT +ConvertULargeInteger (ULARGE_INTEGER num, LPTSTR des, INT len) +{ + TCHAR temp[32]; + INT c = 0; + INT n = 0; + + if (num.QuadPart == 0) + { + des[0] = _T('0'); + des[1] = _T('\0'); + n = 1; + } + else + { + temp[31] = 0; + while (num.QuadPart > 0) + { + if (((c + 1) % (nNumberGroups + 1)) == 0) + temp[30 - c++] = cThousandSeparator; + temp[30 - c++] = (TCHAR)(num.QuadPart % 10) + _T('0'); + num.QuadPart /= 10; + } + + for (n = 0; n <= c; n++) + des[n] = temp[31 - c + n]; + } + + return n; +} + + +static VOID +PrintFileDateTime (LPSYSTEMTIME dt, DWORD dwFlags) +{ + WORD wYear = (dwFlags & DIR_FOUR) ? dt->wYear : dt->wYear%100; + + switch (nDateFormat) + { + case 0: /* mmddyy */ + default: + ConOutPrintf ("%.2d%c%.2d%c%d", dt->wMonth, cDateSeparator, dt->wDay, cDateSeparator, wYear); + break; + + case 1: /* ddmmyy */ + ConOutPrintf ("%.2d%c%.2d%c%d", + dt->wDay, cDateSeparator, dt->wMonth, cDateSeparator, wYear); + break; + + case 2: /* yymmdd */ + ConOutPrintf ("%d%c%.2d%c%.2d", + wYear, cDateSeparator, dt->wMonth, cDateSeparator, dt->wDay); + break; + } + + switch (nTimeFormat) + { + case 0: /* 12 hour format */ + default: + ConOutPrintf (" %2d%c%.2u%c", + (dt->wHour == 0 ? 12 : (dt->wHour <= 12 ? dt->wHour : dt->wHour - 12)), + cTimeSeparator, + dt->wMinute, (dt->wHour <= 11 ? 'a' : 'p')); + break; + + case 1: /* 24 hour format */ + ConOutPrintf (" %2d%c%.2u", + dt->wHour, cTimeSeparator, dt->wMinute); + break; + } +} + + +/* + * print_summary: prints dir summary + * Added by Rob Lake 06/17/98 to compact code + * Just copied Tim's Code and patched it a bit + * + */ +static INT +PrintSummary (int drive, long files, long dirs, ULARGE_INTEGER bytes, + DWORD flags, int *line) +{ + TCHAR buffer[64]; + + if (flags & DIR_BARE) + return 0; + + /* print number of files and bytes */ + ConvertLong (files, buffer, sizeof(buffer)); + ConOutPrintf (_T(" %6s File%c"), + buffer, files == 1 ? _T(' ') : _T('s')); + + ConvertULargeInteger (bytes, buffer, sizeof(buffer)); + ConOutPrintf (_T(" %15s byte%c\n"), + buffer, bytes.QuadPart == 1 ? _T(' ') : _T('s')); + + if (incline (line, flags) != 0) + return 1; + + /* print number of dirs and bytes free */ + ConvertLong (dirs, buffer, sizeof(buffer)); + ConOutPrintf (_T(" %6s Dir%c"), + buffer, files == 1 ? _T(' ') : _T('s')); + + + if (!(flags & DIR_RECURSE)) + { + ULARGE_INTEGER uliFree; + TCHAR szRoot[] = _T("A:\\"); + DWORD dwSecPerCl; + DWORD dwBytPerSec; + DWORD dwFreeCl; + DWORD dwTotCl; + + szRoot[0] = drive + _T('@'); + GetDiskFreeSpace (szRoot, &dwSecPerCl, &dwBytPerSec, &dwFreeCl, &dwTotCl); + uliFree.QuadPart = dwSecPerCl * dwBytPerSec * dwFreeCl; + ConvertULargeInteger (uliFree, buffer, sizeof(buffer)); + ConOutPrintf (_T(" %15s bytes free\n"), buffer); + } + + if (incline (line, flags) != 0) + return 1; + + return 0; +} + + +/* + * dir_list + * + * list the files in the directory + */ +static int +dir_list (int drive, char *directory, char *filespec, int *line, + DWORD flags) +{ + char pathspec[_MAX_PATH], + *ext, + buffer[32]; + WIN32_FIND_DATA file; + ULARGE_INTEGER bytecount; + long filecount = 0, + dircount = 0; + int count; + FILETIME ft; + SYSTEMTIME dt; + HANDLE hFile; + + bytecount.QuadPart = 0; + + if (directory[strlen(directory) - 1] == '\\') + wsprintf(pathspec, "%c:%s%s", drive + '@', directory, filespec); + else + wsprintf(pathspec, "%c:%s\\%s", drive + '@', directory, filespec); + + hFile = FindFirstFile (pathspec, &file); + if (hFile == INVALID_HANDLE_VALUE) + { + /* Don't want to print anything if scanning recursively + * for a file. RL + */ + if ((flags & DIR_RECURSE) == 0) + { + error_file_not_found(); + incline(line, flags); + FindClose (hFile); + return 1; + } + FindClose (hFile); + return 0; + } + + /* moved down here because if we are recursively searching and + * don't find any files, we don't want just to print + * Directory of C:\SOMEDIR + * with nothing else + * Rob Lake 06/13/98 + */ + if ((flags & DIR_BARE) == 0) + { + ConOutPrintf (" Directory of %c:%s\n", drive + '@', directory); + if (incline(line, flags) != 0) + return 1; + ConOutPrintf ("\n"); + if (incline(line, flags) != 0) + return 1; + } + + /* For counting columns of output */ + count = 0; + + do + { + /* next file, if user doesn't want all files */ + if (!(flags & DIR_ALL) && + ((file.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) || + (file.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM))) + continue; + + /* begin Rob Lake */ + if (flags & DIR_LWR) + { + strlwr(file.cAlternateFileName); + } + + if (flags & DIR_WIDE && (flags & DIR_BARE) == 0) + { + if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if (file.cAlternateFileName[0] == '\0') + wsprintf (buffer, _T("[%s]"), file.cFileName); + else + wsprintf (buffer, _T("[%s]"), file.cAlternateFileName); + dircount++; + } + else + { + if (file.cAlternateFileName[0] == '\0') + wsprintf (buffer, _T("%s"), file.cFileName); + else + wsprintf (buffer, _T("%s"), file.cAlternateFileName); + filecount++; + } + ConOutPrintf (_T("%-15s"), buffer); + count++; + if (count == 5) + { + /* output 5 columns */ + ConOutPrintf ("\n"); + if (incline(line, flags) != 0) + return 1; + count = 0; + } + + /* FIXME: this is buggy - now overflow check */ + bytecount.LowPart += file.nFileSizeLow; + bytecount.HighPart += file.nFileSizeHigh; + + /* next block 06/17/98 */ + } + else if (flags & DIR_BARE) + { + if (strcmp(file.cFileName, ".") == 0 || + strcmp(file.cFileName, "..") == 0) + continue; + + if (flags & DIR_RECURSE) + { + TCHAR dir[MAX_PATH]; + wsprintf (dir, _T("%c:%s\\"), drive + _T('@'), directory); + if (flags & DIR_LWR) + strlwr(dir); + ConOutPrintf (dir); + } + ConOutPrintf (_T("%-13s\n"), file.cFileName); + if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + dircount++; + else + filecount++; + if (incline(line, flags) != 0) + return 1; + + /* FIXME: this is buggy - no overflow check */ + bytecount.LowPart += file.nFileSizeLow; + bytecount.HighPart += file.nFileSizeHigh; + } + else + { + /* end Rob Lake */ + if (flags & DIR_NEW) + { + /* print file date and time */ + if (FileTimeToLocalFileTime (&file.ftLastWriteTime, &ft)) + { + FileTimeToSystemTime (&ft, &dt); + PrintFileDateTime (&dt, flags); + } + + /* print file size */ + if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + ConOutPrintf (" "); + dircount++; + } + else + { + ULARGE_INTEGER uliSize; + + uliSize.LowPart = file.nFileSizeLow; + uliSize.HighPart = file.nFileSizeHigh; + + ConvertULargeInteger (uliSize, buffer, sizeof(buffer)); + ConOutPrintf (_T(" %20s"), buffer); + + bytecount.QuadPart += uliSize.QuadPart; + filecount++; + } + + /* print long filename */ + ConOutPrintf (" %s\n", file.cFileName); + } + else + { + if (file.cFileName[0] == '.') + ConOutPrintf ("%-13s ", file.cFileName); + else if (file.cAlternateFileName[0] == '\0') + { + char szShortName[13]; + strncpy (szShortName, file.cFileName, 13); + ext = strchr(szShortName, '.'); + if (!ext) + ext = ""; + else + *ext++ = 0; + ConOutPrintf ("%-8s %-3s ", szShortName, ext); + } + else + { + ext = strchr(file.cAlternateFileName, '.'); + if (!ext) + ext = ""; + else + *ext++ = 0; + ConOutPrintf ("%-8s %-3s ", file.cAlternateFileName, ext); + } + + /* print file size */ + if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + ConOutPrintf ("%-14s", ""); + dircount++; + } + else + { + ULARGE_INTEGER uliSize; + + uliSize.LowPart = file.nFileSizeLow; + uliSize.HighPart = file.nFileSizeHigh; + + ConvertULargeInteger (uliSize, buffer, sizeof(buffer)); + ConOutPrintf (_T(" %10s "), buffer); + + bytecount.QuadPart += uliSize.QuadPart; + filecount++; + } + + /* print file date and time */ + if (FileTimeToLocalFileTime (&file.ftLastWriteTime, &ft)) + { + FileTimeToSystemTime (&ft, &dt); + PrintFileDateTime (&dt, flags); + } + + /* print long filename */ + ConOutPrintf (" %s\n", file.cFileName); + } + + if (incline(line, flags) != 0) + return 1; + } + } + while (FindNextFile (hFile, &file)); + + FindClose (hFile); + + /* Rob Lake, need to make clean output */ + /* JPP 07/08/1998 added check for count != 0 */ + if ((flags & DIR_WIDE) && (count != 0)) + { + ConOutPrintf ("\n"); + if (incline(line, flags) != 0) + return 1; + } + + if (filecount || dircount) + { + recurse_dir_cnt += dircount; + recurse_file_cnt += filecount; + recurse_bytes.QuadPart += bytecount.QuadPart; + + /* The code that was here is now in print_summary */ + if (PrintSummary (drive, filecount, dircount, + bytecount, flags, line) != 0) + return 1; + } + else + { + error_file_not_found (); + return 1; + } + + return 0; +} + + +/* + * _Read_Dir: Actual function that does recursive listing + */ +static int +Read_Dir (int drive, char *parent, char *filespec, int *lines, + DWORD flags) +{ + char fullpath[_MAX_PATH]; + WIN32_FIND_DATA file; + HANDLE hFile; + + strcpy (fullpath, parent); + strcat (fullpath, "\\"); + strcat (fullpath, filespec); + + hFile = FindFirstFile (fullpath, &file); + if (hFile == INVALID_HANDLE_VALUE) + return 1; + + do + { + /* don't list "." and ".." */ + if (strcmp (file.cFileName, ".") == 0 || + strcmp (file.cFileName, "..") == 0) + continue; + + if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if (dir_list(drive, file.cFileName, filespec, lines, flags) != 0) + { + FindClose (hFile); + return 1; + } + if ((flags & DIR_BARE) == 0) + { + ConOutPrintf ("\n"); + if (incline(lines, flags) != 0) + return 1; + } + if (Read_Dir(drive, file.cFileName, filespec, lines, flags) == 1) + { + FindClose (hFile); + return 1; + } + } + } + while (FindNextFile (hFile, &file)); + + if (!FindClose (hFile)) + return 1; + + return 0; +} + + +/* + * do_recurse: Sets up for recursive directory listing + */ +static int +do_recurse(int drive, char *directory, char *filespec, + int *line, DWORD flags) +{ + char cur_dir[_MAX_DIR]; + + recurse_dir_cnt = recurse_file_cnt = 0L; + recurse_bytes.QuadPart = 0; + + _chdrive (drive); + getcwd(cur_dir, sizeof(cur_dir)); + + if (chdir(directory) == -1) + return 1; + + if (!PrintDirectoryHeader (drive, line, flags)) + return 1; + + if (dir_list(drive, directory, filespec, line, flags) != 0) + return 1; + if ((flags & DIR_BARE) == 0) + { + ConOutPrintf ("\n"); + if (incline(line, flags) != 0) + return 1; + } + if (Read_Dir(drive, directory, filespec, line, flags) != 0) + return 1; + if ((flags & DIR_BARE) == 0) + ConOutPrintf ("Total files listed:\n"); + flags &= ~DIR_RECURSE; + + if (PrintSummary (drive, recurse_file_cnt, + recurse_dir_cnt, recurse_bytes, flags, line) != 0) + return 1; + + if ((flags & DIR_BARE) == 0) + { + ConOutPrintf ("\n"); + if (incline(line, flags) != 0) + return 1; + } + chdir(cur_dir); + return 0; +} + + +/* + * dir + * + * internal dir command + */ +INT cmd_dir (LPTSTR first, LPTSTR rest) +{ + DWORD dwFlags = DIR_NEW | DIR_FOUR; + char *param; + TCHAR dircmd[256]; + int line = 0; + int drive, + orig_drive; + char *directory, + *filespec, + orig_dir[_MAX_DIR]; + + + /* read the parameters from the DIRCMD environment variable */ + if (GetEnvironmentVariable (_T("DIRCMD"), dircmd, 256)) + { + if (!DirReadParam (dircmd, ¶m, &dwFlags)) + return 1; + } + + /* read the parameters */ + if (!DirReadParam (rest, ¶m, &dwFlags)) + return 1; + + /* default to current directory */ + if (!param) + param = "."; + + if (strchr(param, '/')) + param = strtok (param, "/"); + + /* save the current directory info */ + orig_drive = _getdrive (); + getcwd(orig_dir, sizeof(orig_dir)); + + /* parse the directory info */ + if (DirParsePathspec (param, &drive, &directory, &filespec) != 0) + { + _chdrive (orig_drive); + chdir(orig_dir); + return 1; + } + + if (dwFlags & DIR_RECURSE) + { + incline(&line, dwFlags); + if (do_recurse (drive, directory, filespec, &line, dwFlags) != 0) + return 1; + _chdrive (orig_drive); + chdir (orig_dir); + return 0; + } + + /* print the header */ + if (!PrintDirectoryHeader (drive, &line, dwFlags)) + return 1; + + chdir (orig_dir); + _chdrive (orig_drive); + + if (dir_list (drive, directory, filespec, &line, dwFlags) != 0) + return 1; + + return 0; +} + +#endif diff --git a/reactos/apps/utils/cmd/dirstack.c b/reactos/apps/utils/cmd/dirstack.c new file mode 100644 index 00000000000..5c00c21d609 --- /dev/null +++ b/reactos/apps/utils/cmd/dirstack.c @@ -0,0 +1,183 @@ +/* + * DIRSTACK.C - pushd / pop (directory stack) internal commands. + * + * + * History: + * + * 14-Dec-1998 (Eric Kohl ) + * Implemented PUSHD and POPD command. + * + * 20-Jan-1999 (Eric Kohl ) + * Unicode and redirection safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef FEATURE_DIRECTORY_STACK + +#include +#include +#include +#include + +#include "cmd.h" + + +typedef struct tagDIRENTRY +{ + struct tagDIRENTRY *next; + LPTSTR pszPath; +} DIRENTRY, *LPDIRENTRY; + + +static INT nStackDepth; +static LPDIRENTRY lpStackTop; + + +static INT +PushDirectory (LPTSTR pszPath) +{ + LPDIRENTRY lpDir; + + lpDir = (LPDIRENTRY)malloc (sizeof (DIRENTRY)); + if (!lpDir) + { + error_out_of_memory (); + return -1; + } + + lpDir->next = (lpStackTop) ? lpStackTop : NULL; + lpStackTop = lpDir; + + lpDir->pszPath = (LPTSTR)malloc ((_tcslen(pszPath)+1)*sizeof(TCHAR)); + if (!lpDir->pszPath) + { + free (lpDir); + error_out_of_memory (); + return -1; + } + + _tcscpy (lpDir->pszPath, pszPath); + + nStackDepth++; + + return 0; +} + + +static VOID +PopDirectory (VOID) +{ + LPDIRENTRY lpDir; + + if (nStackDepth == 0) + return; + + lpDir = lpStackTop; + lpStackTop = lpDir->next; + free (lpDir->pszPath); + free (lpDir); + + nStackDepth--; +} + + +static VOID +GetDirectoryStackTop (LPTSTR pszPath) +{ + if (lpStackTop) + _tcsncpy (pszPath, lpStackTop->pszPath, MAX_PATH); + else + *pszPath = _T('\0'); +} + + +/* + * initialize directory stack + */ +VOID InitDirectoryStack (VOID) +{ + nStackDepth = 0; + lpStackTop = NULL; +} + + +/* + * destroy directory stack + */ +VOID DestroyDirectoryStack (VOID) +{ + while (nStackDepth) + PopDirectory (); +} + + +INT GetDirectoryStackDepth (VOID) +{ + return nStackDepth; +} + + +/* + * pushd command + */ +INT cmd_pushd (LPTSTR first, LPTSTR rest) +{ + TCHAR curPath[MAX_PATH]; + TCHAR newPath[MAX_PATH]; + BOOL bChangePath = FALSE; + + if (!_tcsncmp (rest, _T("/?"), 2)) + { + ConOutPuts (_T("Stores the current directory for use by the POPD command, then\n" + "changes to the specified directory.\n\n" + "PUSHD [path | ..]\n\n" + " path Specifies the directory to make the current directory")); + return 0; + } + + if (rest[0] != _T('\0')) + { + GetFullPathName (rest, MAX_PATH, newPath, NULL); + bChangePath = IsValidPathName (newPath); + } + + GetCurrentDirectory (MAX_PATH, curPath); + if (PushDirectory (curPath)) + return -1; + + if (bChangePath) + SetCurrentDirectory (newPath); + + return 0; +} + + +/* + * popd command + */ +INT cmd_popd (LPTSTR first, LPTSTR rest) +{ + TCHAR szPath[MAX_PATH]; + + if (!_tcsncmp(rest, _T("/?"), 2)) + { + ConOutPuts (_T("Changes to the directory stored by the PUSHD command.\n\n" + "POPD")); + return 0; + } + + if (GetDirectoryStackDepth () == 0) + return 0; + + GetDirectoryStackTop (szPath); + PopDirectory (); + + SetCurrentDirectory (szPath); + + return 0; +} + +#endif /* FEATURE_DIRECTORY_STACK */ \ No newline at end of file diff --git a/reactos/apps/utils/cmd/echo.c b/reactos/apps/utils/cmd/echo.c new file mode 100644 index 00000000000..9d85c5ffe24 --- /dev/null +++ b/reactos/apps/utils/cmd/echo.c @@ -0,0 +1,59 @@ +/* + * ECHO.C - echo internal command. + * + * + * History: + * + * 16 Jul 1998 (Hans B Pufal) + * Started. + * + * 16 Jul 1998 (John P Price) + * Separated commands into individual files. + * + * 27-Jul-1998 (John P Price ) + * Added config.h include + * + * 08-Dec-1998 (Eric Kohl ) + * Added help text ("/?"). + * + * 19-Jan-1999 (Eric Kohl ) + * Unicode and redirection ready! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include + +#include "cmd.h" +#include "batch.h" + + +INT cmd_echo (LPTSTR cmd, LPTSTR param) +{ +#ifdef _DEBUG + DebugPrintf ("cmd_echo '%s' : '%s'\n", cmd, param); +#endif + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts ("Displays messages or switches command echoing on or off.\n\n" + "ECHO [ON | OFF]\nECHO [message]\n\n" + "Type ECHO without a parameter to display the current ECHO setting."); + return 0; + } + + if (_tcsicmp (param, D_OFF) == 0) + bEcho = FALSE; + else if (_tcsicmp (param, D_ON) == 0) + bEcho = TRUE; + else if (*param) + ConOutPuts (param); + else + ConOutPrintf (_T("ECHO is %s\n"), bEcho ? D_ON : D_OFF); + + return 0; +} diff --git a/reactos/apps/utils/cmd/error.c b/reactos/apps/utils/cmd/error.c new file mode 100644 index 00000000000..d89fe3132c6 --- /dev/null +++ b/reactos/apps/utils/cmd/error.c @@ -0,0 +1,177 @@ +/* + * ERROR.C - error reporting functions. + * + * + * History: + * + * 07/12/98 (Rob Lake) + * started + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 24-Jan-1999 (Eric Kohl ) + * Redirection safe! + * + * 02-Feb-1999 (Eric Kohl ) + * Use FormatMessage() for error reports. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include + +#include "cmd.h" + + +#define INVALID_SWITCH _T("Invalid switch - /%c\n") +#define TOO_MANY_PARAMETERS _T("Too many parameters - %s\n") +#define PATH_NOT_FOUND _T("Path not found\n") +#define FILE_NOT_FOUND _T("File not found") +#define REQ_PARAM_MISSING _T("Required parameter missing\n") +#define INVALID_DRIVE _T("Invalid drive specification\n") +#define INVALID_PARAM_FORMAT _T("Invalid parameter format - %s\n") +#define BADCOMMAND _T("Bad command or filename\n") +#define OUT_OF_MEMORY _T("Out of memory error.\n") +#define CANNOTPIPE _T("Error! Cannot pipe! Cannot open temporary file!\n") + +#define D_PAUSEMSG _T("Press any key to continue . . .") + + + +VOID ErrorMessage (DWORD dwErrorCode, LPTSTR szFormat, ...) +{ + TCHAR szMessage[1024]; + LPTSTR szError; + va_list arg_ptr; + + if (dwErrorCode == ERROR_SUCCESS) + return; + + va_start (arg_ptr, szFormat); + wvsprintf (szMessage, szFormat, arg_ptr); + va_end (arg_ptr); + +#if 1 + + if (FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, dwErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&szError, 0, NULL)) + { + ConErrPrintf (_T("%s %s\n"), szError, szMessage); + LocalFree (szError); + return; + } + else + { + ConErrPrintf (_T("Unknown error! Error code: 0x%lx\n"), dwErrorCode); +// ConErrPrintf (_T("No error message available!\n")); + return; + } + +#else + + switch (dwErrorCode) + { + case ERROR_FILE_NOT_FOUND: + szError = _T("File not found --"); + break; + + case ERROR_PATH_NOT_FOUND: + szError = _T("Path not found --"); + break; + + default: + ConErrPrintf (_T("Unknown error! Error code: 0x%lx\n"), dwErrorCode); + return; + } + + ConErrPrintf (_T("%s %s\n"), szError, szMessage); +#endif +} + + + +VOID error_invalid_switch (TCHAR ch) +{ + ConErrPrintf (INVALID_SWITCH, ch); +} + + +VOID error_too_many_parameters (LPTSTR s) +{ + ConErrPrintf (TOO_MANY_PARAMETERS, s); +} + + +VOID error_path_not_found (VOID) +{ + ConErrPrintf (PATH_NOT_FOUND); +} + + +VOID error_file_not_found (VOID) +{ + ConErrPrintf (FILE_NOT_FOUND); +} + + +VOID error_sfile_not_found (LPTSTR f) +{ + ConErrPrintf (FILE_NOT_FOUND _T(" - %s\n"), f); +} + + +VOID error_req_param_missing (VOID) +{ + ConErrPrintf (REQ_PARAM_MISSING); +} + + +VOID error_invalid_drive (VOID) +{ + ConErrPrintf (INVALID_DRIVE); +} + + +VOID error_bad_command (VOID) +{ + ConErrPrintf (BADCOMMAND); +} + + +VOID error_no_pipe (VOID) +{ + ConErrPrintf (CANNOTPIPE); +} + + +VOID error_out_of_memory (VOID) +{ + ConErrPrintf (OUT_OF_MEMORY); +} + + +VOID error_invalid_parameter_format (LPTSTR s) +{ + ConErrPrintf (INVALID_PARAM_FORMAT, s); +} + + +VOID error_syntax (LPTSTR s) +{ + if (s) + ConErrPrintf (_T("Syntax error - %s\n"), s); + else + ConErrPrintf (_T("Syntax error.\n")); +} + + +VOID msg_pause (VOID) +{ + ConOutPuts (D_PAUSEMSG); +} diff --git a/reactos/apps/utils/cmd/filecomp.c b/reactos/apps/utils/cmd/filecomp.c new file mode 100644 index 00000000000..2f9d53823b9 --- /dev/null +++ b/reactos/apps/utils/cmd/filecomp.c @@ -0,0 +1,253 @@ +/* + * FILECOMP.C - handles filename completion. + * + * + * Comments: + * + * 30-Jul-1998 (John P Price ) + * moved from command.c file + * made second TAB display list of filename matches + * made filename be lower case if last character typed is lower case + * + * 25-Jan-1999 (Eric Kohl ) + * Cleanup. Unicode safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include +#include + +#include "cmd.h" + + +#ifdef FEATURE_UNIX_FILENAME_COMPLETION + +VOID CompleteFilename (LPTSTR str, INT charcount) +{ + WIN32_FIND_DATA file; + HANDLE hFile; + + INT curplace = 0; + INT start; + INT count; + BOOL found_dot = FALSE; + BOOL perfectmatch = TRUE; + TCHAR path[MAX_PATH]; + TCHAR fname[MAX_PATH]; + TCHAR maxmatch[MAX_PATH] = _T(""); + TCHAR directory[MAX_PATH]; + + /* expand current file name */ + count = charcount - 1; + if (count < 0) + count = 0; + + /* find front of word */ + while (count > 0 && str[count] != _T(' ')) + count--; + + /* if not at beginning, go forward 1 */ + if (str[count] == _T(' ')) + count++; + + start = count; + + /* extract directory from word */ + _tcscpy (directory, &str[start]); + curplace = _tcslen (directory) - 1; + while (curplace >= 0 && directory[curplace] != _T('\\') && + directory[curplace] != _T(':')) + { + directory[curplace] = 0; + curplace--; + } + + _tcscpy (path, &str[start]); + + /* look for a '.' in the filename */ + for (count = _tcslen (directory); path[count] != 0; count++) + { + if (path[count] == _T('.')) + { + found_dot = 1; + break; + } + } + + if (found_dot) + _tcscat (path, _T("*")); + else + _tcscat (path, _T("*.*")); + + /* current fname */ + curplace = 0; + + hFile = FindFirstFile (path, &file); + if (hFile != INVALID_HANDLE_VALUE) + { + /* find anything */ + do + { + /* ignore "." and ".." */ + if (file.cFileName[0] == _T('.')) + continue; + + _tcscpy (fname, file.cFileName); + + if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + _tcscat (fname, _T("\\")); + else + _tcscat (fname, _T(" ")); + + if (!maxmatch[0] && perfectmatch) + { + _tcscpy(maxmatch, fname); + } + else + { + for (count = 0; maxmatch[count] && fname[count]; count++) + { + if (tolower(maxmatch[count]) != tolower(fname[count])) + { + perfectmatch = FALSE; + maxmatch[count] = 0; + break; + } + } + } + } + while (FindNextFile (hFile, &file)); + + FindClose (hFile); + + _tcscpy (&str[start], directory); + _tcscat (&str[start], maxmatch); + + if (!perfectmatch) + MessageBeep (-1); + } + else + { + /* no match found */ + MessageBeep (-1); + } +} + + +/* + * returns 1 if at least one match, else returns 0 + */ + +BOOL ShowCompletionMatches (LPTSTR str, INT charcount) +{ + WIN32_FIND_DATA file; + HANDLE hFile; + BOOL found_dot = FALSE; + INT curplace = 0; + INT start; + INT count; + TCHAR path[MAX_PATH]; + TCHAR fname[MAX_PATH]; + TCHAR directory[MAX_PATH]; + + /* expand current file name */ + count = charcount - 1; + if (count < 0) + count = 0; + + /* find front of word */ + while (count > 0 && str[count] != _T(' ')) + count--; + + /* if not at beginning, go forward 1 */ + if (str[count] == _T(' ')) + count++; + + start = count; + + /* extract directory from word */ + _tcscpy (directory, &str[start]); + curplace = _tcslen (directory) - 1; + while (curplace >= 0 && directory[curplace] != _T('\\') && + directory[curplace] != _T(':')) + { + directory[curplace] = 0; + curplace--; + } + + _tcscpy (path, &str[start]); + + /* look for a . in the filename */ + for (count = _tcslen (directory); path[count] != 0; count++) + { + if (path[count] == _T('.')) + { + found_dot = TRUE; + break; + } + } + if (found_dot) + _tcscat (path, _T("*")); + else + _tcscat (path, _T("*.*")); + + /* current fname */ + curplace = 0; + + hFile = FindFirstFile (path, &file); + if (hFile != INVALID_HANDLE_VALUE) + { + /* find anything */ + ConOutChar (_T('\n')); + count = 0; + do + { + /* ignore . and .. */ + if (file.cFileName[0] == _T('.')) + continue; + + if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + wsprintf (fname,"[%s]", file.cFileName); + else + _tcscpy (fname, file.cFileName); + + ConOutPrintf (_T("%-14s"), fname); + if (++count == 5) + { + ConOutChar (_T('\n')); + count = 0; + } + } + while (FindNextFile (hFile, &file)); + + FindClose (hFile); + + if (count) + ConOutChar (_T('\n')); + } + else + { + /* no match found */ + MessageBeep (-1); + return FALSE; + } + + return TRUE; +} +#endif + +#ifdef FEATURE_4NT_FILENAME_COMPLETION + +//static VOID BuildFilenameMatchList (...) + +// VOID CompleteFilenameNext (LPTSTR, INT) +// VOID CompleteFilenamePrev (LPTSTR, INT) + +// VOID RemoveFilenameMatchList (VOID) + +#endif \ No newline at end of file diff --git a/reactos/apps/utils/cmd/files.txt b/reactos/apps/utils/cmd/files.txt new file mode 100644 index 00000000000..8f1dfefd3da --- /dev/null +++ b/reactos/apps/utils/cmd/files.txt @@ -0,0 +1,56 @@ +Archive Contents +~~~~~~~~~~~~~~~~ +bugs.txt Bug List +files.txt This file list +history.txt History of the shell development +license.txt GNU license - applies to all files named here +readme.txt General shell info +todo.txt What I have to do +wishlist.txt Wish List + +makefile experimental makefile +makefile.lcc makefile for lcc-win + +alias.c Alias code +alias.h Alias header file +attrib.c Implements attrib command +batch.c Batch file interpreter +beep.c Implements beep command +call.c Implements call command +chcp.c Implements chcp command +cls.c Implements cls command +cmdinput.c Command-line input functions +cmdtable.c Table of available internal commands +cmd.c Main code for command-line interpreter +cmd.h Command header file +color.c Implements color command +console.c Windows console handling code +copy.c Implements copy command +date.c Implements date command +del.c Implements del command +dir.c Directory listing code +dirstack.c Directory stack code (PUSHD and POPD) +echo.c Implements echo command +error.c Error Message Routines +filecomp.c Filename completion functions +for.c Implements for command +goto.c Implements goto command +history.c Command-line history handling +if.c Implements if command +internal.c Internal commands (DIR, RD, etc) +label.c Implements label command +locale.c Locale handling code +misc.c Misc. Functions +move.c Implements move command +path.c Implements path command +pause.c Implements pause command +prompt.c Prompt handling functions +redir.c Redirection and piping parsing functions +ren.c Implements rename command +set.c Implements set command +shift.c Implements shift command +time.c Implements time command +type.c Implements type command +ver.c Implements ver command +where.c Code to search path for executables +verify.c Implements verify command \ No newline at end of file diff --git a/reactos/apps/utils/cmd/for.c b/reactos/apps/utils/cmd/for.c new file mode 100644 index 00000000000..7ccb445252e --- /dev/null +++ b/reactos/apps/utils/cmd/for.c @@ -0,0 +1,135 @@ +/* + * FOR.C - for internal batch command. + * + * + * History: + * + * 16 Jul 1998 (Hans B Pufal) + * started. + * + * 16 Jul 1998 (John P Price) + * Seperated commands into individual files. + * + * 19 Jul 1998 (Hans B Pufal) [HBP_001] + * Implementation of FOR + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 20-Jan-1999 (Eric Kohl ) + * Unicode and redirection safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include +#include + +#include "cmd.h" +#include "batch.h" + + +/* + * Perform FOR command. + * + * First check syntax is correct : FOR %v IN ( ) DO + * v must be alphabetic, must not be empty. + * + * If all is correct build a new bcontext structure which preserves + * the necessary information so that readbatchline can expand + * each the command prototype for each list element. + * + * You might look on a FOR as being a called batch file with one line + * per list element. + */ + +INT cmd_for (LPTSTR cmd, LPTSTR param) +{ + LPBATCH_CONTEXT lpNew; + LPTSTR pp; + TCHAR var; + +#ifdef _DEBUG + DebugPrintf ("cmd_for (\'%s\', \'%s\'\n", cmd, param); +#endif + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts ("FOR :"); + return 0; + } + + /* Check that first element is % then an alpha char followed by space */ + if ((*param != _T('%')) || !_istalpha (*(param + 1)) || !_istspace (*(param + 2))) + { + error_syntax (_T("bad varable specification.")); + return 1; + } + + param++; + var = *param++; /* Save FOR var name */ + + while (_istspace (*param)) + param++; + + /* Check next element is 'IN' */ + if ((_tcsnicmp (param, _T("in"), 2) != 0) || !_istspace (*(param + 2))) + { + error_syntax (_T("'in' missing in for statement.")); + return 1; + } + + param += 2; + while (_istspace (*param)) + param++; + + /* Folowed by a '(', find also matching ')' */ + if ((*param != _T('(')) || (NULL == (pp = _tcsrchr (param, _T(')'))))) + { + error_syntax (_T("no brackets found.")); + return 1; + } + + *pp++ = _T('\0'); + param++; /* param now points at null terminated list */ + + while (_istspace (*pp)) + pp++; + + /* Check DO follows */ + if ((_tcsnicmp (pp, _T("do"), 2) != 0) || !_istspace (*(pp + 2))) + { + error_syntax (_T("'do' missing.")); + return 1; + } + + pp += 2; + while (_istspace (*pp)) + pp++; + + /* Check that command tail is not empty */ + if (*pp == _T('\0')) + { + error_syntax (_T("no command after 'do'.")); + return 1; + } + + /* OK all is correct, build a bcontext.... */ + lpNew = (LPBATCH_CONTEXT)malloc (sizeof (BATCH_CONTEXT)); + + lpNew->prev = bc; + bc = lpNew; + + bc->hBatchFile = INVALID_HANDLE_VALUE; + bc->ffind = NULL; + bc->params = BatchParams (_T(""), param); /* Split out list */ + bc->shiftlevel = 0; + bc->forvar = var; + bc->forproto = _tcsdup (pp); + + return 0; +} diff --git a/reactos/apps/utils/cmd/goto.c b/reactos/apps/utils/cmd/goto.c new file mode 100644 index 00000000000..def1cbf57f2 --- /dev/null +++ b/reactos/apps/utils/cmd/goto.c @@ -0,0 +1,110 @@ +/* + * GOTO.C - goto internal batch command. + * + * History: + * + * 16 Jul 1998 (Hans B Pufal) + * started. + * + * 16 Jul 1998 (John P Price) + * Seperated commands into individual files. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 28 Jul 1998 (Hans B Pufal) [HBP_003] + * Terminate label on first space character, use only first 8 chars of + * label string + * + * 24-Jan-1999 (Eric Kohl ) + * Unicode and redirection safe! + * + * 27-Jan-1999 (Eric Kohl ) + * Added help text ("/?"). + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include + +#include "cmd.h" +#include "batch.h" + + +/* + * Perform GOTO command. + * + * Only valid if batch file current. + * + */ + +INT cmd_goto (LPTSTR cmd, LPTSTR param) +{ + LPTSTR tmp; + LONG lNewPosHigh; + +#ifdef _DEBUG + DebugPrintf ("cmd_goto (\'%s\', \'%s\'\n", cmd, param); +#endif + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Directs CMD to a labeled line in a batch script.\n" + "\n" + "GOTO label\n" + "\n" + " label Specifies a text string used in a batch script as a label.\n" + "\n" + "You type a label on a line by itself, beginning with a colon.")); + return 0; + } + + /* if not in batch -- error!! */ + if (bc == NULL) + { + return 1; + } + + if (*param == _T('\0')) + { + ExitBatch (_T("No label specified for GOTO\n")); + return 1; + } + + /* terminate label at first space char */ + tmp = param; + while (*tmp && !_istspace (*tmp)) + tmp++; + *tmp = _T('\0'); + + /* set file pointer to the beginning of the batch file */ + lNewPosHigh = 0; + SetFilePointer (bc->hBatchFile, 0, &lNewPosHigh, FILE_BEGIN); + + while (FileGetString (bc->hBatchFile, textline, sizeof(textline))) + { + /* Strip out any trailing spaces or control chars */ + tmp = textline + _tcslen (textline) - 1; + while (_istcntrl (*tmp) || _istspace (*tmp)) + tmp--; + *(tmp + 1) = _T('\0'); + + /* Then leading spaces... */ + tmp = textline; + while (_istspace (*tmp)) + tmp++; + + /* use only 1st 8 chars of label */ + if ((*tmp == _T(':')) && (_tcsncmp (++tmp, param, 8) == 0)) + return 0; + } + + ConErrPrintf (_T("Label '%s' not found\n"), param); + ExitBatch (NULL); + + return 1; +} diff --git a/reactos/apps/utils/cmd/history.c b/reactos/apps/utils/cmd/history.c new file mode 100644 index 00000000000..2e48d597882 --- /dev/null +++ b/reactos/apps/utils/cmd/history.c @@ -0,0 +1,126 @@ +/* + * HISTORY.C - command line history. + * + * + * History: + * + * 14/01/95 (Tim Norman) + * started. + * + * 08/08/95 (Matt Rains) + * i have cleaned up the source code. changes now bring this source + * into guidelines for recommended programming practice. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 25-Jan-1999 (Eric Kohl ) + * Cleanup! + * Unicode and redirection safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef FEATURE_HISTORY + +#include +#include +#include +#include + + +#define MAXLINES 128 + +static INT history_size = 2048; /* make this configurable later */ + + +VOID History (INT dir, LPTSTR commandline) +{ + static LPTSTR history = NULL; + static LPTSTR lines[MAXLINES]; + static INT curline = 0; + static INT numlines = 0; + static INT maxpos = 0; + INT count; + INT length; + + if (!history) + { + history = malloc (history_size * sizeof (TCHAR)); + lines[0] = history; + history[0] = 0; + } + + if (dir > 0) + { + /* next command */ + if (curline < numlines) + { + curline++; + } + + if (curline == numlines) + { + commandline[0] = 0; + } + else + { + _tcscpy (commandline, lines[curline]); + } + } + else if (dir < 0) + { + /* prev command */ + if (curline > 0) + { + curline--; + } + + _tcscpy (commandline, lines[curline]); + } + else + { + /* add to history */ + /* remove oldest string until there's enough room for next one */ + /* strlen (commandline) must be less than history_size! */ + while ((maxpos + (INT)_tcslen (commandline) + 1 > history_size) || (numlines >= MAXLINES)) + { + length = _tcslen (lines[0]) + 1; + + for (count = 0; count < maxpos && count + (lines[1] - lines[0]) < history_size; count++) + { + history[count] = history[count + length]; + } + + maxpos -= length; + + for (count = 0; count <= numlines && count < MAXLINES; count++) + { + lines[count] = lines[count + 1] - length; + } + + numlines--; +#ifdef DEBUG + ConOutPrintf (_T("Reduced size: %ld lines\n"), numlines); + + for (count = 0; count < numlines; count++) + { + ConOutPrintf (_T("%d: %s\n"), count, lines[count]); + } +#endif + } + + _tcscpy (lines[numlines], commandline); + numlines++; + lines[numlines] = lines[numlines - 1] + _tcslen (commandline) + 1; + maxpos += _tcslen (commandline) + 1; + /* last line, empty */ + curline = numlines; + } + + return; +} + +#endif diff --git a/reactos/apps/utils/cmd/history.txt b/reactos/apps/utils/cmd/history.txt new file mode 100644 index 00000000000..7b0769bb53c --- /dev/null +++ b/reactos/apps/utils/cmd/history.txt @@ -0,0 +1,345 @@ +FreeDOS Command Line Interface Development History +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +11/11/94 version 0.01 +~~~~~~~~~~~~~~~~~~~~~ +o initial release. + +01/01/95 version 0.10 +~~~~~~~~~~~~~~~~~~~~~ +o removed some scaffolding. +o modified CD. +o added tab file completion. +o added command line history. + +01/15/95 version 0.20 +~~~~~~~~~~~~~~~~~~~~~ +o formatted all existing source modules. +o added prompt support. +o added drive selection. +o added dir command. +o started this development log. + +08/06/95 prerelease of version 0.30 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +o reorganized code into separate source modules. +o added batch processing support (thanks to Evan Jeffrey). +o added exec code (thanks to Steffan Kaiser). +o removed environment handling (thanks again to Steffan Kaiser) + + [ 08/08/95 -- Matt Rains ] +o formatted this development log. +o formatted all existing source modules so that they comply with recommended + programming practice. +o added MD command. +o added RD command. +o added VER command. +o replaced CD command. +o modified DIR command. +o DIR now called regardless of other DIR.??? files. this is done because of + exec() problems. + +12/10/95 version 0.30 +~~~~~~~~~~~~~~~~~~~~~ +o used Borland's spawnve to fix exec problem +o fixed CD again so you don't need a space after it +o couple of spelling fixes + +12/14/95 version 0.31 +~~~~~~~~~~~~~~~~~~~~~ +o modified cmdinput.c to work with non-standard screen sizes (see 28.com) +o fixed a bug in history.c that made it not work when you hit the up arrow + on the first line +o fixed DIR to work a little more like MS-DOS's DIR (see internal.c) +o fixed some code in where.c to make things a bit more efficient and nicer + +01/06/96 version 0.40 (never released) +~~~~~~~~~~~~~~~~~~~~~ +o added redirection and piping support!!! (see redir.c and command.c) +o fixed a stupid pointer problem in where.c that was causing LOTS of + problems in the strangest places... +o added day of the week support to prompt.c (oops, that was already supposed + to be there! :) +o fixed and reorganized the EXEC code!!! Thanks to Svante Frey! +o reorganized command.c and internal.c to handle parsing internal commands + more efficiently and consistently. +o changed the behavior of MD, CD, RD to work without spaces (e.g. CD\DOS) +o small changes here and there to make it work with redirection/piping + (e.g. DIR only pauses if you're not doing redirection) + +01/17/96 version 0.50 +~~~~~~~~~~~~~~~~~~~~~ +Version 0.40 was never released because I was home on Christmas vacation, +and I couldn't upload it. By the time I got back to school, I had the +LOADHIGH patch from Svante Frey, so I decided to jump up to 0.50 without any +release of 0.40... - Tim Norman + +o LOADHIGH/LOADFIX/LH support added!!!! Many thanks go to Svante Frey! +o bug fixed in command parsing that didn't handle / switches correctly... +o removed debugging output from history.c + +07/26/96 version 0.60 +~~~~~~~~~~~~~~~~~~~~~ +Lots of internal changes here... Not much added to the interface. + +o Changed internals to use first,rest parameters instead of arrays of params +o Fixed some bugs +o Some other things I don't remember :) + +07/26/96 version 0.61 +~~~~~~~~~~~~~~~~~~~~~ +Bugfixes + +o Added hook to the PATH command +o Fixed CD.. bug + +08/27/96 version 0.70 +~~~~~~~~~~~~~~~~~~~~~ +Finally added Oliver Mueller's ALIAS command! Also numerous bug fixes. + +o Added ALIAS command +o Removed support for - as a switch in LOADHIGH.C +o Bugfixes in BATCH.C. %0 was returning garbage +o Removed lots of unused variables, reducing # of warnings when compiling +o Other miscellaneous code clean-ups +o Changed WHERE.C to use a little less memory + +06/14/97 version 0.71 +~~~~~~~~~~~~~~~~~~~~~ +Lots of bug fixes, plus some additional features. + +o New DIR command. Now more like MS-DOS's DIR. /p supported, /s coming soon +o bug fix in internal.c - parse_firstarg +o Rewrote parser in batch.c (Steffan Kaiser) +o Ctrl-Break checking in various places (Steffan Kaiser) +o Error level setting/checking (%? in batch files) (Steffan Kaiser) +o bug fix in cmdinput.c ("%i" on command-line caused weird behavior) +o bug fix in where.c (first item in path wasn't searched) + +07/12/97 version 0.72 +~~~~~~~~~~~~~~~~~~~~~ +More bug fixes and code cleanup + +o Rewrote cmdinput.c to be more efficient (Marc Desrochers) +o Added insert/overstrike modes (Marc Desrochers) +o Replaced findxy() with pointers into BIOS (maxx, maxy) (Marc Desrochers) +o Fixed bug that disallowed listing of root directories +o Fixed bug that didn't search the first path (again!) + +07/13/97 version 0.72b +~~~~~~~~~~~~~~~~~~~~~~ +Disabled a feature that caused a crash on some machines. + +o Replaced setcursor calls in cmdinput.c with _setcursortype +o Added dir.c to the distribution (was left out in 0.72) + +07/01/98 version 0.73 (Rob Lake) +~~~~~~~~~~~~~~~~~~~~~~ +o New DIR commands supported: /S, /B, /L, /A and /W. + (/R changed to /S). Also /? added. +o Supports DIRCMD in environment. +o Supports turning off commands with hyphen (ex. /-S + turns off recursive listing) +o Changed error messages for DIR and DEL to more MS-DOS'ish +o Moved error messages from DIR.C and DEL.C to COMMAND.H + (more may go there soon) +o Fixed bug that caused dir *.ext/X not to work (no spaces + between filespec and slash) +o Added wildcard support for DEL command +o Added prompt and help switch for DEL command, /P and /? + respectively. +o Added support for /C when envoking the shell +o Added /P support when Kernel loads shell. This means + the shell now is permanent and runs the autoexec.bat + (/E is not implemented) +o Added my name (Rob Lake) to the developer listing +o Changed version routine to print out copyright notice + with no args, and with appropriate switches, warranty + and redistribution notices and developer listing + +07/08/1998 version 0.74 (John P. Price (linux-guru@gcfl.net)) +~~~~~~~~~~~~~~~~~~~~~~~~ +COMMAND.C/COMMAND.H: +o Now sets COMSPEC environment variable +o misc clean up and optimization +o added date, time and type commands +o changed to using spawnl instead of exec. exec does not copy the + environment to the child process! +DIR.C +o removed extra returns; closer to MSDOS +o fixed wide display so that an extra return is not displayed when + there is five filenames in the last line. +ENVIRON.C +o commented out show_environment function. Not used anymore. +INTERAL.C +o removed call to show_environment in set command. +o moved test for syntax before allocating memory in set command. +o misc clean up and optimization. + +o created DATE.C +o created TIME.C +o created TYPE.C + +07/08/1998 version 0.74b (John P. Price (linux-guru@gcfl.net)) +~~~~~~~~~~~~~~~~~~~~~~~~ +COMMAND.C +o fixed call to spawnl so that it would pass command line arguments + correctly. + +07/12/98 version 0.74c (Rob Lake rlake@cs.mun.ca) +~~~~~~~~~~~~~~~~~~~~~~ +Various Files: +o removed redundant use of error message defines and moved + error printing calls to ERROR.C to reduced program size. + +o created MISC.C +o created ERR_HAND.C/H +o created ERROR.C + +07/13/98 version 0.74d (Rob Lake rlake@cs.mun.ca) +~~~~~~~~~~~~~~~~~~~~~~ +INTERNAL.C +o removed most of the commands and placed them in there own file + -- del, ren, set and ver +o created DEL.C, REN.C SET.C and VER.C +o fixed bug that caused del not to delete files with no attributes +o the critical error handler count number of times called, autofails + at 5 calls + + +16 Jul 1998 (Hans B Pufal ) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +batch.c + A new version, implements CALL, ECHO, GOT, IF, PAUSE, SHIFT and + BEEP. There is a stub for FOR but that's all. + +cmdtable.c + New file to keep the internal command table. I plan on getting rid + of the table real soon now and replacing it with a dynamic + mechanism. + +command.c + A new (improved ;) version. Conforms closely to MS-DOS specs. + Cleaned up (and fixed) the redirection handler. + +command.h + Version D with changes. Look for the HBP tag. + +redir.c + Modified file, now supports append redirects. + + +16 Jul 1998 (Rob Lake rlake@cs.mun.ca) +~~~~~~~~~~~~~~~~~~~~~~ +Added TRUENAME command. + + +19 Jul 1998 (Hans B Pufal) ) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +o Preserve state of echo flag across batch calls. +o Implementation of FOR command + + +20 Jul 1998 (John P Price ) +~~~~~~~~~~~~~~~~~~~~~~ +o Fixed bug in DATE.C. +o Fixed bug in LH.ASM. +o Separated commands into individual files. + + +28 Jul 1998 (John P Price ) +~~~~~~~~~~~~~~~~~~~~~~ +o Added CLS command. +o Put ifdef's around all commands and added include file config.h + Now you can define exact what commands you want to include in + command.com. +o Also added ifdefs for optional features: aliases, command history + and filename completion. +o Added display of available internal commands and options at startup. + + +29 Jul 1998 (Rob Lake rlake@cs.mun.ca) +~~~~~~~~~~~~~~~~~~~~~~ +o changed date.c and time.c, and wrote datefunc.c and timefunc.c to + impliment _dos_getdate, _dos_setdate, _dos_gettime and _dos_settime. + This is the first of many steps to make the shell compatible under + Pacific C. + +30-Jul-1998 (John P Price ) +~~~~~~~~~~~~~~~~~~~~~~ +o Changed filename completion so that a second TAB displays a list of + matching filenames! +o made filename be lower case if last character typed is lower case. +o Moved filename completion code to filecomp.c. +o Change ver command to display email address to report bugs, and the + web page address for updates. +o fixed so that it find_which returns NULL if filename is not + executable (does not have .bat, .com, or .exe extension). Before + command would to execute any file with any extension. (opps!) + +30-Jul-1998 (John P Price ) +~~~~~~~~~~~~~~~~~~~~~~ +o Fixed bug where if you typed something, then hit HOME, then tried to + type something else in insert mode, it locked up. +o Changed default insert mode to on. There should be a way to change + this. Maybe options to doskey command. +o Added VERIFY command + +02-Aug-1998 (Hans B Pufal) ) +~~~~~~~~~~~~~~~~~~~~~~ +o batch.c: Fixed bug in ECHO flag restoration at exit from batch file +o command.c: Fixed return value when called with /C option +o Terminate label on first space character, use only first 8 chars of + label string + +04-Aug-1998 (Hans B Pufal) ) +~~~~~~~~~~~~~~~~~~~~~~ +o call.c: added lines to initialize for pointers. This fixed the + lock-up that happened sometimes when calling a batch file from + another batch file. + +07-Aug-1998 (John P Price ) +~~~~~~~~~~~~~~~~~~~~~~ +o Fixed carrage return output to better match MSDOS with echo on or off. + + +07-Dec-1998 ReactOS CMD version 0.0.1 (Eric Kohl ) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +o First test release. +o Added internal ATTRIB command. + +11-Dec-1998 ReactOS CMD version 0.0.2 (Eric Kohl ) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +o Fixed bug in ALIAS. CMD crashed when you tried to remove an alias. +o Fixed bug in split(). Added freep(). This fixed the DEL command. +o Improved ATTRIB command. +o Added most help texts. +o Fixed recursive DIR ("dir /s"). +o Fixed DATE and TIME command. Now they accept values when used + without parameter. +o Implemented LABEL command. + +05-Jan-1999 ReactOS CMD version 0.0.3 (Eric Kohl ) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +o Added COLOR command and "/t" option. +o Cursor shows insert/overwrite mode. +o COMSPEC environment variable is set upon startup. +o Started COPY command. +o Started MOVE command. +o Added directory stack (PUSHD and POPD commands). +o Added support for file names or paths that contain spaces + (quoted paths / file names). +o Added recursion to ATTRIB command. +o Added locale support for DIR, DATE, TIME and PROMPT. +o Fixed VERIFY. + +10-Feb-1999 ReactOS CMD version 0.0.4 (Eric Kohl ) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +o "?" lists all available commands. +o Most commands are unicode and redirection aware now. +o Input-, Output- and Error-Redirections works with most commands. +o ATTRIB and DEL can handle multiple filenames now. +o Fixed handling of environment variables. +o Added CHCP command. +o Fixed keyboard input bug. +o Rewrote DEL and MOVE commands. \ No newline at end of file diff --git a/reactos/apps/utils/cmd/if.c b/reactos/apps/utils/cmd/if.c new file mode 100644 index 00000000000..64744bca5d6 --- /dev/null +++ b/reactos/apps/utils/cmd/if.c @@ -0,0 +1,157 @@ +/* + * IF.C - if internal batch command. + * + * + * History: + * + * 16 Jul 1998 (Hans B Pufal) + * started. + * + * 16 Jul 1998 (John P Price) + * Seperated commands into individual files. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 07-Jan-1999 (Eric Kohl ) + * Added help text ("if /?") and cleaned up. + * + * 21-Jan-1999 (Eric Kohl ) + * Unicode and redirection ready! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include + +#include "cmd.h" +#include "batch.h" + + +#define X_EXEC 1 +#define X_EMPTY 0x80 + + +INT cmd_if (LPTSTR cmd, LPTSTR param) +{ + INT x_flag = 0; /* when set cause 'then' clause to be executed */ + LPTSTR pp; + +#ifdef _DEBUG + DebugPrintf ("cmd_if: (\'%s\', \'%s\'\n", cmd, param); +#endif + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("IF :")); + return 0; + } + + /* First check if param string begins with word 'not' */ + if (!_tcsnicmp (param, _T("not"), 3) && _istspace (*(param + 3))) + { + x_flag = X_EXEC; /* Remember 'NOT' */ + param += 3; /* Step over 'NOT' */ + while (_istspace (*param)) /* And subsequent spaces */ + param++; + } + + /* Check for 'exist' form */ + if (!_tcsnicmp (param, _T("exist"), 5) && _istspace (*(param + 5))) + { + param += 5; + while (_istspace (*param)) + param++; + + pp = param; + while (*pp && !_istspace (*pp)) + pp++; + + if (*pp) + { + WIN32_FIND_DATA f; + HANDLE hFind; + + *pp++ = _T('\0'); + hFind = FindFirstFile (param, &f); + x_flag ^= (hFind != INVALID_HANDLE_VALUE) ? 0 : X_EXEC; + if (hFind != INVALID_HANDLE_VALUE) + FindClose (hFind); + } + else + return 0; + } + + /* Check for 'errorlevel' form */ + else if (!_tcsnicmp (param, _T("errorlevel"), 10) && _istspace (*(param + 10))) + { + INT n = 0; + + pp = param + 10; + while (_istspace (*pp)) + pp++; + + while (_istdigit (*pp)) + n = n * 10 + (*pp++ - _T('0')); + + x_flag ^= (errorlevel < n) ? 0 : X_EXEC; + + x_flag |= X_EMPTY; /* Syntax error if comd empty */ + } + + /* Check that '==' is present, syntax error if not */ + else if (NULL == (pp = _tcsstr (param, _T("==")))) + { + error_syntax (NULL); + return 1; + } + + else + { + /* Change first '='to space to terminate comparison loop */ + + *pp = _T(' '); /* Need a space to terminate comparison loop */ + pp += 2; /* over '==' */ + while (_istspace (*pp)) /* Skip subsequent spaces */ + pp++; + + _tcscat (pp, _T(" ")); /* Add one space to ensure comparison ends */ + + while (*param == *pp) /* Comparison loop */ + { + if (_istspace (*param)) /* Terminates on space */ + break; + + param++, pp++; + } + + if (x_flag ^= (*param != *pp) ? 0 : X_EXEC) + { + while (*pp && !_istspace (*pp)) /* Find first space, */ + pp++; + + x_flag |= X_EMPTY; + } + } + + if (x_flag & X_EMPTY) + { + while (_istspace (*pp)) /* Then skip spaces */ + pp++; + + if (*pp == _T('\0')) /* If nothing left then syntax err */ + { + error_syntax (NULL); + return 1; + } + } + + if (x_flag & X_EXEC) + ParseCommandLine (pp); + + return 0; +} diff --git a/reactos/apps/utils/cmd/internal.c b/reactos/apps/utils/cmd/internal.c new file mode 100644 index 00000000000..b2019f7d056 --- /dev/null +++ b/reactos/apps/utils/cmd/internal.c @@ -0,0 +1,485 @@ +/* + * INTERNAL.C - command.com internal commands. + * + * + * History: + * + * 17/08/94 (Tim Norman) + * started. + * + * 08/08/95 (Matt Rains) + * i have cleaned up the source code. changes now bring this source into + * guidelines for recommended programming practice. + * + * cd() + * started. + * + * dir() + * i have added support for file attributes to the DIR() function. the + * routine adds "d" (directory) and "r" (read only) output. files with the + * system attribute have the filename converted to lowercase. files with + * the hidden attribute are not displayed. + * + * i have added support for directorys. now if the directory attribute is + * detected the file size if replaced with the string "". + * + * ver() + * started. + * + * md() + * started. + * + * rd() + * started. + * + * del() + * started. + * + * does not support wildcard selection. + * + * todo: add delete directory support. + * add recursive directory delete support. + * + * ren() + * started. + * + * does not support wildcard selection. + * + * todo: add rename directory support. + * + * a general structure has been used for the cd, rd and md commands. this + * will be better in the long run. it is too hard to maintain such diverse + * functions when you are involved in a group project like this. + * + * 12/14/95 (Tim Norman) + * fixed DIR so that it will stick \*.* if a directory is specified and + * that it will stick on .* if a file with no extension is specified or + * *.* if it ends in a \ + * + * 1/6/96 (Tim Norman) + * added an isatty call to DIR so it won't prompt for keypresses unless + * stdin and stdout are the console. + * + * changed parameters to be mutually consistent to make calling the + * functions easier + * + * rem() + * started. + * + * doskey() + * started. + * + * 01/22/96 (Oliver Mueller) + * error messages are now handled by perror. + * + * 02/05/96 (Tim Norman) + * converted all functions to accept first/rest parameters + * + * 07/26/96 (Tim Norman) + * changed return values to int instead of void + * + * path() started. + * + * 12/23/96 (Aaron Kaufman) + * rewrote dir() to mimic MS-DOS's dir + * + * 01/28/97 (Tim Norman) + * cleaned up Aaron's DIR code + * + * 06/13/97 (Tim Norman) + * moved DIR code to dir.c + * re-implemented Aaron's DIR code + * + * 06/14/97 (Steffan Kaiser) + * ctrl-break handling + * bug fixes + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 03-Dec-1998 (Eric Kohl ) + * Replaced DOS calls by Win32 calls. + * + * 08-Dec-1998 (Eric Kohl ) + * Added help texts ("/?"). + * + * 18-Dec-1998 (Eric Kohl ) + * Added support for quoted arguments (cd "program files"). + * + * 07-Jan-1999 (Eric Kohl ) + * Clean up. + * + * 26-Jan-1999 (Eric Kohl ) + * Replaced remaining CRT io functions by Win32 io functions. + * Unicode safe! + * + * 30-Jan-1999 (Eric Kohl ) + * Added "cd -" feature. Changes to the previous directory. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include +#include + +#include "cmd.h" + + +extern COMMAND cmds[]; /* The internal command table, used in '?' */ + + +#ifdef INCLUDE_CMD_CHDIR + +static LPTSTR lpLastPath; + + +VOID InitLastPath (VOID) +{ + lpLastPath = NULL; +} + + +VOID FreeLastPath (VOID) +{ + if (lpLastPath) + free (lpLastPath); +} + + +/* + * CD / CHDIR + * + */ +INT cmd_chdir (LPTSTR cmd, LPTSTR param) +{ + LPTSTR dir; /* pointer to the directory to change to */ + LPTSTR place; /* used to search for the \ when no space is used */ + LPTSTR lpOldPath; + LPTSTR *arg = NULL; + INT argc; + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Changes the current directory or displays it's name\n\n" + "CHDIR [drive:][path]\n" + "CHDIR[..|-]\n" + "CD [drive:][path]\n" + "CD[..|-]\n\n" + " .. parent directory\n" + " - previous directory\n\n" + "Type CD drive: to display the current directory on the specified drive.\n" + "Type CD without a parameter to display the current drive and directory.")); + return 0; + } + + /* check if there is no space between the command and the path */ + if (param[0] == _T('\0')) + { + /* search for the '\', '.' or '-' so that both short & long names will work */ + for (place = cmd; *place; place++) + if (*place == _T('.') || *place == _T('\\') || *place == _T('-')) + break; + + if (*place) + dir = place; + else + /* signal that there are no parameters */ + dir = NULL; + } + else + { + arg = split (param, &argc); + + if (argc > 1) + { + /*JPP 20-Jul-1998 use standard error message */ + error_too_many_parameters (param); + freep (arg); + return 1; + } + else + dir = arg[0]; + } + + /* if doing a CD and no parameters given, print out current directory */ + if (!dir || !dir[0]) + { + TCHAR szPath[MAX_PATH]; + + GetCurrentDirectory (MAX_PATH, szPath); + + ConOutPuts (szPath); + + freep (arg); + + return 0; + } + + if (dir && _tcslen (dir) == 1 && *dir == _T('-')) + { + if (lpLastPath) + dir = lpLastPath; + else + { + freep (arg); + return 0; + } + } + else if (dir && _tcslen (dir) > 1 && dir[1] == _T(':')) + { + TCHAR szRoot[3] = _T("A:"); + TCHAR szPath[MAX_PATH]; + + szRoot[0] = _totupper (dir[0]); + GetFullPathName (szRoot, MAX_PATH, szPath, NULL); + + /* PathRemoveBackslash */ + if (_tcslen (szPath) > 3) + { + LPTSTR p = _tcsrchr (szPath, _T('\\')); + *p = _T('\0'); + } + + ConOutPuts (szPath); + + freep (arg); + + return 0; + } + + /* remove trailing \ if any, but ONLY if dir is not the root dir */ + if (_tcslen (dir) >= 2 && dir[_tcslen (dir) - 1] == _T('\\')) + dir[_tcslen(dir) - 1] = _T('\0'); + + + /* store current directory */ + lpOldPath = (LPTSTR)malloc (MAX_PATH * sizeof(TCHAR)); + GetCurrentDirectory (MAX_PATH, lpOldPath); + + if (!SetCurrentDirectory (dir)) + { + ErrorMessage (GetLastError(), _T("CD")); + + /* throw away current directory */ + free (lpOldPath); + lpOldPath = NULL; + + freep (arg); + return 1; + } + else + { + if (lpLastPath) + free (lpLastPath); + lpLastPath = lpOldPath; + } + + freep (arg); + + return 0; +} +#endif + + + +#ifdef INCLUDE_CMD_MKDIR +/* + * MD / MKDIR + * + */ +INT cmd_mkdir (LPTSTR cmd, LPTSTR param) +{ + LPTSTR dir; /* pointer to the directory to change to */ + LPTSTR place; /* used to search for the \ when no space is used */ + LPTSTR *p = NULL; + INT argc; + + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Creates a directory.\n\n" + "MKDIR [drive:]path\nMD [drive:]path")); + return 0; + } + + + /* check if there is no space between the command and the path */ + if (param[0] == _T('\0')) + { + /* search for the \ or . so that both short & long names will work */ + for (place = cmd; *place; place++) + if (*place == _T('.') || *place == _T('\\')) + break; + + if (*place) + dir = place; + else + /* signal that there are no parameters */ + dir = NULL; + } + else + { + p = split (param, &argc); + if (argc > 1) + { + /*JPP 20-Jul-1998 use standard error message */ + error_too_many_parameters (param); + freep (p); + return 1; + } + else + dir = p[0]; + } + + /* remove trailing \ if any, but ONLY if dir is not the root dir */ + if (_tcslen (dir) >= 2 && dir[_tcslen (dir) - 1] == _T('\\')) + dir[_tcslen(dir) - 1] = _T('\0'); + + if (!CreateDirectory (dir, NULL)) + { + ErrorMessage (GetLastError(), _T("MD")); + + freep (p); + return 1; + } + + freep (p); + + return 0; +} +#endif + + +#ifdef INCLUDE_CMD_RMDIR +/* + * RD / RMDIR + * + */ +INT cmd_rmdir (LPTSTR cmd, LPTSTR param) +{ + LPTSTR dir; /* pointer to the directory to change to */ + LPTSTR place; /* used to search for the \ when no space is used */ + + LPTSTR *p = NULL; + INT argc; + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Removes a directory.\n\n" + "RMDIR [drive:]path\nRD [drive:]path")); + return 0; + } + + /* check if there is no space between the command and the path */ + if (param[0] == _T('\0')) + { + /* search for the \ or . so that both short & long names will work */ + for (place = cmd; *place; place++) + if (*place == _T('.') || *place == _T('\\')) + break; + + if (*place) + dir = place; + else + /* signal that there are no parameters */ + dir = NULL; + } + else + { + p = split (param, &argc); + if (argc > 1) + { + /*JPP 20-Jul-1998 use standard error message */ + error_too_many_parameters (param); + freep (p); + return 1; + } + else + dir = p[0]; + } + + /* remove trailing \ if any, but ONLY if dir is not the root dir */ + if (_tcslen (dir) >= 2 && dir[_tcslen (dir) - 1] == _T('\\')) + dir[_tcslen(dir) - 1] = _T('\0'); + + if (!RemoveDirectory (dir)) + { + ErrorMessage (GetLastError(), _T("RD")); + freep (p); + + return 1; + } + + freep (p); + + return 0; +} +#endif + + +/* + * set the exitflag to true + * + */ +INT internal_exit (LPTSTR cmd, LPTSTR param) +{ + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Exits the command line interpreter.\n\nEXIT")); + } + else + { + bExit = TRUE; + } + + return 0; +} + + +#ifdef INCLUDE_CMD_REM +/* + * does nothing + * + */ +INT cmd_rem (LPTSTR cmd, LPTSTR param) +{ + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Starts a comment line in a batch file.\n\n" + "REM [Comment]")); + } + + return 0; +} +#endif + + +INT cmd_showcommands (LPTSTR cmd, LPTSTR param) +{ + LPCOMMAND cmdptr; + INT y; + + y = 0; + cmdptr = cmds; + while (cmdptr->name) + { + if (++y == 8) + { + ConOutPuts (cmdptr->name); + y = 0; + } + else + ConOutPrintf (_T("%-10s"), cmdptr->name); + + cmdptr++; + } + + if (y != 0) + ConOutChar (_T('\n')); + + return 0; +} diff --git a/reactos/apps/utils/cmd/label.c b/reactos/apps/utils/cmd/label.c new file mode 100644 index 00000000000..285421954dd --- /dev/null +++ b/reactos/apps/utils/cmd/label.c @@ -0,0 +1,121 @@ +/* + * LABEL.C - label internal command. + * + * + * History: + * + * 10-Dec-1998 (Eric Kohl ) + * Started. + * + * 11-Dec-1998 (Eric Kohl ) + * Finished. + * + * 19-Jan-1998 (Eric Kohl ) + * Unicode ready! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_LABEL + +#include +#include +#include + +#include "cmd.h" + + +INT cmd_label (LPTSTR cmd, LPTSTR param) +{ + TCHAR szRootPath[] = _T("A:\\"); + TCHAR szLabel[80]; + TCHAR szOldLabel[80]; + DWORD dwSerialNr; + LPTSTR *arg; + INT args; + + /* set empty label string */ + szLabel[0] = _T('\0'); + + /* print help */ + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Displays or changes drive label.\n\n" + "LABEL [drive:][label]")); + return 0; + } + + /* get parameters */ + arg = split (param, &args); + + if (args > 2) + { + /* too many parameters */ + error_too_many_parameters (arg[args - 1]); + freep (arg); + return 1; + } + + if (args == 0) + { + /* get label of current drive */ + TCHAR szCurPath[MAX_PATH]; + GetCurrentDirectory (MAX_PATH, szCurPath); + szRootPath[0] = szCurPath[0]; + } + else + { + if ((_tcslen (arg[0]) >= 2) && (arg[0][1] == _T(':'))) + { + szRootPath[0] = toupper (*arg[0]); + if (args == 2) + _tcsncpy (szLabel, arg[1], 12); + } + else + { + TCHAR szCurPath[MAX_PATH]; + GetCurrentDirectory (MAX_PATH, szCurPath); + szRootPath[0] = szCurPath[0]; + _tcsncpy (szLabel, arg[0], 12); + } + } + + /* check root path */ + if (!IsValidPathName (szRootPath)) + { + error_invalid_drive (); + freep (arg); + return 1; + } + + GetVolumeInformation (szRootPath, szOldLabel, 80, &dwSerialNr, + NULL, NULL, NULL, 0); + + /* print drive info */ + ConOutPrintf (_T("Volume in drive %c:"), _totupper (szRootPath[0])); + + if (szOldLabel[0] != _T('\0')) + ConOutPrintf (_T(" is %s\n"), szOldLabel); + else + ConOutPrintf (_T(" has no label\n")); + + /* print the volume serial number */ + ConOutPrintf (_T("Volume Serial Number is %04X-%04X\n"), + HIWORD(dwSerialNr), LOWORD(dwSerialNr)); + + if (szLabel[0] == _T('\0')) + { + ConOutPrintf (_T("Drive label (11 Characters, ENTER if none)? ")); + ConInString (szLabel, 80); + } + + SetVolumeLabel (szRootPath, szLabel); + + freep (arg); + + return 0; +} + +#endif /* INCLUDE_CMD_LABEL */ \ No newline at end of file diff --git a/reactos/apps/utils/cmd/license.txt b/reactos/apps/utils/cmd/license.txt new file mode 100644 index 00000000000..c4fb365c774 --- /dev/null +++ b/reactos/apps/utils/cmd/license.txt @@ -0,0 +1,342 @@ + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program 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 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + + diff --git a/reactos/apps/utils/cmd/locale.c b/reactos/apps/utils/cmd/locale.c new file mode 100644 index 00000000000..b97c97102b3 --- /dev/null +++ b/reactos/apps/utils/cmd/locale.c @@ -0,0 +1,118 @@ +/* + * LOCALE.C - locale handling. + * + * + * History: + * + * 09-Jan-1999 (Eric Kohl ) + * Started. + * + * 20-Jan-1999 (Eric Kohl ) + * Unicode safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include +#include + +#include "cmd.h" + + +TCHAR cDateSeparator; +TCHAR cTimeSeparator; +TCHAR cThousandSeparator; +TCHAR cDecimalSeparator; +INT nDateFormat; +INT nTimeFormat; +TCHAR aszDayNames[7][8]; +INT nNumberGroups; + + +VOID InitLocale (VOID) +{ +#ifdef LOCALE_WINDOWS + TCHAR szBuffer[256]; + INT i; + + /* date settings */ + GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_SDATE, szBuffer, 256); + CharToOem (szBuffer, szBuffer); + cDateSeparator = szBuffer[0]; + GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_IDATE, szBuffer, 256); + nDateFormat = _ttoi (szBuffer); + + /* time settings */ + GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_STIME, szBuffer, 256); + CharToOem (szBuffer, szBuffer); + cTimeSeparator = szBuffer[0]; + GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_ITIME, szBuffer, 256); + nTimeFormat = _ttoi (szBuffer); + + /* number settings */ + GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szBuffer, 256); + CharToOem (szBuffer, szBuffer); + cThousandSeparator = szBuffer[0]; + GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, szBuffer, 256); + CharToOem (szBuffer, szBuffer); + cDecimalSeparator = szBuffer[0]; + GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_SGROUPING, szBuffer, 256); + nNumberGroups = _ttoi (szBuffer); + + /* days of week */ + for (i = 0; i < 7; i++) + { + GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_SABBREVDAYNAME1 + i, szBuffer, 256); + CharToOem (szBuffer, szBuffer); + _tcscpy (aszDayNames[(i+1)%7], szBuffer); /* little hack */ + } +#endif + +#ifdef LOCALE_GERMAN + LPTSTR names [7] = {_T("So"), _T("Mo"), _T("Di"), _T("Mi"), _T("Do"), _T("Fr"), _T("Sa")}; + INT i; + + /* date settings */ + cDateSeparator = '.'; + nDateFormat = 1; /* ddmmyy */ + + /* time settings */ + cTimeSeparator = ':'; + nTimeFormat = 1; /* 24 hour */ + + /* number settings */ + cThousandSeparator = '.'; + cDecimalSeparator = ','; + nNumberGroups = 3; + + /* days of week */ + for (i = 0; i < 7; i++) + _tcscpy (aszDayNames[i], names[i]); +#endif + +#ifdef LOCALE_DEFAULT + LPTSTR names [7] = {_T("Son"), _T("Mon"), _T("Tue"), _T("Wed"), _T("Thu"), _T("Fri"), _T("Sat")}; + INT i; + + /* date settings */ + cDateSeparator = '-'; + nDateFormat = 0; /* mmddyy */ + + /* time settings */ + cTimeSeparator = ':'; + nTimeFormat = 0; /* 12 hour */ + + /* number settings */ + cThousandSeparator = ','; + cDecimalSeparator = '.'; + nNumberGroups = 3; + + /* days of week */ + for (i = 0; i < 7; i++) + _tcscpy (aszDayNames[i], names[i]); +#endif +} diff --git a/reactos/apps/utils/cmd/makefile b/reactos/apps/utils/cmd/makefile index 7e36f733496..f956db79f62 100644 --- a/reactos/apps/utils/cmd/makefile +++ b/reactos/apps/utils/cmd/makefile @@ -1,12 +1,29 @@ -all: cmd.bin +# +# -OBJECTS = ../common/crt0.o cmd.o +LIB=../../lib +COMMON=../common -LIBS = ../../lib/mingw32/mingw32.a ../../lib/crtdll/crtdll.a \ - ../../lib/kernel32/kernel32.a ../../lib/ntdll/ntdll.a +# target: raw binary (does not work right now) +#all: cmd.bin + +# target: executable (not tested/experimental) +all: cmd.exe + +OBJECTS = $(COMMON)/crt0.o cmd.o attrib.o alias.o batch.o beep.o call.o cls.o cmdinput.o cmdtable.o\ + color.o date.o del.o dir.o echo.o err_hand.o error.o filecomp.o for.o goto.o history.o if.o\ + internal.o label.o misc.o path.o pause.o redir.o ren.o set.o shift.o tempfile.o time.o type.o ver.o\ + verify.o where.o + +LIBS = $(LIB)/mingw32/mingw32.a $(LIB)/crtdll/crtdll.a \ + $(LIB)/kernel32/kernel32.a $(LIB)/ntdll/ntdll.a cmd.bin: $(OBJECTS) $(LD) -Ttext 0x10000 $(OBJECTS) $(LIBS) -o cmd.exe $(OBJCOPY) -O binary cmd.exe cmd.bin +cmd.exe: $(OBJECTS) + $(LD) $(OBJECTS) $(LIBS) -o cmd.exe + include ../../rules.mak + diff --git a/reactos/apps/utils/cmd/makefile.lcc b/reactos/apps/utils/cmd/makefile.lcc new file mode 100644 index 00000000000..58c114a6bfa --- /dev/null +++ b/reactos/apps/utils/cmd/makefile.lcc @@ -0,0 +1,194 @@ +# ReactOS cmd.exe makefile for lcc-win32 +# 19990119 Emanuele Aliberti +# 19990127 EA +# 19990128 Eric Kohl +# Modified for cmd 0.0.4pre3. +# +# ReactOS : http://www.sid-dis.com/reactos/ +# Lcc-Win32: http://www.cs.virginia.edu/*lcc-win32 +# +TARGET=cmd +CC=lcc.exe +CFLAGS=-c -O +LD=lcclnk.exe +LFLAGS=-subsystem console -s -o $(TARGET).exe +OBJS=alias.obj \ + attrib.obj \ + batch.obj \ + beep.obj \ + call.obj \ + chcp.obj \ + cls.obj \ + cmd.obj \ + cmdinput.obj \ + cmdtable.obj \ + color.obj \ + console.obj \ + copy.obj \ + date.obj \ + del.obj \ + dir.obj \ + dirstack.obj \ + echo.obj \ + error.obj \ + filecomp.obj \ + for.obj \ + goto.obj \ + history.obj \ + if.obj \ + internal.obj \ + label.obj \ + locale.obj \ + misc.obj \ + move.obj \ + path.obj \ + pause.obj \ + prompt.obj \ + redir.obj \ + ren.obj \ + set.obj \ + shift.obj \ + time.obj \ + type.obj \ + ver.obj \ + verify.obj \ + vol.obj \ + where.obj + +# MAIN + +# What about this implicid rule? +# It should compile all c files. +# (To test this, uncomment the following two lines.) EK +#.c.obj: +# $(CC) $(CFLAGS) $< + +$(TARGET).exe: $(OBJS) + $(LD) $(LFLAGS) $(OBJS) + +# MODULES + +alias.obj: alias.c + $(CC) $(CFLAGS) alias.c + +attrib.obj: attrib.c + $(CC) $(CFLAGS) attrib.c + +batch.obj: batch.c + $(CC) $(CFLAGS) batch.c + +beep.obj: beep.c + $(CC) $(CFLAGS) beep.c + +call.obj: call.c + $(CC) $(CFLAGS) call.c + +cls.obj: cls.c + $(CC) $(CFLAGS) cls.c + +cmd.obj: cmd.c + $(CC) $(CFLAGS) cmd.c + +cmdinput.obj: cmdinput.c + $(CC) $(CFLAGS) cmdinput.c + +cmdtable.obj: cmdtable.c + $(CC) $(CFLAGS) cmdtable.c + +color.obj: color.c + $(CC) $(CFLAGS) color.c + +console.obj: console.c + $(CC) $(CFLAGS) console.c + +copy.obj: copy.c + $(CC) $(CFLAGS) copy.c + +date.obj: date.c + $(CC) $(CFLAGS) date.c + +del.obj: del.c + $(CC) $(CFLAGS) del.c + +dir.obj: dir.c + $(CC) $(CFLAGS) dir.c + +dirstack.obj: dirstack.c + $(CC) $(CFLAGS) dirstack.c + +echo.obj: echo.c + $(CC) $(CFLAGS) echo.c + +error.obj: error.c + $(CC) $(CFLAGS) error.c + +filecomp.obj: filecomp.c + $(CC) $(CFLAGS) filecomp.c + +for.obj: for.c + $(CC) $(CFLAGS) for.c + +goto.obj: goto.c + $(CC) $(CFLAGS) goto.c + +history.obj: history.c + $(CC) $(CFLAGS) history.c + +if.obj: if.c + $(CC) $(CFLAGS) if.c + +internal.obj: internal.c + $(CC) $(CFLAGS) internal.c + +label.obj: label.c + $(CC) $(CFLAGS) label.c + +locale.obj: locale.c + $(CC) $(CFLAGS) locale.c + +misc.obj: misc.c + $(CC) $(CFLAGS) misc.c + +move.obj: move.c + $(CC) $(CFLAGS) move.c + +path.obj: path.c + $(CC) $(CFLAGS) path.c + +pause.obj: pause.c + $(CC) $(CFLAGS) pause.c + +prompt.obj: prompt.c + $(CC) $(CFLAGS) prompt.c + +redir.obj: redir.c + $(CC) $(CFLAGS) redir.c + +ren.obj: ren.c + $(CC) $(CFLAGS) ren.c + +set.obj: set.c + $(CC) $(CFLAGS) set.c + +shift.obj: shift.c + $(CC) $(CFLAGS) shift.c + +time.obj: time.c + $(CC) $(CFLAGS) time.c + +type.obj: type.c + $(CC) $(CFLAGS) type.c + +ver.obj: ver.c + $(CC) $(CFLAGS) ver.c + +verify.obj: verify.c + $(CC) $(CFLAGS) verify.c + +vol.obj: vol.c + $(CC) $(CFLAGS) vol.c + +where.obj: where.c + $(CC) $(CFLAGS) where.c + +#EOF diff --git a/reactos/apps/utils/cmd/misc.c b/reactos/apps/utils/cmd/misc.c new file mode 100644 index 00000000000..1eb5ca46869 --- /dev/null +++ b/reactos/apps/utils/cmd/misc.c @@ -0,0 +1,296 @@ +/* + * MISC.C - misc. functions. + * + * + * History: + * + * 07/12/98 (Rob Lake) + * started + * + * 07/13/98 (Rob Lake) + * moved functions in here + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 18-Dec-1998 (Eric Kohl ) + * Changed split() to accept quoted arguments. + * Removed parse_firstarg(). + * + * 23-Jan-1999 (Eric Kohl ) + * Fixed an ugly bug in split(). In rare cases (last character + * of the string is a space) it ignored the NULL character and + * tried to add the following to the argument list. + * + * 28-Jan-1999 (Eric Kohl ) + * FileGetString() seems to be working now. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include +#include + +#include + +#include "cmd.h" + + +/* + * get a character out-of-band and honor Ctrl-Break characters + */ +TCHAR cgetchar (VOID) +{ + TCHAR ch; +#if 0 + DWORD dwRead; + DWORD dwOldMode; + HANDLE hIn; + + hIn = GetStdHandle (STD_INPUT_HANDLE); + ConInSwallowInput (hIn); + + GetConsoleMode (hIn, &dwOldMode); + SetConsoleMode (hIn, 0); + + ReadConsole (hIn, &ch, 1, &dwRead, NULL); + + DebugPrintf ("[cgetchar (0x%x) \'%c\']\n", ch, ch); + + SetConsoleMode (hIn, dwOldMode); +#endif + + if ((ch = getch()) == 0) + ch = getch() << 8; + + if (ch == 3) + bCtrlBreak = TRUE; + + return ch; +} + + +/* + * Check if Ctrl-Break was pressed during the last calls + */ + +BOOL CheckCtrlBreak (INT mode) +{ + static BOOL bLeaveAll = FALSE; /* leave all batch files */ + TCHAR c; + + switch (mode) + { + case BREAK_OUTOFBATCH: + bLeaveAll = 0; + return FALSE; + + case BREAK_BATCHFILE: + if (bLeaveAll) + return TRUE; + + if (!bCtrlBreak) + return FALSE; + + /* we need to be sure the string arrives on the screen! */ + do + ConOutPuts (_T("\r\nCtrl-Break pressed. Cancel batch file? (Yes/No/All) ")); + while (!_tcschr ("YNA\3", c = _totupper (cgetchar())) || !c); + + ConOutPuts (_T("\r\n")); + + if (c == _T('N')) + return bCtrlBreak = FALSE; /* ignore */ + + /* leave all batch files */ + bLeaveAll = ((c == _T('A')) || (c == _T('\3'))); + break; + + case BREAK_INPUT: + if (!bCtrlBreak) + return FALSE; + break; + } + + /* state processed */ + bCtrlBreak = FALSE; + return TRUE; +} + + +/* + * split - splits a line up into separate arguments, deliminators + * are spaces and slashes ('/'). + */ + +LPTSTR *split (LPTSTR s, LPINT args) +{ + LPTSTR *arg; + LPTSTR *p; + LPTSTR start; + LPTSTR q; + INT ac; + INT len; + BOOL bQuoted = FALSE; + + arg = malloc (sizeof (LPTSTR)); + if (!arg) + return NULL; + *arg = NULL; + + ac = 0; + while (*s) + { + /* skip leading spaces */ + while (*s && (_istspace (*s) || _istcntrl (*s))) + ++s; + + /* if quote (") then set bQuoted */ + if (*s == _T('\"')) + { + ++s; + bQuoted = TRUE; + } + + start = s; + + /* the first character can be '/' */ + if (*s == _T('/')) + ++s; + + /* skip to next word delimiter or start of next option */ + if (bQuoted) + { + while (_istprint (*s) && (*s != _T('\"')) && (*s != _T('/'))) + ++s; + } + else + { + while (_istprint (*s) && !_istspace (*s) && (*s != _T('/'))) + ++s; + } + + /* a word was found */ + if (s != start) + { + /* add new entry for new argument */ + arg = realloc (p = arg, (ac + 2) * sizeof (LPTSTR)); + if (!arg) + { + freep (p); + return NULL; + } + + /* create new entry */ + q = arg[ac] = malloc (((len = s - start) + 1) * sizeof (TCHAR)); + arg[++ac] = NULL; + if (!q) + { + freep (arg); + return NULL; + } + memcpy (q, start, len * sizeof (TCHAR)); + q[len] = _T('\0'); + } + + /* adjust string pointer if quoted (") */ + if (bQuoted) + { + ++s; + bQuoted = FALSE; + } + } + + *args = ac; + + return arg; +} + + +/* + * freep -- frees memory used for a call to split + * + */ +VOID freep (LPTSTR *p) +{ + LPTSTR *q; + + if (!p) + return; + + q = p; + while (*q) + free(*q++); + + free(p); +} + + +LPTSTR stpcpy (LPTSTR dest, LPTSTR src) +{ + _tcscpy (dest, src); + return (dest + _tcslen (src)); +} + + + +/* + * Checks if a path is valid (accessible) + */ + +BOOL IsValidPathName (LPCTSTR pszPath) +{ + TCHAR szOldPath[MAX_PATH]; + BOOL bResult; + + GetCurrentDirectory (MAX_PATH, szOldPath); + bResult = SetCurrentDirectory (pszPath); + + SetCurrentDirectory (szOldPath); + + return bResult; +} + + +/* + * Checks if a file exists (accessible) + */ + +BOOL IsValidFileName (LPCTSTR pszPath) +{ + return (GetFileAttributes (pszPath) != 0xFFFFFFFF); +} + + + +BOOL FileGetString (HANDLE hFile, LPTSTR lpBuffer, INT nBufferLength) +{ + LPTSTR lpString; + TCHAR ch; + DWORD dwRead; + + lpString = lpBuffer; + + while ((--nBufferLength > 0) && + ReadFile(hFile, &ch, 1, &dwRead, NULL) && dwRead) + { + *lpString++ = ch; + if (ch == _T('\r')) + { + /* overread '\n' */ + ReadFile (hFile, &ch, 1, &dwRead, NULL); + break; + } + } + + if (!dwRead && lpString == lpBuffer) + return FALSE; + + *lpString++ = _T('\0'); + + return TRUE; +} diff --git a/reactos/apps/utils/cmd/move.c b/reactos/apps/utils/cmd/move.c new file mode 100644 index 00000000000..54158d721a2 --- /dev/null +++ b/reactos/apps/utils/cmd/move.c @@ -0,0 +1,267 @@ +/* + * MOVE.C - move internal command. + * + * + * History: + * + * 14-Dec-1998 (Eric Kohl ) + * Started. + * + * 18-Jan-1999 (Eric Kohl ) + * Unicode safe! + * Preliminary version!!! + * + * 20-Jan-1999 (Eric Kohl ) + * Redirection safe! + * + * 27-Jan-1999 (Eric Kohl ) + * Added help text ("/?"). + * Added more error checks. + * + * 03-Feb-1999 (Eric Kohl ) + * Added "/N" option. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_MOVE + +#include +#include +#include + +#include "cmd.h" + + +#define OVERWRITE_NO 0 +#define OVERWRITE_YES 1 +#define OVERWRITE_ALL 2 +#define OVERWRITE_CANCEL 3 + + +static INT Overwrite (LPTSTR fn) +{ + TCHAR inp[10]; + LPTSTR p; + + ConOutPrintf (_T("Overwrite %s (Yes/No/All)? "), fn); + ConInString (inp, 10); + + _tcsupr (inp); + for (p=inp; _istspace (*p); p++) + ; + + if (*p != _T('Y') && *p != _T('A')) + return OVERWRITE_NO; + if (*p == _T('A')) + return OVERWRITE_ALL; + + return OVERWRITE_YES; +} + + + +INT cmd_move (LPTSTR cmd, LPTSTR param) +{ + LPTSTR *arg; + INT argc, i, nFiles; + TCHAR szDestPath[MAX_PATH]; + TCHAR szSrcPath[MAX_PATH]; + BOOL bPrompt = TRUE; + LPTSTR p; + WIN32_FIND_DATA findBuffer; + HANDLE hFile; + LPTSTR pszFile; + BOOL bNothing = FALSE; + + if (!_tcsncmp (param, _T("/?"), 2)) + { +#if 0 + ConOutPuts (_T("Moves files and renames files and directories.\n\n" + "To move one or more files:\n" + "MOVE [/N][/Y|/-Y][drive:][path]filename1[,...] destination\n" + "\n" + "To rename a directory:\n" + "MOVE [/N][/Y|/-Y][drive:][path]dirname1 dirname2\n" + "\n" + " [drive:][path]filename1 Specifies the location and name of the file\n" + " or files you want to move.\n" + " /N Nothing. Don everthing but move files or direcories.\n" + " /Y\n" + " /-Y\n" + "...")); +#else + ConOutPuts (_T("Moves files and renames files and directories.\n\n" + "To move one or more files:\n" + "MOVE [/N][drive:][path]filename1[,...] destination\n" + "\n" + "To rename a directory:\n" + "MOVE [/N][drive:][path]dirname1 dirname2\n" + "\n" + " [drive:][path]filename1 Specifies the location and name of the file\n" + " or files you want to move.\n" + " /N Nothing. Don everthing but move files or direcories.\n" + "\n" + "Current limitations:\n" + " - You can't move a file or directory from one drive to another.\n" + )); +#endif + return 0; + } + + arg = split (param, &argc); + nFiles = argc; + + /* read options */ + for (i = 0; i < argc; i++) + { + p = arg[i]; + + if (*p == _T('/')) + { + p++; + if (*p == _T('-')) + { + p++; + if (_totupper (*p) == _T('Y')) + bPrompt = TRUE; + } + else + { + if (_totupper (*p) == _T('Y')) + bPrompt = FALSE; + else if (_totupper (*p) == _T('N')) + bNothing = TRUE; + } + nFiles--; + } + } + + if (nFiles < 2) + { + /* there must be at least two pathspecs */ + error_req_param_missing (); + return 1; + } + + /* get destination */ + GetFullPathName (arg[argc - 1], MAX_PATH, szDestPath, NULL); +#ifdef _DEBUG + DebugPrintf (_T("Destination: %s\n"), szDestPath); +#endif + + /* move it*/ + for (i = 0; i < argc - 1; i++) + { + if (*arg[i] == _T('/')) + continue; + + hFile = FindFirstFile (arg[i], &findBuffer); + if (hFile == INVALID_HANDLE_VALUE) + { + ErrorMessage (GetLastError (), arg[i]); + freep (arg); + return 1; + } + + do + { + GetFullPathName (findBuffer.cFileName, MAX_PATH, szSrcPath, &pszFile); + + if (GetFileAttributes (szSrcPath) & FILE_ATTRIBUTE_DIRECTORY) + { + /* source is directory */ + +#ifdef _DEBUG + DebugPrintf (_T("Move directory \'%s\' to \'%s\'\n"), + szSrcPath, szDestPath); +#endif + if (!bNothing) + { + MoveFile (szSrcPath, szDestPath); + } + } + else + { + /* source is file */ + + if (IsValidFileName (szDestPath)) + { + /* destination exists */ + if (GetFileAttributes (szDestPath) & FILE_ATTRIBUTE_DIRECTORY) + { + /* destination is existing directory */ + + TCHAR szFullDestPath[MAX_PATH]; + + _tcscpy (szFullDestPath, szDestPath); + _tcscat (szFullDestPath, _T("\\")); + _tcscat (szFullDestPath, pszFile); + + ConOutPrintf (_T("%s => %s"), szSrcPath, szFullDestPath); + + if (!bNothing) + { + if (MoveFile (szSrcPath, szFullDestPath)) + ConOutPrintf (_T("[OK]\n")); + else + ConOutPrintf (_T("[Error]\n")); + } + } + else + { + /* destination is existing file */ + INT nOverwrite; + + /* must get the overwrite code */ + if ((nOverwrite = Overwrite (szDestPath))) + { +#if 0 + if (nOverwrite == OVERWRITE_ALL) + *lpFlags |= FLAG_OVERWRITE_ALL; +#endif + ConOutPrintf (_T("%s => %s"), szSrcPath, szDestPath); + + if (!bNothing) + { + if (MoveFile (szSrcPath, szDestPath)) + ConOutPrintf (_T("[OK]\n")); + else + ConOutPrintf (_T("[Error]\n")); + } + } + } + } + else + { + /* destination does not exist */ + TCHAR szFullDestPath[MAX_PATH]; + + GetFullPathName (szDestPath, MAX_PATH, szFullDestPath, NULL); + + ConOutPrintf (_T("%s => %s"), szSrcPath, szFullDestPath); + + if (!bNothing) + { + if (MoveFile (szSrcPath, szFullDestPath)) + ConOutPrintf (_T("[OK]\n")); + else + ConOutPrintf (_T("[Error]\n")); + } + } + } + } + while (FindNextFile (hFile, &findBuffer)); + + FindClose (hFile); + } + + + freep (arg); + + return 0; +} + +#endif /* INCLUDE_CMD_MOVE */ \ No newline at end of file diff --git a/reactos/apps/utils/cmd/path.c b/reactos/apps/utils/cmd/path.c new file mode 100644 index 00000000000..714ee3879a7 --- /dev/null +++ b/reactos/apps/utils/cmd/path.c @@ -0,0 +1,88 @@ +/* + * PATH.C - path internal command. + * + * + * History: + * + * 17 Jul 1998 (John P Price) + * Separated commands into individual files. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 09-Dec-1998 (Eric Kohl ) + * Added help text ("/?"). + * + * 18-Jan-1999 (Eric Kohl ) + * Unicode ready! + * + * 18-Jan-1999 (Eric Kohl ) + * Redirection safe! + * + * 24-Jan-1999 (Eric Kohl ) + * Fixed Win32 environment handling. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_PATH + +#include +#include +#include +#include + +#include "cmd.h" + + +/* size of environment variable buffer */ +#define ENV_BUFFER_SIZE 1024 + + +INT cmd_path (LPTSTR cmd, LPTSTR param) +{ + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Displays or sets a search path for executable files.\n\n" + "PATH [[drive:]path[;...]]\nPATH ;\n\n" + "Type PATH ; to clear all search-path settings and direct the command shell\n" + "to search only in the current directory.\n" + "Type PATH without parameters to display the current path.\n")); + return 0; + } + + /* if param is empty, display the PATH environment variable */ + if (!param || !*param) + { + DWORD dwBuffer; + LPTSTR pszBuffer; + + pszBuffer = (LPTSTR)malloc (ENV_BUFFER_SIZE * sizeof(TCHAR)); + dwBuffer = GetEnvironmentVariable (_T("PATH"), pszBuffer, ENV_BUFFER_SIZE); + if (dwBuffer == 0) + { + ConErrPrintf ("CMD: Not in environment \"PATH\"\n"); + return 0; + } + else if (dwBuffer > ENV_BUFFER_SIZE) + { + pszBuffer = (LPTSTR)realloc (pszBuffer, dwBuffer * sizeof (TCHAR)); + GetEnvironmentVariable (_T("PATH"), pszBuffer, ENV_BUFFER_SIZE); + } + + ConOutPrintf (_T("PATH=%s\n"), pszBuffer); + free (pszBuffer); + + return 0; + } + + /* set PATH environment variable */ + if (!SetEnvironmentVariable (_T("PATH"), param)) + return 1; + + return 0; +} + +#endif diff --git a/reactos/apps/utils/cmd/pause.c b/reactos/apps/utils/cmd/pause.c new file mode 100644 index 00000000000..f4c01bba15a --- /dev/null +++ b/reactos/apps/utils/cmd/pause.c @@ -0,0 +1,68 @@ +/* + * PAUSE.C - pause internal command. + * + * + * History: + * + * 16 Jul 1998 (Hans B Pufal) + * started. + * + * 16 Jul 1998 (John P Price) + * Seperated commands into individual files. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 18-Jan-1999 (Eric Kohl ) + * Unicode ready! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_PAUSE + +#include +#include +#include + +#include "cmd.h" +#include "batch.h" + + +/* + * Perform PAUSE command. + * + * FREEDOS extension : If parameter is specified use that as the pause + * message. + * + * ?? Extend to include functionality of CHOICE if switch chars + * specified. + */ + +INT cmd_pause (LPTSTR cmd, LPTSTR param) +{ +#ifdef _DEBUG + DebugPrintf ("cmd_pause: \'%s\' : \'%s\'\n", cmd, param); +#endif + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Stops the execution of a batch file and shows the following message:\n" + "\"Press any key to continue...\" or a user defined message.\n\n" + "PAUSE [message]")); + return 0; + } + + if (*param) + ConOutPrintf (param); + else + msg_pause (); + + cgetchar (); + + return 0; +} + +#endif diff --git a/reactos/apps/utils/cmd/prompt.c b/reactos/apps/utils/cmd/prompt.c new file mode 100644 index 00000000000..fa674f1c4ce --- /dev/null +++ b/reactos/apps/utils/cmd/prompt.c @@ -0,0 +1,237 @@ +/* + * PROMPT.C - prompt handling. + * + * + * History: + * + * 14/01/95 (Tim Normal) + * started. + * + * 08/08/95 (Matt Rains) + * i have cleaned up the source code. changes now bring this source + * into guidelines for recommended programming practice. + * + * 01/06/96 (Tim Norman) + * added day of the week printing (oops, forgot about that!) + * + * 08/07/96 (Steffan Kaiser) + * small changes for speed + * + * 20-Jul-1998 (John P Price ) + * removed redundant day strings. Use ones defined in date.c. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 28-Jul-1998 (John P Price ) + * moved cmd_prompt from internal.c to here + * + * 09-Dec-1998 (Eric Kohl ) + * Added help text ("/?"). + * + * 14-Dec-1998 (Eric Kohl ) + * Added "$+" option. + * + * 09-Jan-1999 (Eric Kohl ) + * Added "$A", "$C" and "$F" option. + * Added locale support. + * Fixed "$V" option. + * + * 20-Jan-1999 (Eric Kohl ) + * Unicode and redirection safe! + * + * 24-Jan-1999 (Eric Kohl ) + * Fixed Win32 environment handling. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include + +#include "cmd.h" + + +/* + * print the command-line prompt + * + */ +VOID PrintPrompt(VOID) +{ + static TCHAR default_pr[] = _T("$P$G"); + TCHAR szPrompt[256]; + LPTSTR pr; + + if (GetEnvironmentVariable (_T("PROMPT"), szPrompt, 256)) + pr = szPrompt; + else + pr = default_pr; + + while (*pr) + { + if (*pr != _T('$')) + { + ConOutChar (*pr); + } + else + { + pr++; + + switch (_totupper (*pr)) + { + case _T('A'): + ConOutChar (_T('&')); + break; + + case _T('B'): + ConOutChar (_T('|')); + break; + + case _T('C'): + ConOutChar (_T('(')); + break; + + case _T('D'): + { + TCHAR szDate[32]; + + GetDateFormat (LOCALE_USER_DEFAULT, DATE_SHORTDATE, + NULL, NULL, szDate, sizeof (szDate)); + ConOutPrintf (_T("%s"), szDate); + } + break; + + case _T('E'): + ConOutChar (_T('\x1B')); + break; + + case _T('F'): + ConOutChar (_T(')')); + break; + + case _T('G'): + ConOutChar (_T('>')); + break; + + case _T('H'): + ConOutChar (_T('\x08')); + break; + + case _T('L'): + ConOutChar (_T('<')); + break; + + case _T('N'): + { + TCHAR szPath[MAX_PATH]; + GetCurrentDirectory (MAX_PATH, szPath); + ConOutChar (szPath[0]); + } + break; + + case _T('P'): + { + TCHAR szPath[MAX_PATH]; + GetCurrentDirectory (MAX_PATH, szPath); + ConOutPrintf (_T("%s"), szPath); + } + break; + + case _T('Q'): + ConOutChar (_T('=')); + break; + + case _T('T'): + { + TCHAR szTime[32]; + GetTimeFormat (LOCALE_USER_DEFAULT, 0, NULL, + NULL, szTime, sizeof (szTime)); + ConOutPrintf (_T("%s"), szTime); + } + break; + + case _T('V'): + switch (osvi.dwPlatformId) + { + case VER_PLATFORM_WIN32_WINDOWS: + if (osvi.dwMajorVersion == 4 && + osvi.dwMinorVersion == 1) + ConOutPrintf (_T("Windows 98")); + else + ConOutPrintf (_T("Windows 95")); + break; + + case VER_PLATFORM_WIN32_NT: + ConOutPrintf (_T("Windows NT Version %lu.%lu"), + osvi.dwMajorVersion, osvi.dwMinorVersion); + break; + } + break; + + case _T('_'): + ConOutChar (_T('\n')); + break; + + case '$': + ConOutChar (_T('$')); + break; + +#ifdef FEATURE_DIRECTORY_STACK + case '+': + { + INT i; + for (i = 0; i < GetDirectoryStackDepth (); i++) + ConOutChar (_T('+')); + } + break; +#endif + } + } + pr++; + } +} + + +#ifdef INCLUDE_CMD_PROMPT + +INT cmd_prompt (LPTSTR cmd, LPTSTR param) +{ + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Changes the command prompt.\n\n" + "PROMPT [text]\n\n" + " text Specifies a new command prompt.\n\n" + "Prompt can be made up of normal characters and the following special codes:\n\n" + " $A & (Ampersand)\n" + " $B | (pipe)\n" + " $C ( (Left parenthesis)\n" + " $D Current date\n" + " $E Escape code (ASCII code 27)\n" + " $F ) (Right parenthesis)\n" + " $G > (greater-than sign)\n" + " $H Backspace (erases previous character)\n" + " $L < (less-than sign)\n" + " $N Current drive\n" + " $P Current drive and path\n" + " $Q = (equal sign)\n" + " $T Current time\n" + " $V OS version number\n" + " $_ Carriage return and linefeed\n" + " $$ $ (dollar sign)")); +#ifdef FEATURE_DIRECTORY_STACK + ConOutPuts (_T(" $+ Displays the current depth of the directory stack")); +#endif + ConOutPuts (_T("\nType PROMPT without parameters to reset the prompt to the default setting.")); + return 0; + } + + /* set PROMPT environment variable */ + if (!SetEnvironmentVariable (_T("PROMPT"), param)) + return 1; + + return 0; +} +#endif diff --git a/reactos/apps/utils/cmd/readme.txt b/reactos/apps/utils/cmd/readme.txt new file mode 100644 index 00000000000..b76a3a77baf --- /dev/null +++ b/reactos/apps/utils/cmd/readme.txt @@ -0,0 +1,101 @@ +ReactOS Command Line Interface "CMD" version 0.0.4 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is the fourth pre-alpha release of CMD.EXE for ReactOS. +It was converted from the FreeDOS COMMAND.COM. + + +Warning!! Warning!! Warning!! +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This is a pre-alpha version! Many features have not been tested! +Be careful when you use commands that write to your disk drives, +they might destroy your files or the file system!!! + + +Status +~~~~~~ +This is a converted version of FreeDOS COMMAND.COM. +I added some commands from WinNT's CMD.EXE. + + +New features and improvements +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + - Fixed redirection and piping. + (E.g. you can use "type > file" now.) + - Added new error redirections "2>" and "2>>". + (E.g.: "make 2>error.log") + - Added CHCP command. + - Fixed environment handling. + - New makefile for lcc-win (makefile.lcc). + - Rewrote DEL and MOVE with a new structure. + - Improved national language support. + - Fixed filename completion. + + +Compiling +~~~~~~~~~ +I converted CMD using MS Visual C++ 5.0 and Win95. The included makefile +is just an experimental version. + +If you want to compile and test CMD with djgpp, modify the makefile as needed. +I put the CMD sources into [reactos\apps], the makefile is written for that +directory. + +If you want to compile and test CMD using another compiler, just create +a new console application project and add all *.c and *.h files to it. +It should compile without an error. + + +Please report bugs which are not listed above. + + +Good luck + + Eric Kohl + + + + +FreeDOS Command Line Interface +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +About +~~~~~ +This software is part of the FreeDOS project. Please email +freedos@sunsite.unc.edu for more information, or visit the freedos +archive at "ftp://sunsite.unc.edu/pub/micro/pc-stuff/freedos". Also, +visit our web page at http://www.freedos.org/. + +The command.com web site is at + + http://www.gcfl.net/FreeDOS/command.com/ + + +This software has been developed by the following people: +(listed in approximate chronological order of contributions) + +FreeDOS developers: + normat@rpi.edu (Tim Norman) + mrains@apanix.apana.org.au (Matt Rains) + ejeffrey@iastate.edu (Evan Jeffrey) + Steffen.Kaiser@Informatik.TU-Chemnitz.DE (Steffen Kaiser) + Svante Frey (sfrey@kuai.se) + Oliver Mueller (ogmueller@t-online.de) + Aaron Kaufman (morgan@remarque.berkeley.edu) + Marc Desrochers (bitzero@hotmail.com) + Rob Lake (rlake@cs.mun.ca) + John P. Price + Hans B Pufal + +ReactOS developers: + Eric Kohl + + +Current Features +~~~~~~~~~~~~~~~~ + - environment handling with prompt and path support. + - directory utilities. + - command-line history with doskey-like features. + - batch file processing. + - input/output redirection and piping. + - alias support. + - filename completion (use TAB) diff --git a/reactos/apps/utils/cmd/redir.c b/reactos/apps/utils/cmd/redir.c new file mode 100644 index 00000000000..594bc112099 --- /dev/null +++ b/reactos/apps/utils/cmd/redir.c @@ -0,0 +1,218 @@ +/* + * REDIR.C - redirection handling. + * + * + * History: + * + * 12/15/95 (Tim Norman) + * started. + * + * 12 Jul 98 (Hans B Pufal) + * Rewrote to make more efficient and to conform to new command.c + * and batch.c processing. + * + * 27-Jul-1998 (John P Price ) + * Added config.h include + * + * 22-Jan-1999 (Eric Kohl ) + * Unicode safe! + * Added new error redirection "2>" and "2>>". + * + * 26-Jan-1999 (Eric Kohl ) + * Added new error AND output redirection "&>" and "&>>". + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef FEATURE_REDIRECTION + +#include +#include +#include +#include + +#include "cmd.h" + + +static BOOL +IsRedirection (TCHAR c) +{ + return (c == _T('<')) || (c == _T('>')) || (c == _T('|')); +} + + +/* + * Gets the redirection info from the command line and copies the + * file names into ifn, ofn and efn removing them from the command + * line. + * + * Converts remaining command line into a series of null terminated + * strings defined by the pipe char '|'. Each string corresponds + * to a single executable command. A double null terminates the + * command strings. + * + * Return number of command strings found. + * + */ + +INT GetRedirection (LPTSTR s, LPTSTR ifn, LPTSTR ofn, LPTSTR efn, LPINT lpnFlags) +{ + INT num = 1; + LPTSTR dp = s; + LPTSTR sp = s; + + /* find and remove all the redirections first */ + while (*sp) + { + if ((*sp == _T('"')) || (*sp == _T('\''))) + { + /* No redirects inside quotes */ + TCHAR qc = *sp; + + do + *dp++ = *sp++; + while (*sp != qc); + + *dp++ = *sp++; + } + else if ((*sp == _T('<')) || (*sp == _T('>')) || + (*sp == _T('2')) || (*sp == _T('&'))) + { + /* MS-DOS ignores multiple redirection symbols and uses the last */ + /* redirection, so we'll emulate that and not check */ + + if (*sp == _T('<')) + { + /* input redirection */ + *lpnFlags |= INPUT_REDIRECTION; + while (_istspace (*sp)) + sp++; + + /* copy file name */ + while (*sp && !IsRedirection (*sp) && !_istspace (*sp)) + *ifn++ = *sp++; + *ifn = _T('\0'); + } + else if (*sp == _T('>')) + { + /* output redirection */ + *lpnFlags |= OUTPUT_REDIRECTION; + sp++; + + /* append request ? */ + if (*sp == _T('>')) + { + *lpnFlags |= OUTPUT_APPEND; + sp++; + } + + while (_istspace (*sp)) + sp++; + + /* copy file name */ + while (*sp && !IsRedirection (*sp) && !_istspace (*sp)) + *ofn++ = *sp++; + *ofn = _T('\0'); + } + else if (*sp == _T('2')) + { + /* error redirection */ + sp++; + + if (*sp == _T('>')) + { + *lpnFlags |= ERROR_REDIRECTION; + sp++; + + /* append request ? */ + if (*sp == _T('>')) + { + *lpnFlags |= ERROR_APPEND; + sp++; + } + } + else + { + /* no redirection!! copy the '2' character! */ + sp--; + *dp++ = *sp++; + continue; + } + + while (_istspace (*sp)) + sp++; + + /* copy file name */ + while (*sp && !IsRedirection (*sp) && !_istspace (*sp)) + *efn++ = *sp++; + *efn = _T('\0'); + } + else if (*sp == _T('&')) + { + /* output AND error redirection */ + sp++; + + if (*sp == _T('>')) + { + *lpnFlags |= (ERROR_REDIRECTION | OUTPUT_REDIRECTION); + sp++; + + /* append request ? */ + if (*sp == _T('>')) + { + *lpnFlags |= (ERROR_APPEND | OUTPUT_APPEND); + sp++; + } + } + else + { + /* no redirection!! copy the '&' character! */ + sp--; + *dp++ = *sp++; + continue; + } + + while (_istspace (*sp)) + sp++; + + /* copy file name */ + while (*sp && !IsRedirection (*sp) && !_istspace (*sp)) + *ofn++ = *efn++ = *sp++; + *ofn = *efn = _T('\0'); + } + } + else + *dp++ = *sp++; + } + *dp++ = _T('\0'); + *dp = _T('\0'); + + /* now go for the pipes */ + sp = s; + while (*sp) + { + if ((*sp == _T('"')) || (*sp == _T('\''))) + { + TCHAR qc = *sp; + + do + sp++; + while (*sp != qc); + + sp++; + } + else if (*sp == _T('|')) + { + *sp++ = '\0'; + num++; + } + else + sp++; + } + + return num; +} + +#endif /* FEATURE_REDIRECTION */ diff --git a/reactos/apps/utils/cmd/ren.c b/reactos/apps/utils/cmd/ren.c new file mode 100644 index 00000000000..2023d075cf6 --- /dev/null +++ b/reactos/apps/utils/cmd/ren.c @@ -0,0 +1,72 @@ +/* + * REN.C - rename internal command. + * + * + * History: + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 18-Dec-1998 (Eric Kohl + * Added support for quoted long file names with spaces. + * + * 20-Jan-1999 (Eric Kohl + * Unicode and redirection safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_RENAME + +#include +#include +#include + +#include "cmd.h" + +/* + * simple file rename internal command. + * + */ +INT cmd_rename (LPTSTR cmd, LPTSTR param) +{ + LPTSTR *arg; + INT argc; + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Renames a file/directory or files/directories.\n" + "\n" + "RENAME [drive:][path][directoryname1 | filename1] [directoryname2 | filename2]\n" + "REN [drive:][path][directoryname1 | filename1] [directoryname2 | filename2]\n" + "\n" + "Note that you cannot specify a new drive or path for your destination. Use\n" + "the MOVE command for that purpose.")); + return 0; + } + + /* split the argument list */ + arg = split (param, &argc); + + if (argc != 2) + { + freep (arg); + error_too_many_parameters (param); + return 1; + } + + if (!MoveFile (arg[0], arg[1])) + { + ConErrPuts (_T("rename")); + freep (arg); + return 1; + } + + freep (arg); + + return 0; +} + +#endif diff --git a/reactos/apps/utils/cmd/set.c b/reactos/apps/utils/cmd/set.c new file mode 100644 index 00000000000..7be3388eac9 --- /dev/null +++ b/reactos/apps/utils/cmd/set.c @@ -0,0 +1,127 @@ +/* + * SET.C - set internal command. + * + * + * History: + * + * 06/14/97 (Tim Norman) + * changed static var in set() to a malloc'd space to pass to putenv. + * need to find a better way to do this, since it seems it is wasting + * memory when variables are redefined. + * + * 07/08/1998 (John P. Price) + * removed call to show_environment in set command. + * moved test for syntax before allocating memory in set command. + * misc clean up and optimization. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 28-Jul-1998 (John P Price ) + * added set_env function to set env. variable without needing set command + * + * 09-Dec-1998 (Eric Kohl ) + * Added help text ("/?"). + * + * 24-Jan-1999 (Eric Kohl ) + * Fixed Win32 environment handling. + * Unicode and redirection safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_SET + +#include +#include +#include +#include + +#include "cmd.h" + + +/* size of environment variable buffer */ +#define ENV_BUFFER_SIZE 1024 + + +INT cmd_set (LPTSTR cmd, LPTSTR param) +{ + LPTSTR p; + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Displays, sets, or removes environment variables.\n\n" + "SET [variable[=][string]]\n\n" + " variable Specifies the environment-variable name.\n" + " string Specifies a series of characters to assign to the variable.\n\n" + "Type SET without parameters to display the current environment variables.\n")); + return 0; + } + + /* if no parameters, show the environment */ + if (param[0] == _T('\0')) + { + LPTSTR lpEnv; + LPTSTR lpOutput; + INT len; + + lpEnv = (LPTSTR)GetEnvironmentStrings (); + if (lpEnv) + { + lpOutput = lpEnv; + while (*lpOutput) + { + len = _tcslen(lpOutput); + if (len) + { + if (*lpOutput != _T('=')) + ConOutPuts (lpOutput); + lpOutput += (len + 1); + } + } + FreeEnvironmentStrings (lpEnv); + } + + return 0; + } + + p = _tcschr (param, _T('=')); + if (p) + { + /* set or remove environment variable */ + *p = _T('\0'); + p++; + + SetEnvironmentVariable (param, p); + } + else + { + /* display environment variable */ + LPTSTR pszBuffer; + DWORD dwBuffer; + + pszBuffer = (LPTSTR)malloc (ENV_BUFFER_SIZE * sizeof(TCHAR)); + dwBuffer = GetEnvironmentVariable (param, pszBuffer, ENV_BUFFER_SIZE); + if (dwBuffer == 0) + { + ConErrPrintf ("CMD: Not in environment \"%s\"\n", param); + return 0; + } + else if (dwBuffer > ENV_BUFFER_SIZE) + { + pszBuffer = (LPTSTR)realloc (pszBuffer, dwBuffer * sizeof (TCHAR)); + GetEnvironmentVariable (param, pszBuffer, ENV_BUFFER_SIZE); + } + + ConOutPrintf ("%s\n", pszBuffer); + free (pszBuffer); + + return 0; + } + + return 0; +} + +#endif diff --git a/reactos/apps/utils/cmd/shift.c b/reactos/apps/utils/cmd/shift.c new file mode 100644 index 00000000000..92ee0363c12 --- /dev/null +++ b/reactos/apps/utils/cmd/shift.c @@ -0,0 +1,72 @@ +/* + * SHIFT.C - shift internal batch command + * + * + * History: + * + * 16 Jul 1998 (Hans B Pufal) + * started. + * + * 16 Jul 1998 (John P Price) + * Separated commands into individual files. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 07-Jan-1999 (Eric Kohl ) + * Added help text ("shift /?") and cleaned up. + * + * 20-Jan-1999 (Eric Kohl ) + * Unicode and redirection safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include + +#include "cmd.h" +#include "batch.h" + + +/* + * Perform the SHIFT command. + * + * Only valid inside batch files. + * + * FREEDOS extension : optional parameter DOWN to allow shifting + * parameters backwards. + */ + +INT cmd_shift (LPTSTR cmd, LPTSTR param) +{ +#ifdef _DEBUG + DebugPrintf ("cmd_shift: (\'%s\', \'%s\'\n", cmd, param); +#endif + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Changes the position of replaceable parameters in a batch file.\n\n" + "SHIFT [DOWN]")); + return 0; + } + + if (bc == NULL) + { + /* not in batch - error!! */ + return 1; + } + + if (!_tcsicmp (param, _T("down"))) + { + if (bc->shiftlevel) + bc->shiftlevel--; + } + else /* shift up */ + bc->shiftlevel++; + + return 0; +} diff --git a/reactos/apps/utils/cmd/time.c b/reactos/apps/utils/cmd/time.c new file mode 100644 index 00000000000..f2b01d84aa2 --- /dev/null +++ b/reactos/apps/utils/cmd/time.c @@ -0,0 +1,253 @@ +/* + * TIME.C - time internal command. + * + * + * History: + * + * 07/08/1998 (John P. Price) + * started. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 09-Jan-1999 (Eric Kohl ) + * Added locale support. + * + * 19-Jan-1999 (Eric Kohl ) + * Unicode and redirection safe! + * Added "/t" option. + * + * 04-Feb-1999 (Eric Kohl ) + * Fixed time input bug. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_TIME + +#include +#include +#include +#include + +#include "cmd.h" + + +static VOID +PrintTime (VOID) +{ +#if 0 + SYSTEMTIME st; + + GetLocalTime (&st); + + switch (nTimeFormat) + { + case 0: /* 12 hour format */ + default: + ConOutPrintf (_T("Current time is %2d%c%02d%c%02d%c%02d%c\n"), + (st.wHour == 0 ? 12 : (st.wHour <= 12 ? st.wHour : st.wHour - 12)), + cTimeSeparator, st.wMinute, cTimeSeparator, st.wSecond, cDecimalSeparator, + st.wMilliseconds / 10, (st.wHour <= 11 ? 'a' : 'p')); + break; + + case 1: /* 24 hour format */ + ConOutPrintf (_T("Current time is %2d%c%02d%c%02d%c%02d\n"), + st.wHour, cTimeSeparator, st.wMinute, cTimeSeparator, + st.wSecond, cDecimalSeparator, st.wMilliseconds / 10); + break; + } +#endif + + TCHAR szTime[32]; + + GetTimeFormat (LOCALE_USER_DEFAULT, 0, NULL, NULL, + szTime, sizeof (szTime)); + ConOutPrintf (_T("Current date is: %s\n"), szTime); +} + + +static BOOL ParseTime (LPTSTR s) +{ + SYSTEMTIME t; + LPTSTR p = s; + + if (!*s) + return TRUE; + + GetLocalTime (&t); + t.wHour = 0; + t.wMinute = 0; + t.wSecond = 0; + t.wMilliseconds = 0; + + // first get hour + if (_istdigit(*p)) + { + while (_istdigit(*p)) + { + t.wHour = t.wHour * 10 + *p - _T('0'); + p++; + } + } + else + return FALSE; + + // get time separator + if (*p != cTimeSeparator) + return FALSE; + p++; + + // now get minutes + if (_istdigit(*p)) + { + while (_istdigit(*p)) + { + t.wMinute = t.wMinute * 10 + *p - _T('0'); + p++; + } + } + else + return FALSE; + + // get time separator + if (*p != cTimeSeparator) + return FALSE; + p++; + + // now get seconds + if (_istdigit(*p)) + { + while (_istdigit(*p)) + { + t.wSecond = t.wSecond * 10 + *p - _T('0'); + p++; + } + } + else + return FALSE; + + // get decimal separator + if (*p == cDecimalSeparator) + { + p++; + + // now get hundreths + if (_istdigit(*p)) + { + while (_istdigit(*p)) + { +// t.wMilliseconds = t.wMilliseconds * 10 + *p - _T('0'); + p++; + } +// t.wMilliseconds *= 10; + } + } + + /* special case: 12 hour format */ + if (nTimeFormat == 0) + { + if (_totupper(*s) == _T('P')) + { + t.wHour += 12; + } + + if ((_totupper(*s) == _T('A')) && (t.wHour == 12)) + { + t.wHour = 0; + } + } + + if (t.wHour > 23 || t.wMinute > 60 || t.wSecond > 60 || t.wMilliseconds > 999) + return FALSE; + + SetLocalTime (&t); + + return TRUE; +} + + +INT cmd_time (LPTSTR cmd, LPTSTR param) +{ + LPTSTR *arg; + INT argc; + INT i; + BOOL bPrompt = TRUE; + INT nTimeString = -1; + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Displays or sets the system time.\n\n" + "TIME [/T][time]\n\n" + " /T display only\n\n" + "Type TIME with no parameters to display the current time setting and a prompt\n" + "for a new one. Press ENTER to keep the same time.")); + return 0; + } + + /* build parameter array */ + arg = split (param, &argc); + + /* check for options */ + for (i = 0; i < argc; i++) + { + if (_tcsicmp (arg[i], _T("/t")) == 0) + bPrompt = FALSE; + if ((*arg[i] != _T('/')) && (nTimeString == -1)) + nTimeString = i; + } + + if (nTimeString == -1) + PrintTime (); + + if (!bPrompt) + { + freep (arg); + return 0; + } + + while (1) + { + if (nTimeString == -1) + { + TCHAR s[40]; + + ConOutPrintf (_T("Enter new time: ")); + + ConInString (s, 40); + +#ifdef _DEBUG + DebugPrintf ("\'%s\'\n", s); +#endif + + while (*s && s[_tcslen (s) - 1] < _T(' ')) + s[_tcslen(s) - 1] = _T('\0'); + + if (ParseTime (s)) + { + freep (arg); + return 0; + } + } + else + { + if (ParseTime (arg[nTimeString])) + { + freep (arg); + return 0; + } + + // force input the next time around. + nTimeString == -1; + } + ConErrPuts (_T("Invalid time.")); + } + + freep (arg); + + return 0; +} + +#endif diff --git a/reactos/apps/utils/cmd/todo.txt b/reactos/apps/utils/cmd/todo.txt new file mode 100644 index 00000000000..bcffe59a323 --- /dev/null +++ b/reactos/apps/utils/cmd/todo.txt @@ -0,0 +1,21 @@ +Things to do +~~~~~~~~~~~~ +Fix bugs :) + +Rewrite DIR command (Unicode aware / new structure). + +Optimize the code! For size and speed. There are numerous places +where the code is hardly optimal for either. + +Sorting in DIR command ("dir /o..."). + +^S and ^Q to pause/resume displays. + +Improve DEL, COPY and MOVE commands. +BREAK command on command-line. + +Add wildcard support to REN. + +Add "/?" support to all batch commands. + +And many, many more... diff --git a/reactos/apps/utils/cmd/type.c b/reactos/apps/utils/cmd/type.c new file mode 100644 index 00000000000..b4713562b90 --- /dev/null +++ b/reactos/apps/utils/cmd/type.c @@ -0,0 +1,96 @@ +/* + * TYPE.C - type internal command. + * + * History: + * + * 07/08/1998 (John P. Price) + * started. + * + * 07/12/98 (Rob Lake) + * Changed error messages + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 07-Jan-1999 (Eric Kohl ) + * Added support for quoted arguments (type "test file.dat"). + * Cleaned up. + * + * 19-Jan-1999 (Eric Kohl ) + * Unicode and redirection ready! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_TYPE + +#include +#include +#include + +#include "cmd.h" + + +INT cmd_type (LPTSTR cmd, LPTSTR param) +{ + TCHAR szBuffer[256]; + HANDLE hFile; + DWORD dwBytesRead; + DWORD dwBytesWritten; + BOOL bResult; + INT args; + LPTSTR *arg; + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Displays the contents of text files.\n\n" + "TYPE [drive:][path]filename")); + return 0; + } + + if (!*param) + { + error_req_param_missing (); + return 1; + } + + arg = split (param, &args); + + if (args > 1) + { + error_too_many_parameters (_T("\b \b")); + freep (arg); + return 1; + } + + hFile = CreateFile (arg[0], GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + + if (hFile == INVALID_HANDLE_VALUE) + { + error_sfile_not_found (param); + freep (arg); + return 1; + } + + do + { + bResult = ReadFile (hFile, szBuffer, sizeof(szBuffer), + &dwBytesRead, NULL); + if (dwBytesRead) + WriteFile (GetStdHandle (STD_OUTPUT_HANDLE), szBuffer, dwBytesRead, + &dwBytesWritten, NULL); + } + while (bResult && dwBytesRead > 0); + + CloseHandle (hFile); + freep (arg); + + return 0; +} + +#endif diff --git a/reactos/apps/utils/cmd/ver.c b/reactos/apps/utils/cmd/ver.c new file mode 100644 index 00000000000..f5e76fc79e7 --- /dev/null +++ b/reactos/apps/utils/cmd/ver.c @@ -0,0 +1,139 @@ +/* + * VER.C - ver internal command. + * + * + * History: + * + * 06/30/98 (Rob Lake) + * rewrote ver command to accept switches, now ver alone prints + * copyright notice only. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 30-Jul-1998 (John P Price ) + * added text about where to send bug reports and get updates. + * + * 20-Jan-1999 (Eric Kohl ) + * Unicode and redirection safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include + +#include "cmd.h" + +#define VER_HELP "display shell version info VER [/C/R/W/?]" + + +VOID ShortVersion (VOID) +{ + ConOutPuts (_T("\n" SHELLINFO " " SHELLVER "\n")); +} + + +#ifdef INCLUDE_CMD_VER + +/* + * display shell version info internal command. + * + * + */ +INT cmd_ver (LPTSTR cmd, LPTSTR param) +{ + INT i; + + /* JPP 07/08/1998 clean up and shortened info. */ + + ConOutPuts (_T("\n" SHELLINFO " " SHELLVER "\nCopyright (C) 1994-1998 Tim Norman and others.")); + ConOutPuts (_T("Copyright (C) 1998,1999 Eric Kohl.")); + + /* Basic copyright notice */ + if (param[0] == _T('\0')) + { + ConOutPuts (_T("\n"SHELLINFO + " comes with ABSOLUTELY NO WARRANTY; for details\n" + "type: `ver /w'. This is free software, and you are welcome to redistribute\n" + "it under certain conditions; type `ver /r' for details. Type `ver /c' for a\n" + "listing of credits.")); + } + else + { + /* MS-DOS ver prints just help if /? is alone or not */ + if (_tcsstr (param, _T("/?")) != NULL) + { + ConOutPuts (_T(USAGE ": " VER_HELP)); + return 0; + } + + for (i = 0; param[i]; i++) + { + /* skip spaces */ + if (param[i] == _T(' ')) + continue; + + if (param[i] == _T('/')) + { + /* is this a lone '/' ? */ + if (param[i + 1] == 0) + { + error_invalid_switch (_T(' ')); + return 1; + } + continue; + } + + if (_totupper (param[i]) == _T('W')) + { + /* Warranty notice */ + /* JPP 07/08/1998 removed extra printf calls */ + ConOutPuts (_T("\n This program is distributed in the hope that it will be useful,\n" + " but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + " GNU General Public License for more details.")); + } + else if (_totupper (param[i]) == _T('R')) + { + /* Redistribution notice */ + /* JPP 07/08/1998 removed extra printf calls */ + ConOutPuts (_T("\n This program is free software; you can redistribute it and/or modify\n" + " it under the terms of the GNU General Public License as published by\n" + " the Free Software Foundation; either version 2 of the License, or\n" + " (at your option) any later version.")); + } + else if (_totupper (param[i]) == _T('C')) + { + /* Developer listing */ + /* JPP 07/08/1998 removed extra printf calls; rearranged names */ + ConOutPuts (_T("\ndeveloped by:\n" + " Tim Norman Matt Rains\n" + " Evan Jeffrey Steffen Kaiser\n" + " Svante Frey Oliver Mueller\n" + " Aaron Kaufman Marc Desrochers\n" + " Rob Lake John P Price\n" + " Hans B Pufal\n" + "\nconverted to Win32 by:\n" + " Eric Kohl\n")); + } + else + { + error_invalid_switch ((TCHAR)_totupper (param[i])); + return 1; + } + } + } + + ConOutPuts (_T("\nSend bug reports to .\n" +/* + "Updates are available at ftp://www.sid-dis.com/..." +*/ + )); + return 0; +} + +#endif diff --git a/reactos/apps/utils/cmd/verify.c b/reactos/apps/utils/cmd/verify.c new file mode 100644 index 00000000000..e3b1f08a8b7 --- /dev/null +++ b/reactos/apps/utils/cmd/verify.c @@ -0,0 +1,59 @@ +/* + * VERIFY.C - verify internal command. + * + * + * History: + * + * 31 Jul 1998 (John P Price) + * started. + * + * 18-Jan-1999 (Eric Kohl ) + * VERIFY is just a dummy under Win32; it only exists + * for compatibility!!! + * + * 20-Jan-1999 (Eric Kohl ) + * Unicode and redirection ready! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_VERIFY + +#include +#include +#include + +#include "cmd.h" + + +/* global verify flag */ +static BOOL bVerify = FALSE; + + +INT cmd_verify (LPTSTR cmd, LPTSTR param) +{ + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("This command is just a dummy!!\n" + "Sets whether to verify that your files are written correctly to a\n" + "disk.\n\n" + "VERIFY [ON | OFF]\n\n" + "Type VERIFY without a parameter to display the current VERIFY setting.")); + return 0; + } + + if (!*param) + ConOutPrintf (_T("VERIFY is %s.\n"), bVerify ? D_ON : D_OFF); + else if (_tcsicmp (param, D_OFF) == 0) + bVerify = FALSE; + else if (_tcsicmp (param, D_ON) == 0) + bVerify = TRUE; + else + ConOutPuts (_T("Must specify ON or OFF.")); + + return 0; +} + +#endif diff --git a/reactos/apps/utils/cmd/vol.c b/reactos/apps/utils/cmd/vol.c new file mode 100644 index 00000000000..13bd0e1e712 --- /dev/null +++ b/reactos/apps/utils/cmd/vol.c @@ -0,0 +1,101 @@ +/* + * VOL.C - vol internal command. + * + * + * History: + * + * 03-Dec-1998 (Eric Kohl ) + * Replaced DOS calls by Win32 calls. + * + * 08-Dec-1998 (Eric Kohl ) + * Added help text ("/?"). + * + * 07-Jan-1999 (Eric Kohl ) + * Cleanup. + * + * 18-Jan-1999 (Eric Kohl ) + * Unicode ready! + * + * 20-Jan-1999 (Eric Kohl ) + * Redirection ready! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_VOL + +#include +#include +#include + +#include "cmd.h" + + +static VOID +PrintVolumeHeader (LPTSTR pszRootPath) +{ + TCHAR szVolName[80]; + DWORD dwSerialNr; + + /* get the volume information of the drive */ + GetVolumeInformation (pszRootPath, szVolName, 80, &dwSerialNr, + NULL, NULL, NULL, 0); + + /* print drive info */ + ConOutPrintf (_T(" Volume in drive %c:"), pszRootPath[0]); + + if (szVolName[0] != '\0') + ConOutPrintf (_T(" is %s\n"), szVolName); + else + ConOutPrintf (_T(" has no label\n")); + + /* print the volume serial number */ + ConOutPrintf (_T(" Volume Serial Number is %04X-%04X\n"), + HIWORD(dwSerialNr), LOWORD(dwSerialNr)); +} + + +INT cmd_vol (LPTSTR cmd, LPTSTR param) +{ + TCHAR szRootPath[] = _T("A:\\"); + TCHAR szPath[MAX_PATH]; + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Displays the disk volume label and serial number, if they exist.\n\n" + "VOL [drive:]")); + return 0; + } + + if (param[0] == _T('\0')) + { + GetCurrentDirectory (MAX_PATH, szPath); + szRootPath[0] = szPath[0]; + } + else + { + _tcsupr (param); + if (param[1] == _T(':')) + szRootPath[0] = param[0]; + else + { + error_invalid_drive (); + return 1; + } + } + + if (!IsValidPathName (szRootPath)) + { + error_invalid_drive (); + return 1; + } + + /* print the header */ + PrintVolumeHeader (szRootPath); + + return 0; +} + +#endif diff --git a/reactos/apps/utils/cmd/where.c b/reactos/apps/utils/cmd/where.c new file mode 100644 index 00000000000..1ea1625f77d --- /dev/null +++ b/reactos/apps/utils/cmd/where.c @@ -0,0 +1,161 @@ +/* + * WHERE.C - file serch functions. + * + * + * History: + * + * 07/15/95 (Tim Norman) + * started. + * + * 08/08/95 (Matt Rains) + * i have cleaned up the source code. changes now bring this source into + * guidelines for recommended programming practice. + * + * 12/12/95 (Steffan Kaiser & Tim Norman) + * added some patches to fix some things and make more efficient + * + * 1/6/96 (Tim Norman) + * fixed a stupid pointer mistake... Thanks to everyone who noticed it! + * + * 8/1/96 (Tim Norman) + * fixed a bug when getenv returns NULL + * + * 8/7/96 (Steffan Kaiser and Tim Norman) + * speed improvements and bug fixes + * + * 8/27/96 (Tim Norman) + * changed code to use pointers directly into PATH environment variable + * rather than making our own copy. This saves some memory, but requires + * we write our own function to copy pathnames out of the variable. + * + * 12/23/96 (Aaron Kaufman) + * Fixed a bug in get_paths() that did not point to the first PATH in the + * environment variable. + * + * 7/12/97 (Tim Norman) + * Apparently, Aaron's bugfix got lost, so I fixed it again. + * + * 16 July 1998 (John P. Price) + * Added stand alone code. + * + * 17 July 1998 (John P. Price) + * Rewrote find_which to use searchpath function + * + * 24-Jul-1998 (John P Price ) + * - fixed bug where didn't check all extensions when path was specified + * + * 27-Jul-1998 (John P Price ) + * - added config.h include + * + * 30-Jul-1998 (John P Price ) + * - fixed so that it find_which returns NULL if filename is not executable + * (does not have .bat, .com, or .exe extention). Before command would + * to execute any file with any extension (opps!) + * + * 03-Dec_1998 (Eric Kohl ) + * Changed find_which(). + * + * 07-Dec_1998 (Eric Kohl ) + * Added ".CMD" extension. + * Replaced numeric constant by _NR_OF_EXTENSIONS. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include + +#include "cmd.h" + + +static LPTSTR ext[] = {".BAT", ".CMD", ".COM", ".EXE"}; +static INT nExtCount = sizeof(ext) / sizeof(LPTSTR); + + +/* searches for file using path info. */ + +BOOL find_which (LPCTSTR fname, LPTSTR fullbuffer) +{ + static TCHAR temp[MAX_PATH]; + LPTSTR fullname; + INT x; + + *fullbuffer = _T('\0'); + + /* if there an extension and it is in the last path component, then + * don't test all the extensions. */ + if (!(fullname = _tcsrchr (fname, _T('.'))) || + _tcschr (fullname + 1, _T('\\'))) + { +#ifdef _DEBUG + DebugPrintf ("No filename extension!\n"); +#endif + + for (x = 0; x < nExtCount; x++) + { + _tcscpy (temp, fname); + _tcscat (temp, ext[x]); +#ifdef _DEBUG + DebugPrintf ("Checking for %s\n", temp); +#endif + if (_tcschr (fname, _T('\\'))) + { + if (IsValidFileName (temp)) + { + _tcscpy (fullbuffer, temp); + return TRUE; + } + } + else + { + _searchenv (temp, _T("PATH"), fullbuffer); + if (*fullbuffer != '\0') + return TRUE; + } + } + } + else + { + /* there is an extension... don't test other extensions */ + /* make sure that the extention is one of the four */ +#ifdef _DEBUG + DebugPrintf ("No filename extension!\n"); +#endif + for (x = 0; x < nExtCount; x++) + { + if (!_tcsicmp (_tcsrchr (fname, _T('.')), ext[x])) + { + if (_tcschr (fname, _T('\\'))) + { + if (IsValidFileName (fname)) + { + _tcscpy (fullbuffer, fname); +#ifdef _DEBUG + DebugPrintf ("Found: %s\n", fullbuffer); +#endif + return TRUE; + } + } + else + { +#ifdef _DEBUG + DebugPrintf ("Checking for %s\n", fname); +#endif + _searchenv (fname, _T("PATH"), fullbuffer); + if (*fullbuffer != _T('\0')) + { +#ifdef _DEBUG + DebugPrintf ("Found: %s\n", fullbuffer); +#endif + return TRUE; + } + } + } + } + } + + return FALSE; +} diff --git a/reactos/apps/utils/cmd/wishlist.txt b/reactos/apps/utils/cmd/wishlist.txt new file mode 100644 index 00000000000..65c518d08f8 --- /dev/null +++ b/reactos/apps/utils/cmd/wishlist.txt @@ -0,0 +1,15 @@ + +Wishlist for ReactOS CMD +~~~~~~~~~~~~~~~~~~~~~~~~ + + - Exclusion wildcards: "del /r *.bak -abcd.bak" + Deletes ALL *.bak files EXCEPT abcd.bak. + + - Progress indikator on long file operations (copy/move). + Percentage at the right side of the filename. + + - [cd test directory] should change to the subdirectoy "test directory". + +More ideas? + + Eric Kohl \ No newline at end of file diff --git a/rosapps/cmd/alias.c b/rosapps/cmd/alias.c new file mode 100644 index 00000000000..ac0a9149d09 --- /dev/null +++ b/rosapps/cmd/alias.c @@ -0,0 +1,327 @@ +/* + * ALIAS.C - alias administration module. + * + * + * History: + * + * 02/02/1996 (Oliver Mueller) + * started. + * + * 02/03/1996 (Oliver Mueller) + * Added sorting algorithm and case sensitive substitution by using + * partstrupr(). + * + * 27 Jul 1998 John P. Price + * added config.h include + * added ifdef's to disable aliases + * + * 09-Dec-1998 (Eric Kohl ) + * Fixed crash when removing an alias in DeleteAlias(). + * Added help text ("/?"). + * + * 14-Jan-1998 (Eric Kohl ) + * Clean up and Unicode safe! + * + * 24-Jan-1998 (Eric Kohl ) + * Redirection safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef FEATURE_ALIASES + +#include +#include +#include +#include +#include + +#include "cmd.h" + + +typedef struct tagALIAS +{ + struct tagALIAS *next; + LPTSTR lpName; + LPTSTR lpSubst; + WORD wUsed; +} ALIAS, *LPALIAS; + + +static LPALIAS lpFirst = NULL; +static LPALIAS lpLast = NULL; +static WORD wUsed = 0; + + +/* module internal functions */ +/* strlwr only for first word in string */ +static VOID +partstrlwr (LPTSTR str) +{ + LPTSTR c = str; + while (*c && !_istspace (*c)) + { + *c = _totlower (*c); + c++; + } +} + + +static VOID +PrintAlias (VOID) +{ + LPALIAS ptr = lpFirst; + while (ptr) + { + ConOutPrintf (_T("%s=%s\n"), ptr->lpName, ptr->lpSubst); + ptr = ptr->next; + } +} + + +static VOID +DeleteAlias (LPTSTR pszName) +{ + LPALIAS ptr = lpFirst; + LPALIAS prev = NULL; + + while (ptr) + { + if (!_tcsicmp (ptr->lpName, pszName)) + { + if (prev) + prev->next = ptr->next; + else + lpFirst = ptr->next; + free (ptr->lpName); + free (ptr->lpSubst); + free (ptr); + return; + } + prev = ptr; + ptr = ptr->next; + } +} + + +static INT +AddAlias (LPTSTR name, LPTSTR subst) +{ + LPALIAS ptr = lpFirst; + LPALIAS prev, entry; + LPTSTR s; + + while (ptr) + { + if (!_tcsicmp (ptr->lpName, name)) + { + s = (LPTSTR)malloc ((_tcslen (subst) + 1)*sizeof(TCHAR)); + if (!s) + { + error_out_of_memory (); + return 1; + } + + free (ptr->lpSubst); + ptr->lpSubst = s; + _tcscpy (ptr->lpSubst, subst); + return 0; + } + ptr = ptr->next; + } + + ptr = (LPALIAS)malloc (sizeof (ALIAS)); + if (!ptr) + return 1; + + ptr->next = 0; + + ptr->lpName = (LPTSTR)malloc ((_tcslen (name) + 1)*sizeof(TCHAR)); + if (!ptr->lpName) + { + error_out_of_memory (); + free (ptr); + return 1; + } + _tcscpy (ptr->lpName, name); + + ptr->lpSubst = (LPTSTR)malloc ((_tcslen (subst) + 1)*sizeof(TCHAR)); + if (!ptr->lpSubst) + { + error_out_of_memory (); + free (ptr->lpName); + free (ptr); + return 1; + } + _tcscpy (ptr->lpSubst, subst); + + /* it's necessary for recursive substitution */ + partstrlwr (ptr->lpSubst); + + ptr->wUsed = 0; + + /* Alias table must be sorted! + * Here a little example: + * command line = "ls -c" + * If the entries are + * ls=dir + * ls -c=ls /w + * command line will be expanded to "dir -c" which is not correct. + * If the entries are sortet as + * ls -c=ls /w + * ls=dir + * it will be expanded to "dir /w" which is a valid DOS command. + */ + entry = lpFirst; + prev = 0; + while (entry) + { + if (_tcsicmp (ptr->lpName, entry->lpName) > 0) + { + if (prev) + { + prev->next = ptr; + ptr->next = entry; + } + else + { + ptr->next = entry; + lpFirst = ptr; + } + return 0; + } + prev = entry; + entry = entry->next; + } + + /* The new entry is the smallest (or the first) and must be + * added to the end of the list. + */ + if (!lpFirst) + lpFirst = ptr; + else + lpLast->next = ptr; + lpLast = ptr; + + return 0; +} + + +/* specified routines */ +VOID ExpandAlias (LPTSTR cmd, INT maxlen) +{ + unsigned n = 0, + m, + i, + len; + short d = 1; + LPALIAS ptr = lpFirst; + + wUsed++; + if (wUsed == 0) + { + while (ptr) + ptr->wUsed = 0; + ptr = lpFirst; + wUsed = 1; + } + + /* skipping white spaces */ + while (_istspace (cmd[n])) + n++; + + partstrlwr (&cmd[n]); + + if (!_tcsncmp (&cmd[n], _T("NOALIAS"), 7) && + (_istspace (cmd[n + 7]) || cmd[n + 7] == _T('\0'))) + { + memmove (cmd, &cmd[n + 7], (_tcslen (&cmd[n + 7]) + 1) * sizeof (TCHAR)); + return; + } + + /* substitution loop */ + while (d) + { + d = 0; + while (ptr) + { + len = _tcslen (ptr->lpName); + if (!_tcsncmp (&cmd[n], ptr->lpName, len) && + (_istspace (cmd[n + len]) || cmd[n + len] == _T('\0')) && + ptr->wUsed != wUsed) + { + m = _tcslen (ptr->lpSubst); + if ((int)(_tcslen (cmd) - len + m - n) > maxlen) + { + ConErrPrintf (_T("Command line too long after alias expansion!\n")); + /* the parser won't cause any problems with an empty line */ + cmd[0] = _T('\0'); + } + else + { + memmove (&cmd[m], &cmd[n + len], (_tcslen(&cmd[n + len]) + 1) * sizeof (TCHAR)); + for (i = 0; i < m; i++) + cmd[i] = ptr->lpSubst[i]; + ptr->wUsed = wUsed; + /* whitespaces are removed! */ + n = 0; + d = 1; + } + } + ptr = ptr->next; + } + } +} + + +INT cmd_alias (LPTSTR cmd, LPTSTR param) +{ + LPTSTR ptr; + INT n = 0; + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Sets, removes or shows aliases.\n" + "\n" + "ALIAS [alias=[command]]\n" + "\n" + " alias Name for an alias.\n" + " command Text to be substituted for an alias.\n" + "\n" +// "For example:\n" + "To list all aliases:\n" + " ALIAS\n\n" + "To set a new or replace an existing alias:\n" + " ALIAS da=dir a:\n\n" + "To remove an alias from the alias list:\n" + " ALIAS da=" +// "Type ALIAS without a parameter to display the alias list.\n" + )); + return 0; + } + + if (param[0] == _T('\0')) + { + PrintAlias (); + return 0; + } + + /* error if no '=' found */ + if ((ptr = _tcschr (param, _T('='))) == 0) + return -1; + + /* Split rest into name and substitute */ + *ptr++ = _T('\0'); + + partstrlwr (param); + + if (ptr[0] == _T('\0')) + DeleteAlias (param); + else + n = AddAlias (param, ptr); + + return n; +} +#endif diff --git a/rosapps/cmd/attrib.c b/rosapps/cmd/attrib.c new file mode 100644 index 00000000000..65a2c316731 --- /dev/null +++ b/rosapps/cmd/attrib.c @@ -0,0 +1,352 @@ +/* + * ATTRIB.C - attrib internal command. + * + * + * History: + * + * 04-Dec-1998 (Eric Kohl ) + * started + * + * 09-Dec-1998 (Eric Kohl ) + * implementation works, except recursion ("attrib /s"). + * + * 05-Jan-1999 (Eric Kohl ) + * major rewrite. + * fixed recursion ("attrib /s"). + * started directory support ("attrib /s /d"). + * updated help text. + * + * 14-Jan-1999 (Eric Kohl ) + * Unicode ready! + * + * 19-Jan-1999 (Eric Kohl ) + * Redirection ready! + * + * 21-Jan-1999 (Eric Kohl ) + * Added check for invalid filenames. + * + * 23-Jan-1999 (Eric Kohl ) + * Added handling of multiple filenames. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_ATTRIB + +#include +#include +#include + +#include "cmd.h" + + +static VOID +PrintAttribute (LPTSTR pszPath, LPTSTR pszFile, BOOL bRecurse) +{ + WIN32_FIND_DATA findData; + HANDLE hFind; + TCHAR szFullName[MAX_PATH]; + LPTSTR pszFileName; + + /* prepare full file name buffer */ + _tcscpy (szFullName, pszPath); + pszFileName = szFullName + _tcslen (szFullName); + + /* display all subdirectories */ + if (bRecurse) + { + /* append file name */ + _tcscpy (pszFileName, pszFile); + + hFind = FindFirstFile (szFullName, &findData); + if (hFind == INVALID_HANDLE_VALUE) + { + ErrorMessage (GetLastError (), pszFile); + return; + } + + do + { + if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + continue; + + if (!_tcscmp (findData.cFileName, _T(".")) || + !_tcscmp (findData.cFileName, _T(".."))) + continue; + + _tcscpy (pszFileName, findData.cFileName); + _tcscat (pszFileName, _T("\\")); + PrintAttribute (szFullName, pszFile, bRecurse); + } + while (FindNextFile (hFind, &findData)); + FindClose (hFind); + } + + /* append file name */ + _tcscpy (pszFileName, pszFile); + + /* display current directory */ + hFind = FindFirstFile (szFullName, &findData); + if (hFind == INVALID_HANDLE_VALUE) + { + ErrorMessage (GetLastError (), pszFile); + return; + } + + do + { + if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + continue; + + _tcscpy (pszFileName, findData.cFileName); + + ConOutPrintf (_T("%c %c%c%c %s\n"), + (findData.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) ? _T('A') : _T(' '), + (findData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) ? _T('S') : _T(' '), + (findData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? _T('H') : _T(' '), + (findData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? _T('R') : _T(' '), + szFullName); + } + while (FindNextFile (hFind, &findData)); + FindClose (hFind); +} + + +static VOID +ChangeAttribute (LPTSTR pszPath, LPTSTR pszFile, DWORD dwMask, + DWORD dwAttrib, BOOL bRecurse, BOOL bDirectories) +{ + WIN32_FIND_DATA findData; + HANDLE hFind; + DWORD dwAttribute; + TCHAR szFullName[MAX_PATH]; + LPTSTR pszFileName; + + /* prepare full file name buffer */ + _tcscpy (szFullName, pszPath); + pszFileName = szFullName + _tcslen (szFullName); + + /* change all subdirectories */ + if (bRecurse) + { + /* append file name */ + _tcscpy (pszFileName, _T("*.*")); + + hFind = FindFirstFile (szFullName, &findData); + if (hFind == INVALID_HANDLE_VALUE) + { + ErrorMessage (GetLastError (), pszFile); + return; + } + + do + { + if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if (!_tcscmp (findData.cFileName, _T(".")) || + !_tcscmp (findData.cFileName, _T(".."))) + continue; + + _tcscpy (pszFileName, findData.cFileName); + _tcscat (pszFileName, _T("\\")); + + ChangeAttribute (szFullName, pszFile, dwMask, + dwAttrib, bRecurse, bDirectories); + } + } + while (FindNextFile (hFind, &findData)); + FindClose (hFind); + } + + /* append file name */ + _tcscpy (pszFileName, pszFile); + + hFind = FindFirstFile (szFullName, &findData); + if (hFind == INVALID_HANDLE_VALUE) + { + ErrorMessage (GetLastError (), pszFile); + return; + } + + do + { + if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + continue; + + _tcscpy (pszFileName, findData.cFileName); + + dwAttribute = GetFileAttributes (szFullName); + + if (dwAttribute != 0xFFFFFFFF) + { + dwAttribute = (dwAttribute & ~dwMask) | dwAttrib; + SetFileAttributes (szFullName, dwAttribute); + } + } + while (FindNextFile (hFind, &findData)); + FindClose (hFind); +} + + +INT cmd_attrib (LPTSTR cmd, LPTSTR param) +{ + LPTSTR *arg; + INT argc, i; + TCHAR szPath[MAX_PATH]; + TCHAR szFileName [MAX_PATH]; + BOOL bRecurse = FALSE; + BOOL bDirectories = FALSE; + DWORD dwAttrib = 0; + DWORD dwMask = 0; + + /* initialize strings */ + szPath[0] = _T('\0'); + szFileName[0] = _T('\0'); + + /* print help */ + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Displays or changes file attributes.\n\n" + "ATTRIB [+R | -R] [+A | -A] [+S | -S] [+H | -H] file ...\n" + " [/S [/D]]\n\n" + " + Sets an attribute\n" + " - Clears an attribute\n" + " R Read-only file attribute\n" + " A Archive file attribute\n" + " S System file attribute\n" + " H Hidden file attribute\n" + " /S Processes matching files in the current directory\n" + " and all subdirectories\n" + " /D Processes direcories as well\n\n" + "Type ATTRIB without a parameter to display the attributes of all files.")); + return 0; + } + + /* build parameter array */ + arg = split (param, &argc); + + /* check for options */ + for (i = 0; i < argc; i++) + { + if (_tcsicmp (arg[i], _T("/s")) == 0) + bRecurse = TRUE; + else if (_tcsicmp (arg[i], _T("/d")) == 0) + bDirectories = TRUE; + } + + /* create attributes and mask */ + for (i = 0; i < argc; i++) + { + if (*arg[i] == _T('+')) + { + if (_tcslen (arg[i]) != 2) + { + error_invalid_parameter_format (arg[i]); + freep (arg); + return -1; + } + + switch ((TCHAR)_totupper (arg[i][1])) + { + case _T('A'): + dwMask |= FILE_ATTRIBUTE_ARCHIVE; + dwAttrib |= FILE_ATTRIBUTE_ARCHIVE; + break; + + case _T('H'): + dwMask |= FILE_ATTRIBUTE_HIDDEN; + dwAttrib |= FILE_ATTRIBUTE_HIDDEN; + break; + + case _T('R'): + dwMask |= FILE_ATTRIBUTE_READONLY; + dwAttrib |= FILE_ATTRIBUTE_READONLY; + break; + + case _T('S'): + dwMask |= FILE_ATTRIBUTE_SYSTEM; + dwAttrib |= FILE_ATTRIBUTE_SYSTEM; + break; + + default: + error_invalid_parameter_format (arg[i]); + freep (arg); + return -1; + } + } + else if (*arg[i] == _T('-')) + { + if (_tcslen (arg[i]) != 2) + { + error_invalid_parameter_format (arg[i]); + freep (arg); + return -1; + } + + switch ((TCHAR)_totupper (arg[i][1])) + { + case _T('A'): + dwMask |= FILE_ATTRIBUTE_ARCHIVE; + dwAttrib &= ~FILE_ATTRIBUTE_ARCHIVE; + break; + + case _T('H'): + dwMask |= FILE_ATTRIBUTE_HIDDEN; + dwAttrib &= ~FILE_ATTRIBUTE_HIDDEN; + break; + + case _T('R'): + dwMask |= FILE_ATTRIBUTE_READONLY; + dwAttrib &= ~FILE_ATTRIBUTE_READONLY; + break; + + case _T('S'): + dwMask |= FILE_ATTRIBUTE_SYSTEM; + dwAttrib &= ~FILE_ATTRIBUTE_SYSTEM; + break; + + default: + error_invalid_parameter_format (arg[i]); + freep (arg); + return -1; + } + } + } + + if (argc == 0) + { + GetCurrentDirectory (MAX_PATH, szPath); + _tcscat (szPath, _T("\\")); + _tcscpy (szFileName, _T("*.*")); + PrintAttribute (szPath, szFileName, bRecurse); + } + else + { + /* get full file name */ + for (i = 0; i < argc; i++) + { + if ((*arg[i] != _T('+')) && (*arg[i] != _T('-')) && (*arg[i] != _T('/'))) + { + LPTSTR p; + GetFullPathName (arg[i], MAX_PATH, szPath, NULL); + p = _tcsrchr (szPath, _T('\\')) + 1; + _tcscpy (szFileName, p); + *p = _T('\0'); + + if (dwMask == 0) + PrintAttribute (szPath, szFileName, bRecurse); + else + ChangeAttribute (szPath, szFileName, dwMask, + dwAttrib, bRecurse, bDirectories); + } + } + } + + freep (arg); + + return 0; +} + +#endif /* INCLUDE_CMD_ATTRIB */ diff --git a/rosapps/cmd/batch.c b/rosapps/cmd/batch.c new file mode 100644 index 00000000000..b1ea5be8903 --- /dev/null +++ b/rosapps/cmd/batch.c @@ -0,0 +1,462 @@ +/* + * BATCH.C - batch file processor for CMD.EXE. + * + * + * History: + * + * ??/??/?? (Evan Jeffrey) + * started. + * + * 15 Jul 1995 (Tim Norman) + * modes and bugfixes. + * + * 08 Aug 1995 (Matt Rains) + * i have cleaned up the source code. changes now bring this + * source into guidelines for recommended programming practice. + * + * i have added some constants to help making changes easier. + * + * 29 Jan 1996 (Steffan Kaiser) + * made a few cosmetic changes + * + * 05 Feb 1996 (Tim Norman) + * changed to comply with new first/rest calling scheme + * + * 14 Jun 1997 (Steffen Kaiser) + * bug fixes. added error level expansion %?. ctrl-break handling + * + * 16 Jul 1998 (Hans B Pufal) + * Totally reorganised in conjunction with COMMAND.C (cf) to + * implement proper BATCH file nesting and other improvements. + * + * 16 Jul 1998 (John P Price ) + * Seperated commands into individual files. + * + * 19 Jul 1998 (Hans B Pufal) [HBP_001] + * Preserve state of echo flag across batch calls. + * + * 19 Jul 1998 (Hans B Pufal) [HBP_002] + * Implementation of FOR command + * + * 20-Jul-1998 (John P Price ) + * added error checking after malloc calls + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 02-Aug-1998 (Hans B Pufal) [HBP_003] + * Fixed bug in ECHO flag restoration at exit from batch file + * + * 26-Jan-1999 (Eric Kohl ) + * Replaced CRT io functions by Win32 io functions. + * Unicode safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include +#include + +#include "cmd.h" +#include "batch.h" + + +/* The stack of current batch contexts. + * NULL when no batch is active + */ +LPBATCH_CONTEXT bc = NULL; + +BOOL bEcho = TRUE; /* The echo flag */ + + + +/* Buffer for reading Batch file lines */ +TCHAR textline[BATCH_BUFFSIZE]; + + +/* + * Returns a pointer to the n'th parameter of the current batch file. + * If no such parameter exists returns pointer to empty string. + * If no batch file is current, returns NULL + * + */ + +LPTSTR FindArg (INT n) +{ + LPTSTR pp; + +#ifdef _DEBUG + DebugPrintf ("FindArg: (%d)\n", n); +#endif + + if (bc == NULL) + return NULL; + + n += bc->shiftlevel; + pp = bc->params; + + /* Step up the strings till we reach the end */ + /* or the one we want */ + while (*pp && n--) + pp += _tcslen (pp) + 1; + + return pp; +} + + +/* HBP_002 { FOR command support */ +/* + * Batch_params builds a parameter list in newlay allocated memory. + * The parameters consist of null terminated strings with a final + * NULL character signalling the end of the parameters. + * +*/ + +LPTSTR BatchParams (LPTSTR s1, LPTSTR s2) +{ + LPTSTR dp = (LPTSTR)malloc ((_tcslen(s1) + _tcslen(s2) + 3) * sizeof (TCHAR)); + + /* JPP 20-Jul-1998 added error checking */ + if (dp == NULL) + { + error_out_of_memory(); + return NULL; + } + + if (s1 && *s1) + { + s1 = stpcpy (dp, s1); + *s1++ = _T('\0'); + } + else + s1 = dp; + + while (*s2) + { + if (_istspace (*s2) || _tcschr (_T(",;"), *s2)) + { + *s1++ = _T('\0'); + s2++; + while (*s2 && _tcschr (_T(" ,;"), *s2)) + s2++; + continue; + } + + if ((*s2 == _T('"')) || (*s2 == _T('\''))) + { + TCHAR st = *s2; + + do + *s1++ = *s2++; + while (*s2 && (*s2 != st)); + } + + *s1++ = *s2++; + } + + *s1++ = _T('\0'); + *s1 = _T('\0'); + + return dp; +} + +/* HBP_002 } */ + + +/* + * If a batch file is current, exits it, freeing the context block and + * chaining back to the previous one. + * + * If no new batch context is found, sets ECHO back ON. + * + * If the parameter is non-null or not empty, it is printed as an exit + * message + */ + +VOID ExitBatch (LPTSTR msg) +{ +#ifdef _DEBUG + DebugPrintf ("ExitBatch: (\'%s\')\n", msg); +#endif + + if (bc) + { + LPBATCH_CONTEXT t = bc; + + if (bc->hBatchFile) + { + CloseHandle (bc->hBatchFile); + bc->hBatchFile = INVALID_HANDLE_VALUE; + } + + if (bc->params) + free(bc->params); + +/* HBP_002 { FOR command support */ + + if (bc->forproto) + free(bc->forproto); + + if (bc->ffind) + free(bc->ffind); + +/* HBP_002 } */ + +/* HBP_003 { fix echo restore */ + /* Preserve echo state across batch calls */ + bEcho = bc->bEcho; + +/* HBP_003 fix echo restore } */ + + bc = bc->prev; + free(t); + } + +/* HBP_001 } */ + + if (msg && *msg) + ConOutPrintf ("%s\n", msg); +} + + +/* + * Start batch file execution + * + * The firstword parameter is the full filename of the batch file. + * + */ + +BOOL Batch (LPTSTR fullname, LPTSTR firstword, LPTSTR param) +{ + HANDLE hFile; + + hFile = CreateFile (fullname, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | + FILE_FLAG_SEQUENTIAL_SCAN, NULL); + +#ifdef _DEBUG + DebugPrintf ("Batch: (\'%s\', \'%s\', \'%s\') hFile = %x\n", + fullname, firstword, param, hFile); +#endif + + if (hFile == INVALID_HANDLE_VALUE) + { + ConErrPrintf (_T("Error opening batch file\n")); + return FALSE; + } + +/* HBP_002 { FOR command support */ + + /* Kill any and all FOR contexts */ + while (bc && bc->forvar) + ExitBatch (NULL); + +/* HBP_002 } */ + + if (bc == NULL) + { + /* No curent batch file, create a new context */ + LPBATCH_CONTEXT n = (LPBATCH_CONTEXT)malloc (sizeof(BATCH_CONTEXT)); + + if (n == NULL) + { + /* JPP 20-Jul-1998 added error checking */ + error_out_of_memory (); + return FALSE; + } + + n->prev = bc; + bc = n; + } + else if (bc->hBatchFile != INVALID_HANDLE_VALUE) + { + /* Then we are transferring to another batch */ + CloseHandle (bc->hBatchFile); + bc->hBatchFile = INVALID_HANDLE_VALUE; + free (bc->params); + } + + bc->hBatchFile = hFile; + bc->bEcho = bEcho; /* Preserve echo across batch calls [HBP_001] */ + bc->shiftlevel = 0; + + /* HBP_002 { FOR command support */ + bc->ffind = NULL; + bc->forvar = _T('\0'); + bc->forproto = NULL; + bc->params = BatchParams (firstword, param); + /* HBP_002 } */ + + return TRUE; +} + + +/* + * Read and return the next executable line form the current batch file + * + * If no batch file is current or no further executable lines are found + * return NULL. + * + * Here we also look out for FOR bcontext structures which trigger the + * FOR expansion code. + * + * Set eflag to 0 if line is not to be echoed else 1 + */ + +LPTSTR ReadBatchLine (LPBOOL bLocalEcho) +{ + HANDLE hFind = INVALID_HANDLE_VALUE; + LPTSTR first; + LPTSTR ip; + + /* No batch */ + if (bc == NULL) + return NULL; + +#ifdef _DEBUG + DebugPrintf ("ReadBatchLine ()\n"); +#endif + + while (1) + { + /* User halt */ + if (CheckCtrlBreak (BREAK_BATCHFILE)) + { + while (bc) + ExitBatch (NULL); + return NULL; + } + + /* HBP_002 { FOR command support */ + /* No batch */ + if (bc == NULL) + return NULL; + + /* If its a FOR context... */ + if (bc->forvar) + { + LPTSTR sp = bc->forproto; /* pointer to prototype command */ + LPTSTR dp = textline; /* Place to expand protoype */ + LPTSTR fv = FindArg (0); /* Next list element */ + + /* End of list so... */ + if ((fv == NULL) || (*fv == _T('\0'))) + { + /* just exit this context */ + ExitBatch (NULL); + continue; + } + + if (_tcscspn (fv, _T("?*")) == _tcslen (fv)) + { + /* element is wild file */ + bc->shiftlevel++; /* No use it and shift list */ + } + else + { + /* Wild file spec, find first (or next) file name */ + if (bc->ffind) + { + /* First already done so do next */ + fv = FindNextFile (hFind, bc->ffind) ? bc->ffind->cFileName : NULL; + } + else + { + /* For first find, allocate a find first block */ + if ((bc->ffind = (LPWIN32_FIND_DATA)malloc (sizeof (WIN32_FIND_DATA))) == NULL) + { + error_out_of_memory(); /* JPP 20-Jul-1998 added error checking */ + return NULL; + } + + hFind = FindFirstFile (fv, bc->ffind); + fv = !(hFind==INVALID_HANDLE_VALUE) ? bc->ffind->cFileName : NULL; + } + + if (fv == NULL) + { + /* Null indicates no more files.. */ + free (bc->ffind); /* free the buffer */ + bc->ffind = NULL; + bc->shiftlevel++; /* On to next list element */ + continue; + } + } + + /* At this point, fv points to parameter string */ + while (*sp) + { + if ((*sp == _T('%')) && (*(sp + 1) == bc->forvar)) + { + /* replace % var */ + dp = stpcpy (dp, fv); + sp += 2; + } + else + { + /* Else just copy */ + *dp++ = *sp++; + } + } + + *dp = _T('\0'); + + *bLocalEcho = bEcho; + + return textline; + } + + /* HBP_002 } */ + + if (!FileGetString (bc->hBatchFile, textline, sizeof (textline))) + { +#ifdef _DEBUG + DebugPrintf (_T("ReadBatchLine(): Reached EOF!\n")); +#endif + /* End of file.... */ + ExitBatch (NULL); + + if (bc == NULL) + return NULL; + + continue; + } + +#ifdef _DEBUG + DebugPrintf (_T("ReadBatchLine(): textline: \'%s\'\n"), textline); +#endif + + /* Strip leading spaces and trailing space/control chars */ + for (first = textline; _istspace (*first); first++) + ; + + for (ip = first + _tcslen (first) - 1; _istspace (*ip) || _istcntrl (*ip); ip--) + ; + + *++ip = _T('\0'); + + /* ignore labels and empty lines */ + if (*first == _T(':') || *first == 0) + continue; + + if (*first == _T('@')) + { + /* don't echo this line */ + do + first++; + while (_istspace (*first)); + + *bLocalEcho = 0; + } + else + *bLocalEcho = bEcho; + + break; + } + + return first; +} diff --git a/rosapps/cmd/batch.h b/rosapps/cmd/batch.h new file mode 100644 index 00000000000..11324e38c61 --- /dev/null +++ b/rosapps/cmd/batch.h @@ -0,0 +1,39 @@ +/* + * BATCH.H - A structure to preserve the context of a batch file + * + * + */ + + +typedef struct tagBATCHCONTEXT +{ + struct tagBATCHCONTEXT *prev; + LPWIN32_FIND_DATA ffind; + HANDLE hBatchFile; + LPTSTR forproto; + LPTSTR params; + INT shiftlevel; + BOOL bEcho; /* Preserve echo flag across batch calls [HBP_001] */ + TCHAR forvar; +} BATCH_CONTEXT, *LPBATCH_CONTEXT; + +/* HBP_002 } */ + + +/* The stack of current batch contexts. + * NULL when no batch is active + */ +extern LPBATCH_CONTEXT bc; + +extern BOOL bEcho; /* The echo flag */ + +#define BATCH_BUFFSIZE 2048 + +extern TCHAR textline[BATCH_BUFFSIZE]; /* Buffer for reading Batch file lines */ + + +LPTSTR FindArg (INT); +LPTSTR BatchParams (LPTSTR, LPTSTR); +VOID ExitBatch (LPTSTR); +BOOL Batch (LPTSTR, LPTSTR, LPTSTR); +LPTSTR ReadBatchLine (LPBOOL); diff --git a/rosapps/cmd/beep.c b/rosapps/cmd/beep.c new file mode 100644 index 00000000000..9f9834c5775 --- /dev/null +++ b/rosapps/cmd/beep.c @@ -0,0 +1,56 @@ +/* + * BEEP.C - beep internal command. + * + * + * History: + * + * 16 Jul 1998 (Hans B Pufal) + * started. + * + * 16 Jul 1998 (John P Price) + * Separated commands into individual files. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 14-Jan-1999 (Eric Kohl ) + * Added help text ("beep /?"). + * Unicode ready! + * + * 20-Jan-1999 (Eric Kohl ) + * Redirection ready! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_BEEP + +#include +#include +#include + +#include "cmd.h" +#include "batch.h" + + +INT cmd_beep (LPTSTR cmd, LPTSTR param) +{ + if (_tcsncmp (param, _T("/?"), 2) == 0) + { + ConOutPuts (_T("Beep the speaker.\n\nBEEP")); + return 0; + } + +#if 0 + /* check if run in batch mode */ + if (bc == NULL) + return 1; +#endif + + MessageBeep (-1); + + return 0; +} +#endif diff --git a/rosapps/cmd/bugs.txt b/rosapps/cmd/bugs.txt new file mode 100644 index 00000000000..2cfa275c5a0 --- /dev/null +++ b/rosapps/cmd/bugs.txt @@ -0,0 +1,15 @@ + **** Please report bugs to ekohl@abo.rhein-zeitung.de! **** + +Known bugs in CMD version 0.0.4 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +o let set work with or without the '=' sign. People like it that way. + (I don't know, if I should really fix this?) + +o command.com ignores control-c and control-break, which makes it difficult + to quit typing a long file, among other things + +o "alias v = dir" doesn't work because of the spaces. + + + **** Please report bugs to ekohl@abo.rhein-zeitung.de! **** diff --git a/rosapps/cmd/call.c b/rosapps/cmd/call.c new file mode 100644 index 00000000000..db5dd630217 --- /dev/null +++ b/rosapps/cmd/call.c @@ -0,0 +1,93 @@ +/* + * CALL.C - call internal batch command. + * + * + * History: + * + * 16 Jul 1998 (Hans B Pufal) + * started. + * + * 16 Jul 1998 (John P Price) + * Seperated commands into individual files. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 04-Aug-1998 (Hans B Pufal) + * added lines to initialize for pointers (HBP004) This fixed the + * lock-up that happened sometimes when calling a batch file from + * another batch file. + * + * 07-Jan-1999 (Eric Kohl ) + * Added help text ("call /?") and cleaned up. + * + * 20-Jan-1999 (Eric Kohl ) + * Unicode and redirection safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include +#include + +#include "cmd.h" +#include "batch.h" + + +/* + * Perform CALL command. + * + * Allocate a new batch context and add it to the current chain. + * Call parsecommandline passing in our param string + * If No batch file was opened then remove our newly allocted + * context block. + */ + +INT cmd_call (LPTSTR cmd, LPTSTR param) +{ + LPBATCH_CONTEXT n = NULL; + +#ifdef _DEBUG + DebugPrintf ("cmd_call: (\'%s\',\'%s\')\n", cmd, param); +#endif + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Calls one batch program from another.\n\n" + "CALL [drive:][path]filename [batch-parameter]\n\n" + " batch-parameter Specifies any command-line information required by the\n" + " batch program.")); + return 0; + } + + n = (LPBATCH_CONTEXT)malloc (sizeof (BATCH_CONTEXT)); + + if (n == NULL) + { + error_out_of_memory (); + return 1; + } + + n->prev = bc; + bc = n; + + bc->hBatchFile = INVALID_HANDLE_VALUE; + bc->params = NULL; + bc->shiftlevel = 0; + bc->forvar = 0; /* HBP004 */ + bc->forproto = NULL; /* HBP004 */ + + ParseCommandLine (param); + + /* Wasn't a batch file so remove conext */ + if (bc->hBatchFile == INVALID_HANDLE_VALUE) + { + bc = bc->prev; + free (n); + } + + return 0; +} diff --git a/rosapps/cmd/chcp.c b/rosapps/cmd/chcp.c new file mode 100644 index 00000000000..6831e576906 --- /dev/null +++ b/rosapps/cmd/chcp.c @@ -0,0 +1,90 @@ +/* + * CHCP.C - chcp internal command. + * + * + * History: + * + * 23-Dec-1998 (Eric Kohl ) + * Started. + * + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_CHCP + +#include +#include +#include + +#include "cmd.h" +#include "chcp.h" + + +INT CommandChcp (LPTSTR cmd, LPTSTR param) +{ + LPTSTR *arg; + INT args; + + /* print help */ + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Displays or sets the active code page number.\n\n" + "CHCP [nnn]\n\n" + " nnn Specifies the active code page number.\n\n" + "Type CHCP without a parameter to display the active code page number.")); + return 0; + } + + /* get parameters */ + arg = split (param, &args); + + if (args == 0) + { + /* display active code page number */ + ConOutPrintf ("Active code page: %u\n", GetConsoleCP ()); + } + else if (args >= 2) + { + /* too many parameters */ + ConErrPrintf ("Invalid parameter format - %s\n", param); + } + else + { + /* set active code page number */ + + UINT uOldCodePage; + UINT uNewCodePage; + + /* save old code page */ + uOldCodePage = GetConsoleCP (); + + uNewCodePage = (UINT)_ttoi (arg[0]); + + if (uNewCodePage == 0) + { + ConErrPrintf ("Parameter format incorrect - %s\n", arg[0]); + + } + else + { + if (!SetConsoleCP (uNewCodePage)) + { + ConErrPrintf ("Invalid code page\n"); + } + else + { + SetConsoleOutputCP (uNewCodePage); + InitLocale (); + } + } + } + + freep (arg); + + return 0; +} + +#endif /* INCLUDE_CMD_CHCP */ \ No newline at end of file diff --git a/rosapps/cmd/chcp.h b/rosapps/cmd/chcp.h new file mode 100644 index 00000000000..11ff568dc59 --- /dev/null +++ b/rosapps/cmd/chcp.h @@ -0,0 +1,8 @@ +/* prototypes for CHCP.C */ + + +#ifdef INCLUDE_CMD_CHCP + +INT CommandChcp (LPTSTR, LPTSTR); + +#endif \ No newline at end of file diff --git a/rosapps/cmd/cls.c b/rosapps/cmd/cls.c new file mode 100644 index 00000000000..2e27fcc0246 --- /dev/null +++ b/rosapps/cmd/cls.c @@ -0,0 +1,67 @@ +/* + * CLS.C - clear screen internal command. + * + * + * History: + * + * 07/27/1998 (John P. Price) + * started. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 04-Dec-1998 (Eric Kohl ) + * Changed to Win32 console app. + * + * 08-Dec-1998 (Eric Kohl ) + * Added help text ("/?"). + * + * 14-Jan-1998 (Eric Kohl ) + * Unicode ready! + * + * 20-Jan-1998 (Eric Kohl ) + * Redirection ready! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_CLS + +#include +#include +#include + +#include "cmd.h" + + +INT cmd_cls (LPTSTR cmd, LPTSTR param) +{ + DWORD dwWritten; + CONSOLE_SCREEN_BUFFER_INFO csbi; + COORD coPos; + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Clears the screen.\n\nCLS")); + return 0; + } + + GetConsoleScreenBufferInfo (hOut, &csbi); + + coPos.X = 0; + coPos.Y = 0; + FillConsoleOutputAttribute (hOut, wColor, + (csbi.dwSize.X)*(csbi.dwSize.Y), + coPos, &dwWritten); + FillConsoleOutputCharacter (hOut, _T(' '), + (csbi.dwSize.X)*(csbi.dwSize.Y), + coPos, &dwWritten); + SetConsoleCursorPosition (hOut, coPos); + + bIgnoreEcho = TRUE; + + return 0; +} +#endif diff --git a/rosapps/cmd/cmd.c b/rosapps/cmd/cmd.c index 22211f73308..2841c33dec0 100644 --- a/rosapps/cmd/cmd.c +++ b/rosapps/cmd/cmd.c @@ -1,158 +1,980 @@ -#include +/* + * CMD.C - command-line interface. + * + * + * History: + * + * 17 Jun 1994 (Tim Norman) + * started. + * + * 08 Aug 1995 (Matt Rains) + * I have cleaned up the source code. changes now bring this source + * into guidelines for recommended programming practice. + * + * A added the the standard FreeDOS GNU licence test to the + * initialize() function. + * + * Started to replace puts() with printf(). this will help + * standardize output. please follow my lead. + * + * I have added some constants to help making changes easier. + * + * 15 Dec 1995 (Tim Norman) + * major rewrite of the code to make it more efficient and add + * redirection support (finally!) + * + * 06 Jan 1996 (Tim Norman) + * finished adding redirection support! Changed to use our own + * exec code (MUCH thanks to Svante Frey!!) + * + * 29 Jan 1996 (Tim Norman) + * added support for CHDIR, RMDIR, MKDIR, and ERASE, as per + * suggestion of Steffan Kaiser + * + * changed "file not found" error message to "bad command or + * filename" thanks to Dustin Norman for noticing that confusing + * message! + * + * changed the format to call internal commands (again) so that if + * they want to split their commands, they can do it themselves + * (none of the internal functions so far need that much power, anyway) + * + * 27 Aug 1996 (Tim Norman) + * added in support for Oliver Mueller's ALIAS command + * + * 14 Jun 1997 (Steffan Kaiser) + * added ctrl-break handling and error level + * + * 16 Jun 1998 (Rob Lake) + * Runs command.com if /P is specified in command line. Command.com + * also stays permanent. If /C is in the command line, starts the + * program next in the line. + * + * 21 Jun 1998 (Rob Lake) + * Fixed up /C so that arguments for the program + * + * 08-Jul-1998 (John P. Price) + * Now sets COMSPEC environment variable + * misc clean up and optimization + * added date and time commands + * changed to using spawnl instead of exec. exec does not copy the + * environment to the child process! + * + * 14 Jul 1998 (Hans B Pufal) + * Reorganised source to be more efficient and to more closely + * follow MS-DOS conventions. (eg %..% environment variable + * replacement works form command line as well as batch file. + * + * New organisation also properly support nested batch files. + * + * New command table structure is half way towards providing a + * system in which COMMAND will find out what internal commands + * are loaded + * + * 24 Jul 1998 (Hans B Pufal) [HBP_003] + * Fixed return value when called with /C option + * + * 27 Jul 1998 John P. Price + * added config.h include + * + * 28 Jul 1998 John P. Price + * added showcmds function to show commands and options available + * + * 07-Aug-1998 (John P Price ) + * Fixed carrage return output to better match MSDOS with echo + * on or off. (marked with "JPP 19980708") + * + * 07-Dec-1998 (Eric Kohl ) + * First ReactOS release. + * Extended length of commandline buffers to 512. + * + * 13-Dec-1998 (Eric Kohl ) + * Added COMSPEC environment variable. + * Added "/t" support (color) on cmd command line. + * + * 07-Jan-1999 (Eric Kohl ) + * Added help text ("cmd /?"). + * + * 25-Jan-1999 (Eric Kohl ) + * Unicode and redirection safe! + * Fixed redirections and piping. + * Piping is based on temporary files, but basic support + * for anonymous pipes already exists. + * + * 27-Jan-1999 (Eric Kohl ) + * Replaced spawnl() by CreateProcess(). + */ + +// #define WIN32_LEAN_AND_MEAN + +#include "config.h" + #include +// #include +#include +#include -HANDLE stdin; -HANDLE stdout; +#include "cmd.h" +#include "batch.h" -void Console_puts(char* str) +#define CMDLINE_LENGTH 512 + + +BOOL bExit = FALSE; /* indicates EXIT was typed */ +BOOL bCanExit = TRUE; /* indicates if this shell is exitable */ +BOOL bCtrlBreak = FALSE; /* Ctrl-Break or Ctrl-C hit */ +BOOL bIgnoreEcho = FALSE; /* Ignore 'newline' before 'cls' */ +INT errorlevel = 0; /* Errorlevel of last launched external program */ +OSVERSIONINFO osvi; +HANDLE hIn; +HANDLE hOut; + +#ifdef INCLUDE_CMD_COLOR +WORD wColor = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN; /* current color */ +WORD wDefColor = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN; /* default color */ +#endif + + +extern COMMAND cmds[]; /* The internal command table */ + + +/* + * is character a delimeter when used on first word? + * + */ + +static BOOL IsDelimiter (TCHAR c) { - ULONG nchar; - - WriteConsole(stdout, - str, - strlen(str), - &nchar, - NULL); + return (c == _T('/') || c == _T('=') || c == _T('\0') || _istspace (c)); } -void Console_printf(char* fmt, ...) -{ - char buffer[255]; - va_list vargs; - va_start(vargs,fmt); - vsprintf(buffer,fmt,vargs); - Console_puts(buffer); - va_end(vargs); +/* + * This command (in first) was not found in the command table + * + * first - first word on command line + * rest - rest of command line + */ + +static VOID +Execute (LPTSTR first, LPTSTR rest) +{ + TCHAR szFullName[MAX_PATH]; + + /* check for a drive change */ + if (!_tcscmp (first + 1, _T(":")) && _istalpha (*first)) + { + TCHAR szPath[MAX_PATH]; + + _tcscpy (szPath, _T("A:")); + szPath[0] = _totupper (*first); + SetCurrentDirectory (szPath); + GetCurrentDirectory (MAX_PATH, szPath); + if (szPath[0] != (TCHAR)_totupper (*first)) + ConErrPuts (INVALIDDRIVE); + + return; + } + + /* get the PATH environment variable and parse it */ + /* search the PATH environment variable for the binary */ + find_which (first, szFullName); + + if (szFullName[0] == _T('\0')) + { + error_bad_command (); + return; + } + + /* check if this is a .BAT or .CMD file */ + if (!_tcsicmp (_tcsrchr (szFullName, _T('.')), _T(".bat")) || + !_tcsicmp (_tcsrchr (szFullName, _T('.')), _T(".cmd"))) + { +#ifdef _DEBUG + DebugPrintf ("[BATCH: %s %s]\n", szFullName, rest); +#endif + Batch (szFullName, first, rest); + } + else + { + /* exec the program */ + TCHAR szFullCmdLine [1024]; + PROCESS_INFORMATION prci; + STARTUPINFO stui; + DWORD dwError = 0; + +#ifdef _DEBUG + DebugPrintf ("[EXEC: %s %s]\n", szFullName, rest); +#endif + /* build command line for CreateProcess() */ + _tcscpy (szFullCmdLine, szFullName); + _tcscat (szFullCmdLine, " "); + _tcscat (szFullCmdLine, rest); + + /* fill startup info */ + memset (&stui, 0, sizeof (STARTUPINFO)); + stui.cb = sizeof (STARTUPINFO); + stui.dwFlags = STARTF_USESHOWWINDOW; + stui.wShowWindow = SW_SHOWDEFAULT; + + if (CreateProcess (NULL, szFullCmdLine, NULL, NULL, FALSE, + 0, NULL, NULL, &stui, &prci)) + { + WaitForSingleObject (prci.hProcess, INFINITE); + GetExitCodeProcess (prci.hProcess, &errorlevel); + CloseHandle (prci.hThread); + CloseHandle (prci.hProcess); + } + else + { + ErrorMessage (GetLastError (), + "Error executing CreateProcess()!!\n"); + } + } } -void Console_getline(PCH Prompt, PCH Output, DWORD OutputLength) + +/* + * look through the internal commands and determine whether or not this + * command is one of them. If it is, call the command. If not, call + * execute to run it as an external program. + * + * line - the command line of the program to run + * + */ + +static VOID +DoCommand (LPTSTR line) { - char ch; - DWORD nbytes; + TCHAR com[MAX_PATH]; /* the first word in the command */ + LPTSTR cp = com; + LPTSTR cstart; + LPTSTR rest = line; /* pointer to the rest of the command line */ + INT cl; + LPCOMMAND cmdptr; - Console_puts(Prompt); + /* Skip over initial white space */ + while (isspace (*rest)) + rest++; - ReadConsole(stdin, - Output, - OutputLength, - &nbytes, - NULL); - Output[nbytes-2]=0; + cstart = rest; + + /* Anything to do ? */ + if (*rest) + { + /* Copy over 1st word as lower case */ + while (!IsDelimiter (*rest)) + *cp++ = _totlower (*rest++); + + /* Terminate first word */ + *cp = _T('\0'); + + /* Skip over whitespace to rest of line */ + while (_istspace (*rest)) + rest++; + + /* Scan internal command table */ + for (cmdptr = cmds;; cmdptr++) + { + /* If end of table execute ext cmd */ + if (cmdptr->name == NULL) + { + Execute (com, rest); + break; + } + + if (!_tcscmp (com, cmdptr->name)) + { + cmdptr->func (com, rest); + break; + } + + /* The following code handles the case of commands like CD which + * are recognised even when the command name and parameter are + * not space separated. + * + * e.g dir.. + * cd\freda + */ + + /* Get length of command name */ + cl = _tcslen (cmdptr->name); + + if ((cmdptr->flags & CMD_SPECIAL) && + (!_tcsncmp (cmdptr->name, com, cl)) && + (_tcschr (_T("\\.-"), *(com + cl)))) + { + /* OK its one of the specials...*/ + + /* Terminate first word properly */ + com[cl] = _T('\0'); + + /* Call with new rest */ + cmdptr->func (com, cstart + cl); + break; + } + } + } } -void func_cd(char* s) + +/* + * process the command line and execute the appropriate functions + * full input/output redirection and piping are supported + */ + +VOID ParseCommandLine (LPTSTR s) { - Console_printf("Changing directory to %s\n",s); - if (!SetCurrentDirectory(s)) - { - Console_puts("Failed to change to directory\n"); - } +#ifdef FEATURE_REDIRECTION + TCHAR in[CMDLINE_LENGTH] = ""; + TCHAR out[CMDLINE_LENGTH] = ""; + TCHAR err[CMDLINE_LENGTH] = ""; + TCHAR szTempPath[MAX_PATH] = _T(".\\"); + TCHAR szFileName[2][MAX_PATH] = {"", ""}; + HANDLE hFile[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}; + LPTSTR t = NULL; + INT num = 0; + INT nRedirFlags = 0; + + HANDLE hOldConIn; + HANDLE hOldConOut; + HANDLE hOldConErr; +#endif /* FEATURE_REDIRECTION */ + +#ifdef _DEBUG + DebugPrintf ("ParseCommandLine: (\'%s\')]\n", s); +#endif /* _DEBUG */ + +#ifdef FEATURE_ALIASES + /* expand all aliases */ + ExpandAlias (s, CMDLINE_LENGTH); +#endif /* FEATURE_ALIAS */ + +#ifdef FEATURE_REDIRECTION + /* find the temp path to store temporary files */ + GetTempPath (MAX_PATH, szTempPath); + if (szTempPath[_tcslen (szTempPath) - 1] != _T('\\')) + _tcscat (szTempPath, _T("\\")); + + /* get the redirections from the command line */ + num = GetRedirection (s, in, out, err, &nRedirFlags); + + /* more efficient, but do we really need to do this? */ + for (t = in; _istspace (*t); t++) + ; + _tcscpy (in, t); + + for (t = out; _istspace (*t); t++) + ; + _tcscpy (out, t); + + for (t = err; _istspace (*t); t++) + ; + _tcscpy (err, t); + + /* Set up the initial conditions ... */ + /* preserve STDIN, STDOUT and STDERR handles */ + hOldConIn = GetStdHandle (STD_INPUT_HANDLE); + hOldConOut = GetStdHandle (STD_OUTPUT_HANDLE); + hOldConErr = GetStdHandle (STD_ERROR_HANDLE); + + /* redirect STDIN */ + if (in[0]) + { + HANDLE hFile; + + hFile = CreateFile (in, GENERIC_READ, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + ConErrPrintf ("Can't redirect input from file %s\n", in); + return; + } + + if (!SetStdHandle (STD_INPUT_HANDLE, hFile)) + { + ConErrPrintf ("Can't redirect input from file %s\n", in); + return; + } +#ifdef _DEBUG + DebugPrintf (_T("Input redirected from: %s\n"), in); +#endif + } + + /* Now do all but the last pipe command */ + *szFileName[0] = '\0'; + hFile[0] = INVALID_HANDLE_VALUE; + + while (num-- > 1) + { + /* Create unique temporary file name */ + GetTempFileName (szTempPath, "CMD", 0, szFileName[1]); + + /* Set current stdout to temporary file */ + hFile[1] = CreateFile (szFileName[1], GENERIC_WRITE, 0, NULL, + TRUNCATE_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL); + SetStdHandle (STD_OUTPUT_HANDLE, hFile[1]); + + DoCommand (s); + + /* close stdout file */ + SetStdHandle (STD_OUTPUT_HANDLE, hOldConOut); + if ((hFile[1] != INVALID_HANDLE_VALUE) && (hFile[1] != hOldConOut)) + { + CloseHandle (hFile[1]); + hFile[1] = INVALID_HANDLE_VALUE; + } + + /* close old stdin file */ + SetStdHandle (STD_INPUT_HANDLE, hOldConIn); + if ((hFile[0] != INVALID_HANDLE_VALUE) && (hFile[0] != hOldConIn)) + { + /* delete old stdin file, if it is a real file */ + CloseHandle (hFile[0]); + hFile[0] = INVALID_HANDLE_VALUE; + DeleteFile (szFileName[0]); + *szFileName[0] = _T('\0'); + } + + /* copy stdout file name to stdin file name */ + _tcscpy (szFileName[0], szFileName[1]); + *szFileName[1] = _T('\0'); + + /* open new stdin file */ + hFile[0] = CreateFile (szFileName[0], GENERIC_READ, 0, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL); + SetStdHandle (STD_INPUT_HANDLE, hFile[0]); + + s = s + _tcslen (s) + 1; + } + + /* Now set up the end conditions... */ + /* redirect STDOUT */ + if (out[0]) + { + /* Final output to here */ + HANDLE hFile; + + hFile = CreateFile (out, GENERIC_WRITE, 0, NULL, + (nRedirFlags & OUTPUT_APPEND) ? OPEN_ALWAYS : CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + ConErrPrintf ("Can't redirect to file %s\n", out); + return; + } + + if (!SetStdHandle (STD_OUTPUT_HANDLE, hFile)) + { + ConErrPrintf ("Can't redirect to file %s\n", out); + return; + } + + if (nRedirFlags & OUTPUT_APPEND) + { + LONG lHighPos = 0; + + if (GetFileType (hFile) == FILE_TYPE_DISK) + SetFilePointer (hFile, 0, &lHighPos, FILE_END); + } +#ifdef _DEBUG + DebugPrintf (_T("Output redirected to: %s\n"), out); +#endif + } + else if (hOldConOut != INVALID_HANDLE_VALUE) + { + /* Restore original stdout */ + HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE); + SetStdHandle (STD_OUTPUT_HANDLE, hOldConOut); + if (hOldConOut != hOut) + CloseHandle (hOut); + hOldConOut = INVALID_HANDLE_VALUE; + } + + /* redirect STDERR */ + if (err[0]) + { + /* Final output to here */ + HANDLE hFile; + + if (!_tcscmp (err, out)) + { +#ifdef _DEBUG + DebugPrintf (_T("Stdout and stderr will use the same file!!\n")); +#endif + DuplicateHandle (GetCurrentProcess (), GetStdHandle (STD_OUTPUT_HANDLE), GetCurrentProcess (), + &hFile, 0, TRUE, DUPLICATE_SAME_ACCESS); + } + else + { + hFile = + CreateFile (err, GENERIC_WRITE, 0, NULL, + (nRedirFlags & ERROR_APPEND) ? OPEN_ALWAYS : CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + ConErrPrintf ("Can't redirect to file %s\n", err); + return; + } + } + if (!SetStdHandle (STD_ERROR_HANDLE, hFile)) + { + ConErrPrintf ("Can't redirect to file %s\n", err); + return; + } + + if (nRedirFlags & ERROR_APPEND) + { + LONG lHighPos = 0; + + if (GetFileType (hFile) == FILE_TYPE_DISK) + SetFilePointer (hFile, 0, &lHighPos, FILE_END); + } +#ifdef _DEBUG + DebugPrintf (_T("Error redirected to: %s\n"), err); +#endif + } + else if (hOldConErr != INVALID_HANDLE_VALUE) + { + /* Restore original stderr */ + HANDLE hErr = GetStdHandle (STD_ERROR_HANDLE); + SetStdHandle (STD_ERROR_HANDLE, hOldConErr); + if (hOldConErr != hErr) + CloseHandle (hErr); + hOldConErr = INVALID_HANDLE_VALUE; + } +#endif + + /* process final command */ + DoCommand (s); + +#ifdef FEATURE_REDIRECTION + /* close old stdin file */ +#if 0 /* buggy implementation */ + SetStdHandle (STD_INPUT_HANDLE, hOldConIn); + if ((hFile[0] != INVALID_HANDLE_VALUE) && + (hFile[0] != hOldConIn)) + { + /* delete old stdin file, if it is a real file */ + CloseHandle (hFile[0]); + hFile[0] = INVALID_HANDLE_VALUE; + DeleteFile (szFileName[0]); + *szFileName[0] = _T('\0'); + } + + /* Restore original STDIN */ + if (hOldConIn != INVALID_HANDLE_VALUE) + { + HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE); + SetStdHandle (STD_INPUT_HANDLE, hOldConIn); + if (hOldConIn != hIn) + CloseHandle (hIn); + hOldConIn = INVALID_HANDLE_VALUE; + } + else + { +#ifdef _DEBUG + DebugPrintf (_T("Can't restore STDIN! Is invalid!!\n"), out); +#endif + } +#endif /* buggy implementation */ + + + if (hOldConIn != INVALID_HANDLE_VALUE) + { + HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE); + SetStdHandle (STD_INPUT_HANDLE, hOldConIn); + if (hIn == INVALID_HANDLE_VALUE) + { +#ifdef _DEBUG + DebugPrintf (_T("Previous STDIN is invalid!!\n")); +#endif + } + else + { + if (GetFileType (hIn) == FILE_TYPE_DISK) + { + if (hFile[0] == hIn) + { + CloseHandle (hFile[0]); + hFile[0] = INVALID_HANDLE_VALUE; + DeleteFile (szFileName[0]); + *szFileName[0] = _T('\0'); + } + else + { +#ifdef _DEBUG + DebugPrintf (_T("hFile[0] and hIn dont match!!!\n")); +#endif + + } + } + } + } + + + /* Restore original STDOUT */ + if (hOldConOut != INVALID_HANDLE_VALUE) + { + HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE); + SetStdHandle (STD_OUTPUT_HANDLE, hOldConOut); + if (hOldConOut != hOut) + CloseHandle (hOut); + hOldConOut = INVALID_HANDLE_VALUE; + } + + /* Restore original STDERR */ + if (hOldConErr != INVALID_HANDLE_VALUE) + { + HANDLE hErr = GetStdHandle (STD_ERROR_HANDLE); + SetStdHandle (STD_ERROR_HANDLE, hOldConErr); + if (hOldConErr != hErr) + CloseHandle (hErr); + hOldConErr = INVALID_HANDLE_VALUE; + } +#endif /* FEATURE_REDIRECTION */ } -void func_dir(char* s) + +/* + * do the prompt/input/process loop + * + */ + +static INT +ProcessInput (BOOL bFlag) { - HANDLE shandle; - WIN32_FIND_DATA FindData; + TCHAR commandline[CMDLINE_LENGTH]; + TCHAR readline[CMDLINE_LENGTH]; + LPTSTR tp; + LPTSTR ip; + LPTSTR cp; - shandle = FindFirstFile("*.*",&FindData); + /* JPP 19980807 - changed name so not to conflict with echo global */ + BOOL bEchoThisLine; - if (shandle==INVALID_HANDLE_VALUE) - { - return; - } - do - { - Console_printf("Scanning %s\n",FindData.cFileName); - } while(FindNextFile(shandle,&FindData)); -} + do + { + /* if no batch input then... */ + if (!(ip = ReadBatchLine (&bEchoThisLine))) + { + if (bFlag) + return 0; -int is_builtin(char* name, char* args) -{ - if (strcmp(name,"dir")==0) - { - func_dir(args); - return(1); - } - if (strcmp(name,"cd")==0) - { - func_cd(args); - return(1); - } - return(0); -} + ReadCommand (readline, CMDLINE_LENGTH); + ip = readline; + bEchoThisLine = FALSE; + } -int process_command(char* str) -{ - char* name; - char* args; - PROCESS_INFORMATION pi; - STARTUPINFO si; - char process_arg[255]; + cp = commandline; + while (*ip) + { + if (*ip == _T('%')) + { + switch (*++ip) + { + case _T('%'): + *cp++ = *ip++; + break; - if (strcmp(str,"exit")==0) - { - return(1); - } + case _T('0'): + case _T('1'): + case _T('2'): + case _T('3'): + case _T('4'): + case _T('5'): + case _T('6'): + case _T('7'): + case _T('8'): + case _T('9'): + if (tp = FindArg (*ip - _T('0'))) + { + cp = stpcpy (cp, tp); + ip++; + } + else + *cp++ = _T('%'); + break; - name = strtok(str," \t"); - args = strtok(NULL,""); + case _T('?'): + cp += wsprintf (cp, _T("%u"), errorlevel); + ip++; + break; - if (is_builtin(name,args)) - { - return(0); - } - memset(&si,0,sizeof(STARTUPINFO)); - si.cb=sizeof(STARTUPINFO); - si.lpTitle=strdup(name); + default: + if (tp = _tcschr (ip, _T('%'))) + { + char evar[512]; + *tp = _T('\0'); - strcpy(process_arg,name); - strcat(process_arg," "); - if(args!=NULL) - { - strcat(process_arg,args); - } - Console_printf("name '%s' process_arg '%s'\n",name,process_arg); - if (!CreateProcess(NULL,process_arg,NULL,NULL,FALSE, - CREATE_NEW_CONSOLE, - NULL,NULL,&si,&pi)) - { - Console_printf("Failed to execute process\n"); - } - return(0); -} + /* FIXME: This is just a quick hack!! */ + /* Do a proper memory allocation!! */ + if (GetEnvironmentVariable (ip, evar, 512)) + cp = stpcpy (cp, evar); -void build_prompt(char* prompt) -{ - int len; + ip = tp + 1; + } + break; + } + continue; + } - len = GetCurrentDirectory(255,prompt); - strcat(prompt,">"); -} + if (_istcntrl (*ip)) + *ip = _T(' '); + *cp++ = *ip++; + } -void command_loop() -{ - char line[255]; - char prompt[255]; - int do_exit = 0; + *cp = _T('\0'); - while (!do_exit) - { - build_prompt(prompt); - Console_getline(prompt,line,255); - Console_printf("Processing command '%s'\n",line); - do_exit = process_command(line); - } -} + /* strip trailing spaces */ + while ((--cp >= commandline) && _istspace (*cp)) + ; -int STDCALL WinMain (HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow) -{ - AllocConsole(); - stdin = GetStdHandle(STD_INPUT_HANDLE); - stdout = GetStdHandle(STD_OUTPUT_HANDLE); + *(cp + 1) = _T('\0'); - command_loop(); + /* JPP 19980807 */ + /* Echo batch file line */ + if (bEchoThisLine) + { + PrintPrompt (); + ConOutPuts (commandline); + } + + if (*commandline) + { + ParseCommandLine (commandline); + if (bEcho && !bIgnoreEcho) + ConOutChar ('\n'); + bIgnoreEcho = FALSE; + } + } + while (!bCanExit || !bExit); return 0; } + + +/* + * control-break handler. + */ +BOOL BreakHandler (DWORD dwCtrlType) +{ + if ((dwCtrlType == CTRL_C_EVENT) || + (dwCtrlType == CTRL_BREAK_EVENT)) + { + bCtrlBreak = TRUE; /* indicate the break condition */ + return TRUE; + } + return FALSE; +} + + +/* + * show commands and options that are available. + * + */ +static VOID +ShowCommands (VOID) +{ + LPCOMMAND cmdptr; + INT y; + + ConOutPrintf (_T("\nInternal commands available:\n")); + y = 0; + cmdptr = cmds; + while (cmdptr->name) + { + if (++y == 8) + { + ConOutPuts (cmdptr->name); + y = 0; + } + else + ConOutPrintf (_T("%-10s"), cmdptr->name); + + cmdptr++; + } + + if (y != 0) + ConOutChar ('\n'); + + /* print feature list */ + ConOutPuts ("\nFeatures available:"); +#ifdef FEATURE_ALIASES + ConOutPuts (" [aliases]"); +#endif +#ifdef FEATURE_HISTORY + ConOutPuts (" [history]"); +#endif +#ifdef FEATURE_UNIX_FILENAME_COMPLETION + ConOutPuts (" [unix filename completion]"); +#endif +#ifdef FEATURE_DIRECTORY_STACK + ConOutPuts (" [directory stack]"); +#endif +#ifdef FEATURE_REDIRECTION + ConOutPuts (" [redirections and piping]"); +#endif + ConOutChar ('\n'); +} + + +/* + * set up global initializations and process parameters + * + * argc - number of parameters to command.com + * argv - command-line parameters + * + */ +static VOID Initialize (int argc, char *argv[]) +{ + INT i; + + /* Added by Rob Lake 06/16/98. This enables the command.com + * to run the autoexec.bat at startup */ + +#ifdef _DEBUG + INT x; + + DebugPrintf ("[command args:\n"); + for (x = 0; x < argc; x++) + { + DebugPrintf ("%d. %s\n", x, argv[x]); + } + DebugPrintf ("]\n"); +#endif + + /* get version information */ + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx (&osvi); + + InitLocale (); + + /* get default input and output console handles */ + hOut = GetStdHandle (STD_OUTPUT_HANDLE); + hIn = GetStdHandle (STD_INPUT_HANDLE); + +#ifdef INCLUDE_CMD_CHDIR + InitLastPath (); +#endif + + if (argc >= 2) + { + if (!_tcsncmp (argv[1], _T("/?"), 2)) + { + ConOutPuts (_T("Starts a new instance of the ReactOS command line interpreter\n\n" + "CMD [/P][/C]...\n\n" + " /P ...\n" + " /C ...")); + ExitProcess (0); + } + else + { + for (i = 1; i < argc; i++) + { + if (!_tcsicmp (argv[i], _T("/p"))) + { + if (!IsValidFileName (_T("\\autoexec.bat"))) + { +#ifdef INCLUDE_CMD_DATE + cmd_date ("", ""); +#endif +#ifdef INCLUDE_CMD_TIME + cmd_time ("", ""); +#endif + } + else + ParseCommandLine ("\\autoexec.bat"); + bCanExit = FALSE; + } + else if (!_tcsicmp (argv[i], _T("/c"))) + { + /* This just runs a program and exits, RL: 06/16,21/98 */ + char commandline[CMDLINE_LENGTH]; + ++i; + strcpy(commandline, argv[i]); + while (argv[++i]) + { + strcat(commandline, " "); + strcat(commandline, argv[i]); + } + + ParseCommandLine(commandline); + + /* HBP_003 { Fix return value when /C used }*/ + ExitProcess (ProcessInput (TRUE)); + } + +#ifdef INCLUDE_CMD_COLOR + else if (!_tcsnicmp (argv[i], _T("/t:"), 3)) + { + /* process /t (color) argument */ + wDefColor = (WORD)strtoul (&argv[i][3], NULL, 16); + wColor = wDefColor; + } +#endif + } + } + } + +#ifdef FEATURE_DIR_STACK + /* initialize directory stack */ + InitDirectoryStack (); +#endif + +#ifdef INCLUDE_CMD_COLOR + /* set default colors */ + SetScreenColor (wColor); +#endif + + ShortVersion (); + ShowCommands (); + + /* Set COMSPEC environment variable */ + SetEnvironmentVariable (_T("COMSPEC"), argv[0]); + + /* add ctrl handler */ + SetConsoleCtrlHandler (NULL, TRUE); +} + + +static VOID Cleanup (VOID) +{ + +#ifdef FEATURE_DIECTORY_STACK + /* destroy directory stack */ + DestroyDirectoryStack (); +#endif + +#ifdef INCLUDE_CMD_CHDIR + FreeLastPath (); +#endif + + /* remove ctrl handler */ +// SetConsoleCtrlHandler ((PHANDLER_ROUTINE)&BreakHandler, FALSE); +} + + +/* + * main function + */ +int main (int argc, char *argv[]) +{ + INT nExitCode; + + AllocConsole (); + SetFileApisToOEM (); + + /* check switches on command-line */ + Initialize (argc, argv); + + /* call prompt routine */ + nExitCode = ProcessInput (FALSE); + + /* do the cleanup */ + Cleanup (); + FreeConsole (); + + return nExitCode; +} diff --git a/rosapps/cmd/cmd.h b/rosapps/cmd/cmd.h new file mode 100644 index 00000000000..e34fffedb1d --- /dev/null +++ b/rosapps/cmd/cmd.h @@ -0,0 +1,300 @@ +/* + * CMD.H - header file for the modules in CMD.EXE + * + * + * History: + * + * 7-15-95 Tim Norman + * started + * + * 06/29/98 (Rob Lake) + * Moved error messages in here + * + * 07/12/98 (Rob Lake) + * Moved more error messages here + * + * 30-Jul-1998 (John P Price ) + * Added compile date to version + */ + +// #define WIN32_LEAN_AND_MEAN + +#include +// #include + +#define SHELLVER "version 0.0.4 [" __DATE__"]" + +#define BREAK_BATCHFILE 1 +#define BREAK_OUTOFBATCH 2 +#define BREAK_INPUT 3 +#define BREAK_IGNORE 4 + +/* define some error messages */ +#define NOENVERR "ERROR: no environment" +#define INVALIDDRIVE "ERROR: invalid drive" +#define INVALIDFUNCTION "ERROR: invalid function" +#define ACCESSDENIED "ERROR: access denied" +#define BADENVIROMENT "ERROR: bad enviroment" +#define BADFORMAT "ERROR: bad format" +#define ERROR_E2BIG "ERROR: Argument list too long" +#define ERROR_EINVAL "ERROR: Invalid argument" + +#define SHELLINFO "ReactOS Command Line Interface" +#define USAGE "usage" + + +#define D_ON "on" +#define D_OFF "off" + + + +/* prototypes for CMD.C */ +extern HANDLE hOut; +extern HANDLE hIn; +extern WORD wColor; +extern WORD wDefColor; +extern BOOL bCtrlBreak; +extern BOOL bIgnoreEcho; +extern BOOL bExit; +extern int errorlevel; +extern SHORT maxx; +extern SHORT maxy; +extern OSVERSIONINFO osvi; + + +// VOID Execute (char *, char *); +void command(char *); +VOID ParseCommandLine (LPTSTR); +int c_brk(void); + + + + +/* prototypes for ALIAS.C */ +VOID ExpandAlias (char *, int); +INT cmd_alias (LPTSTR, LPTSTR); + + +/* prototyped for ATTRIB.C */ +INT cmd_attrib (LPTSTR, LPTSTR); + + +/* prototypes for CLS.C */ +INT cmd_cls (LPTSTR, LPTSTR); + + +/* prototypes for CMDINPUT.C */ +VOID ReadCommand (LPTSTR, INT); + + +/* prototypes for CMDTABLE.C */ +#define CMD_SPECIAL 1 +#define CMD_BATCHONLY 2 + +typedef struct tagCOMMAND +{ + LPTSTR name; + INT flags; + INT (*func) (LPTSTR, LPTSTR); +} COMMAND, *LPCOMMAND; + + +/* prototypes for COLOR.C */ +VOID SetScreenColor (WORD); +INT cmd_color (LPTSTR, LPTSTR); + + +/* prototypes for CONSOLE.C */ +#ifdef _DEBUG +VOID DebugPrintf (LPTSTR, ...); +#endif /* _DEBUG */ + +VOID ConInDummy (VOID); +VOID ConInKey (PINPUT_RECORD); + +VOID ConInString (LPTSTR, DWORD); + + +VOID ConOutChar (TCHAR); +VOID ConOutPuts (LPTSTR); +VOID ConOutPrintf (LPTSTR, ...); +VOID ConErrChar (TCHAR); +VOID ConErrPuts (LPTSTR); +VOID ConErrPrintf (LPTSTR, ...); + + +SHORT wherex (VOID); +SHORT wherey (VOID); +VOID goxy (SHORT, SHORT); + +VOID GetScreenSize (PSHORT, PSHORT); +VOID SetCursorType (BOOL, BOOL); + + +/* prototypes for COPY.C */ +INT cmd_copy (LPTSTR, LPTSTR); + + +/* prototypes for DATE.C */ +INT cmd_date (LPTSTR, LPTSTR); + + +/* prototypes for DEL.C */ +INT cmd_del (LPTSTR, LPTSTR); + + +/* prototypes for DIR.C */ +//int incline(int *line, unsigned flags); +INT cmd_dir (LPTSTR, LPTSTR); + + +/* prototypes for DIRSTACK.C */ +VOID InitDirectoryStack (VOID); +VOID DestroyDirectoryStack (VOID); +INT GetDirectoryStackDepth (VOID); +INT cmd_pushd (LPTSTR, LPTSTR); +INT cmd_popd (LPTSTR, LPTSTR); + + +/* Prototypes for ERROR.C */ +VOID ErrorMessage (DWORD, LPTSTR, ...); + +VOID error_no_pipe (VOID); +VOID error_bad_command (VOID); +VOID error_invalid_drive (VOID); +VOID error_req_param_missing (VOID); +VOID error_sfile_not_found (LPTSTR); +VOID error_file_not_found (VOID); +VOID error_path_not_found (VOID); +VOID error_too_many_parameters (LPTSTR); +VOID error_invalid_switch (TCHAR); +VOID error_invalid_parameter_format (LPTSTR); +VOID error_out_of_memory (VOID); +VOID error_syntax (LPTSTR); + +VOID msg_pause (VOID); + + +/* prototypes for FILECOMP.C */ +#ifdef FEATURE_UNIX_FILENAME_COMPLETION +VOID CompleteFilename (LPTSTR, INT); +INT ShowCompletionMatches (LPTSTR, INT); +#endif +#ifdef FEATURE_4NT_FILENAME_COMPLETION +#endif + + +/* prototypes for HISTORY.C */ +#ifdef FEATURE_HISTORY +VOID History (INT, LPTSTR); +#endif + + +/* prototypes for INTERNAL.C */ +VOID InitLastPath (VOID); +VOID FreeLastPath (VOID); +int cmd_chdir(char *, char *); +int cmd_mkdir(char *, char *); +int cmd_rmdir(char *, char *); +int internal_exit(char *, char *); +int cmd_rem(char *, char *); +int cmd_showcommands(char *, char *); + + +/* prototyped for LABEL.C */ +INT cmd_label (LPTSTR, LPTSTR); + + +/* prototypes for LOCALE.C */ +extern TCHAR cDateSeparator; +extern INT nDateFormat; +extern TCHAR cTimeSeparator; +extern INT nTimeFormat; +extern TCHAR aszDayNames[7][8]; +extern TCHAR cThousandSeparator; +extern TCHAR cDecimalSeparator; +extern INT nNumberGroups; + +VOID InitLocale (VOID); + + +/* Prototypes for MISC.C */ +TCHAR cgetchar (VOID); +BOOL CheckCtrlBreak (INT); +LPTSTR *split (LPTSTR, LPINT); +VOID freep (LPTSTR *); +LPTSTR stpcpy (LPTSTR, LPTSTR); +BOOL IsValidPathName (LPCTSTR); +BOOL IsValidFileName (LPCTSTR); +BOOL FileGetString (HANDLE, LPTSTR, INT); + + +/* prototypes for MOVE.C */ +INT cmd_move (LPTSTR, LPTSTR); + + +/* prototypes from PATH.C */ +INT cmd_path (LPTSTR, LPTSTR); + + +/* prototypes from PROMPT.C */ +VOID PrintPrompt (VOID); +INT cmd_prompt (LPTSTR, LPTSTR); + + +/* prototypes for REDIR.C */ +#define INPUT_REDIRECTION 1 +#define OUTPUT_REDIRECTION 2 +#define OUTPUT_APPEND 4 +#define ERROR_REDIRECTION 8 +#define ERROR_APPEND 16 +INT GetRedirection (LPTSTR, LPTSTR, LPTSTR, LPTSTR, LPINT); + + +/* prototypes for REN.C */ +INT cmd_rename (LPTSTR, LPTSTR); + + +/* prototypes for SET.C */ +INT cmd_set (LPTSTR, LPTSTR); + + +/* prototypes for TIME.C */ +INT cmd_time (LPTSTR, LPTSTR); + + +/* prototypes for TYPE.C */ +INT cmd_type (LPTSTR, LPTSTR); + + +/* prototypes for VER.C */ +VOID ShortVersion (VOID); +INT cmd_ver (LPTSTR, LPTSTR); + + +/* prototypes for VERIFY.C */ +INT cmd_verify (LPTSTR, LPTSTR); + + +/* prototypes for VOL.C */ +INT cmd_vol (LPTSTR, LPTSTR); + + +/* prototypes for WHERE.C */ +BOOL find_which (LPCTSTR, LPTSTR); + + + + +/* The MSDOS Batch Commands [MS-DOS 5.0 User's Guide and Reference p359] */ +int cmd_call(char *, char *); +int cmd_echo(char *, char *); +int cmd_for(char *, char *); +int cmd_goto(char *, char *); +int cmd_if(char *, char *); +int cmd_pause(char *, char *); +int cmd_shift(char *, char *); + +int cmd_beep(char *, char *); + + diff --git a/rosapps/cmd/cmdinput.c b/rosapps/cmd/cmdinput.c new file mode 100644 index 00000000000..6ac5302529d --- /dev/null +++ b/rosapps/cmd/cmdinput.c @@ -0,0 +1,412 @@ +/* + * CMDINPUT.C - handles command input (tab completion, history, etc.). + * + * + * History: + * + * 01/14/95 (Tim Norman) + * started. + * + * 08/08/95 (Matt Rains) + * i have cleaned up the source code. changes now bring this source + * into guidelines for recommended programming practice. + * i have added some constants to help making changes easier. + * + * 12/12/95 (Tim Norman) + * added findxy() function to get max x/y coordinates to display + * correctly on larger screens + * + * 12/14/95 (Tim Norman) + * fixed the Tab completion code that Matt Rains broke by moving local + * variables to a more global scope and forgetting to initialize them + * when needed + * + * 8/1/96 (Tim Norman) + * fixed a bug in tab completion that caused filenames at the beginning + * of the command-line to have their first letter truncated + * + * 9/1/96 (Tim Norman) + * fixed a silly bug using printf instead of fputs, where typing "%i" + * confused printf :) + * + * 6/14/97 (Steffan Kaiser) + * ctrl-break checking + * + * 6/7/97 (Marc Desrochers) + * recoded everything! now properly adjusts when text font is changed. + * removed findxy(), reposition(), and reprint(), as these functions + * were inefficient. added goxy() function as gotoxy() was buggy when + * the screen font was changed. the printf() problem with %i on the + * command line was fixed by doing printf("%s",str) instead of + * printf(str). Don't ask how I find em just be glad I do :) + * + * 7/12/97 (Tim Norman) + * Note: above changes pre-empted Steffan's ctrl-break checking. + * + * 7/7/97 (Marc Desrochers) + * rewrote a new findxy() because the new dir() used it. This + * findxy() simply returns the values of *maxx *maxy. In the + * future, please use the pointers, they will always be correct + * since they point to BIOS values. + * + * 7/8/97 (Marc Desrochers) + * once again removed findxy(), moved the *maxx, *maxy pointers + * global and included them as externs in command.h. Also added + * insert/overstrike capability + * + * 7/13/97 (Tim Norman) + * added different cursor appearance for insert/overstrike mode + * + * 7/13/97 (Tim Norman) + * changed my code to use _setcursortype until I can figure out why + * my code is crashing on some machines. It doesn't crash on mine :) + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 28-Jul-1998 (John P Price ) + * put ifdef's around filename completion code. + * + * 30-Jul-1998 (John P Price ) + * moved filename completion code to filecomp.c + * made second TAB display list of filename matches + * + * 31-Jul-1998 (John P Price ) + * Fixed bug where if you typed something, then hit HOME, then tried + * to type something else in insert mode, it crashed. + * + * 07-Aug-1998 (John P Price ) + * Fixed carrage return output to better match MSDOS with echo + * on or off.(marked with "JPP 19980708") + * + * 13-Dec-1998 (Eric Kohl ) + * Added insert/overwrite cursor. + * + * 25-Jan-1998 (Eric Kohl ) + * Replaced CRT io functions by Win32 console io functions. + * This can handle - for 4NT filename completion. + * Unicode and redirection safe! + * + * 04-Feb-1999 (Eric Kohl ) + * Fixed input bug. A "line feed" character remined in the keyboard + * input queue when you pressed . This sometimes caused + * some very strange effects. + * Fixed some command line editing annoyances. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include + +#include "cmd.h" +#include "batch.h" + + + +SHORT maxx; +SHORT maxy; + +/* + * global command line insert/overwrite flag + */ +static BOOL bInsert = TRUE; + + +static VOID +ClearCommandLine (LPTSTR str, INT maxlen, SHORT orgx, SHORT orgy) +{ + INT count; + + goxy (orgx, orgy); + for (count = 0; count < (INT)_tcslen (str); count++) + ConOutChar (_T(' ')); + _tcsnset (str, _T('\0'), maxlen); + goxy (orgx, orgy); +} + + +/* read in a command line */ +VOID ReadCommand (LPTSTR str, INT maxlen) +{ + SHORT orgx; /* origin x/y */ + SHORT orgy; + SHORT curx; + SHORT cury; + INT count; + INT current = 0; + INT charcount = 0; + INPUT_RECORD ir; + WORD wLastKey = 0; + TCHAR ch; + + /* get screen size */ + GetScreenSize (&maxx, &maxy); + + /* JPP 19980807 - if echo off, don't print prompt */ + if (bEcho) + PrintPrompt(); + + orgx = wherex (); + orgy = wherey (); + + memset (str, 0, maxlen * sizeof (TCHAR)); + + SetCursorType (bInsert, TRUE); + + do + { + ConInKey (&ir); + + switch (ir.Event.KeyEvent.wVirtualKeyCode) + { + case VK_BACK: + /* - delete character to left of cursor */ + if (current > 0 && charcount > 0) + { + if (current == charcount) + { + /* if at end of line */ + str[current - 1] = _T('\0'); + if (wherex () != 0) + { + ConOutPrintf ("\b \b"); + } + else + { + goxy ((SHORT)(maxx - 1), (SHORT)(wherey () - 1)); + ConOutChar (_T(' ')); + goxy ((SHORT)(maxx - 1), (SHORT)(wherey () - 1)); + } + } + else + { + for (count = current - 1; count < charcount; count++) + str[count] = str[count + 1]; + if (wherex () != 0) + goxy ((SHORT)(wherex () - 1), wherey ()); + else + goxy ((SHORT)(maxx - 1), (SHORT)(wherey () - 1)); + curx = wherex (); + cury = wherey (); + ConOutPrintf (_T("%s "), &str[current - 1]); + goxy (curx, cury); + } + charcount--; + current--; + } + break; + + case VK_INSERT: + /* toggle insert/overstrike mode */ + bInsert ^= TRUE; + SetCursorType (bInsert, TRUE); + break; + + case VK_DELETE: + /* delete character under cursor */ + if (current != charcount && charcount > 0) + { + for (count = current; count < charcount; count++) + str[count] = str[count + 1]; + charcount--; + curx = wherex (); + cury = wherey (); + ConOutPrintf (_T("%s "), &str[current]); + goxy (curx, cury); + } + break; + + case VK_HOME: + /* goto beginning of string */ + if (current != 0) + { + goxy (orgx, orgy); + current = 0; + } + break; + + case VK_END: + /* goto end of string */ + if (current != charcount) + { + goxy (orgx, orgy); + ConOutPrintf (_T("%s"), str); + current = charcount; + } + break; + + case VK_TAB: +#ifdef FEATURE_UNIX_FILENAME_COMPLETION + /* expand current file name */ + if (current == charcount) // only works at end of line + { + if (wLastKey != VK_TAB) + { + // if first TAB, complete filename + CompleteFilename (str, charcount); + charcount = _tcslen (str); + current = charcount; + + goxy(orgx, orgy); + ConOutPrintf (_T("%s"), str); + if ((_tcslen (str) > (USHORT)(maxx - orgx)) && (orgy == maxy + 1)) + orgy--; + } + else + { + //if second TAB, list matches + if (ShowCompletionMatches (str, charcount)) + { + PrintPrompt (); + orgx = wherex (); + orgy = wherey (); + ConOutPrintf (_T("%s"), str); + } + } + } + else + { + MessageBeep (-1); + } +#endif +#ifdef FEATURE_4NT_FILENAME_COMPLETION + /* this is not implemented yet */ + if (ir.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) + { + /* get previous match */ + + } + else + { + /* get next match */ + + } +#endif + break; + + case VK_RETURN: + /* end input, return to main */ +#ifdef FEATURE_HISTORY + /* add to the history */ + if (str[0]) + History (0, str); +#endif + ConInDummy (); + ConOutChar (_T('\n')); + break; + + case VK_ESCAPE: + /* clear str Make this callable! */ + ClearCommandLine (str, maxlen, orgx, orgy); + current = charcount = 0; + break; + + case VK_UP: +#ifdef FEATURE_HISTORY + /* get previous command from buffer */ + ClearCommandLine (str, maxlen, orgx, orgy); + History (-1, str); + current = charcount = _tcslen (str); + ConOutPrintf (_T("%s"), str); +#endif + break; + + case VK_DOWN: +#ifdef FEATURE_HISTORY + /* get next command from buffer */ + ClearCommandLine (str, maxlen, orgx, orgy); + History (1, str); + current = charcount = _tcslen (str); + ConOutPrintf (_T("%s"), str); +#endif + break; + + case VK_LEFT: + /* move cursor left */ + if (current > 0) + { + current--; + if (wherex () == 0) + goxy ((SHORT)(maxx - 1), (SHORT)(wherey () - 1)); + else + goxy ((SHORT)(wherex () - 1), wherey ()); + } + else + { +// Beep (440, 100); + MessageBeep (-1); + } + break; + + case VK_RIGHT: + /* move cursor right */ + if (current != charcount) + { + current++; + if (wherex () == maxx - 1) + goxy (0, (SHORT)(wherey () + 1)); + else + goxy ((SHORT)(wherex () + 1), wherey ()); + } + break; + + default: +#ifdef _UNICODE + ch = ir.Event.KeyEvent.uChar.UnicodeChar; +#else + ch = ir.Event.KeyEvent.uChar.AsciiChar; +#endif + if ((ch >= 32 && ch <= 255) && (charcount != (maxlen - 2))) + { + /* insert character into string... */ + if (bInsert && current != charcount) + { + for (count = charcount; count > current; count--) + str[count] = str[count - 1]; + str[current++] = ch; + if (wherex () == maxx - 1) + { + curx = 0; + cury = wherey () + 1; + } + else + { + curx = wherex () + 1; + cury = wherey (); + } + ConOutPrintf (_T("%s"), &str[current - 1]); + if ((_tcslen (str) > (USHORT)(maxx - orgx)) && (orgy == maxy + 1)) + cury--; + goxy (curx, cury); + charcount++; + } + else + { + if (current == charcount) + charcount++; + str[current++] = ch; + ConOutChar (ch); + } + if ((_tcslen (str) > (USHORT)(maxx - orgx)) && (orgy == maxy + 1)) + orgy--; + } +#if 0 + else + { +// Beep (440, 100); + MessageBeep (-1); + } +#endif + break; + + } + wLastKey = ir.Event.KeyEvent.wVirtualKeyCode; + } + while (ir.Event.KeyEvent.wVirtualKeyCode != VK_RETURN); + + SetCursorType (bInsert, TRUE); +} diff --git a/rosapps/cmd/cmdtable.c b/rosapps/cmd/cmdtable.c new file mode 100644 index 00000000000..f2d8339dfce --- /dev/null +++ b/rosapps/cmd/cmdtable.c @@ -0,0 +1,241 @@ +/* + * CMDTABLE.C - table of internal commands. + * + * + * History: + * + * 16 Jul 1998 (Hans B Pufal) + * started. + * New file to keep the internal command table. I plan on + * getting rid of the table real soon now and replacing it + * with a dynamic mechnism. + * + * 27 Jul 1998 John P. Price + * added config.h include + * + * 21-Jan-1999 (Eric Kohl ) + * Unicode ready! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include + +#include "cmd.h" + +#include "chcp.h" + + +/* a list of all the internal commands, associating their command names */ +/* to the functions to process them */ + +/* Lines marked + * + * $$ are external commands + * !! internal commands which are not yet implemented + * ** special FREEDOS specific implementation + */ + +COMMAND cmds[] = +{ + {_T("?"), 0, cmd_showcommands}, + +#ifdef FEATURE_ALIASES + {_T("alias"), 0, cmd_alias}, +#endif + +#ifdef INCLUDE_CMD_ATTRIB + {_T("attrib"), 0, cmd_attrib}, +#endif + +#ifdef INCLUDE_CMD_BEEP + {_T("beep"), 0, cmd_beep}, +#endif + +/* + {_T("break"), 0, cmd_break}, +*/ + + {_T("call"), CMD_BATCHONLY, cmd_call}, + +#ifdef INCLUDE_CMD_CHDIR + {_T("cd"), CMD_SPECIAL, cmd_chdir}, + {_T("chdir"), CMD_SPECIAL, cmd_chdir}, +#endif + +#ifdef INCLUDE_CMD_CHCP + {_T("chcp"), 0, CommandChcp}, +#endif + +#ifdef INCLUDE_CMD_CLS + {_T("cls"), 0, cmd_cls}, +#endif + +#ifdef INCLUDE_CMD_COLOR + {_T("color"), 0, cmd_color}, +#endif + +#ifdef INCLUDE_CMD_COPY + {_T("copy"), 0, cmd_copy}, +#endif + +/* +#define INCLUDE_CMD_CTTY + {_T("ctty"), 0, cmd_ctty}, +#endif +*/ + +#ifdef INCLUDE_CMD_DATE + {_T("date"), 0, cmd_date}, +#endif + +#ifdef INCLUDE_CMD_DEL + {_T("del"), 0, cmd_del}, + {_T("delete"), 0, cmd_del}, +#endif + +#ifdef INCLUDE_CMD_DIR + {_T("dir"), CMD_SPECIAL, cmd_dir}, +#endif + + {_T("echo"), 0, cmd_echo}, + +#ifdef INCLUDE_CMD_DEL + {_T("erase"), 0, cmd_del}, +#endif + + {_T("exit"), 0, internal_exit}, + + {_T("for"), 0, cmd_for}, + + {_T("goto"), CMD_BATCHONLY, cmd_goto}, + + {_T("if"), 0, cmd_if}, + +#ifdef INCLUDE_CMD_LABEL + {_T("label"), 0, cmd_label}, +#endif + +#ifdef INCLUDE_CMD_MKDIR + {_T("md"), CMD_SPECIAL, cmd_mkdir}, + {_T("mkdir"), CMD_SPECIAL, cmd_mkdir}, +#endif + +#ifdef INCLUDE_CMD_MOVE + {_T("move"), 0, cmd_move}, +#endif + +#ifdef INCLUDE_CMD_PATH + {_T("path"), 0, cmd_path}, +#endif + +#ifdef INCLUDE_CMD_PAUSE + {_T("pause"), 0, cmd_pause}, +#endif + +#ifdef FEATURE_DIRECTORY_STACK + {_T("popd"), 0, cmd_popd}, +#endif + +#ifdef INCLUDE_CMD_PROMPT + {_T("prompt"), 0, cmd_prompt}, +#endif + +#ifdef FEATURE_DIRECTORY_STACK + {_T("pushd"), 0, cmd_pushd}, +#endif + +#ifdef INCLUDE_CMD_RMDIR + {_T("rd"), CMD_SPECIAL, cmd_rmdir}, +#endif + +#ifdef INCLUDE_CMD_REM + {_T("rem"), 0, cmd_rem}, +#endif + +#ifdef INCLUDE_CMD_RENAME + {_T("ren"), 0, cmd_rename}, + {_T("rename"), 0, cmd_rename}, +#endif + +#ifdef INCLUDE_CMD_RMDIR + {_T("rmdir"), CMD_SPECIAL, cmd_rmdir}, +#endif + +#ifdef INCLUDE_CMD_SET + {_T("set"), 0, cmd_set}, +#endif + + {_T("shift"), CMD_BATCHONLY, cmd_shift}, + +#ifdef INCLUDE_CMD_TIME + {_T("time"), 0, cmd_time}, +#endif + +#ifdef INCLUDE_CMD_TYPE + {_T("type"), 0, cmd_type}, +#endif + +#ifdef INCLUDE_CMD_VER + {_T("ver"), 0, cmd_ver}, +#endif + +#ifdef INCLUDE_CMD_VERIFY + {_T("verify"), 0, cmd_verify}, +#endif + +#ifdef INCLUDE_CMD_VOL + {_T("vol"), 0, cmd_vol}, +#endif + + {NULL, 0, NULL} +}; + +/* append, $$ */ +/* assign, $$ */ +/* attrib, ** */ +/* backup, $$ */ +/* chkdsk, $$ */ +/* comp, $$ */ +/* debug, $$ */ +/* diskcomp, $$ */ +/* diskcopy, $$ */ +/* doskey, ** */ +/* dosshell, $$ */ +/* edit, $$ */ +/* edlin, $$ */ +/* emm386, $$ */ +/* exe2bin, $$ */ +/* expand, $$ */ +/* fastopen, $$ */ +/* fc, $$ */ +/* fdisk, $$ */ +/* find, $$ */ +/* format, $$ */ +/* graftabl, $$ */ +/* graphics, $$ */ +/* help, $$ */ +/* join, $$ */ +/* keyb, $$ */ +/* mem, $$ */ +/* mirror, $$ */ +/* mode, $$ */ +/* more, $$ */ +/* nlsfunc, $$ */ +/* print, $$ */ +/* qbasic, $$ */ +/* recover, $$ */ +/* replace, $$ */ +/* restore, $$ */ +/* setver, $$ */ +/* share, $$ */ +/* sort, $$ */ +/* subst, $$ */ +/* sys, $$ */ +/* tree, $$ */ +/* undelete, $$ */ +/* unformat, $$ */ +/* xcopy, $$ */ diff --git a/rosapps/cmd/color.c b/rosapps/cmd/color.c new file mode 100644 index 00000000000..f5d086704db --- /dev/null +++ b/rosapps/cmd/color.c @@ -0,0 +1,102 @@ +/* + * COLOR.C - color internal command. + * + * + * History: + * + * 13-Dec-1998 (Eric Kohl ) + * Started. + * + * 19-Jan-1999 (Eric Kohl ) + * Unicode ready! + * + * 20-Jan-1999 (Eric Kohl ) + * Redirection ready! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_COLOR +#include +#include +#include +#include + +#include "cmd.h" + + +VOID SetScreenColor (WORD wColor) +{ + DWORD dwWritten; + CONSOLE_SCREEN_BUFFER_INFO csbi; + COORD coPos; + + GetConsoleScreenBufferInfo (hOut, &csbi); + + coPos.X = 0; + coPos.Y = 0; + FillConsoleOutputAttribute (hOut, wColor, + (csbi.dwSize.X)*(csbi.dwSize.Y), + coPos, &dwWritten); + SetConsoleTextAttribute (hOut, wColor); +} + + +/* + * color + * + * internal dir command + */ +INT cmd_color (LPTSTR first, LPTSTR rest) +{ + if (_tcsncmp (rest, _T("/?"), 2) == 0) + { + ConOutPuts (_T("Sets the default foreground and background colors.\n\n" + "COLOR [attr]\n\n" + " attr Specifies color attribute of console output\n\n" + "Color attributes are specified by TWO hex digits -- the first\n" + "corresponds to the background; the second to the foreground. Each digit\n" + "can be one of the following:\n")); + + ConOutPuts (_T(" 0 = Black 8 = Gray\n" + " 1 = Blue 9 = Light Blue\n" + " 2 = Green A = Light Green\n" + " 3 = Aqua B = Light Aqua\n" + " 4 = Red C = Light Red\n" + " 5 = Purple D = Light Purple\n" + " 6 = Yellow E = Light Yellow\n" + " 7 = White F = Bright White\n")); + return 0; + } + + if (rest[0] == _T('\0')) + { + /* set default color */ + wColor = wDefColor; + SetScreenColor (wColor); + return 0; + } + + if (_tcslen (rest) != 2) + { + ConErrPuts (_T("parameter error!")); + return 1; + } + + wColor = (WORD)_tcstoul (rest, NULL, 16); + + if ((wColor & 0xF) == (wColor &0xF0) >> 4) + { + ConErrPuts (_T("same colors error!")); + return 1; + } + + /* set color */ + SetScreenColor (wColor); + + return 0; +} + +#endif diff --git a/rosapps/cmd/config.h b/rosapps/cmd/config.h new file mode 100644 index 00000000000..1e214e276e4 --- /dev/null +++ b/rosapps/cmd/config.h @@ -0,0 +1,86 @@ +/* + * CONFIG.H - Used to configure what will be compiled into the shell. + * + * + * History: + * + * 27 Jul 1998 - John P. Price + * started. + * + */ + + +/* JPP 20 Jul 1998 - define DEBUG to add debugging code */ +/*#define DEBUG */ + + +/* Define to enable the alias command, and aliases.*/ +#define FEATURE_ALIASES + + +/* Define to enable history */ +#define FEATURE_HISTORY + + +/* Define one of these to enable filename completion */ +#define FEATURE_UNIX_FILENAME_COMPLETION +/* #define FEATURE_4NT_FILENAME_COMPLETION */ + + +/* Define to enable the directory stack */ +#define FEATURE_DIRECTORY_STACK + + +/* Define to activate redirections and piping */ +#define FEATURE_REDIRECTION + + +/* Define one of these to select the used locale. */ +/* (date and time formats etc.) used in DATE, TIME */ +/* DIR and PROMPT. */ +#define LOCALE_WINDOWS /* System locale */ +/* #define LOCALE_GERMAN */ /* German locale */ +/* #define LOCALE_DEFAULT */ /* United States locale */ + + +#define INCLUDE_CMD_ATTRIB +//#define INCLUDE_CMD_BREAK +#define INCLUDE_CMD_CHCP +#define INCLUDE_CMD_CHDIR +#define INCLUDE_CMD_CLS +#define INCLUDE_CMD_COLOR +#define INCLUDE_CMD_COPY +//#define INCLUDE_CMD_CTTY +#define INCLUDE_CMD_DATE +#define INCLUDE_CMD_DEL +#define INCLUDE_CMD_DIR +#define INCLUDE_CMD_LABEL +#define INCLUDE_CMD_MKDIR +#define INCLUDE_CMD_MOVE +#define INCLUDE_CMD_PATH +#define INCLUDE_CMD_PROMPT +#define INCLUDE_CMD_RMDIR +#define INCLUDE_CMD_RENAME +#define INCLUDE_CMD_SET +#define INCLUDE_CMD_TIME +#define INCLUDE_CMD_TYPE +#define INCLUDE_CMD_VER +#define INCLUDE_CMD_REM +#define INCLUDE_CMD_PAUSE +#define INCLUDE_CMD_BEEP +#define INCLUDE_CMD_VERIFY +#define INCLUDE_CMD_VOL + +/* +command that do not have a define: + +exit +call +echo +goto +for +if +shift + +*/ + diff --git a/rosapps/cmd/console.c b/rosapps/cmd/console.c new file mode 100644 index 00000000000..c740f2a2ed7 --- /dev/null +++ b/rosapps/cmd/console.c @@ -0,0 +1,273 @@ +/* + * CONSOLE.C - console input/output functions. + * + * + * History: + * + * 20-Jan-1999 (Eric Kohl ) + * started + */ + + + +#define WIN32_LEAN_AND_MEAN + +#include +#include + +#include "cmd.h" + + + +/* internal variables for paged output */ +SHORT sLineCount; +SHORT sMaxLines; +BOOL bPageable; + + + +#ifdef _DEBUG +VOID DebugPrintf (LPTSTR szFormat, ...) +{ + TCHAR szOut[512]; + va_list arg_ptr; + + va_start (arg_ptr, szFormat); + wvsprintf (szOut, szFormat, arg_ptr); + va_end (arg_ptr); + + OutputDebugString (szOut); +} +#endif /* _DEBUG */ + + +VOID ConInDummy (VOID) +{ + HANDLE hInput = GetStdHandle (STD_INPUT_HANDLE); + INPUT_RECORD dummy; + DWORD dwRead; + +#ifdef _DEBUG + if (hInput == INVALID_HANDLE_VALUE) + DebugPrintf ("Invalid input handle!!!\n"); +#endif + + ReadConsoleInput (hInput, &dummy, 1, &dwRead); +} + + +VOID ConInKey (PINPUT_RECORD lpBuffer) +{ + HANDLE hInput = GetStdHandle (STD_INPUT_HANDLE); + DWORD dwRead; + +#ifdef _DEBUG + if (hInput == INVALID_HANDLE_VALUE) + DebugPrintf ("Invalid input handle!!!\n"); +#endif + + do + { + WaitForSingleObject (hInput, INFINITE); + ReadConsoleInput (hInput, lpBuffer, 1, &dwRead); + if ((lpBuffer->EventType == KEY_EVENT) && + (lpBuffer->Event.KeyEvent.bKeyDown == TRUE)) + break; + } + while (TRUE); +} + + + +VOID ConInString (LPTSTR lpInput, DWORD dwLength) +{ + DWORD dwOldMode; + DWORD dwRead; + HANDLE hFile; + + LPTSTR p; + DWORD i; + + ZeroMemory (lpInput, dwLength * sizeof(TCHAR)); + hFile = GetStdHandle (STD_INPUT_HANDLE); + GetConsoleMode (hFile, &dwOldMode); + + SetConsoleMode (hFile, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT); + + ReadFile (hFile, lpInput, dwLength, &dwRead, NULL); + + p = lpInput; + for (i = 0; i < dwRead; i++, p++) + { + if (*p == _T('\x0d')) + { + *p = _T('\0'); + break; + } + } + + SetConsoleMode (hFile, dwOldMode); +} + + +VOID ConOutChar (TCHAR c) +{ + DWORD dwWritten; + + WriteFile (GetStdHandle (STD_OUTPUT_HANDLE), &c, 1, &dwWritten, NULL); +} + + +VOID ConOutPuts (LPTSTR szText) +{ + DWORD dwWritten; + + WriteFile (GetStdHandle (STD_OUTPUT_HANDLE), szText, _tcslen(szText), &dwWritten, NULL); + WriteFile (GetStdHandle (STD_OUTPUT_HANDLE), "\x0a\x0d", 2, &dwWritten, NULL); +} + + +VOID ConOutPrintf (LPTSTR szFormat, ...) +{ + DWORD dwWritten; + TCHAR szOut[256]; + va_list arg_ptr; + + va_start (arg_ptr, szFormat); + wvsprintf (szOut, szFormat, arg_ptr); + va_end (arg_ptr); + + WriteFile (GetStdHandle (STD_OUTPUT_HANDLE), szOut, _tcslen(szOut), &dwWritten, NULL); +} + + +VOID ConErrChar (TCHAR c) +{ + DWORD dwWritten; + + WriteFile (GetStdHandle (STD_ERROR_HANDLE), &c, 1, &dwWritten, NULL); +} + + +VOID ConErrPuts (LPTSTR szText) +{ + DWORD dwWritten; + + WriteFile (GetStdHandle (STD_ERROR_HANDLE), szText, _tcslen(szText), &dwWritten, NULL); + WriteFile (GetStdHandle (STD_ERROR_HANDLE), "\x0a\x0d", 2, &dwWritten, NULL); +} + + +VOID ConErrPrintf (LPTSTR szFormat, ...) +{ + DWORD dwWritten; + TCHAR szOut[4096]; + va_list arg_ptr; + + va_start (arg_ptr, szFormat); + wvsprintf (szOut, szFormat, arg_ptr); + va_end (arg_ptr); + + WriteFile (GetStdHandle (STD_ERROR_HANDLE), szOut, _tcslen(szOut), &dwWritten, NULL); +} + + + + +/* + * goxy -- move the cursor on the screen. + */ +VOID goxy (SHORT x, SHORT y) +{ + COORD coPos; + + coPos.X = x; + coPos.Y = y; + SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), coPos); +} + + +SHORT wherex (VOID) +{ + CONSOLE_SCREEN_BUFFER_INFO csbi; + + GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &csbi); + + return csbi.dwCursorPosition.X; +} + + +SHORT wherey (VOID) +{ + CONSOLE_SCREEN_BUFFER_INFO csbi; + + GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &csbi); + + return csbi.dwCursorPosition.Y; +} + + +VOID GetScreenSize (PSHORT maxx, PSHORT maxy) +{ + CONSOLE_SCREEN_BUFFER_INFO csbi; + + GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &csbi); + + if (maxx) + *maxx = csbi.dwSize.X; + if (maxy) + *maxy = csbi.dwSize.Y; +} + + +VOID SetCursorType (BOOL bInsert, BOOL bVisible) +{ + CONSOLE_CURSOR_INFO cci; + + cci.dwSize = bInsert ? 10 : 100; + cci.bVisible = bVisible; + + SetConsoleCursorInfo (GetStdHandle (STD_OUTPUT_HANDLE), &cci); +} + + + +VOID InitializePageOut (VOID) +{ + sLineCount = 0; + + if (GetFileType (GetStdHandle (STD_OUTPUT_HANDLE)) == FILE_TYPE_CHAR) + { + bPageable = TRUE; + GetScreenSize (NULL, &sMaxLines); + } + else + { + bPageable = FALSE; + } +} + + +VOID TerminatePageOut (VOID) +{ + + +} + + + +int LinePageOut (LPTSTR szLine) +{ + ConOutPuts (szLine); + + if (bPageable) + { + sLineCount++; + if (sLineCount >= sMaxLines) + { + sLineCount = 0; + cmd_pause ("", ""); + } + } + return 0; +} diff --git a/rosapps/cmd/copy.c b/rosapps/cmd/copy.c new file mode 100644 index 00000000000..16b561727d0 --- /dev/null +++ b/rosapps/cmd/copy.c @@ -0,0 +1,733 @@ +/* + * COPY.C -- copy internal command. + * + * + * History: + * + * 01-Aug-98 (Rob Lake z63rrl@morgan.ucs.mun.ca) + * started + * + * 13-Aug-1998 (John P. Price) + * fixed memory leak problem in copy function. + * fixed copy function so it would work with wildcards in the source + * + * 13-Dec-1998 (Eric Kohl ) + * Added COPY command to CMD. + * + * 26-Jan-1998 (Eric Kohl ) + * Replaced CRT io functions by Win32 io functions. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_COPY + +#include +#include +#include +#include +#include + +#include "cmd.h" + + +#define VERIFY 1 /* VERIFY Switch */ +#define BINARY 2 /* File is to be copied as BINARY */ +#define ASCII 4 /* File is to be copied as ASCII */ +#define PROMPT 8 /* Prompt before overwriting files */ +#define NPROMPT 16 /* Do not prompt before overwriting files */ +#define HELP 32 /* Help was asked for */ +#define SOURCE 128 /* File is a source */ + + +typedef struct tagFILES +{ + struct tagFILES *next; + TCHAR szFile[MAX_PATH]; + DWORD dwFlag; /* BINARY -xor- ASCII */ +} FILES, *LPFILES; + + +static BOOL DoSwitches (LPTSTR, LPDWORD); +static BOOL AddFile (LPFILES, char *, int *, int *, unsigned *); +static BOOL AddFiles (LPFILES, char *, int *, int *, int *, unsigned *); +static BOOL GetDestination (LPFILES, LPFILES); +static INT ParseCommand (LPFILES, int, char **, LPDWORD); +static VOID DeleteFileList (LPFILES); +static INT Overwrite (LPTSTR); + + + +static BOOL IsDirectory (LPTSTR fn) +{ + if (!IsValidFileName (fn)) + return FALSE; + return (GetFileAttributes (fn) & FILE_ATTRIBUTE_DIRECTORY); +} + + +static BOOL DoSwitches (LPTSTR arg, LPDWORD lpdwFlags) +{ + if (!_tcsicmp (arg, _T("/-Y"))) + { + *lpdwFlags |= PROMPT; + *lpdwFlags &= ~NPROMPT; + return TRUE; + } + else if (_tcslen (arg) > 2) + { + error_too_many_parameters (""); + return FALSE; + } + + switch (_totupper (arg[1])) + { + case _T('V'): + *lpdwFlags |= VERIFY; + break; + + case _T('A'): + *lpdwFlags |= ASCII; + *lpdwFlags &= ~BINARY; + break; + + case _T('B'): + *lpdwFlags |= BINARY; + *lpdwFlags &= ~ASCII; + break; + + case _T('Y'): + *lpdwFlags &= ~PROMPT; + *lpdwFlags |= NPROMPT; + break; + + default: + error_invalid_switch (arg[1]); + return FALSE; + } + return TRUE; +} + + +static BOOL +AddFile (LPFILES f, char *arg, int *source, int *dest, unsigned *flags) +{ + if (*dest) + { + error_too_many_parameters (""); + return FALSE; + } + if (*source) + { + *dest = 1; + f->dwFlag = 0; + } + else + { + *source = 1; + f->dwFlag = SOURCE; + } + _tcscpy(f->szFile, arg); + f->dwFlag |= *flags & ASCII ? ASCII : BINARY; + if ((f->next = (LPFILES)malloc (sizeof (FILES))) == NULL) + { + error_out_of_memory (); + return FALSE; + } + f = f->next; + f->dwFlag = 0; + f->next = NULL; + return TRUE; +} + + +static BOOL +AddFiles (LPFILES f, char *arg, int *source, int *dest, + int *count, unsigned *flags) +{ + char t[128]; + int j; + int k; + + if (*dest) + { + error_too_many_parameters (""); + return FALSE; + } + + j = 0; + k = 0; + + while (arg[j] == _T('+')) + j++; + + while (arg[j] != _T('\0')) + { + t[k] = arg[j++]; + if (t[k] == '+' || arg[j] == _T('\0')) + { + if (!k) + continue; + if (arg[j] == _T('\0') && t[k] != _T('+')) + k++; + t[k] = _T('\0'); + *count += 1; + _tcscpy (f->szFile, t); + *source = 1; + if (*flags & ASCII) + f->dwFlag |= *flags | SOURCE | ASCII; + else + f->dwFlag |= *flags | BINARY | SOURCE; + + if ((f->next = (LPFILES)malloc (sizeof (FILES))) == NULL) + { + error_out_of_memory (); + return FALSE; + } + f = f->next; + f->next = NULL; + k = 0; + f->dwFlag = 0; + continue; + } + k++; + } + + if (arg[--j] == _T('+')) + *source = 0; + + return 1; +} + + +static BOOL GetDestination (LPFILES f, LPFILES dest) +{ + LPFILES p; + LPFILES start = f; + + while (f->next != NULL) + { + p = f; + f = f->next; + } + + f = p; + + if ((f->dwFlag & SOURCE) == 0) + { + free (p->next); + p->next = NULL; + _tcscpy (dest->szFile, f->szFile); + dest->dwFlag = f->dwFlag; + dest->next = NULL; + f = start; + return TRUE; + } + + return FALSE; +} + + +static INT +ParseCommand (LPFILES f, int argc, char **arg, LPDWORD lpdwFlags) +{ + INT i; + INT dest; + INT source; + INT count; + + dest = 0; + source = 0; + count = 0; + + for (i = 0; i < argc; i++) + { + if (arg[i][0] == _T('/')) + { + if (!DoSwitches (arg[i], lpdwFlags)) + return -1; + } + else + { + if (!_tcscmp(arg[i], _T("+"))) + source = 0; + else if (!_tcschr(arg[i], _T('+')) && source) + { + if (!AddFile(f, arg[i], &source, &dest, lpdwFlags)) + return -1; + f = f->next; + count++; + } + else + { + if (!AddFiles(f, arg[i], &source, &dest, &count, lpdwFlags)) + return -1; + while (f->next != NULL) + f = f->next; + } + } + } +#ifdef _DEBUG + DebugPrintf ("ParseCommand: flags has %s\n", + *lpdwFlags & ASCII ? "ASCII" : "BINARY"); +#endif + return count; +} + + +static VOID DeleteFileList (LPFILES f) +{ + LPFILES temp; + + while (f != NULL) + { + temp = f; + f = f->next; + free (temp); + } +} + + +static INT +Overwrite (LPTSTR fn) +{ + TCHAR inp[10]; + LPTSTR p; + + ConOutPrintf (_T("Overwrite %s (Yes/No/All)? "), fn); + ConInString (inp, 10); + + _tcsupr (inp); + for (p = inp; _istspace (*p); p++) + ; + + if (*p != _T('Y') && *p != _T('A')) + return 0; + if (*p == _T('A')) + return 2; + + return 1; +} + + +#define BUFF_SIZE 16384 /* 16k = max buffer size */ + + +int copy (LPTSTR source, LPTSTR dest, int append, LPDWORD lpdwFlags) +{ + FILETIME srctime; + HANDLE hFileSrc; + HANDLE hFileDest; + LPBYTE buffer; + DWORD dwAttrib; + DWORD dwRead; + DWORD dwWritten; + DWORD i; + BOOL bEof = FALSE; + +#ifdef _DEBUG + DebugPrintf ("checking mode\n"); +#endif + + dwAttrib = GetFileAttributes (source); + + hFileSrc = CreateFile (source, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, 0, NULL); + if (hFileSrc == INVALID_HANDLE_VALUE) + { + ConErrPrintf (_T("Error: Cannot open source - %s!\n"), source); + return 0; + } + +#ifdef _DEBUG + DebugPrintf (_T("getting time\n")); +#endif + + GetFileTime (hFileSrc, &srctime, NULL, NULL); + +#ifdef _DEBUG + DebugPrintf (_T("copy: flags has %s\n"), + *lpdwFlags & ASCII ? "ASCII" : "BINARY"); +#endif + + if (!IsValidFileName (dest)) + { +#ifdef _DEBUG + DebugPrintf (_T("opening/creating\n")); +#endif + hFileDest = + CreateFile (dest, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + } + else if (!append) + { + if (!_tcscmp (dest, source)) + { + ConErrPrintf (_T("Error: Can't copy onto itself!\n")); + CloseHandle (hFileSrc); + return 0; + } + +#ifdef _DEBUG + DebugPrintf (_T("SetFileAttributes (%s, FILE_ATTRIBUTE_NORMAL);\n"), dest); +#endif + SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL); + +#ifdef _DEBUG + DebugPrintf (_T("DeleteFile (%s);\n"), dest); +#endif + DeleteFile (dest); + + hFileDest = + CreateFile (dest, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + } + else + { + LONG lFilePosHigh = 0; + + if (!_tcscmp (dest, source)) + { + CloseHandle (hFileSrc); + return 0; + } + +#ifdef _DEBUG + DebugPrintf (_T("opening/appending\n")); +#endif + hFileDest = + CreateFile (dest, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + SetFilePointer (hFileDest, 0, &lFilePosHigh,FILE_END); + } + + if (hFileDest == INVALID_HANDLE_VALUE) + { + CloseHandle (hFileSrc); + error_path_not_found (); + return 0; + } + + buffer = (LPBYTE)malloc (BUFF_SIZE); + if (buffer == NULL) + { + CloseHandle (hFileDest); + CloseHandle (hFileSrc); + error_out_of_memory (); + return 0; + } + + ConOutPuts (source); + + do + { + ReadFile (hFileSrc, buffer, BUFF_SIZE, &dwRead, NULL); + if (*lpdwFlags & ASCII) + { + for (i = 0; i < dwRead; i++) + { + if (((LPTSTR)buffer)[i] == 0x1A) + { + bEof = TRUE; + break; + } + } + dwRead = i; + } + + if (dwRead == 0) + break; + + WriteFile (hFileDest, buffer, dwRead, &dwWritten, NULL); + if (dwWritten != dwRead) + { + ConErrPrintf (_T("Error writing destination!\n")); + free (buffer); + CloseHandle (hFileDest); + CloseHandle (hFileSrc); + return 0; + } + } + while (dwRead && !bEof); + +#ifdef _DEBUG + DebugPrintf (_T("setting time\n")); +#endif + SetFileTime (hFileDest, &srctime, NULL, NULL); + + if (*lpdwFlags & ASCII) + { + ((LPTSTR)buffer)[0] = 0x1A; + ((LPTSTR)buffer)[1] = _T('\0'); +#ifdef _DEBUG + DebugPrintf (_T("appending ^Z\n")); +#endif + WriteFile (hFileDest, buffer, sizeof(TCHAR), &dwWritten, NULL); + } + + free (buffer); + CloseHandle (hFileDest); + CloseHandle (hFileSrc); + +#ifdef _DEBUG + DebugPrintf (_T("setting mode\n")); +#endif + SetFileAttributes (dest, dwAttrib); + + return 1; +} + + +int setup_copy (LPFILES sources, char **p, BOOL bMultiple, + char *drive_d, char *dir_d, char *file_d, + char *ext_d, int *append, LPDWORD lpdwFlags) +{ + WIN32_FIND_DATA find; + + char drive_s[_MAX_DRIVE], + dir_s[_MAX_DIR], + file_s[_MAX_FNAME], + ext_s[_MAX_EXT]; + char from_merge[_MAX_PATH]; + + LPTSTR real_source; + LPTSTR real_dest; + + INT nCopied = 0; + BOOL bAll = FALSE; + BOOL bDone; + HANDLE hFind; + + + real_source = (LPTSTR)malloc (MAX_PATH); + real_dest = (LPTSTR)malloc (MAX_PATH); + + if (!real_source || !real_dest) + { + error_out_of_memory (); + DeleteFileList (sources); + free (real_source); + free (real_dest); + freep (p); + return 0; + } + + while (sources->next != NULL) + { + _splitpath (sources->szFile, drive_s, dir_s, file_s, ext_s); + hFind = FindFirstFile (sources->szFile, &find); + if (hFind == INVALID_HANDLE_VALUE) + { + error_file_not_found(); + DeleteFileList (sources); + freep(p); + free(real_source); + free(real_dest); + return 0; + } + + do + { + if (find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + goto next; + + _makepath(from_merge, drive_d, dir_d, file_d, ext_d); + if (from_merge[_tcslen(from_merge) - 1] == _T('\\')) + from_merge[_tcslen(from_merge) - 1] = 0; + + if (IsDirectory (from_merge)) + { + bMultiple = FALSE; + _tcscat (from_merge, _T("\\")); + _tcscat (from_merge, find.cFileName); + } + else + bMultiple = TRUE; + + _tcscpy (real_dest, from_merge); + _makepath (real_source, drive_s, dir_s, find.cFileName, NULL); + +#ifdef _DEBUG + DebugPrintf (_T("copying %s -> %s (%sappending%s)\n"), + real_source, real_dest, + *append ? "" : "not ", + sources->dwFlag & ASCII ? ", ASCII" : ", BINARY"); +#endif + + if (IsValidFileName (real_dest) && !bAll) + { + int over = Overwrite (real_dest); + if (over == 2) + bAll = TRUE; + else if (over == 0) + goto next; + else if (bMultiple) + bAll = TRUE; + } + if (copy (real_source, real_dest, *append, lpdwFlags)) + nCopied++; + next: + bDone = FindNextFile (hFind, &find); + + if (bMultiple) + *append = 1; + } + while (bDone); + + FindClose (hFind); + sources = sources->next; + + } + free (real_source); + free (real_dest); + + return nCopied; +} + + +INT cmd_copy (LPTSTR first, LPTSTR rest) +{ + char **p; + char drive_d[_MAX_DRIVE], + dir_d[_MAX_DIR], + file_d[_MAX_FNAME], + ext_d[_MAX_EXT]; + + int argc, + append, + files, + copied; + + LPFILES sources; + FILES dest; + LPFILES start; + BOOL bMultiple; + BOOL bWildcards; + BOOL bDestFound; + DWORD dwFlags = 0; + + if (!_tcsncmp (rest, _T("/?"), 2)) + { + ConOutPuts (_T("Copies one or more files to another location.\n" + "\n" + "COPY [/V][/Y|/-Y][/A|/B] source [/A|/B]\n" + " [+ source [/A|/B] [+ ...]] [destination [/A|/B]]\n" + "\n" + " source Specifies the file or files to be copied.\n" + " /A Indicates an ASCII text file.\n" + " /B Indicates a binary file.\n" + " destination Specifies the directory and/or filename for the new file(s).\n" + " /V Verifies that new files are written correctly.\n" + " /Y Suppresses prompting to confirm you want to overwrite an\n" + " existing destination file.\n" + " /-Y Causes prompting to confirm you want to overwrite an\n" + " existing destination file.\n" + "\n" + "The switch /Y may be present in the COPYCMD environment variable.\n" + "...")); + return 1; + } + + p = split (rest, &argc); + + if (argc == 0) + { + error_req_param_missing (); + return 0; + } + + sources = (LPFILES)malloc (sizeof (FILES)); + if (!sources) + { + error_out_of_memory (); + return 0; + } + sources->next = NULL; + sources->dwFlag = 0; + + if ((files = ParseCommand (sources, argc, p, &dwFlags)) == -1) + { + DeleteFileList (sources); + freep (p); + return 0; + } + else if (files == 0) + { + error_req_param_missing(); + DeleteFileList (sources); + freep (p); + return 0; + } + start = sources; + + bDestFound = GetDestination (sources, &dest); + if (bDestFound) + { + _splitpath (dest.szFile, drive_d, dir_d, file_d, ext_d); + if (IsDirectory (dest.szFile)) + { + _tcscat (dir_d, file_d); + _tcscat (dir_d, ext_d); + file_d[0] = _T('\0'); + ext_d[0] = _T('\0'); + } + } + + if (_tcschr (dest.szFile, _T('*')) || _tcschr (dest.szFile, _T('?'))) + bWildcards = TRUE; + else + bWildcards = FALSE; + + if (strchr(rest, '+')) + bMultiple = TRUE; + else + bMultiple = FALSE; + + append = 0; + copied = 0; + + if (bDestFound && !bWildcards) + { + copied = setup_copy (sources, p, bMultiple, drive_d, dir_d, file_d, ext_d, &append, &dwFlags); + } + else if (bDestFound && bWildcards) + { + ConErrPrintf (_T("Error: Not implemented yet!\n")); + DeleteFileList (sources); + freep (p); + return 0; + } + else if (!bDestFound && !bMultiple) + { + _splitpath (sources->szFile, drive_d, dir_d, file_d, ext_d); + if (IsDirectory (sources->szFile)) + { + _tcscat (dir_d, file_d); + _tcscat (dir_d, ext_d); + file_d[0] = _T('\0'); + ext_d[0] = _T('\0'); + } + copied = setup_copy (sources, p, FALSE, "", "", file_d, ext_d, &append, &dwFlags); + } + else + { + _splitpath(sources->szFile, drive_d, dir_d, file_d, ext_d); + if (IsDirectory (sources->szFile)) + { + _tcscat (dir_d, file_d); + _tcscat (dir_d, ext_d); + file_d[0] = _T('\0'); + ext_d[0] = _T('\0'); + } + + ConOutPuts (sources->szFile); + append = 1; + copied = setup_copy (sources->next, p, bMultiple, drive_d, dir_d, file_d, ext_d, &append, &dwFlags) + 1; + } + + DeleteFileList (start); + freep (p); + ConOutPrintf (_T(" %d file(s) copied\n"), copied); + + return 1; +} +#endif /* INCLUDE_CMD_COPY */ diff --git a/rosapps/cmd/date.c b/rosapps/cmd/date.c new file mode 100644 index 00000000000..e2712366d85 --- /dev/null +++ b/rosapps/cmd/date.c @@ -0,0 +1,298 @@ +/* + * DATE.C - date internal command. + * + * + * History: + * + * 08 Jul 1998 (John P. Price) + * started. + * + * 20 Jul 1998 (John P. Price) + * corrected number of days for December from 30 to 31. + * (Thanx to Steffen Kaiser for bug report) + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 29-Jul-1998 (Rob Lake) + * fixed stand-alone mode. + * Added Pacific C compatible dos_getdate functions + * + * 09-Jan-1999 (Eric Kohl ) + * Added locale support + * + * 23-Jan-1999 (Eric Kohl ) + * Unicode and redirection safe! + * + * 04-Feb-1999 (Eric Kohl ) + * Fixed date input bug. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_DATE + +#include +#include +#include +#include + +#include "cmd.h" + + +static WORD awMonths[2][13] = +{ + {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} +}; + + +static VOID +PrintDate (VOID) +{ +#if 0 + SYSTEMTIME st; + + GetLocalTime (&st); + + switch (nDateFormat) + { + case 0: /* mmddyy */ + default: + ConOutPrintf (_T("Current date is: %s %02d%c%02d%c%04d\n"), + aszDayNames[st.wDayOfWeek], st.wMonth, cDateSeparator, st.wDay, cDateSeparator, st.wYear); + break; + + case 1: /* ddmmyy */ + ConOutPrintf (_T("Current date is: %s %02d%c%02d%c%04d\n"), + aszDayNames[st.wDayOfWeek], st.wDay, cDateSeparator, st.wMonth, cDateSeparator, st.wYear); + break; + + case 2: /* yymmdd */ + ConOutPrintf (_T("Current date is: %s %04d%c%02d%c%02d\n"), + aszDayNames[st.wDayOfWeek], st.wYear, cDateSeparator, st.wMonth, cDateSeparator, st.wDay); + break; + } +#endif + TCHAR szDate[32]; + + GetDateFormat (LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, + szDate, sizeof (szDate)); + ConOutPrintf (_T("Current date is: %s\n"), szDate); +} + + +static VOID +PrintDateString (VOID) +{ + switch (nDateFormat) + { + case 0: /* mmddyy */ + default: + ConOutPrintf (_T("Enter new date (mm%cdd%cyyyy): "), + cDateSeparator, cDateSeparator); + break; + + case 1: /* ddmmyy */ + ConOutPrintf (_T("Enter new date (dd%cmm%cyyyy): "), + cDateSeparator, cDateSeparator); + break; + + case 2: /* yymmdd */ + ConOutPrintf (_T("Enter new date (yyyy%cmm%cdd): "), + cDateSeparator, cDateSeparator); + break; + } +} + + +static BOOL +ReadNumber (LPTSTR *s, LPWORD lpwValue) +{ + if (_istdigit (**s)) + { + while (_istdigit (**s)) + { + *lpwValue = *lpwValue * 10 + **s - _T('0'); + (*s)++; + } + return TRUE; + } + return FALSE; +} + + +static BOOL +ReadSeparator (LPTSTR *s) +{ + if (**s == _T('/') || **s == _T('-') || **s == cDateSeparator) + { + (*s)++; + return TRUE; + } + return FALSE; +} + + +static BOOL +ParseDate (LPTSTR s) +{ + SYSTEMTIME d; + unsigned char leap; + LPTSTR p = s; + + if (!*s) + return TRUE; + + GetLocalTime (&d); + + d.wYear = 0; + d.wDay = 0; + d.wMonth = 0; + + switch (nDateFormat) + { + case 0: /* mmddyy */ + default: + if (!ReadNumber (&p, &d.wMonth)) + return FALSE; + if (!ReadSeparator (&p)) + return FALSE; + if (!ReadNumber (&p, &d.wDay)) + return FALSE; + if (!ReadSeparator (&p)) + return FALSE; + if (!ReadNumber (&p, &d.wYear)) + return FALSE; + break; + + case 1: /* ddmmyy */ + if (!ReadNumber (&p, &d.wDay)) + return FALSE; + if (!ReadSeparator (&p)) + return FALSE; + if (!ReadNumber (&p, &d.wMonth)) + return FALSE; + if (!ReadSeparator (&p)) + return FALSE; + if (!ReadNumber (&p, &d.wYear)) + return FALSE; + break; + + case 2: /* yymmdd */ + if (!ReadNumber (&p, &d.wYear)) + return FALSE; + if (!ReadSeparator (&p)) + return FALSE; + if (!ReadNumber (&p, &d.wMonth)) + return FALSE; + if (!ReadSeparator (&p)) + return FALSE; + if (!ReadNumber (&p, &d.wDay)) + return FALSE; + break; + } + + /* if only entered two digits: + /* assume 2000's if value less than 80 */ + /* assume 1900's if value greater or equal 80 */ + if (d.wYear <= 99) + { + if (d.wYear >= 80) + d.wYear = 1900 + d.wYear; + else + d.wYear = 2000 + d.wYear; + } + + leap = (!(d.wYear % 4) && (d.wYear % 100)) || !(d.wYear % 400); + + if ((d.wMonth >= 1 && d.wMonth <= 12) && + (d.wDay >= 1 && d.wDay <= awMonths[leap][d.wMonth]) && + (d.wYear >= 1980 && d.wYear <= 2099)) + { + SetLocalTime (&d); + return TRUE; + } + + return FALSE; +} + + +INT cmd_date (LPTSTR cmd, LPTSTR param) +{ + LPTSTR *arg; + INT argc; + INT i; + BOOL bPrompt = TRUE; + INT nDateString = -1; + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Displays or sets the date.\n\n" + "DATE [/T][date]\n\n" + " /T display only\n\n" + "Type DATE without parameters to display the current date setting and\n" + "a prompt for a new one. Press ENTER to keep the same date.")); + return 0; + } + + /* build parameter array */ + arg = split (param, &argc); + + /* check for options */ + for (i = 0; i < argc; i++) + { + if (_tcsicmp (arg[i], _T("/t")) == 0) + bPrompt = FALSE; + if ((*arg[i] != _T('/')) && (nDateString == -1)) + nDateString = i; + } + + if (nDateString == -1) + PrintDate (); + + if (!bPrompt) + { + freep (arg); + return 0; + } + + if (nDateString == -1) + { + while (TRUE) /* forever loop */ + { + TCHAR s[40]; + + PrintDateString (); + ConInString (s, 40); +#ifdef _DEBUG + DebugPrintf ("\'%s\'\n", s); +#endif + while (*s && s[_tcslen (s) - 1] < ' ') + s[_tcslen (s) - 1] = '\0'; + if (ParseDate (s)) + { + freep (arg); + return 0; + } + ConErrPuts ("Invalid date."); + } + } + else + { + if (ParseDate (arg[nDateString])) + { + freep (arg); + return 0; + } + ConErrPuts ("Invalid date."); + } + + freep (arg); + + return 0; +} +#endif + diff --git a/rosapps/cmd/del.c b/rosapps/cmd/del.c new file mode 100644 index 00000000000..c249670c472 --- /dev/null +++ b/rosapps/cmd/del.c @@ -0,0 +1,271 @@ +/* + * DEL.C - del internal command. + * + * + * History: + * + * 06/29/98 (Rob Lake rlake@cs.mun.ca) + * rewrote del to support wildcards + * added my name to the contributors + * + * 07/13/98 (Rob Lake) + * fixed bug that caused del not to delete file with out + * attribute. moved set, del, ren, and ver to there own files + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 09-Dec-1998 (Eric Kohl ) + * Fixed command line parsing bugs. + * + * 21-Jan-1999 (Eric Kohl ) + * Started major rewrite using a new structure. + * + * 03-Jan-1999 (Eric Kohl ) + * First working version. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_DEL + +#include +#include +#include +#include + +#include "cmd.h" + + +#define PROMPT_NO 0 +#define PROMPT_YES 1 +#define PROMPT_ALL 2 +#define PROMPT_BREAK 3 + + +static BOOL ConfirmDeleteAll (VOID) +{ + TCHAR inp[10]; + LPTSTR p; + + ConOutPrintf ("All files in directory will be deleted!\n" + "Are you sure (Y/N)? "); + ConInString (inp, 10); + + _tcsupr (inp); + for (p = inp; _istspace (*p); p++) + ; + + if (*p == _T('Y')) + return PROMPT_YES; + else if (*p == _T('N')) + return PROMPT_NO; + +#if 0 + if (*p == _T('A')) + return PROMPT_ALL; + else if (*p == _T('\03')) + return PROMPT_BREAK; +#endif + + return PROMPT_NO; +} + + +static INT Prompt (LPTSTR str) +{ + TCHAR inp[10]; + LPTSTR p; + + ConOutPrintf (_T("Delete %s (Yes/No)? "), str); + ConInString (inp, 10); + + _tcsupr (inp); + for (p = inp; _istspace (*p); p++) + ; + + if (*p == _T('Y')) + return PROMPT_YES; + else if (*p == _T('N')) + return PROMPT_NO; + +#if 0 + if (*p == _T('A')) + return PROMPT_ALL; + else if (*p == _T('\03')) + return PROMPT_BREAK; +#endif +} + + + +INT cmd_del (LPTSTR cmd, LPTSTR param) +{ + LPTSTR *arg = NULL; + INT args; + INT i; + INT nEvalArgs = 0; /* nunber of evaluated arguments */ + BOOL bNothing = FALSE; + BOOL bQuiet = FALSE; + BOOL bPrompt = FALSE; + + HANDLE hFile; + WIN32_FIND_DATA f; +// DWORD dwAttributes; + + + if (!_tcsncmp (param, _T("/?"), 2)) + { +/* + ConOutPuts (_T("Deletes one or more files.\n\n" + "DEL [drive:][path]filename [/P]\n" + "DELETE [drive:][path]filename [/P]\n" + "ERASE [drive:][path]filename [/P]\n\n" + " [drive:][path]filename Specifies the file(s) to delete. Specify multiple\n" + " files by using wildcards.\n" + " /P Prompts for confirmation before deleting each file.")); +*/ + + ConOutPuts (_T("Deletes one or more files.\n" + "\n" + "DEL [/N /P /Q] file ...\n" + "DELETE [/N /P /Q] file ...\n" + "ERASE [/N /P /Q] file ...\n" + "\n" + " file Specifies the file(s) to delete.\n" + "\n" + " /N Nothing.\n" + " /P Prompts for confirmation before deleting each file.\n" + " (Not implemented yet!)\n" + " /Q Quiet." + )); + + return 0; + } + + arg = split (param, &args); + + if (args > 0) + { + /* check for options anywhere in command line */ + for (i = 0; i < args; i++) + { + if (*arg[i] == _T('/')) + { + if (_tcslen (arg[i]) >= 2) + { + switch (_totupper (arg[i][1])) + { + case _T('N'): + bNothing = TRUE; + break; + + case _T('P'): + bPrompt = TRUE; + break; + + case _T('Q'): + bQuiet = TRUE; + break; + } + + } + + nEvalArgs++; + } + } + + /* there are only options on the command line --> error!!! */ + if (args == nEvalArgs) + { + error_req_param_missing (); + freep (arg); + return 1; + } + + /* check for filenames anywhere in command line */ + for (i = 0; i < args; i++) + { + if (!_tcscmp (arg[i], _T("*")) || + !_tcscmp (arg[i], _T("*.*"))) + { + if (!ConfirmDeleteAll ()) + break; + + } + + if (*arg[i] != _T('/')) + { +#ifdef _DEBUG + ConErrPrintf ("File: %s\n", arg[i]); +#endif + + if (_tcschr (arg[i], _T('*')) || _tcschr (arg[i], _T('?'))) + { + /* wildcards in filespec */ +#ifdef _DEBUG + ConErrPrintf ("Wildcards!\n\n"); +#endif + + hFile = FindFirstFile (arg[i], &f); + if (hFile == INVALID_HANDLE_VALUE) + { + error_file_not_found (); + freep (arg); + return 0; + } + + do + { + if (!_tcscmp (f.cFileName, _T(".")) || + !_tcscmp (f.cFileName, _T(".."))) + continue; + +#ifdef _DEBUG + ConErrPrintf ("Delete file: %s\n", f.cFileName); +#endif + + if (!bNothing) + { + if (!DeleteFile (f.cFileName)) + ErrorMessage (GetLastError(), _T("")); + } + + + } + while (FindNextFile (hFile, &f)); + FindClose (hFile); + } + else + { + /* no wildcards in filespec */ +#ifdef _DEBUG + ConErrPrintf ("No Wildcards!\n"); + ConErrPrintf ("Delete file: %s\n", arg[i]); +#endif + + if (!bNothing) + { + if (!DeleteFile (arg[i])) + ErrorMessage (GetLastError(), _T("")); + } + } + } + } + } + else + { + /* only command given */ + error_req_param_missing (); + freep (arg); + return 1; + } + + freep (arg); + + return 0; +} + +#endif diff --git a/rosapps/cmd/dir.c b/rosapps/cmd/dir.c new file mode 100644 index 00000000000..c56d8470bb3 --- /dev/null +++ b/rosapps/cmd/dir.c @@ -0,0 +1,1225 @@ +/* + * DIR.C - dir internal command. + * + * + * History: + * + * 01/29/97 (Tim Norman) + * started. + * + * 06/13/97 (Tim Norman) + * Fixed code. + * + * 07/12/97 (Tim Norman) + * Fixed bug that caused the root directory to be unlistable + * + * 07/12/97 (Marc Desrochers) + * Changed to use maxx, maxy instead of findxy() + * + * 06/08/98 (Rob Lake) + * Added compatibility for /w in dir + * + * 06/09/98 (Rob Lake) + * Compatibility for dir/s started + * Tested that program finds directories off root fine + * + * 06/10/98 (Rob Lake) + * do_recurse saves the cwd and also stores it in Root + * build_tree adds the cwd to the beginning of its' entries + * Program runs fine, added print_tree -- works fine.. as EXE, + * program won't work properly as COM. + * + * 06/11/98 (Rob Lake) + * Found problem that caused COM not to work + * + * 06/12/98 (Rob Lake) + * debugged... + * added free mem routine + * + * 06/13/98 (Rob Lake) + * debugged the free mem routine + * debugged whole thing some more + * Notes: + * ReadDir stores Root name and _Read_Dir does the hard work + * PrintDir prints Root and _Print_Dir does the hard work + * KillDir kills Root _after_ _Kill_Dir does the hard work + * Integrated program into DIR.C(this file) and made some same + * changes throughout + * + * 06/14/98 (Rob Lake) + * Cleaned up code a bit, added comments + * + * 06/16/98 (Rob Lake) + * Added error checking to my previously added routines + * + * 06/17/98 (Rob Lake) + * Rewrote recursive functions, again! Most other recursive + * functions are now obsolete -- ReadDir, PrintDir, _Print_Dir, + * KillDir and _Kill_Dir. do_recurse does what PrintDir did + * and _Read_Dir did what it did before along with what _Print_Dir + * did. Makes /s a lot faster! + * Reports 2 more files/dirs that MS-DOS actually reports + * when used in root directory(is this because dir defaults + * to look for read only files?) + * Added support for /b, /a and /l + * Made error message similar to DOS error messages + * Added help screen + * + * 06/20/98 (Rob Lake) + * Added check for /-(switch) to turn off previously defined + * switches. + * Added ability to check for DIRCMD in environment and + * process it + * + * 06/21/98 (Rob Lake) + * Fixed up /B + * Now can dir *.ext/X, no spaces! + * + * 06/29/98 (Rob Lake) + * error message now found in command.h + * + * 07/08/1998 (John P. Price) + * removed extra returns; closer to MSDOS + * fixed wide display so that an extra return is not displayed + * when there is five filenames in the last line. + * + * 07/12/98 (Rob Lake) + * Changed error messages + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * + * 04-Dec-1998 (Eric Kohl ) + * Converted source code to Win32, except recursive dir ("dir /s"). + * + * 10-Dec-1998 (Eric Kohl ) + * Fixed recursive dir ("dir /s"). + * + * 14-Dec-1998 (Eric Kohl ) + * Converted to Win32 directory functions and + * fixed some output bugs. There are still some more ;) + * + * 10-Jan-1999 (Eric Kohl ) + * Added "/N" and "/4" options, "/O" is a dummy. + * Added locale support. + * + * 20-Jan-1999 (Eric Kohl ) + * Redirection safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_DIR +#include +#include +#include +#include +#include + +#include + +#include "cmd.h" + + +/* useful macro */ +#define MEM_ERR error_out_of_memory(); return 1; + + +/* flag definitions */ +/* Changed hex to decimal, hex wouldn't work + * if > 8, Rob Lake 06/17/98. + */ +enum +{ + DIR_RECURSE = 0x0001, + DIR_PAGE = 0x0002, + DIR_WIDE = 0x0004, /* Rob Lake */ + DIR_BARE = 0x0008, /* Rob Lake */ + DIR_ALL = 0x0010, /* Rob Lake */ + DIR_LWR = 0x0020, /* Rob Lake */ + DIR_SORT = 0x0040, /* /O sort */ + DIR_NEW = 0x0080, /* /N new style */ + DIR_FOUR = 0x0100 /* /4 four digit year */ +}; + + +/* Globally save the # of dirs, files and bytes, + * probabaly later pass them to functions. Rob Lake */ +long recurse_dir_cnt; +long recurse_file_cnt; +ULARGE_INTEGER recurse_bytes; + + +/* + * help + * + * displays help screen for dir + * Rob Lake + */ +static VOID Help (VOID) +{ +#if 1 + ConOutPuts (_T("Displays a list of files and subdirectories in a directory.\n" + "\n" + "DIR [drive:][path][filename] [/A] [/B] [/L] [/N] [/S] [/P] [/W] [/4]\n" + "\n" + " [drive:][path][filename]\n" + " Specifies drive, directory, and/or files to list.\n" + "\n" + " /A Displays files with HIDDEN SYSTEM attributes\n" + " default is ARCHIVE and READ ONLY\n" + " /B Uses bare format (no heading information or summary).\n" + " /L Uses lowercase.\n" + " /N New long list format where filenames are on the far right.\n" + " /S Displays files in specified directory and all subdirectories\n" + " /P Pauses after each screen full\n" + " /W Prints in wide format\n" + " /4 Display four digit years.\n" + "\n" + "Switches may be present in the DIRCMD environment variable. Use\n" + "of the - (hyphen) can turn off defined swtiches. Ex. /-W would\n" + "turn off printing in wide format.\n" + )); +#endif +#if 0 + InitializePageOut (); + LinePageOut (_T("Displays a list of files and subdirectories in a directory.")); + LinePageOut (_T("")); + LinePageOut (_T("DIR [drive:][path][filename] [/A] [/B] [/L] [/N] [/S] [/P] [/W] [/4]")); + LinePageOut (_T("")); + LinePageOut (_T(" [drive:][path][filename]")); + LinePageOut (_T(" Specifies drive, directory, and/or files to list.")); + LinePageOut (_T("")); + LinePageOut (_T(" /A Displays files with HIDDEN SYSTEM attributes")); + LinePageOut (_T(" default is ARCHIVE and READ ONLY")); + LinePageOut (_T(" /B Uses bare format (no heading information or summary).")); + LinePageOut (_T(" /L Uses lowercase.")); + LinePageOut (_T(" /N New long list format where filenames are on the far right.")); + LinePageOut (_T(" /S Displays files in specified directory and all subdirectories")); + LinePageOut (_T(" /P Pauses after each screen full")); + LinePageOut (_T(" /W Prints in wide format")); + LinePageOut (_T(" /4 Display four digit years.")); + LinePageOut (_T("")); + LinePageOut (_T("Switches may be present in the DIRCMD environment variable. Use")); + LinePageOut (_T("of the - (hyphen) can turn off defined swtiches. Ex. /-W would")); + LinePageOut (_T("turn off printing in wide format.")); + TerminatePageOut (); +#endif +} + + +/* + * dir_read_param + * + * read the parameters from the command line + */ +static BOOL +DirReadParam (char *line, char **param, LPDWORD lpFlags) +{ + int slash = 0; + + if (!line) + return TRUE; + + *param = NULL; + + /* scan the command line, processing switches */ + while (*line) + { + /* process switch */ + if (*line == _T('/') || slash) + { + if (!slash) + line++; + slash = 0; + if (*line == _T('-')) + { + line++; + if (_totupper (*line) == _T('S')) + *lpFlags &= ~DIR_RECURSE; + else if (_totupper (*line) == _T('P')) + *lpFlags &= ~DIR_PAGE; + else if (_totupper (*line) == _T('W')) + *lpFlags &= ~DIR_WIDE; + else if (_totupper (*line) == _T('B')) + *lpFlags &= ~DIR_BARE; + else if (_totupper (*line) == _T('A')) + *lpFlags &= ~DIR_ALL; + else if (_totupper (*line) == _T('L')) + *lpFlags &= ~DIR_LWR; + else if (_totupper (*line) == _T('N')) + *lpFlags &= ~DIR_NEW; + else if (_totupper (*line) == _T('O')) + *lpFlags &= ~DIR_SORT; + else if (_totupper (*line) == _T('4')) + *lpFlags &= ~DIR_FOUR; + else + { + error_invalid_switch ((TCHAR)_totupper (*line)); + return FALSE; + } + line++; + continue; + } + else + { + if (_totupper (*line) == _T('S')) + *lpFlags |= DIR_RECURSE; + else if (_toupper (*line) == _T('P')) + *lpFlags |= DIR_PAGE; + else if (_totupper (*line) == _T('W')) + *lpFlags |= DIR_WIDE; + else if (_totupper (*line) == _T('B')) + *lpFlags |= DIR_BARE; + else if (_totupper (*line) == _T('A')) + *lpFlags |= DIR_ALL; + else if (_totupper (*line) == _T('L')) + *lpFlags |= DIR_LWR; + else if (_totupper (*line) == _T('N')) + *lpFlags |= DIR_NEW; + else if (_totupper (*line) == _T('O')) + *lpFlags |= DIR_SORT; + else if (_totupper (*line) == _T('4')) + *lpFlags |= DIR_FOUR; + else if (*line == _T('?')) + { + Help(); + return FALSE; + } + else + { + error_invalid_switch ((TCHAR)_totupper (*line)); + return FALSE; + } + line++; + continue; + } + } + + /* process parameter */ + if (!_istspace (*line)) + { + if (*param) + { + error_too_many_parameters (*param); + return FALSE; + } + + *param = line; + + /* skip to end of line or next whitespace or next / */ + while (*line && !_istspace (*line) && *line != _T('/')) + line++; + + /* if end of line, return */ + if (!*line) + return TRUE; + + /* if parameter, remember to process it later */ + if (*line == _T('/')) + slash = 1; + + *line++ = 0; + continue; + } + + line++; + } + + if (slash) + { + error_invalid_switch ((TCHAR)_totupper (*line)); + return FALSE; + } + + return TRUE; +} + + +/* + * extend_file + * + * extend the filespec, possibly adding wildcards + */ +void extend_file (char **file) +{ + LPTSTR tmp; + + if (!*file) + return; + + /* if no file spec, change to "*.*" */ + if (!**file) + { + free (*file); + *file = _tcsdup (_T("*.*")); + return; + } + + /* if starts with . add * in front */ + if (**file == _T('.')) + { + tmp = malloc ((_tcslen (*file) + 2) * sizeof(TCHAR)); + if (tmp) + { + *tmp = _T('*'); + _tcscpy (&tmp[1], *file); + } + free (*file); + *file = tmp; + return; + } + + /* if no . add .* */ + if (!_tcschr (*file, _T('.'))) + { + tmp = malloc ((_tcslen (*file) + 3) * sizeof(TCHAR)); + if (tmp) + { + _tcscpy (tmp, *file); + _tcscat (tmp, _T(".*")); + } + free (*file); + *file = tmp; + return; + } +} + + +/* + * dir_parse_pathspec + * + * split the pathspec into drive, directory, and filespec + */ +static int +DirParsePathspec (char *pathspec, int *drive, char **dir, char **file) +{ + TCHAR orig_dir[MAX_PATH]; + LPTSTR start; + LPTSTR tmp; + INT i; + INT wildcards = 0; + + + /* get the drive and change to it */ + if (pathspec[1] == _T(':')) + { + *drive = _totupper (pathspec[0]) - _T('@'); + start = pathspec + 2; + _chdrive (*drive); + } + else + { + *drive = _getdrive (); + start = pathspec; + } + + GetCurrentDirectory (MAX_PATH, orig_dir); + + /* check for wildcards */ + for (i = 0; pathspec[i]; i++) + if (pathspec[i] == _T('*') || pathspec[i] == _T('?')) + wildcards = 1; + + /* check if this spec is a directory */ + if (!wildcards) + { + if (chdir(pathspec) == 0) + { + *file = _tcsdup (_T("*.*")); + if (!*file) + { + MEM_ERR + } + + tmp = getcwd (NULL, MAX_PATH); + if (!tmp) + { + free (*file); + chdir (orig_dir); + MEM_ERR + } + + *dir = _tcsdup (&tmp[2]); + free (tmp); + if (!*dir) + { + free (*file); + chdir (orig_dir); + MEM_ERR + } + + chdir (orig_dir); + return 0; + } + } + + /* find the file spec */ + tmp = _tcsrchr (start, _T('\\')); + + /* if no path is specified */ + if (!tmp) + { + *file = _tcsdup (start); + extend_file (file); + if (!*file) + { + MEM_ERR + } + + tmp = getcwd (NULL, _MAX_PATH); + if (!tmp) + { + free (*file); + chdir (orig_dir); + MEM_ERR + } + *dir = _tcsdup (&tmp[2]); + free(tmp); + if (!*dir) + { + free (*file); + chdir (orig_dir); + MEM_ERR + } + + return 0; + } + + /* get the filename */ + *file = _tcsdup (tmp + 1); + extend_file (file); + if (!*file) + { + MEM_ERR + } + + *tmp = 0; + + /* change to this directory and get its full name */ + if (chdir (start) < 0) + { + error_path_not_found (); + *tmp = _T('\\'); + free (*file); + chdir (orig_dir); + return 1; + } + + tmp = getcwd (NULL, _MAX_PATH); + if (!tmp) + { + free (*file); + MEM_ERR + } + *dir = _tcsdup (&tmp[2]); + free(tmp); + if (!*dir) + { + free(*file); + MEM_ERR + } + + *tmp = _T('\\'); + + chdir(orig_dir); + return 0; +} + + +/* + * pause + * + * pause until a key is pressed + */ +static INT +Pause (VOID) +{ + cmd_pause ("", ""); + + return 0; +} + + +/* + * incline + * + * increment our line if paginating, display message at end of screen + */ +static INT +incline (int *line, DWORD dwFlags) +{ + if (!(dwFlags & DIR_PAGE)) + return 0; + + (*line)++; + + if (*line >= (int)maxy - 2) + { + *line = 0; + return Pause (); + } + + return 0; +} + + +/* + * PrintDirectoryHeader + * + * print the header for the dir command + */ +static BOOL +PrintDirectoryHeader (int drive, int *line, DWORD dwFlags) +{ + TCHAR szRootName[] = _T("A:\\"); + TCHAR szVolName[80]; + DWORD dwSerialNr; + + if (dwFlags & DIR_BARE) + return TRUE; + + /* get the media ID of the drive */ + szRootName[0] = drive + _T('@'); + if (!GetVolumeInformation (szRootName, szVolName, 80, &dwSerialNr, + NULL, NULL, NULL, 0)) + { + error_invalid_drive(); + return FALSE; + } + + /* print drive info */ + ConOutPrintf (_T(" Volume in drive %c"), szRootName[0]); + + if (szVolName[0] != _T('\0')) + ConOutPrintf (_T(" is %s\n"), szVolName); + else + ConOutPrintf (_T(" has no label\n")); + + if (incline (line, dwFlags) != 0) + return FALSE; + + /* print the volume serial number if the return was successful */ + ConOutPrintf (_T(" Volume Serial Number is %04X-%04X\n"), + HIWORD(dwSerialNr), LOWORD(dwSerialNr)); + if (incline (line, dwFlags) != 0) + return FALSE; + + return TRUE; +} + + +/* + * convert + * + * insert commas into a number + */ +static INT +ConvertLong (LONG num, LPTSTR des, INT len) +{ + TCHAR temp[32]; + INT c = 0; + INT n = 0; + + if (num == 0) + { + des[0] = _T('0'); + des[1] = _T('\0'); + n = 1; + } + else + { + temp[31] = 0; + while (num > 0) + { + if (((c + 1) % (nNumberGroups + 1)) == 0) + temp[30 - c++] = cThousandSeparator; + temp[30 - c++] = (TCHAR)(num % 10) + _T('0'); + num /= 10; + } + + for (n = 0; n <= c; n++) + des[n] = temp[31 - c + n]; + } + + return n; +} + + +static INT +ConvertULargeInteger (ULARGE_INTEGER num, LPTSTR des, INT len) +{ + TCHAR temp[32]; + INT c = 0; + INT n = 0; + + if (num.QuadPart == 0) + { + des[0] = _T('0'); + des[1] = _T('\0'); + n = 1; + } + else + { + temp[31] = 0; + while (num.QuadPart > 0) + { + if (((c + 1) % (nNumberGroups + 1)) == 0) + temp[30 - c++] = cThousandSeparator; + temp[30 - c++] = (TCHAR)(num.QuadPart % 10) + _T('0'); + num.QuadPart /= 10; + } + + for (n = 0; n <= c; n++) + des[n] = temp[31 - c + n]; + } + + return n; +} + + +static VOID +PrintFileDateTime (LPSYSTEMTIME dt, DWORD dwFlags) +{ + WORD wYear = (dwFlags & DIR_FOUR) ? dt->wYear : dt->wYear%100; + + switch (nDateFormat) + { + case 0: /* mmddyy */ + default: + ConOutPrintf ("%.2d%c%.2d%c%d", dt->wMonth, cDateSeparator, dt->wDay, cDateSeparator, wYear); + break; + + case 1: /* ddmmyy */ + ConOutPrintf ("%.2d%c%.2d%c%d", + dt->wDay, cDateSeparator, dt->wMonth, cDateSeparator, wYear); + break; + + case 2: /* yymmdd */ + ConOutPrintf ("%d%c%.2d%c%.2d", + wYear, cDateSeparator, dt->wMonth, cDateSeparator, dt->wDay); + break; + } + + switch (nTimeFormat) + { + case 0: /* 12 hour format */ + default: + ConOutPrintf (" %2d%c%.2u%c", + (dt->wHour == 0 ? 12 : (dt->wHour <= 12 ? dt->wHour : dt->wHour - 12)), + cTimeSeparator, + dt->wMinute, (dt->wHour <= 11 ? 'a' : 'p')); + break; + + case 1: /* 24 hour format */ + ConOutPrintf (" %2d%c%.2u", + dt->wHour, cTimeSeparator, dt->wMinute); + break; + } +} + + +/* + * print_summary: prints dir summary + * Added by Rob Lake 06/17/98 to compact code + * Just copied Tim's Code and patched it a bit + * + */ +static INT +PrintSummary (int drive, long files, long dirs, ULARGE_INTEGER bytes, + DWORD flags, int *line) +{ + TCHAR buffer[64]; + + if (flags & DIR_BARE) + return 0; + + /* print number of files and bytes */ + ConvertLong (files, buffer, sizeof(buffer)); + ConOutPrintf (_T(" %6s File%c"), + buffer, files == 1 ? _T(' ') : _T('s')); + + ConvertULargeInteger (bytes, buffer, sizeof(buffer)); + ConOutPrintf (_T(" %15s byte%c\n"), + buffer, bytes.QuadPart == 1 ? _T(' ') : _T('s')); + + if (incline (line, flags) != 0) + return 1; + + /* print number of dirs and bytes free */ + ConvertLong (dirs, buffer, sizeof(buffer)); + ConOutPrintf (_T(" %6s Dir%c"), + buffer, files == 1 ? _T(' ') : _T('s')); + + + if (!(flags & DIR_RECURSE)) + { + ULARGE_INTEGER uliFree; + TCHAR szRoot[] = _T("A:\\"); + DWORD dwSecPerCl; + DWORD dwBytPerSec; + DWORD dwFreeCl; + DWORD dwTotCl; + + szRoot[0] = drive + _T('@'); + GetDiskFreeSpace (szRoot, &dwSecPerCl, &dwBytPerSec, &dwFreeCl, &dwTotCl); + uliFree.QuadPart = dwSecPerCl * dwBytPerSec * dwFreeCl; + ConvertULargeInteger (uliFree, buffer, sizeof(buffer)); + ConOutPrintf (_T(" %15s bytes free\n"), buffer); + } + + if (incline (line, flags) != 0) + return 1; + + return 0; +} + + +/* + * dir_list + * + * list the files in the directory + */ +static int +dir_list (int drive, char *directory, char *filespec, int *line, + DWORD flags) +{ + char pathspec[_MAX_PATH], + *ext, + buffer[32]; + WIN32_FIND_DATA file; + ULARGE_INTEGER bytecount; + long filecount = 0, + dircount = 0; + int count; + FILETIME ft; + SYSTEMTIME dt; + HANDLE hFile; + + bytecount.QuadPart = 0; + + if (directory[strlen(directory) - 1] == '\\') + wsprintf(pathspec, "%c:%s%s", drive + '@', directory, filespec); + else + wsprintf(pathspec, "%c:%s\\%s", drive + '@', directory, filespec); + + hFile = FindFirstFile (pathspec, &file); + if (hFile == INVALID_HANDLE_VALUE) + { + /* Don't want to print anything if scanning recursively + * for a file. RL + */ + if ((flags & DIR_RECURSE) == 0) + { + error_file_not_found(); + incline(line, flags); + FindClose (hFile); + return 1; + } + FindClose (hFile); + return 0; + } + + /* moved down here because if we are recursively searching and + * don't find any files, we don't want just to print + * Directory of C:\SOMEDIR + * with nothing else + * Rob Lake 06/13/98 + */ + if ((flags & DIR_BARE) == 0) + { + ConOutPrintf (" Directory of %c:%s\n", drive + '@', directory); + if (incline(line, flags) != 0) + return 1; + ConOutPrintf ("\n"); + if (incline(line, flags) != 0) + return 1; + } + + /* For counting columns of output */ + count = 0; + + do + { + /* next file, if user doesn't want all files */ + if (!(flags & DIR_ALL) && + ((file.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) || + (file.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM))) + continue; + + /* begin Rob Lake */ + if (flags & DIR_LWR) + { + strlwr(file.cAlternateFileName); + } + + if (flags & DIR_WIDE && (flags & DIR_BARE) == 0) + { + if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if (file.cAlternateFileName[0] == '\0') + wsprintf (buffer, _T("[%s]"), file.cFileName); + else + wsprintf (buffer, _T("[%s]"), file.cAlternateFileName); + dircount++; + } + else + { + if (file.cAlternateFileName[0] == '\0') + wsprintf (buffer, _T("%s"), file.cFileName); + else + wsprintf (buffer, _T("%s"), file.cAlternateFileName); + filecount++; + } + ConOutPrintf (_T("%-15s"), buffer); + count++; + if (count == 5) + { + /* output 5 columns */ + ConOutPrintf ("\n"); + if (incline(line, flags) != 0) + return 1; + count = 0; + } + + /* FIXME: this is buggy - now overflow check */ + bytecount.LowPart += file.nFileSizeLow; + bytecount.HighPart += file.nFileSizeHigh; + + /* next block 06/17/98 */ + } + else if (flags & DIR_BARE) + { + if (strcmp(file.cFileName, ".") == 0 || + strcmp(file.cFileName, "..") == 0) + continue; + + if (flags & DIR_RECURSE) + { + TCHAR dir[MAX_PATH]; + wsprintf (dir, _T("%c:%s\\"), drive + _T('@'), directory); + if (flags & DIR_LWR) + strlwr(dir); + ConOutPrintf (dir); + } + ConOutPrintf (_T("%-13s\n"), file.cFileName); + if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + dircount++; + else + filecount++; + if (incline(line, flags) != 0) + return 1; + + /* FIXME: this is buggy - no overflow check */ + bytecount.LowPart += file.nFileSizeLow; + bytecount.HighPart += file.nFileSizeHigh; + } + else + { + /* end Rob Lake */ + if (flags & DIR_NEW) + { + /* print file date and time */ + if (FileTimeToLocalFileTime (&file.ftLastWriteTime, &ft)) + { + FileTimeToSystemTime (&ft, &dt); + PrintFileDateTime (&dt, flags); + } + + /* print file size */ + if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + ConOutPrintf (" "); + dircount++; + } + else + { + ULARGE_INTEGER uliSize; + + uliSize.LowPart = file.nFileSizeLow; + uliSize.HighPart = file.nFileSizeHigh; + + ConvertULargeInteger (uliSize, buffer, sizeof(buffer)); + ConOutPrintf (_T(" %20s"), buffer); + + bytecount.QuadPart += uliSize.QuadPart; + filecount++; + } + + /* print long filename */ + ConOutPrintf (" %s\n", file.cFileName); + } + else + { + if (file.cFileName[0] == '.') + ConOutPrintf ("%-13s ", file.cFileName); + else if (file.cAlternateFileName[0] == '\0') + { + char szShortName[13]; + strncpy (szShortName, file.cFileName, 13); + ext = strchr(szShortName, '.'); + if (!ext) + ext = ""; + else + *ext++ = 0; + ConOutPrintf ("%-8s %-3s ", szShortName, ext); + } + else + { + ext = strchr(file.cAlternateFileName, '.'); + if (!ext) + ext = ""; + else + *ext++ = 0; + ConOutPrintf ("%-8s %-3s ", file.cAlternateFileName, ext); + } + + /* print file size */ + if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + ConOutPrintf ("%-14s", ""); + dircount++; + } + else + { + ULARGE_INTEGER uliSize; + + uliSize.LowPart = file.nFileSizeLow; + uliSize.HighPart = file.nFileSizeHigh; + + ConvertULargeInteger (uliSize, buffer, sizeof(buffer)); + ConOutPrintf (_T(" %10s "), buffer); + + bytecount.QuadPart += uliSize.QuadPart; + filecount++; + } + + /* print file date and time */ + if (FileTimeToLocalFileTime (&file.ftLastWriteTime, &ft)) + { + FileTimeToSystemTime (&ft, &dt); + PrintFileDateTime (&dt, flags); + } + + /* print long filename */ + ConOutPrintf (" %s\n", file.cFileName); + } + + if (incline(line, flags) != 0) + return 1; + } + } + while (FindNextFile (hFile, &file)); + + FindClose (hFile); + + /* Rob Lake, need to make clean output */ + /* JPP 07/08/1998 added check for count != 0 */ + if ((flags & DIR_WIDE) && (count != 0)) + { + ConOutPrintf ("\n"); + if (incline(line, flags) != 0) + return 1; + } + + if (filecount || dircount) + { + recurse_dir_cnt += dircount; + recurse_file_cnt += filecount; + recurse_bytes.QuadPart += bytecount.QuadPart; + + /* The code that was here is now in print_summary */ + if (PrintSummary (drive, filecount, dircount, + bytecount, flags, line) != 0) + return 1; + } + else + { + error_file_not_found (); + return 1; + } + + return 0; +} + + +/* + * _Read_Dir: Actual function that does recursive listing + */ +static int +Read_Dir (int drive, char *parent, char *filespec, int *lines, + DWORD flags) +{ + char fullpath[_MAX_PATH]; + WIN32_FIND_DATA file; + HANDLE hFile; + + strcpy (fullpath, parent); + strcat (fullpath, "\\"); + strcat (fullpath, filespec); + + hFile = FindFirstFile (fullpath, &file); + if (hFile == INVALID_HANDLE_VALUE) + return 1; + + do + { + /* don't list "." and ".." */ + if (strcmp (file.cFileName, ".") == 0 || + strcmp (file.cFileName, "..") == 0) + continue; + + if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if (dir_list(drive, file.cFileName, filespec, lines, flags) != 0) + { + FindClose (hFile); + return 1; + } + if ((flags & DIR_BARE) == 0) + { + ConOutPrintf ("\n"); + if (incline(lines, flags) != 0) + return 1; + } + if (Read_Dir(drive, file.cFileName, filespec, lines, flags) == 1) + { + FindClose (hFile); + return 1; + } + } + } + while (FindNextFile (hFile, &file)); + + if (!FindClose (hFile)) + return 1; + + return 0; +} + + +/* + * do_recurse: Sets up for recursive directory listing + */ +static int +do_recurse(int drive, char *directory, char *filespec, + int *line, DWORD flags) +{ + char cur_dir[_MAX_DIR]; + + recurse_dir_cnt = recurse_file_cnt = 0L; + recurse_bytes.QuadPart = 0; + + _chdrive (drive); + getcwd(cur_dir, sizeof(cur_dir)); + + if (chdir(directory) == -1) + return 1; + + if (!PrintDirectoryHeader (drive, line, flags)) + return 1; + + if (dir_list(drive, directory, filespec, line, flags) != 0) + return 1; + if ((flags & DIR_BARE) == 0) + { + ConOutPrintf ("\n"); + if (incline(line, flags) != 0) + return 1; + } + if (Read_Dir(drive, directory, filespec, line, flags) != 0) + return 1; + if ((flags & DIR_BARE) == 0) + ConOutPrintf ("Total files listed:\n"); + flags &= ~DIR_RECURSE; + + if (PrintSummary (drive, recurse_file_cnt, + recurse_dir_cnt, recurse_bytes, flags, line) != 0) + return 1; + + if ((flags & DIR_BARE) == 0) + { + ConOutPrintf ("\n"); + if (incline(line, flags) != 0) + return 1; + } + chdir(cur_dir); + return 0; +} + + +/* + * dir + * + * internal dir command + */ +INT cmd_dir (LPTSTR first, LPTSTR rest) +{ + DWORD dwFlags = DIR_NEW | DIR_FOUR; + char *param; + TCHAR dircmd[256]; + int line = 0; + int drive, + orig_drive; + char *directory, + *filespec, + orig_dir[_MAX_DIR]; + + + /* read the parameters from the DIRCMD environment variable */ + if (GetEnvironmentVariable (_T("DIRCMD"), dircmd, 256)) + { + if (!DirReadParam (dircmd, ¶m, &dwFlags)) + return 1; + } + + /* read the parameters */ + if (!DirReadParam (rest, ¶m, &dwFlags)) + return 1; + + /* default to current directory */ + if (!param) + param = "."; + + if (strchr(param, '/')) + param = strtok (param, "/"); + + /* save the current directory info */ + orig_drive = _getdrive (); + getcwd(orig_dir, sizeof(orig_dir)); + + /* parse the directory info */ + if (DirParsePathspec (param, &drive, &directory, &filespec) != 0) + { + _chdrive (orig_drive); + chdir(orig_dir); + return 1; + } + + if (dwFlags & DIR_RECURSE) + { + incline(&line, dwFlags); + if (do_recurse (drive, directory, filespec, &line, dwFlags) != 0) + return 1; + _chdrive (orig_drive); + chdir (orig_dir); + return 0; + } + + /* print the header */ + if (!PrintDirectoryHeader (drive, &line, dwFlags)) + return 1; + + chdir (orig_dir); + _chdrive (orig_drive); + + if (dir_list (drive, directory, filespec, &line, dwFlags) != 0) + return 1; + + return 0; +} + +#endif diff --git a/rosapps/cmd/dirstack.c b/rosapps/cmd/dirstack.c new file mode 100644 index 00000000000..5c00c21d609 --- /dev/null +++ b/rosapps/cmd/dirstack.c @@ -0,0 +1,183 @@ +/* + * DIRSTACK.C - pushd / pop (directory stack) internal commands. + * + * + * History: + * + * 14-Dec-1998 (Eric Kohl ) + * Implemented PUSHD and POPD command. + * + * 20-Jan-1999 (Eric Kohl ) + * Unicode and redirection safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef FEATURE_DIRECTORY_STACK + +#include +#include +#include +#include + +#include "cmd.h" + + +typedef struct tagDIRENTRY +{ + struct tagDIRENTRY *next; + LPTSTR pszPath; +} DIRENTRY, *LPDIRENTRY; + + +static INT nStackDepth; +static LPDIRENTRY lpStackTop; + + +static INT +PushDirectory (LPTSTR pszPath) +{ + LPDIRENTRY lpDir; + + lpDir = (LPDIRENTRY)malloc (sizeof (DIRENTRY)); + if (!lpDir) + { + error_out_of_memory (); + return -1; + } + + lpDir->next = (lpStackTop) ? lpStackTop : NULL; + lpStackTop = lpDir; + + lpDir->pszPath = (LPTSTR)malloc ((_tcslen(pszPath)+1)*sizeof(TCHAR)); + if (!lpDir->pszPath) + { + free (lpDir); + error_out_of_memory (); + return -1; + } + + _tcscpy (lpDir->pszPath, pszPath); + + nStackDepth++; + + return 0; +} + + +static VOID +PopDirectory (VOID) +{ + LPDIRENTRY lpDir; + + if (nStackDepth == 0) + return; + + lpDir = lpStackTop; + lpStackTop = lpDir->next; + free (lpDir->pszPath); + free (lpDir); + + nStackDepth--; +} + + +static VOID +GetDirectoryStackTop (LPTSTR pszPath) +{ + if (lpStackTop) + _tcsncpy (pszPath, lpStackTop->pszPath, MAX_PATH); + else + *pszPath = _T('\0'); +} + + +/* + * initialize directory stack + */ +VOID InitDirectoryStack (VOID) +{ + nStackDepth = 0; + lpStackTop = NULL; +} + + +/* + * destroy directory stack + */ +VOID DestroyDirectoryStack (VOID) +{ + while (nStackDepth) + PopDirectory (); +} + + +INT GetDirectoryStackDepth (VOID) +{ + return nStackDepth; +} + + +/* + * pushd command + */ +INT cmd_pushd (LPTSTR first, LPTSTR rest) +{ + TCHAR curPath[MAX_PATH]; + TCHAR newPath[MAX_PATH]; + BOOL bChangePath = FALSE; + + if (!_tcsncmp (rest, _T("/?"), 2)) + { + ConOutPuts (_T("Stores the current directory for use by the POPD command, then\n" + "changes to the specified directory.\n\n" + "PUSHD [path | ..]\n\n" + " path Specifies the directory to make the current directory")); + return 0; + } + + if (rest[0] != _T('\0')) + { + GetFullPathName (rest, MAX_PATH, newPath, NULL); + bChangePath = IsValidPathName (newPath); + } + + GetCurrentDirectory (MAX_PATH, curPath); + if (PushDirectory (curPath)) + return -1; + + if (bChangePath) + SetCurrentDirectory (newPath); + + return 0; +} + + +/* + * popd command + */ +INT cmd_popd (LPTSTR first, LPTSTR rest) +{ + TCHAR szPath[MAX_PATH]; + + if (!_tcsncmp(rest, _T("/?"), 2)) + { + ConOutPuts (_T("Changes to the directory stored by the PUSHD command.\n\n" + "POPD")); + return 0; + } + + if (GetDirectoryStackDepth () == 0) + return 0; + + GetDirectoryStackTop (szPath); + PopDirectory (); + + SetCurrentDirectory (szPath); + + return 0; +} + +#endif /* FEATURE_DIRECTORY_STACK */ \ No newline at end of file diff --git a/rosapps/cmd/echo.c b/rosapps/cmd/echo.c new file mode 100644 index 00000000000..9d85c5ffe24 --- /dev/null +++ b/rosapps/cmd/echo.c @@ -0,0 +1,59 @@ +/* + * ECHO.C - echo internal command. + * + * + * History: + * + * 16 Jul 1998 (Hans B Pufal) + * Started. + * + * 16 Jul 1998 (John P Price) + * Separated commands into individual files. + * + * 27-Jul-1998 (John P Price ) + * Added config.h include + * + * 08-Dec-1998 (Eric Kohl ) + * Added help text ("/?"). + * + * 19-Jan-1999 (Eric Kohl ) + * Unicode and redirection ready! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include + +#include "cmd.h" +#include "batch.h" + + +INT cmd_echo (LPTSTR cmd, LPTSTR param) +{ +#ifdef _DEBUG + DebugPrintf ("cmd_echo '%s' : '%s'\n", cmd, param); +#endif + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts ("Displays messages or switches command echoing on or off.\n\n" + "ECHO [ON | OFF]\nECHO [message]\n\n" + "Type ECHO without a parameter to display the current ECHO setting."); + return 0; + } + + if (_tcsicmp (param, D_OFF) == 0) + bEcho = FALSE; + else if (_tcsicmp (param, D_ON) == 0) + bEcho = TRUE; + else if (*param) + ConOutPuts (param); + else + ConOutPrintf (_T("ECHO is %s\n"), bEcho ? D_ON : D_OFF); + + return 0; +} diff --git a/rosapps/cmd/error.c b/rosapps/cmd/error.c new file mode 100644 index 00000000000..d89fe3132c6 --- /dev/null +++ b/rosapps/cmd/error.c @@ -0,0 +1,177 @@ +/* + * ERROR.C - error reporting functions. + * + * + * History: + * + * 07/12/98 (Rob Lake) + * started + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 24-Jan-1999 (Eric Kohl ) + * Redirection safe! + * + * 02-Feb-1999 (Eric Kohl ) + * Use FormatMessage() for error reports. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include + +#include "cmd.h" + + +#define INVALID_SWITCH _T("Invalid switch - /%c\n") +#define TOO_MANY_PARAMETERS _T("Too many parameters - %s\n") +#define PATH_NOT_FOUND _T("Path not found\n") +#define FILE_NOT_FOUND _T("File not found") +#define REQ_PARAM_MISSING _T("Required parameter missing\n") +#define INVALID_DRIVE _T("Invalid drive specification\n") +#define INVALID_PARAM_FORMAT _T("Invalid parameter format - %s\n") +#define BADCOMMAND _T("Bad command or filename\n") +#define OUT_OF_MEMORY _T("Out of memory error.\n") +#define CANNOTPIPE _T("Error! Cannot pipe! Cannot open temporary file!\n") + +#define D_PAUSEMSG _T("Press any key to continue . . .") + + + +VOID ErrorMessage (DWORD dwErrorCode, LPTSTR szFormat, ...) +{ + TCHAR szMessage[1024]; + LPTSTR szError; + va_list arg_ptr; + + if (dwErrorCode == ERROR_SUCCESS) + return; + + va_start (arg_ptr, szFormat); + wvsprintf (szMessage, szFormat, arg_ptr); + va_end (arg_ptr); + +#if 1 + + if (FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, dwErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&szError, 0, NULL)) + { + ConErrPrintf (_T("%s %s\n"), szError, szMessage); + LocalFree (szError); + return; + } + else + { + ConErrPrintf (_T("Unknown error! Error code: 0x%lx\n"), dwErrorCode); +// ConErrPrintf (_T("No error message available!\n")); + return; + } + +#else + + switch (dwErrorCode) + { + case ERROR_FILE_NOT_FOUND: + szError = _T("File not found --"); + break; + + case ERROR_PATH_NOT_FOUND: + szError = _T("Path not found --"); + break; + + default: + ConErrPrintf (_T("Unknown error! Error code: 0x%lx\n"), dwErrorCode); + return; + } + + ConErrPrintf (_T("%s %s\n"), szError, szMessage); +#endif +} + + + +VOID error_invalid_switch (TCHAR ch) +{ + ConErrPrintf (INVALID_SWITCH, ch); +} + + +VOID error_too_many_parameters (LPTSTR s) +{ + ConErrPrintf (TOO_MANY_PARAMETERS, s); +} + + +VOID error_path_not_found (VOID) +{ + ConErrPrintf (PATH_NOT_FOUND); +} + + +VOID error_file_not_found (VOID) +{ + ConErrPrintf (FILE_NOT_FOUND); +} + + +VOID error_sfile_not_found (LPTSTR f) +{ + ConErrPrintf (FILE_NOT_FOUND _T(" - %s\n"), f); +} + + +VOID error_req_param_missing (VOID) +{ + ConErrPrintf (REQ_PARAM_MISSING); +} + + +VOID error_invalid_drive (VOID) +{ + ConErrPrintf (INVALID_DRIVE); +} + + +VOID error_bad_command (VOID) +{ + ConErrPrintf (BADCOMMAND); +} + + +VOID error_no_pipe (VOID) +{ + ConErrPrintf (CANNOTPIPE); +} + + +VOID error_out_of_memory (VOID) +{ + ConErrPrintf (OUT_OF_MEMORY); +} + + +VOID error_invalid_parameter_format (LPTSTR s) +{ + ConErrPrintf (INVALID_PARAM_FORMAT, s); +} + + +VOID error_syntax (LPTSTR s) +{ + if (s) + ConErrPrintf (_T("Syntax error - %s\n"), s); + else + ConErrPrintf (_T("Syntax error.\n")); +} + + +VOID msg_pause (VOID) +{ + ConOutPuts (D_PAUSEMSG); +} diff --git a/rosapps/cmd/filecomp.c b/rosapps/cmd/filecomp.c new file mode 100644 index 00000000000..2f9d53823b9 --- /dev/null +++ b/rosapps/cmd/filecomp.c @@ -0,0 +1,253 @@ +/* + * FILECOMP.C - handles filename completion. + * + * + * Comments: + * + * 30-Jul-1998 (John P Price ) + * moved from command.c file + * made second TAB display list of filename matches + * made filename be lower case if last character typed is lower case + * + * 25-Jan-1999 (Eric Kohl ) + * Cleanup. Unicode safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include +#include + +#include "cmd.h" + + +#ifdef FEATURE_UNIX_FILENAME_COMPLETION + +VOID CompleteFilename (LPTSTR str, INT charcount) +{ + WIN32_FIND_DATA file; + HANDLE hFile; + + INT curplace = 0; + INT start; + INT count; + BOOL found_dot = FALSE; + BOOL perfectmatch = TRUE; + TCHAR path[MAX_PATH]; + TCHAR fname[MAX_PATH]; + TCHAR maxmatch[MAX_PATH] = _T(""); + TCHAR directory[MAX_PATH]; + + /* expand current file name */ + count = charcount - 1; + if (count < 0) + count = 0; + + /* find front of word */ + while (count > 0 && str[count] != _T(' ')) + count--; + + /* if not at beginning, go forward 1 */ + if (str[count] == _T(' ')) + count++; + + start = count; + + /* extract directory from word */ + _tcscpy (directory, &str[start]); + curplace = _tcslen (directory) - 1; + while (curplace >= 0 && directory[curplace] != _T('\\') && + directory[curplace] != _T(':')) + { + directory[curplace] = 0; + curplace--; + } + + _tcscpy (path, &str[start]); + + /* look for a '.' in the filename */ + for (count = _tcslen (directory); path[count] != 0; count++) + { + if (path[count] == _T('.')) + { + found_dot = 1; + break; + } + } + + if (found_dot) + _tcscat (path, _T("*")); + else + _tcscat (path, _T("*.*")); + + /* current fname */ + curplace = 0; + + hFile = FindFirstFile (path, &file); + if (hFile != INVALID_HANDLE_VALUE) + { + /* find anything */ + do + { + /* ignore "." and ".." */ + if (file.cFileName[0] == _T('.')) + continue; + + _tcscpy (fname, file.cFileName); + + if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + _tcscat (fname, _T("\\")); + else + _tcscat (fname, _T(" ")); + + if (!maxmatch[0] && perfectmatch) + { + _tcscpy(maxmatch, fname); + } + else + { + for (count = 0; maxmatch[count] && fname[count]; count++) + { + if (tolower(maxmatch[count]) != tolower(fname[count])) + { + perfectmatch = FALSE; + maxmatch[count] = 0; + break; + } + } + } + } + while (FindNextFile (hFile, &file)); + + FindClose (hFile); + + _tcscpy (&str[start], directory); + _tcscat (&str[start], maxmatch); + + if (!perfectmatch) + MessageBeep (-1); + } + else + { + /* no match found */ + MessageBeep (-1); + } +} + + +/* + * returns 1 if at least one match, else returns 0 + */ + +BOOL ShowCompletionMatches (LPTSTR str, INT charcount) +{ + WIN32_FIND_DATA file; + HANDLE hFile; + BOOL found_dot = FALSE; + INT curplace = 0; + INT start; + INT count; + TCHAR path[MAX_PATH]; + TCHAR fname[MAX_PATH]; + TCHAR directory[MAX_PATH]; + + /* expand current file name */ + count = charcount - 1; + if (count < 0) + count = 0; + + /* find front of word */ + while (count > 0 && str[count] != _T(' ')) + count--; + + /* if not at beginning, go forward 1 */ + if (str[count] == _T(' ')) + count++; + + start = count; + + /* extract directory from word */ + _tcscpy (directory, &str[start]); + curplace = _tcslen (directory) - 1; + while (curplace >= 0 && directory[curplace] != _T('\\') && + directory[curplace] != _T(':')) + { + directory[curplace] = 0; + curplace--; + } + + _tcscpy (path, &str[start]); + + /* look for a . in the filename */ + for (count = _tcslen (directory); path[count] != 0; count++) + { + if (path[count] == _T('.')) + { + found_dot = TRUE; + break; + } + } + if (found_dot) + _tcscat (path, _T("*")); + else + _tcscat (path, _T("*.*")); + + /* current fname */ + curplace = 0; + + hFile = FindFirstFile (path, &file); + if (hFile != INVALID_HANDLE_VALUE) + { + /* find anything */ + ConOutChar (_T('\n')); + count = 0; + do + { + /* ignore . and .. */ + if (file.cFileName[0] == _T('.')) + continue; + + if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + wsprintf (fname,"[%s]", file.cFileName); + else + _tcscpy (fname, file.cFileName); + + ConOutPrintf (_T("%-14s"), fname); + if (++count == 5) + { + ConOutChar (_T('\n')); + count = 0; + } + } + while (FindNextFile (hFile, &file)); + + FindClose (hFile); + + if (count) + ConOutChar (_T('\n')); + } + else + { + /* no match found */ + MessageBeep (-1); + return FALSE; + } + + return TRUE; +} +#endif + +#ifdef FEATURE_4NT_FILENAME_COMPLETION + +//static VOID BuildFilenameMatchList (...) + +// VOID CompleteFilenameNext (LPTSTR, INT) +// VOID CompleteFilenamePrev (LPTSTR, INT) + +// VOID RemoveFilenameMatchList (VOID) + +#endif \ No newline at end of file diff --git a/rosapps/cmd/files.txt b/rosapps/cmd/files.txt new file mode 100644 index 00000000000..8f1dfefd3da --- /dev/null +++ b/rosapps/cmd/files.txt @@ -0,0 +1,56 @@ +Archive Contents +~~~~~~~~~~~~~~~~ +bugs.txt Bug List +files.txt This file list +history.txt History of the shell development +license.txt GNU license - applies to all files named here +readme.txt General shell info +todo.txt What I have to do +wishlist.txt Wish List + +makefile experimental makefile +makefile.lcc makefile for lcc-win + +alias.c Alias code +alias.h Alias header file +attrib.c Implements attrib command +batch.c Batch file interpreter +beep.c Implements beep command +call.c Implements call command +chcp.c Implements chcp command +cls.c Implements cls command +cmdinput.c Command-line input functions +cmdtable.c Table of available internal commands +cmd.c Main code for command-line interpreter +cmd.h Command header file +color.c Implements color command +console.c Windows console handling code +copy.c Implements copy command +date.c Implements date command +del.c Implements del command +dir.c Directory listing code +dirstack.c Directory stack code (PUSHD and POPD) +echo.c Implements echo command +error.c Error Message Routines +filecomp.c Filename completion functions +for.c Implements for command +goto.c Implements goto command +history.c Command-line history handling +if.c Implements if command +internal.c Internal commands (DIR, RD, etc) +label.c Implements label command +locale.c Locale handling code +misc.c Misc. Functions +move.c Implements move command +path.c Implements path command +pause.c Implements pause command +prompt.c Prompt handling functions +redir.c Redirection and piping parsing functions +ren.c Implements rename command +set.c Implements set command +shift.c Implements shift command +time.c Implements time command +type.c Implements type command +ver.c Implements ver command +where.c Code to search path for executables +verify.c Implements verify command \ No newline at end of file diff --git a/rosapps/cmd/for.c b/rosapps/cmd/for.c new file mode 100644 index 00000000000..7ccb445252e --- /dev/null +++ b/rosapps/cmd/for.c @@ -0,0 +1,135 @@ +/* + * FOR.C - for internal batch command. + * + * + * History: + * + * 16 Jul 1998 (Hans B Pufal) + * started. + * + * 16 Jul 1998 (John P Price) + * Seperated commands into individual files. + * + * 19 Jul 1998 (Hans B Pufal) [HBP_001] + * Implementation of FOR + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 20-Jan-1999 (Eric Kohl ) + * Unicode and redirection safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include +#include + +#include "cmd.h" +#include "batch.h" + + +/* + * Perform FOR command. + * + * First check syntax is correct : FOR %v IN ( ) DO + * v must be alphabetic, must not be empty. + * + * If all is correct build a new bcontext structure which preserves + * the necessary information so that readbatchline can expand + * each the command prototype for each list element. + * + * You might look on a FOR as being a called batch file with one line + * per list element. + */ + +INT cmd_for (LPTSTR cmd, LPTSTR param) +{ + LPBATCH_CONTEXT lpNew; + LPTSTR pp; + TCHAR var; + +#ifdef _DEBUG + DebugPrintf ("cmd_for (\'%s\', \'%s\'\n", cmd, param); +#endif + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts ("FOR :"); + return 0; + } + + /* Check that first element is % then an alpha char followed by space */ + if ((*param != _T('%')) || !_istalpha (*(param + 1)) || !_istspace (*(param + 2))) + { + error_syntax (_T("bad varable specification.")); + return 1; + } + + param++; + var = *param++; /* Save FOR var name */ + + while (_istspace (*param)) + param++; + + /* Check next element is 'IN' */ + if ((_tcsnicmp (param, _T("in"), 2) != 0) || !_istspace (*(param + 2))) + { + error_syntax (_T("'in' missing in for statement.")); + return 1; + } + + param += 2; + while (_istspace (*param)) + param++; + + /* Folowed by a '(', find also matching ')' */ + if ((*param != _T('(')) || (NULL == (pp = _tcsrchr (param, _T(')'))))) + { + error_syntax (_T("no brackets found.")); + return 1; + } + + *pp++ = _T('\0'); + param++; /* param now points at null terminated list */ + + while (_istspace (*pp)) + pp++; + + /* Check DO follows */ + if ((_tcsnicmp (pp, _T("do"), 2) != 0) || !_istspace (*(pp + 2))) + { + error_syntax (_T("'do' missing.")); + return 1; + } + + pp += 2; + while (_istspace (*pp)) + pp++; + + /* Check that command tail is not empty */ + if (*pp == _T('\0')) + { + error_syntax (_T("no command after 'do'.")); + return 1; + } + + /* OK all is correct, build a bcontext.... */ + lpNew = (LPBATCH_CONTEXT)malloc (sizeof (BATCH_CONTEXT)); + + lpNew->prev = bc; + bc = lpNew; + + bc->hBatchFile = INVALID_HANDLE_VALUE; + bc->ffind = NULL; + bc->params = BatchParams (_T(""), param); /* Split out list */ + bc->shiftlevel = 0; + bc->forvar = var; + bc->forproto = _tcsdup (pp); + + return 0; +} diff --git a/rosapps/cmd/goto.c b/rosapps/cmd/goto.c new file mode 100644 index 00000000000..def1cbf57f2 --- /dev/null +++ b/rosapps/cmd/goto.c @@ -0,0 +1,110 @@ +/* + * GOTO.C - goto internal batch command. + * + * History: + * + * 16 Jul 1998 (Hans B Pufal) + * started. + * + * 16 Jul 1998 (John P Price) + * Seperated commands into individual files. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 28 Jul 1998 (Hans B Pufal) [HBP_003] + * Terminate label on first space character, use only first 8 chars of + * label string + * + * 24-Jan-1999 (Eric Kohl ) + * Unicode and redirection safe! + * + * 27-Jan-1999 (Eric Kohl ) + * Added help text ("/?"). + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include + +#include "cmd.h" +#include "batch.h" + + +/* + * Perform GOTO command. + * + * Only valid if batch file current. + * + */ + +INT cmd_goto (LPTSTR cmd, LPTSTR param) +{ + LPTSTR tmp; + LONG lNewPosHigh; + +#ifdef _DEBUG + DebugPrintf ("cmd_goto (\'%s\', \'%s\'\n", cmd, param); +#endif + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Directs CMD to a labeled line in a batch script.\n" + "\n" + "GOTO label\n" + "\n" + " label Specifies a text string used in a batch script as a label.\n" + "\n" + "You type a label on a line by itself, beginning with a colon.")); + return 0; + } + + /* if not in batch -- error!! */ + if (bc == NULL) + { + return 1; + } + + if (*param == _T('\0')) + { + ExitBatch (_T("No label specified for GOTO\n")); + return 1; + } + + /* terminate label at first space char */ + tmp = param; + while (*tmp && !_istspace (*tmp)) + tmp++; + *tmp = _T('\0'); + + /* set file pointer to the beginning of the batch file */ + lNewPosHigh = 0; + SetFilePointer (bc->hBatchFile, 0, &lNewPosHigh, FILE_BEGIN); + + while (FileGetString (bc->hBatchFile, textline, sizeof(textline))) + { + /* Strip out any trailing spaces or control chars */ + tmp = textline + _tcslen (textline) - 1; + while (_istcntrl (*tmp) || _istspace (*tmp)) + tmp--; + *(tmp + 1) = _T('\0'); + + /* Then leading spaces... */ + tmp = textline; + while (_istspace (*tmp)) + tmp++; + + /* use only 1st 8 chars of label */ + if ((*tmp == _T(':')) && (_tcsncmp (++tmp, param, 8) == 0)) + return 0; + } + + ConErrPrintf (_T("Label '%s' not found\n"), param); + ExitBatch (NULL); + + return 1; +} diff --git a/rosapps/cmd/history.c b/rosapps/cmd/history.c new file mode 100644 index 00000000000..2e48d597882 --- /dev/null +++ b/rosapps/cmd/history.c @@ -0,0 +1,126 @@ +/* + * HISTORY.C - command line history. + * + * + * History: + * + * 14/01/95 (Tim Norman) + * started. + * + * 08/08/95 (Matt Rains) + * i have cleaned up the source code. changes now bring this source + * into guidelines for recommended programming practice. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 25-Jan-1999 (Eric Kohl ) + * Cleanup! + * Unicode and redirection safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef FEATURE_HISTORY + +#include +#include +#include +#include + + +#define MAXLINES 128 + +static INT history_size = 2048; /* make this configurable later */ + + +VOID History (INT dir, LPTSTR commandline) +{ + static LPTSTR history = NULL; + static LPTSTR lines[MAXLINES]; + static INT curline = 0; + static INT numlines = 0; + static INT maxpos = 0; + INT count; + INT length; + + if (!history) + { + history = malloc (history_size * sizeof (TCHAR)); + lines[0] = history; + history[0] = 0; + } + + if (dir > 0) + { + /* next command */ + if (curline < numlines) + { + curline++; + } + + if (curline == numlines) + { + commandline[0] = 0; + } + else + { + _tcscpy (commandline, lines[curline]); + } + } + else if (dir < 0) + { + /* prev command */ + if (curline > 0) + { + curline--; + } + + _tcscpy (commandline, lines[curline]); + } + else + { + /* add to history */ + /* remove oldest string until there's enough room for next one */ + /* strlen (commandline) must be less than history_size! */ + while ((maxpos + (INT)_tcslen (commandline) + 1 > history_size) || (numlines >= MAXLINES)) + { + length = _tcslen (lines[0]) + 1; + + for (count = 0; count < maxpos && count + (lines[1] - lines[0]) < history_size; count++) + { + history[count] = history[count + length]; + } + + maxpos -= length; + + for (count = 0; count <= numlines && count < MAXLINES; count++) + { + lines[count] = lines[count + 1] - length; + } + + numlines--; +#ifdef DEBUG + ConOutPrintf (_T("Reduced size: %ld lines\n"), numlines); + + for (count = 0; count < numlines; count++) + { + ConOutPrintf (_T("%d: %s\n"), count, lines[count]); + } +#endif + } + + _tcscpy (lines[numlines], commandline); + numlines++; + lines[numlines] = lines[numlines - 1] + _tcslen (commandline) + 1; + maxpos += _tcslen (commandline) + 1; + /* last line, empty */ + curline = numlines; + } + + return; +} + +#endif diff --git a/rosapps/cmd/history.txt b/rosapps/cmd/history.txt new file mode 100644 index 00000000000..7b0769bb53c --- /dev/null +++ b/rosapps/cmd/history.txt @@ -0,0 +1,345 @@ +FreeDOS Command Line Interface Development History +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +11/11/94 version 0.01 +~~~~~~~~~~~~~~~~~~~~~ +o initial release. + +01/01/95 version 0.10 +~~~~~~~~~~~~~~~~~~~~~ +o removed some scaffolding. +o modified CD. +o added tab file completion. +o added command line history. + +01/15/95 version 0.20 +~~~~~~~~~~~~~~~~~~~~~ +o formatted all existing source modules. +o added prompt support. +o added drive selection. +o added dir command. +o started this development log. + +08/06/95 prerelease of version 0.30 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +o reorganized code into separate source modules. +o added batch processing support (thanks to Evan Jeffrey). +o added exec code (thanks to Steffan Kaiser). +o removed environment handling (thanks again to Steffan Kaiser) + + [ 08/08/95 -- Matt Rains ] +o formatted this development log. +o formatted all existing source modules so that they comply with recommended + programming practice. +o added MD command. +o added RD command. +o added VER command. +o replaced CD command. +o modified DIR command. +o DIR now called regardless of other DIR.??? files. this is done because of + exec() problems. + +12/10/95 version 0.30 +~~~~~~~~~~~~~~~~~~~~~ +o used Borland's spawnve to fix exec problem +o fixed CD again so you don't need a space after it +o couple of spelling fixes + +12/14/95 version 0.31 +~~~~~~~~~~~~~~~~~~~~~ +o modified cmdinput.c to work with non-standard screen sizes (see 28.com) +o fixed a bug in history.c that made it not work when you hit the up arrow + on the first line +o fixed DIR to work a little more like MS-DOS's DIR (see internal.c) +o fixed some code in where.c to make things a bit more efficient and nicer + +01/06/96 version 0.40 (never released) +~~~~~~~~~~~~~~~~~~~~~ +o added redirection and piping support!!! (see redir.c and command.c) +o fixed a stupid pointer problem in where.c that was causing LOTS of + problems in the strangest places... +o added day of the week support to prompt.c (oops, that was already supposed + to be there! :) +o fixed and reorganized the EXEC code!!! Thanks to Svante Frey! +o reorganized command.c and internal.c to handle parsing internal commands + more efficiently and consistently. +o changed the behavior of MD, CD, RD to work without spaces (e.g. CD\DOS) +o small changes here and there to make it work with redirection/piping + (e.g. DIR only pauses if you're not doing redirection) + +01/17/96 version 0.50 +~~~~~~~~~~~~~~~~~~~~~ +Version 0.40 was never released because I was home on Christmas vacation, +and I couldn't upload it. By the time I got back to school, I had the +LOADHIGH patch from Svante Frey, so I decided to jump up to 0.50 without any +release of 0.40... - Tim Norman + +o LOADHIGH/LOADFIX/LH support added!!!! Many thanks go to Svante Frey! +o bug fixed in command parsing that didn't handle / switches correctly... +o removed debugging output from history.c + +07/26/96 version 0.60 +~~~~~~~~~~~~~~~~~~~~~ +Lots of internal changes here... Not much added to the interface. + +o Changed internals to use first,rest parameters instead of arrays of params +o Fixed some bugs +o Some other things I don't remember :) + +07/26/96 version 0.61 +~~~~~~~~~~~~~~~~~~~~~ +Bugfixes + +o Added hook to the PATH command +o Fixed CD.. bug + +08/27/96 version 0.70 +~~~~~~~~~~~~~~~~~~~~~ +Finally added Oliver Mueller's ALIAS command! Also numerous bug fixes. + +o Added ALIAS command +o Removed support for - as a switch in LOADHIGH.C +o Bugfixes in BATCH.C. %0 was returning garbage +o Removed lots of unused variables, reducing # of warnings when compiling +o Other miscellaneous code clean-ups +o Changed WHERE.C to use a little less memory + +06/14/97 version 0.71 +~~~~~~~~~~~~~~~~~~~~~ +Lots of bug fixes, plus some additional features. + +o New DIR command. Now more like MS-DOS's DIR. /p supported, /s coming soon +o bug fix in internal.c - parse_firstarg +o Rewrote parser in batch.c (Steffan Kaiser) +o Ctrl-Break checking in various places (Steffan Kaiser) +o Error level setting/checking (%? in batch files) (Steffan Kaiser) +o bug fix in cmdinput.c ("%i" on command-line caused weird behavior) +o bug fix in where.c (first item in path wasn't searched) + +07/12/97 version 0.72 +~~~~~~~~~~~~~~~~~~~~~ +More bug fixes and code cleanup + +o Rewrote cmdinput.c to be more efficient (Marc Desrochers) +o Added insert/overstrike modes (Marc Desrochers) +o Replaced findxy() with pointers into BIOS (maxx, maxy) (Marc Desrochers) +o Fixed bug that disallowed listing of root directories +o Fixed bug that didn't search the first path (again!) + +07/13/97 version 0.72b +~~~~~~~~~~~~~~~~~~~~~~ +Disabled a feature that caused a crash on some machines. + +o Replaced setcursor calls in cmdinput.c with _setcursortype +o Added dir.c to the distribution (was left out in 0.72) + +07/01/98 version 0.73 (Rob Lake) +~~~~~~~~~~~~~~~~~~~~~~ +o New DIR commands supported: /S, /B, /L, /A and /W. + (/R changed to /S). Also /? added. +o Supports DIRCMD in environment. +o Supports turning off commands with hyphen (ex. /-S + turns off recursive listing) +o Changed error messages for DIR and DEL to more MS-DOS'ish +o Moved error messages from DIR.C and DEL.C to COMMAND.H + (more may go there soon) +o Fixed bug that caused dir *.ext/X not to work (no spaces + between filespec and slash) +o Added wildcard support for DEL command +o Added prompt and help switch for DEL command, /P and /? + respectively. +o Added support for /C when envoking the shell +o Added /P support when Kernel loads shell. This means + the shell now is permanent and runs the autoexec.bat + (/E is not implemented) +o Added my name (Rob Lake) to the developer listing +o Changed version routine to print out copyright notice + with no args, and with appropriate switches, warranty + and redistribution notices and developer listing + +07/08/1998 version 0.74 (John P. Price (linux-guru@gcfl.net)) +~~~~~~~~~~~~~~~~~~~~~~~~ +COMMAND.C/COMMAND.H: +o Now sets COMSPEC environment variable +o misc clean up and optimization +o added date, time and type commands +o changed to using spawnl instead of exec. exec does not copy the + environment to the child process! +DIR.C +o removed extra returns; closer to MSDOS +o fixed wide display so that an extra return is not displayed when + there is five filenames in the last line. +ENVIRON.C +o commented out show_environment function. Not used anymore. +INTERAL.C +o removed call to show_environment in set command. +o moved test for syntax before allocating memory in set command. +o misc clean up and optimization. + +o created DATE.C +o created TIME.C +o created TYPE.C + +07/08/1998 version 0.74b (John P. Price (linux-guru@gcfl.net)) +~~~~~~~~~~~~~~~~~~~~~~~~ +COMMAND.C +o fixed call to spawnl so that it would pass command line arguments + correctly. + +07/12/98 version 0.74c (Rob Lake rlake@cs.mun.ca) +~~~~~~~~~~~~~~~~~~~~~~ +Various Files: +o removed redundant use of error message defines and moved + error printing calls to ERROR.C to reduced program size. + +o created MISC.C +o created ERR_HAND.C/H +o created ERROR.C + +07/13/98 version 0.74d (Rob Lake rlake@cs.mun.ca) +~~~~~~~~~~~~~~~~~~~~~~ +INTERNAL.C +o removed most of the commands and placed them in there own file + -- del, ren, set and ver +o created DEL.C, REN.C SET.C and VER.C +o fixed bug that caused del not to delete files with no attributes +o the critical error handler count number of times called, autofails + at 5 calls + + +16 Jul 1998 (Hans B Pufal ) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +batch.c + A new version, implements CALL, ECHO, GOT, IF, PAUSE, SHIFT and + BEEP. There is a stub for FOR but that's all. + +cmdtable.c + New file to keep the internal command table. I plan on getting rid + of the table real soon now and replacing it with a dynamic + mechanism. + +command.c + A new (improved ;) version. Conforms closely to MS-DOS specs. + Cleaned up (and fixed) the redirection handler. + +command.h + Version D with changes. Look for the HBP tag. + +redir.c + Modified file, now supports append redirects. + + +16 Jul 1998 (Rob Lake rlake@cs.mun.ca) +~~~~~~~~~~~~~~~~~~~~~~ +Added TRUENAME command. + + +19 Jul 1998 (Hans B Pufal) ) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +o Preserve state of echo flag across batch calls. +o Implementation of FOR command + + +20 Jul 1998 (John P Price ) +~~~~~~~~~~~~~~~~~~~~~~ +o Fixed bug in DATE.C. +o Fixed bug in LH.ASM. +o Separated commands into individual files. + + +28 Jul 1998 (John P Price ) +~~~~~~~~~~~~~~~~~~~~~~ +o Added CLS command. +o Put ifdef's around all commands and added include file config.h + Now you can define exact what commands you want to include in + command.com. +o Also added ifdefs for optional features: aliases, command history + and filename completion. +o Added display of available internal commands and options at startup. + + +29 Jul 1998 (Rob Lake rlake@cs.mun.ca) +~~~~~~~~~~~~~~~~~~~~~~ +o changed date.c and time.c, and wrote datefunc.c and timefunc.c to + impliment _dos_getdate, _dos_setdate, _dos_gettime and _dos_settime. + This is the first of many steps to make the shell compatible under + Pacific C. + +30-Jul-1998 (John P Price ) +~~~~~~~~~~~~~~~~~~~~~~ +o Changed filename completion so that a second TAB displays a list of + matching filenames! +o made filename be lower case if last character typed is lower case. +o Moved filename completion code to filecomp.c. +o Change ver command to display email address to report bugs, and the + web page address for updates. +o fixed so that it find_which returns NULL if filename is not + executable (does not have .bat, .com, or .exe extension). Before + command would to execute any file with any extension. (opps!) + +30-Jul-1998 (John P Price ) +~~~~~~~~~~~~~~~~~~~~~~ +o Fixed bug where if you typed something, then hit HOME, then tried to + type something else in insert mode, it locked up. +o Changed default insert mode to on. There should be a way to change + this. Maybe options to doskey command. +o Added VERIFY command + +02-Aug-1998 (Hans B Pufal) ) +~~~~~~~~~~~~~~~~~~~~~~ +o batch.c: Fixed bug in ECHO flag restoration at exit from batch file +o command.c: Fixed return value when called with /C option +o Terminate label on first space character, use only first 8 chars of + label string + +04-Aug-1998 (Hans B Pufal) ) +~~~~~~~~~~~~~~~~~~~~~~ +o call.c: added lines to initialize for pointers. This fixed the + lock-up that happened sometimes when calling a batch file from + another batch file. + +07-Aug-1998 (John P Price ) +~~~~~~~~~~~~~~~~~~~~~~ +o Fixed carrage return output to better match MSDOS with echo on or off. + + +07-Dec-1998 ReactOS CMD version 0.0.1 (Eric Kohl ) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +o First test release. +o Added internal ATTRIB command. + +11-Dec-1998 ReactOS CMD version 0.0.2 (Eric Kohl ) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +o Fixed bug in ALIAS. CMD crashed when you tried to remove an alias. +o Fixed bug in split(). Added freep(). This fixed the DEL command. +o Improved ATTRIB command. +o Added most help texts. +o Fixed recursive DIR ("dir /s"). +o Fixed DATE and TIME command. Now they accept values when used + without parameter. +o Implemented LABEL command. + +05-Jan-1999 ReactOS CMD version 0.0.3 (Eric Kohl ) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +o Added COLOR command and "/t" option. +o Cursor shows insert/overwrite mode. +o COMSPEC environment variable is set upon startup. +o Started COPY command. +o Started MOVE command. +o Added directory stack (PUSHD and POPD commands). +o Added support for file names or paths that contain spaces + (quoted paths / file names). +o Added recursion to ATTRIB command. +o Added locale support for DIR, DATE, TIME and PROMPT. +o Fixed VERIFY. + +10-Feb-1999 ReactOS CMD version 0.0.4 (Eric Kohl ) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +o "?" lists all available commands. +o Most commands are unicode and redirection aware now. +o Input-, Output- and Error-Redirections works with most commands. +o ATTRIB and DEL can handle multiple filenames now. +o Fixed handling of environment variables. +o Added CHCP command. +o Fixed keyboard input bug. +o Rewrote DEL and MOVE commands. \ No newline at end of file diff --git a/rosapps/cmd/if.c b/rosapps/cmd/if.c new file mode 100644 index 00000000000..64744bca5d6 --- /dev/null +++ b/rosapps/cmd/if.c @@ -0,0 +1,157 @@ +/* + * IF.C - if internal batch command. + * + * + * History: + * + * 16 Jul 1998 (Hans B Pufal) + * started. + * + * 16 Jul 1998 (John P Price) + * Seperated commands into individual files. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 07-Jan-1999 (Eric Kohl ) + * Added help text ("if /?") and cleaned up. + * + * 21-Jan-1999 (Eric Kohl ) + * Unicode and redirection ready! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include + +#include "cmd.h" +#include "batch.h" + + +#define X_EXEC 1 +#define X_EMPTY 0x80 + + +INT cmd_if (LPTSTR cmd, LPTSTR param) +{ + INT x_flag = 0; /* when set cause 'then' clause to be executed */ + LPTSTR pp; + +#ifdef _DEBUG + DebugPrintf ("cmd_if: (\'%s\', \'%s\'\n", cmd, param); +#endif + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("IF :")); + return 0; + } + + /* First check if param string begins with word 'not' */ + if (!_tcsnicmp (param, _T("not"), 3) && _istspace (*(param + 3))) + { + x_flag = X_EXEC; /* Remember 'NOT' */ + param += 3; /* Step over 'NOT' */ + while (_istspace (*param)) /* And subsequent spaces */ + param++; + } + + /* Check for 'exist' form */ + if (!_tcsnicmp (param, _T("exist"), 5) && _istspace (*(param + 5))) + { + param += 5; + while (_istspace (*param)) + param++; + + pp = param; + while (*pp && !_istspace (*pp)) + pp++; + + if (*pp) + { + WIN32_FIND_DATA f; + HANDLE hFind; + + *pp++ = _T('\0'); + hFind = FindFirstFile (param, &f); + x_flag ^= (hFind != INVALID_HANDLE_VALUE) ? 0 : X_EXEC; + if (hFind != INVALID_HANDLE_VALUE) + FindClose (hFind); + } + else + return 0; + } + + /* Check for 'errorlevel' form */ + else if (!_tcsnicmp (param, _T("errorlevel"), 10) && _istspace (*(param + 10))) + { + INT n = 0; + + pp = param + 10; + while (_istspace (*pp)) + pp++; + + while (_istdigit (*pp)) + n = n * 10 + (*pp++ - _T('0')); + + x_flag ^= (errorlevel < n) ? 0 : X_EXEC; + + x_flag |= X_EMPTY; /* Syntax error if comd empty */ + } + + /* Check that '==' is present, syntax error if not */ + else if (NULL == (pp = _tcsstr (param, _T("==")))) + { + error_syntax (NULL); + return 1; + } + + else + { + /* Change first '='to space to terminate comparison loop */ + + *pp = _T(' '); /* Need a space to terminate comparison loop */ + pp += 2; /* over '==' */ + while (_istspace (*pp)) /* Skip subsequent spaces */ + pp++; + + _tcscat (pp, _T(" ")); /* Add one space to ensure comparison ends */ + + while (*param == *pp) /* Comparison loop */ + { + if (_istspace (*param)) /* Terminates on space */ + break; + + param++, pp++; + } + + if (x_flag ^= (*param != *pp) ? 0 : X_EXEC) + { + while (*pp && !_istspace (*pp)) /* Find first space, */ + pp++; + + x_flag |= X_EMPTY; + } + } + + if (x_flag & X_EMPTY) + { + while (_istspace (*pp)) /* Then skip spaces */ + pp++; + + if (*pp == _T('\0')) /* If nothing left then syntax err */ + { + error_syntax (NULL); + return 1; + } + } + + if (x_flag & X_EXEC) + ParseCommandLine (pp); + + return 0; +} diff --git a/rosapps/cmd/internal.c b/rosapps/cmd/internal.c new file mode 100644 index 00000000000..b2019f7d056 --- /dev/null +++ b/rosapps/cmd/internal.c @@ -0,0 +1,485 @@ +/* + * INTERNAL.C - command.com internal commands. + * + * + * History: + * + * 17/08/94 (Tim Norman) + * started. + * + * 08/08/95 (Matt Rains) + * i have cleaned up the source code. changes now bring this source into + * guidelines for recommended programming practice. + * + * cd() + * started. + * + * dir() + * i have added support for file attributes to the DIR() function. the + * routine adds "d" (directory) and "r" (read only) output. files with the + * system attribute have the filename converted to lowercase. files with + * the hidden attribute are not displayed. + * + * i have added support for directorys. now if the directory attribute is + * detected the file size if replaced with the string "". + * + * ver() + * started. + * + * md() + * started. + * + * rd() + * started. + * + * del() + * started. + * + * does not support wildcard selection. + * + * todo: add delete directory support. + * add recursive directory delete support. + * + * ren() + * started. + * + * does not support wildcard selection. + * + * todo: add rename directory support. + * + * a general structure has been used for the cd, rd and md commands. this + * will be better in the long run. it is too hard to maintain such diverse + * functions when you are involved in a group project like this. + * + * 12/14/95 (Tim Norman) + * fixed DIR so that it will stick \*.* if a directory is specified and + * that it will stick on .* if a file with no extension is specified or + * *.* if it ends in a \ + * + * 1/6/96 (Tim Norman) + * added an isatty call to DIR so it won't prompt for keypresses unless + * stdin and stdout are the console. + * + * changed parameters to be mutually consistent to make calling the + * functions easier + * + * rem() + * started. + * + * doskey() + * started. + * + * 01/22/96 (Oliver Mueller) + * error messages are now handled by perror. + * + * 02/05/96 (Tim Norman) + * converted all functions to accept first/rest parameters + * + * 07/26/96 (Tim Norman) + * changed return values to int instead of void + * + * path() started. + * + * 12/23/96 (Aaron Kaufman) + * rewrote dir() to mimic MS-DOS's dir + * + * 01/28/97 (Tim Norman) + * cleaned up Aaron's DIR code + * + * 06/13/97 (Tim Norman) + * moved DIR code to dir.c + * re-implemented Aaron's DIR code + * + * 06/14/97 (Steffan Kaiser) + * ctrl-break handling + * bug fixes + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 03-Dec-1998 (Eric Kohl ) + * Replaced DOS calls by Win32 calls. + * + * 08-Dec-1998 (Eric Kohl ) + * Added help texts ("/?"). + * + * 18-Dec-1998 (Eric Kohl ) + * Added support for quoted arguments (cd "program files"). + * + * 07-Jan-1999 (Eric Kohl ) + * Clean up. + * + * 26-Jan-1999 (Eric Kohl ) + * Replaced remaining CRT io functions by Win32 io functions. + * Unicode safe! + * + * 30-Jan-1999 (Eric Kohl ) + * Added "cd -" feature. Changes to the previous directory. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include +#include + +#include "cmd.h" + + +extern COMMAND cmds[]; /* The internal command table, used in '?' */ + + +#ifdef INCLUDE_CMD_CHDIR + +static LPTSTR lpLastPath; + + +VOID InitLastPath (VOID) +{ + lpLastPath = NULL; +} + + +VOID FreeLastPath (VOID) +{ + if (lpLastPath) + free (lpLastPath); +} + + +/* + * CD / CHDIR + * + */ +INT cmd_chdir (LPTSTR cmd, LPTSTR param) +{ + LPTSTR dir; /* pointer to the directory to change to */ + LPTSTR place; /* used to search for the \ when no space is used */ + LPTSTR lpOldPath; + LPTSTR *arg = NULL; + INT argc; + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Changes the current directory or displays it's name\n\n" + "CHDIR [drive:][path]\n" + "CHDIR[..|-]\n" + "CD [drive:][path]\n" + "CD[..|-]\n\n" + " .. parent directory\n" + " - previous directory\n\n" + "Type CD drive: to display the current directory on the specified drive.\n" + "Type CD without a parameter to display the current drive and directory.")); + return 0; + } + + /* check if there is no space between the command and the path */ + if (param[0] == _T('\0')) + { + /* search for the '\', '.' or '-' so that both short & long names will work */ + for (place = cmd; *place; place++) + if (*place == _T('.') || *place == _T('\\') || *place == _T('-')) + break; + + if (*place) + dir = place; + else + /* signal that there are no parameters */ + dir = NULL; + } + else + { + arg = split (param, &argc); + + if (argc > 1) + { + /*JPP 20-Jul-1998 use standard error message */ + error_too_many_parameters (param); + freep (arg); + return 1; + } + else + dir = arg[0]; + } + + /* if doing a CD and no parameters given, print out current directory */ + if (!dir || !dir[0]) + { + TCHAR szPath[MAX_PATH]; + + GetCurrentDirectory (MAX_PATH, szPath); + + ConOutPuts (szPath); + + freep (arg); + + return 0; + } + + if (dir && _tcslen (dir) == 1 && *dir == _T('-')) + { + if (lpLastPath) + dir = lpLastPath; + else + { + freep (arg); + return 0; + } + } + else if (dir && _tcslen (dir) > 1 && dir[1] == _T(':')) + { + TCHAR szRoot[3] = _T("A:"); + TCHAR szPath[MAX_PATH]; + + szRoot[0] = _totupper (dir[0]); + GetFullPathName (szRoot, MAX_PATH, szPath, NULL); + + /* PathRemoveBackslash */ + if (_tcslen (szPath) > 3) + { + LPTSTR p = _tcsrchr (szPath, _T('\\')); + *p = _T('\0'); + } + + ConOutPuts (szPath); + + freep (arg); + + return 0; + } + + /* remove trailing \ if any, but ONLY if dir is not the root dir */ + if (_tcslen (dir) >= 2 && dir[_tcslen (dir) - 1] == _T('\\')) + dir[_tcslen(dir) - 1] = _T('\0'); + + + /* store current directory */ + lpOldPath = (LPTSTR)malloc (MAX_PATH * sizeof(TCHAR)); + GetCurrentDirectory (MAX_PATH, lpOldPath); + + if (!SetCurrentDirectory (dir)) + { + ErrorMessage (GetLastError(), _T("CD")); + + /* throw away current directory */ + free (lpOldPath); + lpOldPath = NULL; + + freep (arg); + return 1; + } + else + { + if (lpLastPath) + free (lpLastPath); + lpLastPath = lpOldPath; + } + + freep (arg); + + return 0; +} +#endif + + + +#ifdef INCLUDE_CMD_MKDIR +/* + * MD / MKDIR + * + */ +INT cmd_mkdir (LPTSTR cmd, LPTSTR param) +{ + LPTSTR dir; /* pointer to the directory to change to */ + LPTSTR place; /* used to search for the \ when no space is used */ + LPTSTR *p = NULL; + INT argc; + + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Creates a directory.\n\n" + "MKDIR [drive:]path\nMD [drive:]path")); + return 0; + } + + + /* check if there is no space between the command and the path */ + if (param[0] == _T('\0')) + { + /* search for the \ or . so that both short & long names will work */ + for (place = cmd; *place; place++) + if (*place == _T('.') || *place == _T('\\')) + break; + + if (*place) + dir = place; + else + /* signal that there are no parameters */ + dir = NULL; + } + else + { + p = split (param, &argc); + if (argc > 1) + { + /*JPP 20-Jul-1998 use standard error message */ + error_too_many_parameters (param); + freep (p); + return 1; + } + else + dir = p[0]; + } + + /* remove trailing \ if any, but ONLY if dir is not the root dir */ + if (_tcslen (dir) >= 2 && dir[_tcslen (dir) - 1] == _T('\\')) + dir[_tcslen(dir) - 1] = _T('\0'); + + if (!CreateDirectory (dir, NULL)) + { + ErrorMessage (GetLastError(), _T("MD")); + + freep (p); + return 1; + } + + freep (p); + + return 0; +} +#endif + + +#ifdef INCLUDE_CMD_RMDIR +/* + * RD / RMDIR + * + */ +INT cmd_rmdir (LPTSTR cmd, LPTSTR param) +{ + LPTSTR dir; /* pointer to the directory to change to */ + LPTSTR place; /* used to search for the \ when no space is used */ + + LPTSTR *p = NULL; + INT argc; + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Removes a directory.\n\n" + "RMDIR [drive:]path\nRD [drive:]path")); + return 0; + } + + /* check if there is no space between the command and the path */ + if (param[0] == _T('\0')) + { + /* search for the \ or . so that both short & long names will work */ + for (place = cmd; *place; place++) + if (*place == _T('.') || *place == _T('\\')) + break; + + if (*place) + dir = place; + else + /* signal that there are no parameters */ + dir = NULL; + } + else + { + p = split (param, &argc); + if (argc > 1) + { + /*JPP 20-Jul-1998 use standard error message */ + error_too_many_parameters (param); + freep (p); + return 1; + } + else + dir = p[0]; + } + + /* remove trailing \ if any, but ONLY if dir is not the root dir */ + if (_tcslen (dir) >= 2 && dir[_tcslen (dir) - 1] == _T('\\')) + dir[_tcslen(dir) - 1] = _T('\0'); + + if (!RemoveDirectory (dir)) + { + ErrorMessage (GetLastError(), _T("RD")); + freep (p); + + return 1; + } + + freep (p); + + return 0; +} +#endif + + +/* + * set the exitflag to true + * + */ +INT internal_exit (LPTSTR cmd, LPTSTR param) +{ + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Exits the command line interpreter.\n\nEXIT")); + } + else + { + bExit = TRUE; + } + + return 0; +} + + +#ifdef INCLUDE_CMD_REM +/* + * does nothing + * + */ +INT cmd_rem (LPTSTR cmd, LPTSTR param) +{ + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Starts a comment line in a batch file.\n\n" + "REM [Comment]")); + } + + return 0; +} +#endif + + +INT cmd_showcommands (LPTSTR cmd, LPTSTR param) +{ + LPCOMMAND cmdptr; + INT y; + + y = 0; + cmdptr = cmds; + while (cmdptr->name) + { + if (++y == 8) + { + ConOutPuts (cmdptr->name); + y = 0; + } + else + ConOutPrintf (_T("%-10s"), cmdptr->name); + + cmdptr++; + } + + if (y != 0) + ConOutChar (_T('\n')); + + return 0; +} diff --git a/rosapps/cmd/label.c b/rosapps/cmd/label.c new file mode 100644 index 00000000000..285421954dd --- /dev/null +++ b/rosapps/cmd/label.c @@ -0,0 +1,121 @@ +/* + * LABEL.C - label internal command. + * + * + * History: + * + * 10-Dec-1998 (Eric Kohl ) + * Started. + * + * 11-Dec-1998 (Eric Kohl ) + * Finished. + * + * 19-Jan-1998 (Eric Kohl ) + * Unicode ready! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_LABEL + +#include +#include +#include + +#include "cmd.h" + + +INT cmd_label (LPTSTR cmd, LPTSTR param) +{ + TCHAR szRootPath[] = _T("A:\\"); + TCHAR szLabel[80]; + TCHAR szOldLabel[80]; + DWORD dwSerialNr; + LPTSTR *arg; + INT args; + + /* set empty label string */ + szLabel[0] = _T('\0'); + + /* print help */ + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Displays or changes drive label.\n\n" + "LABEL [drive:][label]")); + return 0; + } + + /* get parameters */ + arg = split (param, &args); + + if (args > 2) + { + /* too many parameters */ + error_too_many_parameters (arg[args - 1]); + freep (arg); + return 1; + } + + if (args == 0) + { + /* get label of current drive */ + TCHAR szCurPath[MAX_PATH]; + GetCurrentDirectory (MAX_PATH, szCurPath); + szRootPath[0] = szCurPath[0]; + } + else + { + if ((_tcslen (arg[0]) >= 2) && (arg[0][1] == _T(':'))) + { + szRootPath[0] = toupper (*arg[0]); + if (args == 2) + _tcsncpy (szLabel, arg[1], 12); + } + else + { + TCHAR szCurPath[MAX_PATH]; + GetCurrentDirectory (MAX_PATH, szCurPath); + szRootPath[0] = szCurPath[0]; + _tcsncpy (szLabel, arg[0], 12); + } + } + + /* check root path */ + if (!IsValidPathName (szRootPath)) + { + error_invalid_drive (); + freep (arg); + return 1; + } + + GetVolumeInformation (szRootPath, szOldLabel, 80, &dwSerialNr, + NULL, NULL, NULL, 0); + + /* print drive info */ + ConOutPrintf (_T("Volume in drive %c:"), _totupper (szRootPath[0])); + + if (szOldLabel[0] != _T('\0')) + ConOutPrintf (_T(" is %s\n"), szOldLabel); + else + ConOutPrintf (_T(" has no label\n")); + + /* print the volume serial number */ + ConOutPrintf (_T("Volume Serial Number is %04X-%04X\n"), + HIWORD(dwSerialNr), LOWORD(dwSerialNr)); + + if (szLabel[0] == _T('\0')) + { + ConOutPrintf (_T("Drive label (11 Characters, ENTER if none)? ")); + ConInString (szLabel, 80); + } + + SetVolumeLabel (szRootPath, szLabel); + + freep (arg); + + return 0; +} + +#endif /* INCLUDE_CMD_LABEL */ \ No newline at end of file diff --git a/rosapps/cmd/license.txt b/rosapps/cmd/license.txt new file mode 100644 index 00000000000..c4fb365c774 --- /dev/null +++ b/rosapps/cmd/license.txt @@ -0,0 +1,342 @@ + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program 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 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + + diff --git a/rosapps/cmd/locale.c b/rosapps/cmd/locale.c new file mode 100644 index 00000000000..b97c97102b3 --- /dev/null +++ b/rosapps/cmd/locale.c @@ -0,0 +1,118 @@ +/* + * LOCALE.C - locale handling. + * + * + * History: + * + * 09-Jan-1999 (Eric Kohl ) + * Started. + * + * 20-Jan-1999 (Eric Kohl ) + * Unicode safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include +#include + +#include "cmd.h" + + +TCHAR cDateSeparator; +TCHAR cTimeSeparator; +TCHAR cThousandSeparator; +TCHAR cDecimalSeparator; +INT nDateFormat; +INT nTimeFormat; +TCHAR aszDayNames[7][8]; +INT nNumberGroups; + + +VOID InitLocale (VOID) +{ +#ifdef LOCALE_WINDOWS + TCHAR szBuffer[256]; + INT i; + + /* date settings */ + GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_SDATE, szBuffer, 256); + CharToOem (szBuffer, szBuffer); + cDateSeparator = szBuffer[0]; + GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_IDATE, szBuffer, 256); + nDateFormat = _ttoi (szBuffer); + + /* time settings */ + GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_STIME, szBuffer, 256); + CharToOem (szBuffer, szBuffer); + cTimeSeparator = szBuffer[0]; + GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_ITIME, szBuffer, 256); + nTimeFormat = _ttoi (szBuffer); + + /* number settings */ + GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szBuffer, 256); + CharToOem (szBuffer, szBuffer); + cThousandSeparator = szBuffer[0]; + GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, szBuffer, 256); + CharToOem (szBuffer, szBuffer); + cDecimalSeparator = szBuffer[0]; + GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_SGROUPING, szBuffer, 256); + nNumberGroups = _ttoi (szBuffer); + + /* days of week */ + for (i = 0; i < 7; i++) + { + GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_SABBREVDAYNAME1 + i, szBuffer, 256); + CharToOem (szBuffer, szBuffer); + _tcscpy (aszDayNames[(i+1)%7], szBuffer); /* little hack */ + } +#endif + +#ifdef LOCALE_GERMAN + LPTSTR names [7] = {_T("So"), _T("Mo"), _T("Di"), _T("Mi"), _T("Do"), _T("Fr"), _T("Sa")}; + INT i; + + /* date settings */ + cDateSeparator = '.'; + nDateFormat = 1; /* ddmmyy */ + + /* time settings */ + cTimeSeparator = ':'; + nTimeFormat = 1; /* 24 hour */ + + /* number settings */ + cThousandSeparator = '.'; + cDecimalSeparator = ','; + nNumberGroups = 3; + + /* days of week */ + for (i = 0; i < 7; i++) + _tcscpy (aszDayNames[i], names[i]); +#endif + +#ifdef LOCALE_DEFAULT + LPTSTR names [7] = {_T("Son"), _T("Mon"), _T("Tue"), _T("Wed"), _T("Thu"), _T("Fri"), _T("Sat")}; + INT i; + + /* date settings */ + cDateSeparator = '-'; + nDateFormat = 0; /* mmddyy */ + + /* time settings */ + cTimeSeparator = ':'; + nTimeFormat = 0; /* 12 hour */ + + /* number settings */ + cThousandSeparator = ','; + cDecimalSeparator = '.'; + nNumberGroups = 3; + + /* days of week */ + for (i = 0; i < 7; i++) + _tcscpy (aszDayNames[i], names[i]); +#endif +} diff --git a/rosapps/cmd/makefile b/rosapps/cmd/makefile index 7e36f733496..f956db79f62 100644 --- a/rosapps/cmd/makefile +++ b/rosapps/cmd/makefile @@ -1,12 +1,29 @@ -all: cmd.bin +# +# -OBJECTS = ../common/crt0.o cmd.o +LIB=../../lib +COMMON=../common -LIBS = ../../lib/mingw32/mingw32.a ../../lib/crtdll/crtdll.a \ - ../../lib/kernel32/kernel32.a ../../lib/ntdll/ntdll.a +# target: raw binary (does not work right now) +#all: cmd.bin + +# target: executable (not tested/experimental) +all: cmd.exe + +OBJECTS = $(COMMON)/crt0.o cmd.o attrib.o alias.o batch.o beep.o call.o cls.o cmdinput.o cmdtable.o\ + color.o date.o del.o dir.o echo.o err_hand.o error.o filecomp.o for.o goto.o history.o if.o\ + internal.o label.o misc.o path.o pause.o redir.o ren.o set.o shift.o tempfile.o time.o type.o ver.o\ + verify.o where.o + +LIBS = $(LIB)/mingw32/mingw32.a $(LIB)/crtdll/crtdll.a \ + $(LIB)/kernel32/kernel32.a $(LIB)/ntdll/ntdll.a cmd.bin: $(OBJECTS) $(LD) -Ttext 0x10000 $(OBJECTS) $(LIBS) -o cmd.exe $(OBJCOPY) -O binary cmd.exe cmd.bin +cmd.exe: $(OBJECTS) + $(LD) $(OBJECTS) $(LIBS) -o cmd.exe + include ../../rules.mak + diff --git a/rosapps/cmd/makefile.lcc b/rosapps/cmd/makefile.lcc new file mode 100644 index 00000000000..58c114a6bfa --- /dev/null +++ b/rosapps/cmd/makefile.lcc @@ -0,0 +1,194 @@ +# ReactOS cmd.exe makefile for lcc-win32 +# 19990119 Emanuele Aliberti +# 19990127 EA +# 19990128 Eric Kohl +# Modified for cmd 0.0.4pre3. +# +# ReactOS : http://www.sid-dis.com/reactos/ +# Lcc-Win32: http://www.cs.virginia.edu/*lcc-win32 +# +TARGET=cmd +CC=lcc.exe +CFLAGS=-c -O +LD=lcclnk.exe +LFLAGS=-subsystem console -s -o $(TARGET).exe +OBJS=alias.obj \ + attrib.obj \ + batch.obj \ + beep.obj \ + call.obj \ + chcp.obj \ + cls.obj \ + cmd.obj \ + cmdinput.obj \ + cmdtable.obj \ + color.obj \ + console.obj \ + copy.obj \ + date.obj \ + del.obj \ + dir.obj \ + dirstack.obj \ + echo.obj \ + error.obj \ + filecomp.obj \ + for.obj \ + goto.obj \ + history.obj \ + if.obj \ + internal.obj \ + label.obj \ + locale.obj \ + misc.obj \ + move.obj \ + path.obj \ + pause.obj \ + prompt.obj \ + redir.obj \ + ren.obj \ + set.obj \ + shift.obj \ + time.obj \ + type.obj \ + ver.obj \ + verify.obj \ + vol.obj \ + where.obj + +# MAIN + +# What about this implicid rule? +# It should compile all c files. +# (To test this, uncomment the following two lines.) EK +#.c.obj: +# $(CC) $(CFLAGS) $< + +$(TARGET).exe: $(OBJS) + $(LD) $(LFLAGS) $(OBJS) + +# MODULES + +alias.obj: alias.c + $(CC) $(CFLAGS) alias.c + +attrib.obj: attrib.c + $(CC) $(CFLAGS) attrib.c + +batch.obj: batch.c + $(CC) $(CFLAGS) batch.c + +beep.obj: beep.c + $(CC) $(CFLAGS) beep.c + +call.obj: call.c + $(CC) $(CFLAGS) call.c + +cls.obj: cls.c + $(CC) $(CFLAGS) cls.c + +cmd.obj: cmd.c + $(CC) $(CFLAGS) cmd.c + +cmdinput.obj: cmdinput.c + $(CC) $(CFLAGS) cmdinput.c + +cmdtable.obj: cmdtable.c + $(CC) $(CFLAGS) cmdtable.c + +color.obj: color.c + $(CC) $(CFLAGS) color.c + +console.obj: console.c + $(CC) $(CFLAGS) console.c + +copy.obj: copy.c + $(CC) $(CFLAGS) copy.c + +date.obj: date.c + $(CC) $(CFLAGS) date.c + +del.obj: del.c + $(CC) $(CFLAGS) del.c + +dir.obj: dir.c + $(CC) $(CFLAGS) dir.c + +dirstack.obj: dirstack.c + $(CC) $(CFLAGS) dirstack.c + +echo.obj: echo.c + $(CC) $(CFLAGS) echo.c + +error.obj: error.c + $(CC) $(CFLAGS) error.c + +filecomp.obj: filecomp.c + $(CC) $(CFLAGS) filecomp.c + +for.obj: for.c + $(CC) $(CFLAGS) for.c + +goto.obj: goto.c + $(CC) $(CFLAGS) goto.c + +history.obj: history.c + $(CC) $(CFLAGS) history.c + +if.obj: if.c + $(CC) $(CFLAGS) if.c + +internal.obj: internal.c + $(CC) $(CFLAGS) internal.c + +label.obj: label.c + $(CC) $(CFLAGS) label.c + +locale.obj: locale.c + $(CC) $(CFLAGS) locale.c + +misc.obj: misc.c + $(CC) $(CFLAGS) misc.c + +move.obj: move.c + $(CC) $(CFLAGS) move.c + +path.obj: path.c + $(CC) $(CFLAGS) path.c + +pause.obj: pause.c + $(CC) $(CFLAGS) pause.c + +prompt.obj: prompt.c + $(CC) $(CFLAGS) prompt.c + +redir.obj: redir.c + $(CC) $(CFLAGS) redir.c + +ren.obj: ren.c + $(CC) $(CFLAGS) ren.c + +set.obj: set.c + $(CC) $(CFLAGS) set.c + +shift.obj: shift.c + $(CC) $(CFLAGS) shift.c + +time.obj: time.c + $(CC) $(CFLAGS) time.c + +type.obj: type.c + $(CC) $(CFLAGS) type.c + +ver.obj: ver.c + $(CC) $(CFLAGS) ver.c + +verify.obj: verify.c + $(CC) $(CFLAGS) verify.c + +vol.obj: vol.c + $(CC) $(CFLAGS) vol.c + +where.obj: where.c + $(CC) $(CFLAGS) where.c + +#EOF diff --git a/rosapps/cmd/misc.c b/rosapps/cmd/misc.c new file mode 100644 index 00000000000..1eb5ca46869 --- /dev/null +++ b/rosapps/cmd/misc.c @@ -0,0 +1,296 @@ +/* + * MISC.C - misc. functions. + * + * + * History: + * + * 07/12/98 (Rob Lake) + * started + * + * 07/13/98 (Rob Lake) + * moved functions in here + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 18-Dec-1998 (Eric Kohl ) + * Changed split() to accept quoted arguments. + * Removed parse_firstarg(). + * + * 23-Jan-1999 (Eric Kohl ) + * Fixed an ugly bug in split(). In rare cases (last character + * of the string is a space) it ignored the NULL character and + * tried to add the following to the argument list. + * + * 28-Jan-1999 (Eric Kohl ) + * FileGetString() seems to be working now. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include +#include + +#include + +#include "cmd.h" + + +/* + * get a character out-of-band and honor Ctrl-Break characters + */ +TCHAR cgetchar (VOID) +{ + TCHAR ch; +#if 0 + DWORD dwRead; + DWORD dwOldMode; + HANDLE hIn; + + hIn = GetStdHandle (STD_INPUT_HANDLE); + ConInSwallowInput (hIn); + + GetConsoleMode (hIn, &dwOldMode); + SetConsoleMode (hIn, 0); + + ReadConsole (hIn, &ch, 1, &dwRead, NULL); + + DebugPrintf ("[cgetchar (0x%x) \'%c\']\n", ch, ch); + + SetConsoleMode (hIn, dwOldMode); +#endif + + if ((ch = getch()) == 0) + ch = getch() << 8; + + if (ch == 3) + bCtrlBreak = TRUE; + + return ch; +} + + +/* + * Check if Ctrl-Break was pressed during the last calls + */ + +BOOL CheckCtrlBreak (INT mode) +{ + static BOOL bLeaveAll = FALSE; /* leave all batch files */ + TCHAR c; + + switch (mode) + { + case BREAK_OUTOFBATCH: + bLeaveAll = 0; + return FALSE; + + case BREAK_BATCHFILE: + if (bLeaveAll) + return TRUE; + + if (!bCtrlBreak) + return FALSE; + + /* we need to be sure the string arrives on the screen! */ + do + ConOutPuts (_T("\r\nCtrl-Break pressed. Cancel batch file? (Yes/No/All) ")); + while (!_tcschr ("YNA\3", c = _totupper (cgetchar())) || !c); + + ConOutPuts (_T("\r\n")); + + if (c == _T('N')) + return bCtrlBreak = FALSE; /* ignore */ + + /* leave all batch files */ + bLeaveAll = ((c == _T('A')) || (c == _T('\3'))); + break; + + case BREAK_INPUT: + if (!bCtrlBreak) + return FALSE; + break; + } + + /* state processed */ + bCtrlBreak = FALSE; + return TRUE; +} + + +/* + * split - splits a line up into separate arguments, deliminators + * are spaces and slashes ('/'). + */ + +LPTSTR *split (LPTSTR s, LPINT args) +{ + LPTSTR *arg; + LPTSTR *p; + LPTSTR start; + LPTSTR q; + INT ac; + INT len; + BOOL bQuoted = FALSE; + + arg = malloc (sizeof (LPTSTR)); + if (!arg) + return NULL; + *arg = NULL; + + ac = 0; + while (*s) + { + /* skip leading spaces */ + while (*s && (_istspace (*s) || _istcntrl (*s))) + ++s; + + /* if quote (") then set bQuoted */ + if (*s == _T('\"')) + { + ++s; + bQuoted = TRUE; + } + + start = s; + + /* the first character can be '/' */ + if (*s == _T('/')) + ++s; + + /* skip to next word delimiter or start of next option */ + if (bQuoted) + { + while (_istprint (*s) && (*s != _T('\"')) && (*s != _T('/'))) + ++s; + } + else + { + while (_istprint (*s) && !_istspace (*s) && (*s != _T('/'))) + ++s; + } + + /* a word was found */ + if (s != start) + { + /* add new entry for new argument */ + arg = realloc (p = arg, (ac + 2) * sizeof (LPTSTR)); + if (!arg) + { + freep (p); + return NULL; + } + + /* create new entry */ + q = arg[ac] = malloc (((len = s - start) + 1) * sizeof (TCHAR)); + arg[++ac] = NULL; + if (!q) + { + freep (arg); + return NULL; + } + memcpy (q, start, len * sizeof (TCHAR)); + q[len] = _T('\0'); + } + + /* adjust string pointer if quoted (") */ + if (bQuoted) + { + ++s; + bQuoted = FALSE; + } + } + + *args = ac; + + return arg; +} + + +/* + * freep -- frees memory used for a call to split + * + */ +VOID freep (LPTSTR *p) +{ + LPTSTR *q; + + if (!p) + return; + + q = p; + while (*q) + free(*q++); + + free(p); +} + + +LPTSTR stpcpy (LPTSTR dest, LPTSTR src) +{ + _tcscpy (dest, src); + return (dest + _tcslen (src)); +} + + + +/* + * Checks if a path is valid (accessible) + */ + +BOOL IsValidPathName (LPCTSTR pszPath) +{ + TCHAR szOldPath[MAX_PATH]; + BOOL bResult; + + GetCurrentDirectory (MAX_PATH, szOldPath); + bResult = SetCurrentDirectory (pszPath); + + SetCurrentDirectory (szOldPath); + + return bResult; +} + + +/* + * Checks if a file exists (accessible) + */ + +BOOL IsValidFileName (LPCTSTR pszPath) +{ + return (GetFileAttributes (pszPath) != 0xFFFFFFFF); +} + + + +BOOL FileGetString (HANDLE hFile, LPTSTR lpBuffer, INT nBufferLength) +{ + LPTSTR lpString; + TCHAR ch; + DWORD dwRead; + + lpString = lpBuffer; + + while ((--nBufferLength > 0) && + ReadFile(hFile, &ch, 1, &dwRead, NULL) && dwRead) + { + *lpString++ = ch; + if (ch == _T('\r')) + { + /* overread '\n' */ + ReadFile (hFile, &ch, 1, &dwRead, NULL); + break; + } + } + + if (!dwRead && lpString == lpBuffer) + return FALSE; + + *lpString++ = _T('\0'); + + return TRUE; +} diff --git a/rosapps/cmd/move.c b/rosapps/cmd/move.c new file mode 100644 index 00000000000..54158d721a2 --- /dev/null +++ b/rosapps/cmd/move.c @@ -0,0 +1,267 @@ +/* + * MOVE.C - move internal command. + * + * + * History: + * + * 14-Dec-1998 (Eric Kohl ) + * Started. + * + * 18-Jan-1999 (Eric Kohl ) + * Unicode safe! + * Preliminary version!!! + * + * 20-Jan-1999 (Eric Kohl ) + * Redirection safe! + * + * 27-Jan-1999 (Eric Kohl ) + * Added help text ("/?"). + * Added more error checks. + * + * 03-Feb-1999 (Eric Kohl ) + * Added "/N" option. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_MOVE + +#include +#include +#include + +#include "cmd.h" + + +#define OVERWRITE_NO 0 +#define OVERWRITE_YES 1 +#define OVERWRITE_ALL 2 +#define OVERWRITE_CANCEL 3 + + +static INT Overwrite (LPTSTR fn) +{ + TCHAR inp[10]; + LPTSTR p; + + ConOutPrintf (_T("Overwrite %s (Yes/No/All)? "), fn); + ConInString (inp, 10); + + _tcsupr (inp); + for (p=inp; _istspace (*p); p++) + ; + + if (*p != _T('Y') && *p != _T('A')) + return OVERWRITE_NO; + if (*p == _T('A')) + return OVERWRITE_ALL; + + return OVERWRITE_YES; +} + + + +INT cmd_move (LPTSTR cmd, LPTSTR param) +{ + LPTSTR *arg; + INT argc, i, nFiles; + TCHAR szDestPath[MAX_PATH]; + TCHAR szSrcPath[MAX_PATH]; + BOOL bPrompt = TRUE; + LPTSTR p; + WIN32_FIND_DATA findBuffer; + HANDLE hFile; + LPTSTR pszFile; + BOOL bNothing = FALSE; + + if (!_tcsncmp (param, _T("/?"), 2)) + { +#if 0 + ConOutPuts (_T("Moves files and renames files and directories.\n\n" + "To move one or more files:\n" + "MOVE [/N][/Y|/-Y][drive:][path]filename1[,...] destination\n" + "\n" + "To rename a directory:\n" + "MOVE [/N][/Y|/-Y][drive:][path]dirname1 dirname2\n" + "\n" + " [drive:][path]filename1 Specifies the location and name of the file\n" + " or files you want to move.\n" + " /N Nothing. Don everthing but move files or direcories.\n" + " /Y\n" + " /-Y\n" + "...")); +#else + ConOutPuts (_T("Moves files and renames files and directories.\n\n" + "To move one or more files:\n" + "MOVE [/N][drive:][path]filename1[,...] destination\n" + "\n" + "To rename a directory:\n" + "MOVE [/N][drive:][path]dirname1 dirname2\n" + "\n" + " [drive:][path]filename1 Specifies the location and name of the file\n" + " or files you want to move.\n" + " /N Nothing. Don everthing but move files or direcories.\n" + "\n" + "Current limitations:\n" + " - You can't move a file or directory from one drive to another.\n" + )); +#endif + return 0; + } + + arg = split (param, &argc); + nFiles = argc; + + /* read options */ + for (i = 0; i < argc; i++) + { + p = arg[i]; + + if (*p == _T('/')) + { + p++; + if (*p == _T('-')) + { + p++; + if (_totupper (*p) == _T('Y')) + bPrompt = TRUE; + } + else + { + if (_totupper (*p) == _T('Y')) + bPrompt = FALSE; + else if (_totupper (*p) == _T('N')) + bNothing = TRUE; + } + nFiles--; + } + } + + if (nFiles < 2) + { + /* there must be at least two pathspecs */ + error_req_param_missing (); + return 1; + } + + /* get destination */ + GetFullPathName (arg[argc - 1], MAX_PATH, szDestPath, NULL); +#ifdef _DEBUG + DebugPrintf (_T("Destination: %s\n"), szDestPath); +#endif + + /* move it*/ + for (i = 0; i < argc - 1; i++) + { + if (*arg[i] == _T('/')) + continue; + + hFile = FindFirstFile (arg[i], &findBuffer); + if (hFile == INVALID_HANDLE_VALUE) + { + ErrorMessage (GetLastError (), arg[i]); + freep (arg); + return 1; + } + + do + { + GetFullPathName (findBuffer.cFileName, MAX_PATH, szSrcPath, &pszFile); + + if (GetFileAttributes (szSrcPath) & FILE_ATTRIBUTE_DIRECTORY) + { + /* source is directory */ + +#ifdef _DEBUG + DebugPrintf (_T("Move directory \'%s\' to \'%s\'\n"), + szSrcPath, szDestPath); +#endif + if (!bNothing) + { + MoveFile (szSrcPath, szDestPath); + } + } + else + { + /* source is file */ + + if (IsValidFileName (szDestPath)) + { + /* destination exists */ + if (GetFileAttributes (szDestPath) & FILE_ATTRIBUTE_DIRECTORY) + { + /* destination is existing directory */ + + TCHAR szFullDestPath[MAX_PATH]; + + _tcscpy (szFullDestPath, szDestPath); + _tcscat (szFullDestPath, _T("\\")); + _tcscat (szFullDestPath, pszFile); + + ConOutPrintf (_T("%s => %s"), szSrcPath, szFullDestPath); + + if (!bNothing) + { + if (MoveFile (szSrcPath, szFullDestPath)) + ConOutPrintf (_T("[OK]\n")); + else + ConOutPrintf (_T("[Error]\n")); + } + } + else + { + /* destination is existing file */ + INT nOverwrite; + + /* must get the overwrite code */ + if ((nOverwrite = Overwrite (szDestPath))) + { +#if 0 + if (nOverwrite == OVERWRITE_ALL) + *lpFlags |= FLAG_OVERWRITE_ALL; +#endif + ConOutPrintf (_T("%s => %s"), szSrcPath, szDestPath); + + if (!bNothing) + { + if (MoveFile (szSrcPath, szDestPath)) + ConOutPrintf (_T("[OK]\n")); + else + ConOutPrintf (_T("[Error]\n")); + } + } + } + } + else + { + /* destination does not exist */ + TCHAR szFullDestPath[MAX_PATH]; + + GetFullPathName (szDestPath, MAX_PATH, szFullDestPath, NULL); + + ConOutPrintf (_T("%s => %s"), szSrcPath, szFullDestPath); + + if (!bNothing) + { + if (MoveFile (szSrcPath, szFullDestPath)) + ConOutPrintf (_T("[OK]\n")); + else + ConOutPrintf (_T("[Error]\n")); + } + } + } + } + while (FindNextFile (hFile, &findBuffer)); + + FindClose (hFile); + } + + + freep (arg); + + return 0; +} + +#endif /* INCLUDE_CMD_MOVE */ \ No newline at end of file diff --git a/rosapps/cmd/path.c b/rosapps/cmd/path.c new file mode 100644 index 00000000000..714ee3879a7 --- /dev/null +++ b/rosapps/cmd/path.c @@ -0,0 +1,88 @@ +/* + * PATH.C - path internal command. + * + * + * History: + * + * 17 Jul 1998 (John P Price) + * Separated commands into individual files. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 09-Dec-1998 (Eric Kohl ) + * Added help text ("/?"). + * + * 18-Jan-1999 (Eric Kohl ) + * Unicode ready! + * + * 18-Jan-1999 (Eric Kohl ) + * Redirection safe! + * + * 24-Jan-1999 (Eric Kohl ) + * Fixed Win32 environment handling. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_PATH + +#include +#include +#include +#include + +#include "cmd.h" + + +/* size of environment variable buffer */ +#define ENV_BUFFER_SIZE 1024 + + +INT cmd_path (LPTSTR cmd, LPTSTR param) +{ + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Displays or sets a search path for executable files.\n\n" + "PATH [[drive:]path[;...]]\nPATH ;\n\n" + "Type PATH ; to clear all search-path settings and direct the command shell\n" + "to search only in the current directory.\n" + "Type PATH without parameters to display the current path.\n")); + return 0; + } + + /* if param is empty, display the PATH environment variable */ + if (!param || !*param) + { + DWORD dwBuffer; + LPTSTR pszBuffer; + + pszBuffer = (LPTSTR)malloc (ENV_BUFFER_SIZE * sizeof(TCHAR)); + dwBuffer = GetEnvironmentVariable (_T("PATH"), pszBuffer, ENV_BUFFER_SIZE); + if (dwBuffer == 0) + { + ConErrPrintf ("CMD: Not in environment \"PATH\"\n"); + return 0; + } + else if (dwBuffer > ENV_BUFFER_SIZE) + { + pszBuffer = (LPTSTR)realloc (pszBuffer, dwBuffer * sizeof (TCHAR)); + GetEnvironmentVariable (_T("PATH"), pszBuffer, ENV_BUFFER_SIZE); + } + + ConOutPrintf (_T("PATH=%s\n"), pszBuffer); + free (pszBuffer); + + return 0; + } + + /* set PATH environment variable */ + if (!SetEnvironmentVariable (_T("PATH"), param)) + return 1; + + return 0; +} + +#endif diff --git a/rosapps/cmd/pause.c b/rosapps/cmd/pause.c new file mode 100644 index 00000000000..f4c01bba15a --- /dev/null +++ b/rosapps/cmd/pause.c @@ -0,0 +1,68 @@ +/* + * PAUSE.C - pause internal command. + * + * + * History: + * + * 16 Jul 1998 (Hans B Pufal) + * started. + * + * 16 Jul 1998 (John P Price) + * Seperated commands into individual files. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 18-Jan-1999 (Eric Kohl ) + * Unicode ready! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_PAUSE + +#include +#include +#include + +#include "cmd.h" +#include "batch.h" + + +/* + * Perform PAUSE command. + * + * FREEDOS extension : If parameter is specified use that as the pause + * message. + * + * ?? Extend to include functionality of CHOICE if switch chars + * specified. + */ + +INT cmd_pause (LPTSTR cmd, LPTSTR param) +{ +#ifdef _DEBUG + DebugPrintf ("cmd_pause: \'%s\' : \'%s\'\n", cmd, param); +#endif + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Stops the execution of a batch file and shows the following message:\n" + "\"Press any key to continue...\" or a user defined message.\n\n" + "PAUSE [message]")); + return 0; + } + + if (*param) + ConOutPrintf (param); + else + msg_pause (); + + cgetchar (); + + return 0; +} + +#endif diff --git a/rosapps/cmd/prompt.c b/rosapps/cmd/prompt.c new file mode 100644 index 00000000000..fa674f1c4ce --- /dev/null +++ b/rosapps/cmd/prompt.c @@ -0,0 +1,237 @@ +/* + * PROMPT.C - prompt handling. + * + * + * History: + * + * 14/01/95 (Tim Normal) + * started. + * + * 08/08/95 (Matt Rains) + * i have cleaned up the source code. changes now bring this source + * into guidelines for recommended programming practice. + * + * 01/06/96 (Tim Norman) + * added day of the week printing (oops, forgot about that!) + * + * 08/07/96 (Steffan Kaiser) + * small changes for speed + * + * 20-Jul-1998 (John P Price ) + * removed redundant day strings. Use ones defined in date.c. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 28-Jul-1998 (John P Price ) + * moved cmd_prompt from internal.c to here + * + * 09-Dec-1998 (Eric Kohl ) + * Added help text ("/?"). + * + * 14-Dec-1998 (Eric Kohl ) + * Added "$+" option. + * + * 09-Jan-1999 (Eric Kohl ) + * Added "$A", "$C" and "$F" option. + * Added locale support. + * Fixed "$V" option. + * + * 20-Jan-1999 (Eric Kohl ) + * Unicode and redirection safe! + * + * 24-Jan-1999 (Eric Kohl ) + * Fixed Win32 environment handling. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include + +#include "cmd.h" + + +/* + * print the command-line prompt + * + */ +VOID PrintPrompt(VOID) +{ + static TCHAR default_pr[] = _T("$P$G"); + TCHAR szPrompt[256]; + LPTSTR pr; + + if (GetEnvironmentVariable (_T("PROMPT"), szPrompt, 256)) + pr = szPrompt; + else + pr = default_pr; + + while (*pr) + { + if (*pr != _T('$')) + { + ConOutChar (*pr); + } + else + { + pr++; + + switch (_totupper (*pr)) + { + case _T('A'): + ConOutChar (_T('&')); + break; + + case _T('B'): + ConOutChar (_T('|')); + break; + + case _T('C'): + ConOutChar (_T('(')); + break; + + case _T('D'): + { + TCHAR szDate[32]; + + GetDateFormat (LOCALE_USER_DEFAULT, DATE_SHORTDATE, + NULL, NULL, szDate, sizeof (szDate)); + ConOutPrintf (_T("%s"), szDate); + } + break; + + case _T('E'): + ConOutChar (_T('\x1B')); + break; + + case _T('F'): + ConOutChar (_T(')')); + break; + + case _T('G'): + ConOutChar (_T('>')); + break; + + case _T('H'): + ConOutChar (_T('\x08')); + break; + + case _T('L'): + ConOutChar (_T('<')); + break; + + case _T('N'): + { + TCHAR szPath[MAX_PATH]; + GetCurrentDirectory (MAX_PATH, szPath); + ConOutChar (szPath[0]); + } + break; + + case _T('P'): + { + TCHAR szPath[MAX_PATH]; + GetCurrentDirectory (MAX_PATH, szPath); + ConOutPrintf (_T("%s"), szPath); + } + break; + + case _T('Q'): + ConOutChar (_T('=')); + break; + + case _T('T'): + { + TCHAR szTime[32]; + GetTimeFormat (LOCALE_USER_DEFAULT, 0, NULL, + NULL, szTime, sizeof (szTime)); + ConOutPrintf (_T("%s"), szTime); + } + break; + + case _T('V'): + switch (osvi.dwPlatformId) + { + case VER_PLATFORM_WIN32_WINDOWS: + if (osvi.dwMajorVersion == 4 && + osvi.dwMinorVersion == 1) + ConOutPrintf (_T("Windows 98")); + else + ConOutPrintf (_T("Windows 95")); + break; + + case VER_PLATFORM_WIN32_NT: + ConOutPrintf (_T("Windows NT Version %lu.%lu"), + osvi.dwMajorVersion, osvi.dwMinorVersion); + break; + } + break; + + case _T('_'): + ConOutChar (_T('\n')); + break; + + case '$': + ConOutChar (_T('$')); + break; + +#ifdef FEATURE_DIRECTORY_STACK + case '+': + { + INT i; + for (i = 0; i < GetDirectoryStackDepth (); i++) + ConOutChar (_T('+')); + } + break; +#endif + } + } + pr++; + } +} + + +#ifdef INCLUDE_CMD_PROMPT + +INT cmd_prompt (LPTSTR cmd, LPTSTR param) +{ + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Changes the command prompt.\n\n" + "PROMPT [text]\n\n" + " text Specifies a new command prompt.\n\n" + "Prompt can be made up of normal characters and the following special codes:\n\n" + " $A & (Ampersand)\n" + " $B | (pipe)\n" + " $C ( (Left parenthesis)\n" + " $D Current date\n" + " $E Escape code (ASCII code 27)\n" + " $F ) (Right parenthesis)\n" + " $G > (greater-than sign)\n" + " $H Backspace (erases previous character)\n" + " $L < (less-than sign)\n" + " $N Current drive\n" + " $P Current drive and path\n" + " $Q = (equal sign)\n" + " $T Current time\n" + " $V OS version number\n" + " $_ Carriage return and linefeed\n" + " $$ $ (dollar sign)")); +#ifdef FEATURE_DIRECTORY_STACK + ConOutPuts (_T(" $+ Displays the current depth of the directory stack")); +#endif + ConOutPuts (_T("\nType PROMPT without parameters to reset the prompt to the default setting.")); + return 0; + } + + /* set PROMPT environment variable */ + if (!SetEnvironmentVariable (_T("PROMPT"), param)) + return 1; + + return 0; +} +#endif diff --git a/rosapps/cmd/readme.txt b/rosapps/cmd/readme.txt new file mode 100644 index 00000000000..b76a3a77baf --- /dev/null +++ b/rosapps/cmd/readme.txt @@ -0,0 +1,101 @@ +ReactOS Command Line Interface "CMD" version 0.0.4 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is the fourth pre-alpha release of CMD.EXE for ReactOS. +It was converted from the FreeDOS COMMAND.COM. + + +Warning!! Warning!! Warning!! +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This is a pre-alpha version! Many features have not been tested! +Be careful when you use commands that write to your disk drives, +they might destroy your files or the file system!!! + + +Status +~~~~~~ +This is a converted version of FreeDOS COMMAND.COM. +I added some commands from WinNT's CMD.EXE. + + +New features and improvements +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + - Fixed redirection and piping. + (E.g. you can use "type > file" now.) + - Added new error redirections "2>" and "2>>". + (E.g.: "make 2>error.log") + - Added CHCP command. + - Fixed environment handling. + - New makefile for lcc-win (makefile.lcc). + - Rewrote DEL and MOVE with a new structure. + - Improved national language support. + - Fixed filename completion. + + +Compiling +~~~~~~~~~ +I converted CMD using MS Visual C++ 5.0 and Win95. The included makefile +is just an experimental version. + +If you want to compile and test CMD with djgpp, modify the makefile as needed. +I put the CMD sources into [reactos\apps], the makefile is written for that +directory. + +If you want to compile and test CMD using another compiler, just create +a new console application project and add all *.c and *.h files to it. +It should compile without an error. + + +Please report bugs which are not listed above. + + +Good luck + + Eric Kohl + + + + +FreeDOS Command Line Interface +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +About +~~~~~ +This software is part of the FreeDOS project. Please email +freedos@sunsite.unc.edu for more information, or visit the freedos +archive at "ftp://sunsite.unc.edu/pub/micro/pc-stuff/freedos". Also, +visit our web page at http://www.freedos.org/. + +The command.com web site is at + + http://www.gcfl.net/FreeDOS/command.com/ + + +This software has been developed by the following people: +(listed in approximate chronological order of contributions) + +FreeDOS developers: + normat@rpi.edu (Tim Norman) + mrains@apanix.apana.org.au (Matt Rains) + ejeffrey@iastate.edu (Evan Jeffrey) + Steffen.Kaiser@Informatik.TU-Chemnitz.DE (Steffen Kaiser) + Svante Frey (sfrey@kuai.se) + Oliver Mueller (ogmueller@t-online.de) + Aaron Kaufman (morgan@remarque.berkeley.edu) + Marc Desrochers (bitzero@hotmail.com) + Rob Lake (rlake@cs.mun.ca) + John P. Price + Hans B Pufal + +ReactOS developers: + Eric Kohl + + +Current Features +~~~~~~~~~~~~~~~~ + - environment handling with prompt and path support. + - directory utilities. + - command-line history with doskey-like features. + - batch file processing. + - input/output redirection and piping. + - alias support. + - filename completion (use TAB) diff --git a/rosapps/cmd/redir.c b/rosapps/cmd/redir.c new file mode 100644 index 00000000000..594bc112099 --- /dev/null +++ b/rosapps/cmd/redir.c @@ -0,0 +1,218 @@ +/* + * REDIR.C - redirection handling. + * + * + * History: + * + * 12/15/95 (Tim Norman) + * started. + * + * 12 Jul 98 (Hans B Pufal) + * Rewrote to make more efficient and to conform to new command.c + * and batch.c processing. + * + * 27-Jul-1998 (John P Price ) + * Added config.h include + * + * 22-Jan-1999 (Eric Kohl ) + * Unicode safe! + * Added new error redirection "2>" and "2>>". + * + * 26-Jan-1999 (Eric Kohl ) + * Added new error AND output redirection "&>" and "&>>". + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef FEATURE_REDIRECTION + +#include +#include +#include +#include + +#include "cmd.h" + + +static BOOL +IsRedirection (TCHAR c) +{ + return (c == _T('<')) || (c == _T('>')) || (c == _T('|')); +} + + +/* + * Gets the redirection info from the command line and copies the + * file names into ifn, ofn and efn removing them from the command + * line. + * + * Converts remaining command line into a series of null terminated + * strings defined by the pipe char '|'. Each string corresponds + * to a single executable command. A double null terminates the + * command strings. + * + * Return number of command strings found. + * + */ + +INT GetRedirection (LPTSTR s, LPTSTR ifn, LPTSTR ofn, LPTSTR efn, LPINT lpnFlags) +{ + INT num = 1; + LPTSTR dp = s; + LPTSTR sp = s; + + /* find and remove all the redirections first */ + while (*sp) + { + if ((*sp == _T('"')) || (*sp == _T('\''))) + { + /* No redirects inside quotes */ + TCHAR qc = *sp; + + do + *dp++ = *sp++; + while (*sp != qc); + + *dp++ = *sp++; + } + else if ((*sp == _T('<')) || (*sp == _T('>')) || + (*sp == _T('2')) || (*sp == _T('&'))) + { + /* MS-DOS ignores multiple redirection symbols and uses the last */ + /* redirection, so we'll emulate that and not check */ + + if (*sp == _T('<')) + { + /* input redirection */ + *lpnFlags |= INPUT_REDIRECTION; + while (_istspace (*sp)) + sp++; + + /* copy file name */ + while (*sp && !IsRedirection (*sp) && !_istspace (*sp)) + *ifn++ = *sp++; + *ifn = _T('\0'); + } + else if (*sp == _T('>')) + { + /* output redirection */ + *lpnFlags |= OUTPUT_REDIRECTION; + sp++; + + /* append request ? */ + if (*sp == _T('>')) + { + *lpnFlags |= OUTPUT_APPEND; + sp++; + } + + while (_istspace (*sp)) + sp++; + + /* copy file name */ + while (*sp && !IsRedirection (*sp) && !_istspace (*sp)) + *ofn++ = *sp++; + *ofn = _T('\0'); + } + else if (*sp == _T('2')) + { + /* error redirection */ + sp++; + + if (*sp == _T('>')) + { + *lpnFlags |= ERROR_REDIRECTION; + sp++; + + /* append request ? */ + if (*sp == _T('>')) + { + *lpnFlags |= ERROR_APPEND; + sp++; + } + } + else + { + /* no redirection!! copy the '2' character! */ + sp--; + *dp++ = *sp++; + continue; + } + + while (_istspace (*sp)) + sp++; + + /* copy file name */ + while (*sp && !IsRedirection (*sp) && !_istspace (*sp)) + *efn++ = *sp++; + *efn = _T('\0'); + } + else if (*sp == _T('&')) + { + /* output AND error redirection */ + sp++; + + if (*sp == _T('>')) + { + *lpnFlags |= (ERROR_REDIRECTION | OUTPUT_REDIRECTION); + sp++; + + /* append request ? */ + if (*sp == _T('>')) + { + *lpnFlags |= (ERROR_APPEND | OUTPUT_APPEND); + sp++; + } + } + else + { + /* no redirection!! copy the '&' character! */ + sp--; + *dp++ = *sp++; + continue; + } + + while (_istspace (*sp)) + sp++; + + /* copy file name */ + while (*sp && !IsRedirection (*sp) && !_istspace (*sp)) + *ofn++ = *efn++ = *sp++; + *ofn = *efn = _T('\0'); + } + } + else + *dp++ = *sp++; + } + *dp++ = _T('\0'); + *dp = _T('\0'); + + /* now go for the pipes */ + sp = s; + while (*sp) + { + if ((*sp == _T('"')) || (*sp == _T('\''))) + { + TCHAR qc = *sp; + + do + sp++; + while (*sp != qc); + + sp++; + } + else if (*sp == _T('|')) + { + *sp++ = '\0'; + num++; + } + else + sp++; + } + + return num; +} + +#endif /* FEATURE_REDIRECTION */ diff --git a/rosapps/cmd/ren.c b/rosapps/cmd/ren.c new file mode 100644 index 00000000000..2023d075cf6 --- /dev/null +++ b/rosapps/cmd/ren.c @@ -0,0 +1,72 @@ +/* + * REN.C - rename internal command. + * + * + * History: + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 18-Dec-1998 (Eric Kohl + * Added support for quoted long file names with spaces. + * + * 20-Jan-1999 (Eric Kohl + * Unicode and redirection safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_RENAME + +#include +#include +#include + +#include "cmd.h" + +/* + * simple file rename internal command. + * + */ +INT cmd_rename (LPTSTR cmd, LPTSTR param) +{ + LPTSTR *arg; + INT argc; + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Renames a file/directory or files/directories.\n" + "\n" + "RENAME [drive:][path][directoryname1 | filename1] [directoryname2 | filename2]\n" + "REN [drive:][path][directoryname1 | filename1] [directoryname2 | filename2]\n" + "\n" + "Note that you cannot specify a new drive or path for your destination. Use\n" + "the MOVE command for that purpose.")); + return 0; + } + + /* split the argument list */ + arg = split (param, &argc); + + if (argc != 2) + { + freep (arg); + error_too_many_parameters (param); + return 1; + } + + if (!MoveFile (arg[0], arg[1])) + { + ConErrPuts (_T("rename")); + freep (arg); + return 1; + } + + freep (arg); + + return 0; +} + +#endif diff --git a/rosapps/cmd/set.c b/rosapps/cmd/set.c new file mode 100644 index 00000000000..7be3388eac9 --- /dev/null +++ b/rosapps/cmd/set.c @@ -0,0 +1,127 @@ +/* + * SET.C - set internal command. + * + * + * History: + * + * 06/14/97 (Tim Norman) + * changed static var in set() to a malloc'd space to pass to putenv. + * need to find a better way to do this, since it seems it is wasting + * memory when variables are redefined. + * + * 07/08/1998 (John P. Price) + * removed call to show_environment in set command. + * moved test for syntax before allocating memory in set command. + * misc clean up and optimization. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 28-Jul-1998 (John P Price ) + * added set_env function to set env. variable without needing set command + * + * 09-Dec-1998 (Eric Kohl ) + * Added help text ("/?"). + * + * 24-Jan-1999 (Eric Kohl ) + * Fixed Win32 environment handling. + * Unicode and redirection safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_SET + +#include +#include +#include +#include + +#include "cmd.h" + + +/* size of environment variable buffer */ +#define ENV_BUFFER_SIZE 1024 + + +INT cmd_set (LPTSTR cmd, LPTSTR param) +{ + LPTSTR p; + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Displays, sets, or removes environment variables.\n\n" + "SET [variable[=][string]]\n\n" + " variable Specifies the environment-variable name.\n" + " string Specifies a series of characters to assign to the variable.\n\n" + "Type SET without parameters to display the current environment variables.\n")); + return 0; + } + + /* if no parameters, show the environment */ + if (param[0] == _T('\0')) + { + LPTSTR lpEnv; + LPTSTR lpOutput; + INT len; + + lpEnv = (LPTSTR)GetEnvironmentStrings (); + if (lpEnv) + { + lpOutput = lpEnv; + while (*lpOutput) + { + len = _tcslen(lpOutput); + if (len) + { + if (*lpOutput != _T('=')) + ConOutPuts (lpOutput); + lpOutput += (len + 1); + } + } + FreeEnvironmentStrings (lpEnv); + } + + return 0; + } + + p = _tcschr (param, _T('=')); + if (p) + { + /* set or remove environment variable */ + *p = _T('\0'); + p++; + + SetEnvironmentVariable (param, p); + } + else + { + /* display environment variable */ + LPTSTR pszBuffer; + DWORD dwBuffer; + + pszBuffer = (LPTSTR)malloc (ENV_BUFFER_SIZE * sizeof(TCHAR)); + dwBuffer = GetEnvironmentVariable (param, pszBuffer, ENV_BUFFER_SIZE); + if (dwBuffer == 0) + { + ConErrPrintf ("CMD: Not in environment \"%s\"\n", param); + return 0; + } + else if (dwBuffer > ENV_BUFFER_SIZE) + { + pszBuffer = (LPTSTR)realloc (pszBuffer, dwBuffer * sizeof (TCHAR)); + GetEnvironmentVariable (param, pszBuffer, ENV_BUFFER_SIZE); + } + + ConOutPrintf ("%s\n", pszBuffer); + free (pszBuffer); + + return 0; + } + + return 0; +} + +#endif diff --git a/rosapps/cmd/shift.c b/rosapps/cmd/shift.c new file mode 100644 index 00000000000..92ee0363c12 --- /dev/null +++ b/rosapps/cmd/shift.c @@ -0,0 +1,72 @@ +/* + * SHIFT.C - shift internal batch command + * + * + * History: + * + * 16 Jul 1998 (Hans B Pufal) + * started. + * + * 16 Jul 1998 (John P Price) + * Separated commands into individual files. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 07-Jan-1999 (Eric Kohl ) + * Added help text ("shift /?") and cleaned up. + * + * 20-Jan-1999 (Eric Kohl ) + * Unicode and redirection safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include + +#include "cmd.h" +#include "batch.h" + + +/* + * Perform the SHIFT command. + * + * Only valid inside batch files. + * + * FREEDOS extension : optional parameter DOWN to allow shifting + * parameters backwards. + */ + +INT cmd_shift (LPTSTR cmd, LPTSTR param) +{ +#ifdef _DEBUG + DebugPrintf ("cmd_shift: (\'%s\', \'%s\'\n", cmd, param); +#endif + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Changes the position of replaceable parameters in a batch file.\n\n" + "SHIFT [DOWN]")); + return 0; + } + + if (bc == NULL) + { + /* not in batch - error!! */ + return 1; + } + + if (!_tcsicmp (param, _T("down"))) + { + if (bc->shiftlevel) + bc->shiftlevel--; + } + else /* shift up */ + bc->shiftlevel++; + + return 0; +} diff --git a/rosapps/cmd/time.c b/rosapps/cmd/time.c new file mode 100644 index 00000000000..f2b01d84aa2 --- /dev/null +++ b/rosapps/cmd/time.c @@ -0,0 +1,253 @@ +/* + * TIME.C - time internal command. + * + * + * History: + * + * 07/08/1998 (John P. Price) + * started. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 09-Jan-1999 (Eric Kohl ) + * Added locale support. + * + * 19-Jan-1999 (Eric Kohl ) + * Unicode and redirection safe! + * Added "/t" option. + * + * 04-Feb-1999 (Eric Kohl ) + * Fixed time input bug. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_TIME + +#include +#include +#include +#include + +#include "cmd.h" + + +static VOID +PrintTime (VOID) +{ +#if 0 + SYSTEMTIME st; + + GetLocalTime (&st); + + switch (nTimeFormat) + { + case 0: /* 12 hour format */ + default: + ConOutPrintf (_T("Current time is %2d%c%02d%c%02d%c%02d%c\n"), + (st.wHour == 0 ? 12 : (st.wHour <= 12 ? st.wHour : st.wHour - 12)), + cTimeSeparator, st.wMinute, cTimeSeparator, st.wSecond, cDecimalSeparator, + st.wMilliseconds / 10, (st.wHour <= 11 ? 'a' : 'p')); + break; + + case 1: /* 24 hour format */ + ConOutPrintf (_T("Current time is %2d%c%02d%c%02d%c%02d\n"), + st.wHour, cTimeSeparator, st.wMinute, cTimeSeparator, + st.wSecond, cDecimalSeparator, st.wMilliseconds / 10); + break; + } +#endif + + TCHAR szTime[32]; + + GetTimeFormat (LOCALE_USER_DEFAULT, 0, NULL, NULL, + szTime, sizeof (szTime)); + ConOutPrintf (_T("Current date is: %s\n"), szTime); +} + + +static BOOL ParseTime (LPTSTR s) +{ + SYSTEMTIME t; + LPTSTR p = s; + + if (!*s) + return TRUE; + + GetLocalTime (&t); + t.wHour = 0; + t.wMinute = 0; + t.wSecond = 0; + t.wMilliseconds = 0; + + // first get hour + if (_istdigit(*p)) + { + while (_istdigit(*p)) + { + t.wHour = t.wHour * 10 + *p - _T('0'); + p++; + } + } + else + return FALSE; + + // get time separator + if (*p != cTimeSeparator) + return FALSE; + p++; + + // now get minutes + if (_istdigit(*p)) + { + while (_istdigit(*p)) + { + t.wMinute = t.wMinute * 10 + *p - _T('0'); + p++; + } + } + else + return FALSE; + + // get time separator + if (*p != cTimeSeparator) + return FALSE; + p++; + + // now get seconds + if (_istdigit(*p)) + { + while (_istdigit(*p)) + { + t.wSecond = t.wSecond * 10 + *p - _T('0'); + p++; + } + } + else + return FALSE; + + // get decimal separator + if (*p == cDecimalSeparator) + { + p++; + + // now get hundreths + if (_istdigit(*p)) + { + while (_istdigit(*p)) + { +// t.wMilliseconds = t.wMilliseconds * 10 + *p - _T('0'); + p++; + } +// t.wMilliseconds *= 10; + } + } + + /* special case: 12 hour format */ + if (nTimeFormat == 0) + { + if (_totupper(*s) == _T('P')) + { + t.wHour += 12; + } + + if ((_totupper(*s) == _T('A')) && (t.wHour == 12)) + { + t.wHour = 0; + } + } + + if (t.wHour > 23 || t.wMinute > 60 || t.wSecond > 60 || t.wMilliseconds > 999) + return FALSE; + + SetLocalTime (&t); + + return TRUE; +} + + +INT cmd_time (LPTSTR cmd, LPTSTR param) +{ + LPTSTR *arg; + INT argc; + INT i; + BOOL bPrompt = TRUE; + INT nTimeString = -1; + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Displays or sets the system time.\n\n" + "TIME [/T][time]\n\n" + " /T display only\n\n" + "Type TIME with no parameters to display the current time setting and a prompt\n" + "for a new one. Press ENTER to keep the same time.")); + return 0; + } + + /* build parameter array */ + arg = split (param, &argc); + + /* check for options */ + for (i = 0; i < argc; i++) + { + if (_tcsicmp (arg[i], _T("/t")) == 0) + bPrompt = FALSE; + if ((*arg[i] != _T('/')) && (nTimeString == -1)) + nTimeString = i; + } + + if (nTimeString == -1) + PrintTime (); + + if (!bPrompt) + { + freep (arg); + return 0; + } + + while (1) + { + if (nTimeString == -1) + { + TCHAR s[40]; + + ConOutPrintf (_T("Enter new time: ")); + + ConInString (s, 40); + +#ifdef _DEBUG + DebugPrintf ("\'%s\'\n", s); +#endif + + while (*s && s[_tcslen (s) - 1] < _T(' ')) + s[_tcslen(s) - 1] = _T('\0'); + + if (ParseTime (s)) + { + freep (arg); + return 0; + } + } + else + { + if (ParseTime (arg[nTimeString])) + { + freep (arg); + return 0; + } + + // force input the next time around. + nTimeString == -1; + } + ConErrPuts (_T("Invalid time.")); + } + + freep (arg); + + return 0; +} + +#endif diff --git a/rosapps/cmd/todo.txt b/rosapps/cmd/todo.txt new file mode 100644 index 00000000000..bcffe59a323 --- /dev/null +++ b/rosapps/cmd/todo.txt @@ -0,0 +1,21 @@ +Things to do +~~~~~~~~~~~~ +Fix bugs :) + +Rewrite DIR command (Unicode aware / new structure). + +Optimize the code! For size and speed. There are numerous places +where the code is hardly optimal for either. + +Sorting in DIR command ("dir /o..."). + +^S and ^Q to pause/resume displays. + +Improve DEL, COPY and MOVE commands. +BREAK command on command-line. + +Add wildcard support to REN. + +Add "/?" support to all batch commands. + +And many, many more... diff --git a/rosapps/cmd/type.c b/rosapps/cmd/type.c new file mode 100644 index 00000000000..b4713562b90 --- /dev/null +++ b/rosapps/cmd/type.c @@ -0,0 +1,96 @@ +/* + * TYPE.C - type internal command. + * + * History: + * + * 07/08/1998 (John P. Price) + * started. + * + * 07/12/98 (Rob Lake) + * Changed error messages + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 07-Jan-1999 (Eric Kohl ) + * Added support for quoted arguments (type "test file.dat"). + * Cleaned up. + * + * 19-Jan-1999 (Eric Kohl ) + * Unicode and redirection ready! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_TYPE + +#include +#include +#include + +#include "cmd.h" + + +INT cmd_type (LPTSTR cmd, LPTSTR param) +{ + TCHAR szBuffer[256]; + HANDLE hFile; + DWORD dwBytesRead; + DWORD dwBytesWritten; + BOOL bResult; + INT args; + LPTSTR *arg; + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Displays the contents of text files.\n\n" + "TYPE [drive:][path]filename")); + return 0; + } + + if (!*param) + { + error_req_param_missing (); + return 1; + } + + arg = split (param, &args); + + if (args > 1) + { + error_too_many_parameters (_T("\b \b")); + freep (arg); + return 1; + } + + hFile = CreateFile (arg[0], GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + + if (hFile == INVALID_HANDLE_VALUE) + { + error_sfile_not_found (param); + freep (arg); + return 1; + } + + do + { + bResult = ReadFile (hFile, szBuffer, sizeof(szBuffer), + &dwBytesRead, NULL); + if (dwBytesRead) + WriteFile (GetStdHandle (STD_OUTPUT_HANDLE), szBuffer, dwBytesRead, + &dwBytesWritten, NULL); + } + while (bResult && dwBytesRead > 0); + + CloseHandle (hFile); + freep (arg); + + return 0; +} + +#endif diff --git a/rosapps/cmd/ver.c b/rosapps/cmd/ver.c new file mode 100644 index 00000000000..f5e76fc79e7 --- /dev/null +++ b/rosapps/cmd/ver.c @@ -0,0 +1,139 @@ +/* + * VER.C - ver internal command. + * + * + * History: + * + * 06/30/98 (Rob Lake) + * rewrote ver command to accept switches, now ver alone prints + * copyright notice only. + * + * 27-Jul-1998 (John P Price ) + * added config.h include + * + * 30-Jul-1998 (John P Price ) + * added text about where to send bug reports and get updates. + * + * 20-Jan-1999 (Eric Kohl ) + * Unicode and redirection safe! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include + +#include "cmd.h" + +#define VER_HELP "display shell version info VER [/C/R/W/?]" + + +VOID ShortVersion (VOID) +{ + ConOutPuts (_T("\n" SHELLINFO " " SHELLVER "\n")); +} + + +#ifdef INCLUDE_CMD_VER + +/* + * display shell version info internal command. + * + * + */ +INT cmd_ver (LPTSTR cmd, LPTSTR param) +{ + INT i; + + /* JPP 07/08/1998 clean up and shortened info. */ + + ConOutPuts (_T("\n" SHELLINFO " " SHELLVER "\nCopyright (C) 1994-1998 Tim Norman and others.")); + ConOutPuts (_T("Copyright (C) 1998,1999 Eric Kohl.")); + + /* Basic copyright notice */ + if (param[0] == _T('\0')) + { + ConOutPuts (_T("\n"SHELLINFO + " comes with ABSOLUTELY NO WARRANTY; for details\n" + "type: `ver /w'. This is free software, and you are welcome to redistribute\n" + "it under certain conditions; type `ver /r' for details. Type `ver /c' for a\n" + "listing of credits.")); + } + else + { + /* MS-DOS ver prints just help if /? is alone or not */ + if (_tcsstr (param, _T("/?")) != NULL) + { + ConOutPuts (_T(USAGE ": " VER_HELP)); + return 0; + } + + for (i = 0; param[i]; i++) + { + /* skip spaces */ + if (param[i] == _T(' ')) + continue; + + if (param[i] == _T('/')) + { + /* is this a lone '/' ? */ + if (param[i + 1] == 0) + { + error_invalid_switch (_T(' ')); + return 1; + } + continue; + } + + if (_totupper (param[i]) == _T('W')) + { + /* Warranty notice */ + /* JPP 07/08/1998 removed extra printf calls */ + ConOutPuts (_T("\n This program is distributed in the hope that it will be useful,\n" + " but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + " GNU General Public License for more details.")); + } + else if (_totupper (param[i]) == _T('R')) + { + /* Redistribution notice */ + /* JPP 07/08/1998 removed extra printf calls */ + ConOutPuts (_T("\n This program is free software; you can redistribute it and/or modify\n" + " it under the terms of the GNU General Public License as published by\n" + " the Free Software Foundation; either version 2 of the License, or\n" + " (at your option) any later version.")); + } + else if (_totupper (param[i]) == _T('C')) + { + /* Developer listing */ + /* JPP 07/08/1998 removed extra printf calls; rearranged names */ + ConOutPuts (_T("\ndeveloped by:\n" + " Tim Norman Matt Rains\n" + " Evan Jeffrey Steffen Kaiser\n" + " Svante Frey Oliver Mueller\n" + " Aaron Kaufman Marc Desrochers\n" + " Rob Lake John P Price\n" + " Hans B Pufal\n" + "\nconverted to Win32 by:\n" + " Eric Kohl\n")); + } + else + { + error_invalid_switch ((TCHAR)_totupper (param[i])); + return 1; + } + } + } + + ConOutPuts (_T("\nSend bug reports to .\n" +/* + "Updates are available at ftp://www.sid-dis.com/..." +*/ + )); + return 0; +} + +#endif diff --git a/rosapps/cmd/verify.c b/rosapps/cmd/verify.c new file mode 100644 index 00000000000..e3b1f08a8b7 --- /dev/null +++ b/rosapps/cmd/verify.c @@ -0,0 +1,59 @@ +/* + * VERIFY.C - verify internal command. + * + * + * History: + * + * 31 Jul 1998 (John P Price) + * started. + * + * 18-Jan-1999 (Eric Kohl ) + * VERIFY is just a dummy under Win32; it only exists + * for compatibility!!! + * + * 20-Jan-1999 (Eric Kohl ) + * Unicode and redirection ready! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_VERIFY + +#include +#include +#include + +#include "cmd.h" + + +/* global verify flag */ +static BOOL bVerify = FALSE; + + +INT cmd_verify (LPTSTR cmd, LPTSTR param) +{ + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("This command is just a dummy!!\n" + "Sets whether to verify that your files are written correctly to a\n" + "disk.\n\n" + "VERIFY [ON | OFF]\n\n" + "Type VERIFY without a parameter to display the current VERIFY setting.")); + return 0; + } + + if (!*param) + ConOutPrintf (_T("VERIFY is %s.\n"), bVerify ? D_ON : D_OFF); + else if (_tcsicmp (param, D_OFF) == 0) + bVerify = FALSE; + else if (_tcsicmp (param, D_ON) == 0) + bVerify = TRUE; + else + ConOutPuts (_T("Must specify ON or OFF.")); + + return 0; +} + +#endif diff --git a/rosapps/cmd/vol.c b/rosapps/cmd/vol.c new file mode 100644 index 00000000000..13bd0e1e712 --- /dev/null +++ b/rosapps/cmd/vol.c @@ -0,0 +1,101 @@ +/* + * VOL.C - vol internal command. + * + * + * History: + * + * 03-Dec-1998 (Eric Kohl ) + * Replaced DOS calls by Win32 calls. + * + * 08-Dec-1998 (Eric Kohl ) + * Added help text ("/?"). + * + * 07-Jan-1999 (Eric Kohl ) + * Cleanup. + * + * 18-Jan-1999 (Eric Kohl ) + * Unicode ready! + * + * 20-Jan-1999 (Eric Kohl ) + * Redirection ready! + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#ifdef INCLUDE_CMD_VOL + +#include +#include +#include + +#include "cmd.h" + + +static VOID +PrintVolumeHeader (LPTSTR pszRootPath) +{ + TCHAR szVolName[80]; + DWORD dwSerialNr; + + /* get the volume information of the drive */ + GetVolumeInformation (pszRootPath, szVolName, 80, &dwSerialNr, + NULL, NULL, NULL, 0); + + /* print drive info */ + ConOutPrintf (_T(" Volume in drive %c:"), pszRootPath[0]); + + if (szVolName[0] != '\0') + ConOutPrintf (_T(" is %s\n"), szVolName); + else + ConOutPrintf (_T(" has no label\n")); + + /* print the volume serial number */ + ConOutPrintf (_T(" Volume Serial Number is %04X-%04X\n"), + HIWORD(dwSerialNr), LOWORD(dwSerialNr)); +} + + +INT cmd_vol (LPTSTR cmd, LPTSTR param) +{ + TCHAR szRootPath[] = _T("A:\\"); + TCHAR szPath[MAX_PATH]; + + if (!_tcsncmp (param, _T("/?"), 2)) + { + ConOutPuts (_T("Displays the disk volume label and serial number, if they exist.\n\n" + "VOL [drive:]")); + return 0; + } + + if (param[0] == _T('\0')) + { + GetCurrentDirectory (MAX_PATH, szPath); + szRootPath[0] = szPath[0]; + } + else + { + _tcsupr (param); + if (param[1] == _T(':')) + szRootPath[0] = param[0]; + else + { + error_invalid_drive (); + return 1; + } + } + + if (!IsValidPathName (szRootPath)) + { + error_invalid_drive (); + return 1; + } + + /* print the header */ + PrintVolumeHeader (szRootPath); + + return 0; +} + +#endif diff --git a/rosapps/cmd/where.c b/rosapps/cmd/where.c new file mode 100644 index 00000000000..1ea1625f77d --- /dev/null +++ b/rosapps/cmd/where.c @@ -0,0 +1,161 @@ +/* + * WHERE.C - file serch functions. + * + * + * History: + * + * 07/15/95 (Tim Norman) + * started. + * + * 08/08/95 (Matt Rains) + * i have cleaned up the source code. changes now bring this source into + * guidelines for recommended programming practice. + * + * 12/12/95 (Steffan Kaiser & Tim Norman) + * added some patches to fix some things and make more efficient + * + * 1/6/96 (Tim Norman) + * fixed a stupid pointer mistake... Thanks to everyone who noticed it! + * + * 8/1/96 (Tim Norman) + * fixed a bug when getenv returns NULL + * + * 8/7/96 (Steffan Kaiser and Tim Norman) + * speed improvements and bug fixes + * + * 8/27/96 (Tim Norman) + * changed code to use pointers directly into PATH environment variable + * rather than making our own copy. This saves some memory, but requires + * we write our own function to copy pathnames out of the variable. + * + * 12/23/96 (Aaron Kaufman) + * Fixed a bug in get_paths() that did not point to the first PATH in the + * environment variable. + * + * 7/12/97 (Tim Norman) + * Apparently, Aaron's bugfix got lost, so I fixed it again. + * + * 16 July 1998 (John P. Price) + * Added stand alone code. + * + * 17 July 1998 (John P. Price) + * Rewrote find_which to use searchpath function + * + * 24-Jul-1998 (John P Price ) + * - fixed bug where didn't check all extensions when path was specified + * + * 27-Jul-1998 (John P Price ) + * - added config.h include + * + * 30-Jul-1998 (John P Price ) + * - fixed so that it find_which returns NULL if filename is not executable + * (does not have .bat, .com, or .exe extention). Before command would + * to execute any file with any extension (opps!) + * + * 03-Dec_1998 (Eric Kohl ) + * Changed find_which(). + * + * 07-Dec_1998 (Eric Kohl ) + * Added ".CMD" extension. + * Replaced numeric constant by _NR_OF_EXTENSIONS. + */ + +#define WIN32_LEAN_AND_MEAN + +#include "config.h" + +#include +#include +#include + +#include "cmd.h" + + +static LPTSTR ext[] = {".BAT", ".CMD", ".COM", ".EXE"}; +static INT nExtCount = sizeof(ext) / sizeof(LPTSTR); + + +/* searches for file using path info. */ + +BOOL find_which (LPCTSTR fname, LPTSTR fullbuffer) +{ + static TCHAR temp[MAX_PATH]; + LPTSTR fullname; + INT x; + + *fullbuffer = _T('\0'); + + /* if there an extension and it is in the last path component, then + * don't test all the extensions. */ + if (!(fullname = _tcsrchr (fname, _T('.'))) || + _tcschr (fullname + 1, _T('\\'))) + { +#ifdef _DEBUG + DebugPrintf ("No filename extension!\n"); +#endif + + for (x = 0; x < nExtCount; x++) + { + _tcscpy (temp, fname); + _tcscat (temp, ext[x]); +#ifdef _DEBUG + DebugPrintf ("Checking for %s\n", temp); +#endif + if (_tcschr (fname, _T('\\'))) + { + if (IsValidFileName (temp)) + { + _tcscpy (fullbuffer, temp); + return TRUE; + } + } + else + { + _searchenv (temp, _T("PATH"), fullbuffer); + if (*fullbuffer != '\0') + return TRUE; + } + } + } + else + { + /* there is an extension... don't test other extensions */ + /* make sure that the extention is one of the four */ +#ifdef _DEBUG + DebugPrintf ("No filename extension!\n"); +#endif + for (x = 0; x < nExtCount; x++) + { + if (!_tcsicmp (_tcsrchr (fname, _T('.')), ext[x])) + { + if (_tcschr (fname, _T('\\'))) + { + if (IsValidFileName (fname)) + { + _tcscpy (fullbuffer, fname); +#ifdef _DEBUG + DebugPrintf ("Found: %s\n", fullbuffer); +#endif + return TRUE; + } + } + else + { +#ifdef _DEBUG + DebugPrintf ("Checking for %s\n", fname); +#endif + _searchenv (fname, _T("PATH"), fullbuffer); + if (*fullbuffer != _T('\0')) + { +#ifdef _DEBUG + DebugPrintf ("Found: %s\n", fullbuffer); +#endif + return TRUE; + } + } + } + } + } + + return FALSE; +} diff --git a/rosapps/cmd/wishlist.txt b/rosapps/cmd/wishlist.txt new file mode 100644 index 00000000000..65c518d08f8 --- /dev/null +++ b/rosapps/cmd/wishlist.txt @@ -0,0 +1,15 @@ + +Wishlist for ReactOS CMD +~~~~~~~~~~~~~~~~~~~~~~~~ + + - Exclusion wildcards: "del /r *.bak -abcd.bak" + Deletes ALL *.bak files EXCEPT abcd.bak. + + - Progress indikator on long file operations (copy/move). + Percentage at the right side of the filename. + + - [cd test directory] should change to the subdirectoy "test directory". + +More ideas? + + Eric Kohl \ No newline at end of file