C Programming - using ANSI escape codes on Windows, macOS and Linux terminals
Posted on April 8, 2019 by Paul
In this article I will show you how to use ANSI escape codes to control the colors of your Terminal, write text at arbitrary positions, erase lines of text or portions of the terminal and move the cursor. The advantage of using ANSI escape codes is that, today, these are available on most operating systems, including Windows, and you don’t need to install third party libraries. These are well suited for simple command line applications. If you need to do complex text graphics check the ncurses library.
You can find all the code examples at the GitHub repo for this article.
There is also a video version of this tutorial:
Let’s start with a simple C example that will print a green text message on your Terminal:
If you build and run the above code, on Linux or macOS, you should see the message Hello, World printed in green. A side effect of the above program is that your Terminal will switch the default text color to green. Let’s remedy the above problem by resetting the colors to the original ones before the program ends:
This is what I see on a macOS machine:
Let’s analyze a bit the ANSI escape code that changes the text color to green, this is made up from a few parts:
We can represent the ESC key in a string in a few ways:
The 32 number from the ANSI escape code is the color code for green.
Originally the ANSI escape codes specified only 8 colors for foreground (the text) from 30 to 37: black, red, green, yellow, blue, magenta, cyan and white. Same colors can be used for the terminal background but these are defined as the numbers from 40 to 47. For example, if you want to set the background to blue and the text color to red you can use this code:
This is what I see on my machine:
As a side note, you can use ANSI escape codes in the Chrome Console window, if you want to change the color of the output text:
If you try one of the above C codes on a Windows 10 machine, you will be able to compile it successfully, but the output will be mangled with non printable characters. This is because the Windows console needs to be programmatically put in ANSI escape mode.
I wrote two simple helper functions to setup the console and restore it before the caller program ends. In short, you need to get the output handle for the console and set ENABLE_VIRTUAL_TERMINAL_PROCESSING. Put the next code in a file named ansi_escapes.c:
You’ll also need the header file ansi_escapes.h:
Let’s modify the C code that writes a red text message on blue background in order to work on Linux, macOS and Windows. I’ve saved the modified code as t1b.c:
You can build the code on Linux and macOS with:
and on Windows, assuming that you are using the Visual Studio command line compiler:
This is what I see on a Windows console:
Let’s also collect the color codes for the foreground and background in an enum in ansi_escapes.h:
If you remember from earlier, we’ve used this ANSI escape code to set the foreground or background color:
You can bright the above colors by using:
for example, to have a bright green text you could use:
There are also ANSI escape codes to clear the screen:
and another ones to clear the current line of text:
We can abstract the above operations in ansi_escapes.c like this:
don’t forget to copy the above functions signatures to ansi_escapes.h if you want to be able to use them.
Another useful group of ANSI escape code is the movement set. You can move relative to the current cursor position up, down, left, right or you can jump to a specific position. I’ve grouped these escape codes in a set of helper functions:
Assuming that you’ve placed the above helper functions in ansi_escapes.h and ansi_escapes.c, let’s write a slightly more complex code. Start by clearing the screen, move the cursor position to (1, 1), set the text color to green, set the background color to yellow, write 3 lines of text, move back to second line, erase it and write another text on the second line, move down three lines, move right 5 positions, change text color to magenta, write something else, move down 1:
Here is what I see on my machine if I run the above code:
There are also ANSI escape codes to save and restore the text cursor position, these are useful you plan to go back later and do some edits:
Let’s also modify the last code example, in order to save the cursor position after writing the second line and instead of moving up, let’s use the restore cursor position. Also, we’ll erase the line to the left instead of erasing the entire line:
Please note that I’ve placed the ANSI escape codes for saving and restoring the cursor position in two new functions saveCursorPosition and restoreCursorPosition
This is what I see on my machine, if I run the above code:
You can also inquire about the current cursor position using:
The problem with the above is that the position will be shown on the Terminal in this format:
If you want to not mess your already printed text, you will need a way to put the stdin stream in a no echo, unbuffered mode, read the cursor position from stdin and parse the string to recover the actual coordinates. Changing the stdin mode requires OS specific code, for example on Posix systems you will use functions from termios.h and on Windows functions from windows.h. The GitHub repo for this article contains a possible implementation for the above with this signature:
As a side note, Windows provides a function to get the cursor position, but you will get the absolute cursor position relative the console buffer and not the relative position to your running code as it is the case for when you use ANSI escape codes.
Let’s use getCursorPosition to get the current cursor position in our last example after the cursor was move 5 positions to the right:
This is what I see on my machine:
If you want to learn more about C99/C11 I would recommend reading 21st Century C: C Tips from the New School by Ben Klemens:
or the classic C Bible, The C Programming Language by B.W. Kernighan, D.M. Ritchie: