Computing: DOS, OS/2 & Windows Programming

Text positioning and coloring using ANSI escape sequences on DOS.

ANSI.SYS is a device driver in the DOS family of operating systems that provides extra console functions through so-called ANSI escape sequences. It is partially based upon a subset of the text terminal control standard proposed by the ANSI X3L2 Technical Committee on Codes and Character Sets. As ANSI.SYS was not installed by default on MS-DOS (that used DISPLAY.SYS instead), and also because it was notoriously slow, little software took advantage of it and instead resorted to directly manipulating the IBM PC hardware. For further details, please have a look at the ANSI.SYS article in Wikipedia.

ANSI escape sequences are a standard for in-band signaling to control cursor location, color, font styling, and other options on video text terminals and terminal emulators. Certain sequences of bytes (normally starting with an ANSI escape character plus a left square bracket), if embedded into text, are interpreted by the terminal as commands, rather than text to display verbatim. With ANSI.SYS installed, these escape sequences can be used for text positioning and coloring on DOS. For further details, please have a look at the ANSI escape code article in Wikipedia.

FreeDOS is distributed with the driver NANSI.SYS installed by default. NANSI.SYS executes the same ANSI cursor control sequences as does the standard console driver ANSI.SYS, but significantly faster. It also offers several extra features, while still being simple, small, and cheap. Versions 3.4 and later are under the GPL, and are Free Software. You can find details about the driver in this article about NANSI.SYS and NNANSI.COM.

As ANSI escape sequences are pre-defined sequences of ASCII characters, they can be used in any programming language to do things like clearing the screen, moving the cursor to a given screen position, or display text with a given font or background color. This tutorial shows examples of the usage of ANSI escape sequences in C, FORTRAN, Pascal, and assembly (NASM) programs, as well as in DOS batch files, . All program samples have been developed and tested on FreeDOS 1.3 RC5, with the default NANSI.SYS driver resp. with NNANSI.COM.

Before viewing those examples, lets have a brief look at the ANSI escape sequences. Their general format is
    ESC[<parameter-list><command-code>
where ESC means the ASCII code of the escape control character.

The parameter list is one or more (numeric) parameters, separated by a semicolon (;). The command code is one letter; important to note that this code is case-sensitive.

Here is a description of the sequences used in the tutorial samples (for a full description of the available commands and their usage, cf. the file NANSI.DOC, that you find in the DOC\NANSI subfolder of your FreeDOS installation directory.

SequenceCommandNotes
ESC[2JClear screenClear the screen (using the actual background color)
ESC[0mReset text attributesReset text color and text background to default colors and attributes (light gray on black; "normal" attributes)
ESC[3CmSet text colorSet text color to 30 + C, where C is a 0 - 7 color code; cf. below
ESC[4CmSet background colorSet text background to 40 + C, where C is a 0 - 7 color code; cf. below
ESC[1mText attribute "bold"Display the text with light colors (ex: red bold = light red; brown bold = yellow)
ESC[5mText attribute "blink"Display the text with blinking effect
ESC[7mReverse videoSwap text color and text background color (black text on light gray background, for default colors)
ESC[v;hHSet cursor positionPosition the cursor at position v,h; v being the vertical position (line): 1 - 25; h being the horizontal position (column): 1 - 80

Color codes are as follows:

Code"Normal" colorBold color
0blackdark gray
1redlight red
2greenlight green
3brownyellow
4bluelight blue
5magentalight magenta
6cyanlight cyan
7light graywhite

Notes:

In the following paragraphs, you can find ANSI escape sequence program samples in various programming languages. Use the following link to download the source code.

ANSI escape sequences in C.

The escape control character has the hexadecimal ASCII code 1B (decimal 27). In a C program, hexadecimal values may be written using a hexadecimal escape sequence of the form \x<hexadecimal-digits>. The ASCII code of the escape control character can thus be written as the character constant '\x1b'. In C, ANSI escape sequences are strings starting with "\x1b[".

For example, to clear the screen from a C program, you can use the statement
    printf("%s", "\x1b[2J");

In the sample program NANSI1.C, that writes some colored text to the screen, I have used the directive #define to define the clear screen and all text color, background and attributes related escape sequences as "manifest constants". Here is the code (I used Watcom C to create a 16-bit DOS executable; may work with other C compilers, too):

    #include <stdio.h>
    #define NANSI_CLS "\x1b[2J"
    #define NANSI_NORMAL "\x1b[0m"
    #define NANSI_BOLD "\x1b[1m"
    #define NANSI_REVERSE "\x1b[7m"
    #define NANSI_FG_BLACK "\x1b[30m"
    #define NANSI_FG_RED "\x1b[31m"
    #define NANSI_FG_GREEN "\x1b[32m"
    #define NANSI_FG_BROWN "\x1b[33m"
    #define NANSI_FG_BLUE "\x1b[34m"
    #define NANSI_FG_MAGENTA "\x1b[35m"
    #define NANSI_FG_CYAN "\x1b[36m"
    #define NANSI_FG_LIGHTGRAY "\x1b[37m"
    #define NANSI_FG_DARKGRAY "\x1b[30;1m"
    #define NANSI_FG_LIGHTRED "\x1b[31;1m"
    #define NANSI_FG_LIGHTGREEN "\x1b[32;1m"
    #define NANSI_FG_YELLOW "\x1b[33;1m"
    #define NANSI_FG_LIGHTBLUE "\x1b[34;1m"
    #define NANSI_FG_LIGHTMAGENTA "\x1b[35;1m"
    #define NANSI_FG_LIGHTCYAN "\x1b[36;1m"
    #define NANSI_FG_WHITE "\x1b[37;1m"
    #define NANSI_BG_BLACK "\x1b[40m"
    #define NANSI_BG_RED "\x1b[41m"
    #define NANSI_BG_GREEN "\x1b[42m"
    #define NANSI_BG_BROWN "\x1b[43m"
    #define NANSI_BG_BLUE "\x1b[44m"
    #define NANSI_BG_MAGENTA "\x1b[45m"
    #define NANSI_BG_CYAN "\x1b[46m"
    #define NANSI_BG_LIGHTGRAY "\x1b[47m"
    int main() {
        printf("%s", NANSI_CLS);
        printf("NANSI color test with C:\n\n");
        printf("%sThis is red text\n", NANSI_FG_RED);
        printf("%sThis is lightred text\n\n", NANSI_FG_LIGHTRED);
        printf("%sThis is lightred text on blue background\n", NANSI_BG_BLUE);
        printf("%sThis is yellow text on blue background\n\n", NANSI_FG_YELLOW);
        printf("%s%sThis is white text on cyan background\n\n", NANSI_FG_WHITE, NANSI_BG_CYAN);
        printf("%sThis is reversed colors text\n\n", NANSI_REVERSE);
        printf("%s", NANSI_NORMAL);
        printf("%sThis is magenta text\n", NANSI_FG_MAGENTA);
        printf("%sThis is bold magenta text\n", NANSI_BOLD);
        printf("%s\n", NANSI_NORMAL);
        return(0);
    }

The screenshots show the program output: on the left using NANSI.SYS, on the right using NNANSI.COM.

ANSI escape sequences on FreeDOS: Watcom C colored output (with NANSI.SYS)
ANSI escape sequences on FreeDOS: Watcom C colored output (with NNANSI.COM)

Notes:

ANSI escape sequences in FORTRAN.

In FORTRAN, the character corresponding to a given ASCII code is obtained using the function CHAR(). Example: CHAR(27) returns the escape control character. Thus, in FORTRAN, ANSI escape sequences are concatenations of CHAR(27) and a string starting with '['.

For example, to clear the screen from a FORTRAN program, you can use the statement
    WRITE (*,*) CHAR(27) // '[2J'

The sample program NANSI2.FOR displays a yellow on blue "Hello World", horizontally centered on the screen. To make the code more readable, I have declared the ASCII sequences using the parameter declarative. Here is the code (I used Watcom FORTRAN to create a 16-bit DOS executable; may work with other FORTRAN 77 compilers, too):

    PROGRAM NANSI2
    IMPLICIT NONE
    CHARACTER*16 HELLO, SPACES
    CHARACTER*3 CLS, RESET
    CHARACTER*4 BG_BLUE
    CHARACTER*6 FG_WHITE, LINE1, LINE2, LINE3
    PARAMETER (HELLO = ' HELLO WORLD! ')
    PARAMETER (SPACES = ' ')
    PARAMETER (CLS = '[2J')
    PARAMETER (RESET = '[0m')
    PARAMETER (LINE1 = '[2;32H')
    PARAMETER (LINE2 = '[3;32H')
    PARAMETER (LINE3 = '[4;32H')
    PARAMETER (FG_WHITE = '[37;1m')
    PARAMETER (BG_BLUE = '[44m')
    WRITE (*,*) CHAR(27) // CLS
    WRITE (*,*) CHAR(27) // BG_BLUE
    WRITE (*,*) CHAR(27) // FG_WHITE
    WRITE (*,*) CHAR(27) // LINE1, SPACES
    WRITE (*,*) CHAR(27) // LINE2, HELLO
    WRITE (*,*) CHAR(27) // LINE3, SPACES
    WRITE (*,*) CHAR(27) // RESET
    END

And here is a screenshot of the program output.

ANSI escape sequences on FreeDOS: Watcom FORTRAN colored text on screen positioning

ANSI escape sequences in Pascal.

Free Pascal (as Turbo Pascal) comes with the Crt unit, that contains all routines that you might need for text coloring and positioning. But, it is of course also possible to use the ANSI escape sequences (Crt unit not needed in this case). By the way, note that the ANSI color codes and the Pascal color constants of the Crt unit are not compatible (Examples: blue is 34/44 with ANSI, 1 with Pascal, red = 31/41 with ANSI, 4 with Pascal).

In Pascal, the character corresponding to a given ASCII code is obtained using the function Chr(). Example: Chr(27) returns the escape control character. Thus, in Pascal, ANSI escape sequences are concatenations of Chr(27) and a string starting with '['.

Calling the Write procedure with 2 arguments, you can clear the screen from a Pascal program using the statement
    Write(Chr(27), '[2J');

The sample program NANSI.PAS displays, for each of the 8 background colors, two X with each of the 16 text colors. I have declared some constants for the escape sequences. The color related sequences are obtained by replacing the '0' of the 'black' sequence by the actual color code, adding a 'bold' sequence for the light colors. Color display and display of an ANSI escape sequence in general is done by calling functions. Here is the code (I built it with Free Pascal for go32v2; may work with other Pascal compilers, too):

    program nansi;
    uses
        SysUtils;
    const
        NANSI_CLS = '2J';
        NANSI_NORMAL = '0m';
        NANSI_BOLD = '1m';
        NANSI_FG = '30m';
        NANSI_BG = '40m';
        Colors: array[0..7] of string = (
            'black', 'red', 'green', 'brown', 'blue', 'magenta', 'cyan', 'gray'
        );
    var
        L, I, J: Integer;
        S: string;
    procedure NansiWrite(NANSISeq: string);
    begin
        Write(Chr(27), '[', NANSISeq);
    end;
    procedure NansiWriteColor(Ground: string; Colour: Integer);
    var
        NANSISeq: string;
        Bold: Boolean;
    begin
        if Ground = 'fg' then
            NANSISeq := NANSI_FG
        else
            NANSISeq := NANSI_BG;
        Bold := False;
        if Colour > 7 then begin
            Colour := Colour - 7;
            if Ground = 'fg' then
                Bold := True;
        end;
        NANSISeq := StringReplace(NANSISeq, '0', IntToStr(Colour), []);
        if Bold then begin
            NANSISeq := StringReplace(NANSISeq, 'm', '', []);
            NANSISeq := NANSISeq + ';' + NANSI_BOLD;
        end;
        NansiWrite(NANSISeq);
    end;
    begin
        NansiWrite(NANSI_CLS);
        Writeln('NANSI colors:'); Writeln;
        for I := 0 to 7 do begin
            S := Colors[I]; L := Length(S);
            for J := 1 to 7 - L do
                S := S + ' ';
            NansiWrite(NANSI_NORMAL); Write(S, ': ');
            NansiWriteColor('bg', I);
            for J := 0 to 14 do begin
                NansiWriteColor('fg', J); Write('XX');
                if J < 14 then
                    Write(' ');
            end;
            Writeln;
        end;
        NansiWrite(NANSI_NORMAL);
        Writeln; Writeln;
    end.

And here is a screenshot of the program output.

ANSI escape sequences on FreeDOS: Free Pascal ANSI color table

ANSI escape sequences in assembly.

Using ANSI escape sequences in an assembly program is even easier than in other programming languages. As the character to displayed is the character coded by the ASCII code sent to the display, all we have to do is to place the value 1Bh (decimal 27) in the memory location from where display is done. In assembly, ANSI escape sequences are a sequence of bytes starting with 1Bh, 5Bh (where 5Bh = 91 decimal is the ASCII code of the left square bracket).

For example, to clear the screen from an assembly (NASM; 16-bit real mode) program, you can define the ANSI escape sequence as follows
  cls     db    1Bh, 5Bh, '2J', '$'
and sending it to the screen using the instructions
          mov   dx, cls
          mov   ah, 9
          int   21h

The sample program HELLORED.ASM displays a "Hello World" in red. Here is the code (I built it with NASM creating a 16-bit real mode executable; similar code should work with other assemblers, too).

  org 100h
  section .text
  start:
  ; Display message (calling the DOS write-string function)
          mov   dx, hello
          mov   ah, 9
          int   0x21
  ; Terminate the program (calling the DOS exit function)
          mov   ax, 0x4c00
          int   0x21
  section .data
  hello   db    27, '[31m', 'Hello, World!', 13, 10, 27, '[0m', '$'

The screenshot shows the build (using my custom batch file) and the execution of the program.

ANSI escape sequences on FreeDOS: Building and executing a NASM program with colored text output

ANSI escape sequences in DOS batch files.

For people, who work a lot with batch files, creating colored output or using other special console operations from within such files can be interesting. But, how do we tell the echo command to output an escape control character? Is there a way to code this or other control characters in the (Free)DOS editor? Yes, there is! The ASCII control characters (characters with ASCII codes from 0 to 31, plus 127) have a "character representation" made of CTRL+<letter-code>, and may this way be entered from the DOS command line (or as program input). Examples: CTRL+G corresponds to ASCII code 07h (BEL) and entering this key combination makes the computer beep; CTRL+H corresponds to ASCII code 07h (BS) and you can use this key combination instead of the backspace key. Another example is CTRL+M corresponding to ASCII code 0Dh (CR) and you can use this key combination instead of the ENTER key.

The escape control character (ASCII code 1Bh = decimal 27) can be entered in DOS using the key combination CTRL+[. The important thing to know is that you must use the "[" key as is on a US keyboard, this independently of your actual keyboard driver. At least it seems so, because on my laptop with German keyboard and using keyb with the German keyboard layout, I have to push CTRL+ΓΌ to enter the escape control character.

This is however only a part of the solution. If, in the FreeDOS editor, we enter CTRL+[, we don't enter a printable character, but execute a control character. So, what we need is a way to tell the editor that what we want actually is the printable character corresponding to ASCII code 1bH and not the control character. The FreeDOS editor allows to enter control characters as printable characters (instead of interpreting them as control codes) by prefixing them with CTRL+P. Thus, to enter the escape control character as character (not as ESC control code), push CTRL+P followed by CTRL+[. In the editor this will appear as a left arrow, what corresponds to the printable character assigned to ASCII code 1Bh on the original IBM PC, and also in the character set of code page 437.

ANSI escape sequences on FreeDOS: Batch file including ANSI escape sequences created with the default FreeDOS editor

The sample script NANSI.BAT writes some colored text to the screen. Here is the code (note that ESC represents the escape control character that you have to enter in the FreeDOS editor as the CTRL+P, CTRL+[ key sequence).

    @echo off
    echo ESC[2J
    echo ESC[31mThis text is in red
    echo ESC[1mThis text is in bold red = lightred
    echo ESC[0m
    echo ESC[32mThis text is in green
    echo ESC[32;1mThis text is in bold green
    echo ESC[5mThis text is in bold green and blinking
    echo ESC[0m
    echo ESC[44m This text is lightgray on blue background
    echo ESC[1m This text is in bold lightgray = white on blue background
    echo ESC[7mThis text is in reversed colors
    echo ESC[0m
    echo ESC[33;44;1m This text is in bold brown = yellow on blue background
    echo ESC[4mThis text is NOT yellow underlined on blue backgraound
    echo ESC[0m

The screenshot shows the screen output of the batch file.

ANSI escape sequences on FreeDOS: Colored text output from a DOS batch file

Notes:

Other ways to perform advanced console functions from within a batch file:

Enjoy a colorful DOS programming experience!


If you find this text helpful, please, support me and this website by signing my guestbook.