Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Add Colors to Batch Files

0.00/5 (No votes)
24 Aug 2010 32  
An enhanced ECHO command line utility with color support.

Colorize Batch File

Introduction

Batch files are useful to deal with repetitive tasks. However, they lack some user-friendly features such as colorizing console outputs. Colorized outputs might be useful to draw attention to important information. The Win32 API provides some useful functions to interact with the console (see Console Functions in MSDN). But in your batch files, the only command available is COLOR. The COLOR command only defines the color of the entire window console.

cecho is an enhanced ECHO command line utility with color support, inspired by the CTEXT utility by Dennis Bareis.

The last section explains how to embed the cecho utility into a batch file using the Debug.exe program (until Windows Vista).

Using the Code

cecho simply redirects the command arguments to the standard output after parsing color information. cecho arguments include:

  • {XX}: colors coded as two hexadecimal digits. E.g., {0A} light green
  • {color}: color information as understandable text. E.g., {light red on black}
  • {\n \t}: New line character - Tab character.
  • {\u0000}: Unicode character code.
  • {{: escape character '{'.
  • {#}: restore initial colors.

Available colors:

0 = black 8 = gray
1 = navy 9 = blue
2 = green A = lime
3 = teal B = aqua
4 = maroon C = red
5 = purple D = fuchsia
6 = olive E = yellow
7 = silver F = white

Sample batch file:

@echo off

cecho {0C}This line is red{#}

REM Print ASCII char 0x07 (beep) 
cecho {\u07 \u07}

cecho This {black on blue}word{#} is black on a blue background

...

Changes log: in cecho v2.0, the {0x00} ASCII code has been replaced by the {\u0000} Unicode character.

Inside cecho

Colorized Console Output

Colorizing console output is pretty straightforward. Simply call the SetConsoleTextAttribute Win32 API with the correct color code. All further console outputs will be displayed in the specified color. We'll explain tokStack later.

void setColor()
{
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    tokStack[tokCurs-1] = 0;
    SetConsoleTextAttribute(hConsole, (WORD)strtol(tokStack, 0, 16));
}

Parsing Command Arguments

According to the cecho documentation, parsing command arguments can be described by the following parse tree:

Parse Tree

Fig. 1: Parse Tree

The parse tree grammar in C language becomes:

#define MAX_TRANS 5

// expected tokens list
wchar_t* Grammar[][MAX_TRANS] = {
    {L"{", L""},
    {L"{}", L"\\", L"0123456789abcdefABCDEF", L" \t", L""},
    {L"tn", L"u"},
    {L"0123456789abcdefABCDEF"},
    {L"0123456789abcdefABCDEF", L" \t", L"}", L"\\"},
    {L"0123456789abcdefABCDEF", L""},
    {L"}", L""},
    {L"}", L""}
};

// action executed on state changed
Fct Action[][MAX_TRANS] = {
    {&printStack,0},
    {&resetStack,0,0,0,0},
    {&printEscChar,0},
    {0},
    {0,&printHexChar,&printHexChar,&printHexChar},
    {0,0},
    {&setColor,0},
    {&parseColor,0}
};

// next state Ids
char Successor[][MAX_TRANS] = {
    {1,0},
    {0,2,5,1,7},
    {1,3},
    {4},
    {4,1,0,2},
    {6,7},
    {0,7},
    {0,7}
};

The parser state chart contains 7 states. The Grammar array stores lists of expected tokens that trigger a transition for a specific state. An empty list acts as the wild char token. The Action array maintains pointers to the function to execute during a specific transition. The Successor array identifies the next state for each transition.

The parser engine iterates through all input characters. If the character triggers an outgoing transition of the current parser state, then the character is added to the tokStack token stack, the action associated with the transition (if any) is executed, and the parser state is updated.

// token stack
wchar_t tokStack[MAX_STACK];
// token stack cursor
int tokCurs = 0;

int wmain(int argc, wchar_t* argv[])
{
    short trans, clr, fired;
    wchar_t* token;
    char state = 0;

    [...]

    // retrieve command argument
    LPWSTR input = GetCommandLineW();
    
    if (*input == L'"')
        input += 2;

    input += wcslen(argv[0]) + 1;

    // parse input string
    for (fired = 0, token = input; *token != 0; token++)
    {
        // does token trigger a transition ?
        for (trans = 0; trans < MAX_TRANS && Grammar[state][trans] != 0; trans++)
        {
            // check if token belongs to the expected tokens list ? 
            // a empty list acts as a wildchar token
            if (wcschr(Grammar[state][trans], *token) || *Grammar[state][trans] == 0)
            {
                // push token into the stack
                if (tokCurs < MAX_STACK)
                    tokStack[tokCurs++] = *token;

                // execute the action associated to the transition (if any)
                if (Action[state][trans] != 0)
                {
                    (*Action[state][trans])();
                    tokCurs = 0; // reset token stack
                }
                // update parser state
                state = Successor[state][trans];
                fired = 1;
                break;
            }
        }
        if (fired == 0)
        {
            wprintf(L"Syntax error: '%c' col %i", *token, input - token);
            return -1;
        }
    }
    // print remaing token stack
    tokCurs++;
    printStack();
    return 0;
}

The Action's functions are quite simple and aren't worth any comments.

Annexe: How to embed cecho.exe inside a batch file

Note: Debug.exe has been phased out in Windows 7. I keep this section for reference, but I no longer recommend using it.

The embedding mechanism relies on the Debug.exe program. The cecho binary is converted to a debug script using the BIN2DBG.EXE utility by Anthony Caruso. The debug script is then embedded in the batch file. At run time, the debug script is processed by Debug.exe to recreate the cecho executable file.

  1. Convert cecho.exe into cecho.dbg using BIN2DBG.EXE.
  2. C:\>bin2dbg.exe cecho.exe
  3. Edit cecho.dbg with a text editor. Modify the file extension on the first line of cecho.dbg because Debug.exe is not allowed to write an EXE file. Use a *.com extension, for instance.
  4. n cecho.com
    
    e 100 4D 5A 90 0 3 0 0 0 4 0 0 0 FF FF 0 0 
    e 110 B8 0 0 0 0 0 0 0 40 0 0 0 0 0 0 0 
    e 120 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    ...
  5. Include cecho.dbg into your batch file. Your batch file must reconstruct exactly the same cecho.dbg file. A batch command could be useful:
  6. C:\>for /f "delims=" %l in (cecho.dbg) do (echo echo %l ^>^> tmp.dbg >> cecho.bat)
  7. Add commands to rebuild cecho.com (formerly cecho.exe) to the end of cecho.bat.
  8. ...
    echo e 10E0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0  >> tmp.dbg
    echo e 10F0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0  >> tmp.dbg
    echo e 1100 0  >> tmp.dbg
    echo rcx >> tmp.dbg
    echo 1000 >> tmp.dbg
    echo w >> tmp.dbg
    echo q >> tmp.dbg
    
    echo debug ^< tmp.dbg > tmp.bat
    echo exit >> tmp.bat
    
    start /wait /min tmp.bat
    
    del tmp.bat
    del tmp.dbg

    The trick with the tmp.bat file and the start /wait /min command is detailed by Jakob Bohm in the forum section of this article: Possible reason for the start /min /wait trick. It basically runs the 16 bit DOS Debug.exe in a separate console to prevent file handles from remaining open.

  9. We're done! cecho is now available and ready to colorize your batch output.
  10. ...
    call :unpack_cecho
    
    REM cecho.com is now available for use.
    cecho.com {red}This line in red{#}
    ...
    del cecho.com
    goto :eof

Because the debug script size is much bigger than the EXE size, we need to keep cecho.exe as small as possible. The UPX executable packer reduces cecho.exe (compiled with VC++10) by 50%.

I also suggest to include the debug script as a "function" in your batch file. See the batch function syntax by Ritchie Laurence.

History

  • Initial release - January 03, 2007
  • Minor changes - August 07, 2007
    • Added the "start /min /wait" trick and reduced the EXE size with UPX.
  • cecho v2.0 - August 23, 2010
    • Added Unicode support.
    • Added x64 support.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here