Instead of having DOSKEY print something when it successfully adds an alias, print...
authorJeffrey Morlan <mrnobo1024@yahoo.com>
Thu, 12 Mar 2009 04:37:01 +0000 (04:37 +0000)
committerJeffrey Morlan <mrnobo1024@yahoo.com>
Thu, 12 Mar 2009 04:37:01 +0000 (04:37 +0000)
svn path=/trunk/; revision=39973

reactos/base/applications/cmdutils/doskey/doskey.c
reactos/base/applications/cmdutils/doskey/doskey.h [new file with mode: 0644]
reactos/base/applications/cmdutils/doskey/doskey.rbuild
reactos/base/applications/cmdutils/doskey/doskey.rc
reactos/base/applications/cmdutils/doskey/lang/en-US.rc [new file with mode: 0644]

index 2738cf1..e876622 100644 (file)
@@ -1,71 +1,95 @@
 #include <windows.h>
 #include <stdio.h>
 #include <tchar.h>
+#include "doskey.h"
 
-static VOID
-PrintAlias (VOID)
-{
-    LPTSTR Aliases;
-    LPTSTR ptr;
-    DWORD len;
-
-    len = GetConsoleAliasesLength(_T("cmd.exe"));
-    if (len <= 0)
-        return;
-
-    /* allocate memory for an extra \0 char to make parsing easier */
-    ptr = HeapAlloc(GetProcessHeap(), 0, (len + sizeof(TCHAR)));
-    if (!ptr)
-        return;
-
-    Aliases = ptr;
+#define MAX_STRING 2000
+TCHAR szStringBuf[MAX_STRING];
+LPTSTR pszExeName = _T("cmd.exe");
 
-    ZeroMemory(Aliases, len + sizeof(TCHAR));
+static VOID SetInsert(DWORD dwFlag)
+{
+    DWORD dwMode;
+    HANDLE hConsole = GetStdHandle(STD_INPUT_HANDLE);
+    GetConsoleMode(hConsole, &dwMode);
+    dwMode |= ENABLE_EXTENDED_FLAGS;
+    SetConsoleMode(hConsole, (dwMode & ~ENABLE_INSERT_MODE) | dwFlag);
+}
 
-    if (GetConsoleAliases(Aliases, len, _T("cmd.exe")) != 0)
-    {
-        while (*Aliases != '\0')
-        {
-            _tprintf(_T("%s\n"), Aliases);
-            Aliases = Aliases + lstrlen(Aliases);
-            Aliases++;
-        }
-    }
-    HeapFree(GetProcessHeap(), 0 , ptr);
+static VOID PrintHistory(VOID)
+{
+    DWORD Length = GetConsoleCommandHistoryLength(pszExeName);
+    /* On Windows, the ANSI version of GetConsoleCommandHistory requires
+     * a buffer twice as large as the actual history length. */
+    BYTE HistBuf[Length * (sizeof(WCHAR) / sizeof(TCHAR))];
+    TCHAR *Hist    = (TCHAR *)HistBuf;
+    TCHAR *HistEnd = (TCHAR *)&HistBuf[Length];
+
+    if (GetConsoleCommandHistory(Hist, sizeof HistBuf, pszExeName))
+        for (; Hist < HistEnd; Hist += _tcslen(Hist) + 1)
+            _tprintf(_T("%s\n"), Hist);
 }
 
-INT SetMacro (LPTSTR param)
+static INT SetMacro(LPTSTR definition)
 {
-    LPTSTR ptr, text;
+    TCHAR *name, *nameend, *text, temp;
 
-    while (*param == _T(' '))
-        param++;
+    name = definition;
+    while (*name == _T(' '))
+        name++;
 
     /* error if no '=' found */
-    if ((ptr = _tcschr (param, _T('='))) == 0)
-        return 1;
-
-    text = ptr + 1;
-    while (*text == _T(' '))
-        text++;
-
-    while (ptr > param && ptr[-1] == _T(' '))
-        ptr--;
-
-    /* Split rest into name and substitute */
-    *ptr++ = _T('\0');
+    if ((nameend = _tcschr(name, _T('='))) != NULL)
+    {
+        text = nameend + 1;
+        while (*text == _T(' '))
+            text++;
+
+        while (nameend > name && nameend[-1] == _T(' '))
+            nameend--;
+
+        /* Split rest into name and substitute */
+        temp = *nameend;
+        *nameend = _T('\0');
+        /* Don't allow spaces in the name, since such a macro would be unusable */
+        if (!_tcschr(name, _T(' ')) && AddConsoleAlias(name, text, pszExeName))
+            return 0;
+        *nameend = temp;
+    }
 
-    if (*param == _T('\0') || _tcschr(param, _T(' ')))
-        return 1;
+    LoadString(GetModuleHandle(NULL), IDS_INVALID_MACRO_DEF, szStringBuf, MAX_STRING);
+    _tprintf(szStringBuf, definition);
+    return 1;
+}
 
-    _tprintf(_T("%s, %s\n"), text, param);
+static VOID PrintMacros(LPTSTR pszExeName, LPTSTR Indent)
+{
+    DWORD Length = GetConsoleAliasesLength(pszExeName);
+    BYTE AliasBuf[Length];
+    TCHAR *Alias    = (TCHAR *)AliasBuf;
+    TCHAR *AliasEnd = (TCHAR *)&AliasBuf[Length];
+
+    if (GetConsoleAliases(Alias, sizeof AliasBuf, pszExeName))
+        for (; Alias < AliasEnd; Alias += _tcslen(Alias) + 1)
+            _tprintf(_T("%s%s\n"), Indent, Alias);
+}
 
-    if (ptr[0] == _T('\0'))
-        AddConsoleAlias(param, NULL, _T("cmd.exe"));
-    else
-        AddConsoleAlias(param, text, _T("cmd.exe"));
+static VOID PrintAllMacros(VOID)
+{
+    DWORD Length = GetConsoleAliasExesLength();
+    BYTE ExeNameBuf[Length];
+    TCHAR *ExeName    = (TCHAR *)ExeNameBuf;
+    TCHAR *ExeNameEnd = (TCHAR *)&ExeNameBuf[Length];
 
-    return 0;
+    if (GetConsoleAliasExes(ExeName, sizeof ExeNameBuf))
+    {
+        for (; ExeName < ExeNameEnd; ExeName += _tcslen(ExeName) + 1)
+        {
+            _tprintf(_T("[%s]\n"), ExeName);
+            PrintMacros(ExeName, _T("    "));
+            _tprintf(_T("\n"));
+        }
+    }
 }
 
 static VOID ReadFromFile(LPTSTR param)
@@ -73,10 +97,16 @@ static VOID ReadFromFile(LPTSTR param)
     FILE* fp;
     TCHAR line[MAX_PATH];
 
-    /* Skip the "/macrofile=" prefix */
-    param += 11;
-
     fp = _tfopen(param, _T("r"));
+    if (!fp)
+    {
+#ifdef UNICODE
+        _wperror(param);
+#else
+        perror(param);
+#endif
+        return;
+    }
 
     while ( _fgetts(line, MAX_PATH, fp) != NULL) 
     {
@@ -85,53 +115,122 @@ static VOID ReadFromFile(LPTSTR param)
         if (*end == _T('\n'))
             *end = _T('\0');
 
-        SetMacro(line);
+        if (*line)
+            SetMacro(line);
     }
 
     fclose(fp);
     return;
 }
 
-int
-_tmain (int argc, LPTSTR argv[])
+/* Get the start and end of the next command-line argument. */
+static BOOL GetArg(TCHAR **pStart, TCHAR **pEnd)
 {
-    if (argc < 2)
-        return 0;
+    BOOL bInQuotes = FALSE;
+    TCHAR *p = *pEnd;
+    p += _tcsspn(p, _T(" \t"));
+    if (!*p)
+        return FALSE;
+    *pStart = p;
+    do
+    {
+        if (!bInQuotes && (*p == _T(' ') || *p == _T('\t')))
+            break;
+        bInQuotes ^= (*p++ == _T('"'));
+    } while (*p);
+    *pEnd = p;
+    return TRUE;
+}
 
-    if (argv[1][0] == '/')
+/* Remove starting and ending quotes from a string, if present */
+static LPTSTR RemoveQuotes(LPTSTR str)
+{
+    TCHAR *end;
+    if (*str == _T('"') && *(end = str + _tcslen(str) - 1) == _T('"'))
     {
-        if (_tcsnicmp(argv[1], _T("/macrofile"), 10) == 0)
-            ReadFromFile(argv[1]);
-        if (_tcscmp(argv[1], _T("/macros")) == 0)
-            PrintAlias();
+        str++;
+        *end = _T('\0');
     }
-    else
+    return str;
+}
+
+int
+_tmain(VOID)
+{
+    /* Get the full command line using GetCommandLine(). We can't just use argv,
+     * because then a parameter like "gotoroot=cd \" wouldn't be passed completely. */
+    TCHAR *pArgStart;
+    TCHAR *pArgEnd = GetCommandLine();
+
+    /* Skip the application name */
+    GetArg(&pArgStart, &pArgEnd);
+
+    while (GetArg(&pArgStart, &pArgEnd))
     {
-        /* Get the full command line using GetCommandLine().
-           We can't just pass argv[1] here, because then a parameter like "gotoroot=cd \" wouldn't be passed completely. */
-        TCHAR* szCommandLine = GetCommandLine();
+        /* NUL-terminate this argument to make processing easier */
+        TCHAR tmp = *pArgEnd;
+        *pArgEnd = _T('\0');
 
-        /* Skip the application name */
-        if(*szCommandLine == '\"')
+        if (!_tcscmp(pArgStart, _T("/?")))
+        {
+            LoadString(GetModuleHandle(NULL), IDS_HELP, szStringBuf, MAX_STRING);
+            _tprintf(szStringBuf);
+            break;
+        }
+        else if (!_tcsnicmp(pArgStart, _T("/EXENAME="), 9))
+        {
+            pszExeName = RemoveQuotes(pArgStart + 9);
+        }
+        else if (!_tcsicmp(pArgStart, _T("/H")) ||
+                 !_tcsicmp(pArgStart, _T("/HISTORY")))
+        {
+            PrintHistory();
+        }
+        else if (!_tcsnicmp(pArgStart, _T("/LISTSIZE="), 10))
+        {
+            SetConsoleNumberOfCommands(_ttoi(pArgStart + 10), pszExeName);
+        }
+        else if (!_tcsicmp(pArgStart, _T("/REINSTALL")))
+        {
+            ExpungeConsoleCommandHistory(pszExeName);
+        }
+        else if (!_tcsicmp(pArgStart, _T("/INSERT")))
+        {
+            SetInsert(ENABLE_INSERT_MODE);
+        }
+        else if (!_tcsicmp(pArgStart, _T("/OVERSTRIKE")))
+        {
+            SetInsert(0);
+        }
+        else if (!_tcsicmp(pArgStart, _T("/M")) ||
+                 !_tcsicmp(pArgStart, _T("/MACROS")))
+        {
+            PrintMacros(pszExeName, _T(""));
+        }
+        else if (!_tcsnicmp(pArgStart, _T("/M:"),      3) ||
+                 !_tcsnicmp(pArgStart, _T("/MACROS:"), 8))
+        {
+            LPTSTR exe = RemoveQuotes(_tcschr(pArgStart, _T(':')) + 1);
+            if (!_tcsicmp(exe, _T("ALL")))
+                PrintAllMacros();
+            else
+                PrintMacros(exe, _T(""));
+        }
+        else if (!_tcsnicmp(pArgStart, _T("/MACROFILE="), 11))
         {
-            do
-            {
-                szCommandLine++;
-            }
-            while(*szCommandLine != '\"');
-            szCommandLine++;
+            ReadFromFile(RemoveQuotes(pArgStart + 11));
         }
         else
         {
-            do
-            {
-                szCommandLine++;
-            }
-            while(*szCommandLine != ' ');
+            /* This is the beginning of a macro definition. It includes
+             * the entire remainder of the line, so first put back the
+             * character that we replaced with NUL. */
+            *pArgEnd = tmp;
+            return SetMacro(pArgStart);
         }
 
-        /* Skip the leading whitespace and pass the command line to SetMacro */
-        SetMacro(szCommandLine + _tcsspn(szCommandLine, _T(" \t")));
+        if (!tmp) break;
+        pArgEnd++;
     }
 
     return 0;
diff --git a/reactos/base/applications/cmdutils/doskey/doskey.h b/reactos/base/applications/cmdutils/doskey/doskey.h
new file mode 100644 (file)
index 0000000..2309864
--- /dev/null
@@ -0,0 +1,67 @@
+#define IDS_HELP 0
+#define IDS_INVALID_MACRO_DEF 1
+
+#ifndef RC_INVOKED
+
+#ifdef UNICODE
+#define TNAME(x) x##W
+#else
+#define TNAME(x) x##A
+#endif
+
+/* Missing from include/psdk/wincon.h */
+#ifndef ENABLE_INSERT_MODE
+#define ENABLE_INSERT_MODE 0x20
+#endif
+#ifndef ENABLE_EXTENDED_FLAGS
+#define ENABLE_EXTENDED_FLAGS 0x80
+#endif
+
+/* Undocumented APIs */
+#ifndef AddConsoleAlias
+BOOL WINAPI AddConsoleAliasA(LPSTR, LPSTR, LPSTR);
+BOOL WINAPI AddConsoleAliasW(LPWSTR, LPWSTR, LPWSTR);
+#define AddConsoleAlias TNAME(AddConsoleAlias)
+#endif
+#ifndef ExpungeConsoleCommandHistory
+BOOL WINAPI ExpungeConsoleCommandHistoryA(LPSTR);
+BOOL WINAPI ExpungeConsoleCommandHistoryW(LPWSTR);
+#define ExpungeConsoleCommandHistory TNAME(ExpungeConsoleCommandHistory)
+#endif
+#ifndef GetConsoleAliases
+DWORD WINAPI GetConsoleAliasesA(LPSTR, DWORD, LPSTR);
+DWORD WINAPI GetConsoleAliasesW(LPWSTR, DWORD, LPWSTR);
+#define GetConsoleAliases TNAME(GetConsoleAliases)
+#endif
+#ifndef GetConsoleAliasesLength
+DWORD WINAPI GetConsoleAliasesLengthA(LPSTR); 
+DWORD WINAPI GetConsoleAliasesLengthW(LPWSTR); 
+#define GetConsoleAliasesLength TNAME(GetConsoleAliasesLength)
+#endif
+#ifndef GetConsoleAliasExes
+DWORD WINAPI GetConsoleAliasExesA(LPSTR, DWORD);
+DWORD WINAPI GetConsoleAliasExesW(LPWSTR, DWORD);
+#define GetConsoleAliasExes TNAME(GetConsoleAliasExes)
+#endif
+#ifndef GetConsoleAliasExesLength
+DWORD WINAPI GetConsoleAliasExesLengthA(VOID);
+DWORD WINAPI GetConsoleAliasExesLengthW(VOID);
+#define GetConsoleAliasExesLength TNAME(GetConsoleAliasExesLength)
+#endif
+#ifndef GetConsoleCommandHistory
+DWORD WINAPI GetConsoleCommandHistoryA(LPSTR, DWORD, LPSTR);
+DWORD WINAPI GetConsoleCommandHistoryW(LPWSTR, DWORD, LPWSTR);
+#define GetConsoleCommandHistory TNAME(GetConsoleCommandHistory)
+#endif
+#ifndef GetConsoleCommandHistoryLength
+DWORD WINAPI GetConsoleCommandHistoryLengthA(LPSTR);
+DWORD WINAPI GetConsoleCommandHistoryLengthW(LPWSTR);
+#define GetConsoleCommandHistoryLength TNAME(GetConsoleCommandHistoryLength)
+#endif
+#ifndef SetConsoleNumberOfCommands
+BOOL WINAPI SetConsoleNumberOfCommandsA(DWORD, LPSTR);
+BOOL WINAPI SetConsoleNumberOfCommandsW(DWORD, LPWSTR);
+#define SetConsoleNumberOfCommands TNAME(SetConsoleNumberOfCommands)
+#endif
+
+#endif /* RC_INVOKED */
index eb36e96..4793ff3 100644 (file)
@@ -2,6 +2,7 @@
 <!DOCTYPE module SYSTEM "../../../../tools/rbuild/project.dtd">
 <module name="doskey" type="win32cui" installbase="system32" installname="doskey.exe" unicode="yes">
        <library>kernel32</library>
+       <library>user32</library>
        <file>doskey.c</file>
        <file>doskey.rc</file>
 </module>
index 71440c7..c4f5032 100644 (file)
@@ -1,7 +1,8 @@
-/* $Id: find.rc 28350 2007-08-15 14:46:36Z fireball $ */
-
 #define REACTOS_STR_FILE_DESCRIPTION   "W32 doskey command\0"
 #define REACTOS_STR_INTERNAL_NAME      "doskey\0"
 #define REACTOS_STR_ORIGINAL_FILENAME  "doskey.exe\0"
 #include <reactos/version.rc>
 
+#include <windows.h>
+#include "doskey.h"
+#include "lang/en-US.rc"
diff --git a/reactos/base/applications/cmdutils/doskey/lang/en-US.rc b/reactos/base/applications/cmdutils/doskey/lang/en-US.rc
new file mode 100644 (file)
index 0000000..1b70286
--- /dev/null
@@ -0,0 +1,27 @@
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+STRINGTABLE DISCARDABLE
+BEGIN
+
+IDS_HELP, "Manages command-line editing settings, history, and macros.\n\
+\n\
+DOSKEY [/INSERT | /OVERSTRIKE] [/EXENAME=exe] [/HISTORY] [/LISTSIZE=size]\n\
+       [/REINSTALL] [/MACROS[:exe | :ALL]] [/MACROFILE=file] [macroname=[text]]\n\
+\n\
+  /INSERT             Enables insert mode.\n\
+  /OVERSTRIKE         Disables insert mode.\n\
+  /EXENAME=exename    Sets the name of the program to view/change history\n\
+                      and macros for. The default is cmd.exe.\n\
+  /HISTORY            Displays the command history.\n\
+  /LISTSIZE=size      Sets the number of commands per history buffer.\n\
+  /REINSTALL          Clears the command history.\n\
+  /MACROS             Displays macro definitions.\n\
+  /MACROS:exename     Displays macro definitions for a specific program.\n\
+  /MACROS:ALL         Displays macro definitions for all programs.\n\
+  /MACROFILE=filename Loads macro definitions from a file.\n\
+  macroname           Specifies the name of a macro to create.\n\
+  text                Specifies the replacement text for the macro.\n"
+
+IDS_INVALID_MACRO_DEF, "Invalid macro definition: %s\n"
+
+END