Write Your Own conio.h for GNU/Linux

GNU-visualHere’s a close look at the technique and code for console handling in Standard (i.e., ISO/ANSI) C/C++.   In the latter part of the article readers are encouraged to write their own code for the clrscr, getch, gotoxy, text color, and text background functions.

Before taking up the matter at hand, it would be useful to note the key differences between Turbo C/C++ and Standard C/C++:
1.    Turbo C and Turbo C++ are IDEs developed by Borland, which use their C/C++ implementations and compilers, while Standard C and C++ are supported by all famous compilers such as GCC.
2.    Turbo C/C++ are only for DOS (and Windows), while Standard C/C++ is portable.
3.    Turbo C++ was discontinued in 2006, while Standard C/C++ will be sustained for ever (even though the standards might be updated).
4.    Turbo C and C++ are proprietary software, while Standard C and C++ are just languages that are supported by Free (Libre) compilers.
Hence it is recommended that you use Standard C/C++ if you are doing anything serious. It may be noted here that:
1.     Standard C/C++, ANSI C/C++ and ISO C/C++ are the same.
2.    For the sake of convenience, I will use only stdio.h and printf from this point onwards. You may replace it with iostream and cout if you are using C++.
3.    If you are new to Standard C++, use iostream instead of iostream.h and add a line using namespace std; after adding all header files. There will be no other notable differences. C, Turbo and Standard are almost the same (at least at the basic levels).

Console formatting with Turbo C
Consider a simple program to make the background colour of the console blue, and to print the message ‘Hello, World! in white.
You may use the following code in Turbo C.

#include <stdio.h>
#include <conio.h>
void main()
{
    clrscr(); // Clear the console
     textbackground(BLUE);
     textcolor(WHITE);
     printf(Hello, World!\n);
     return;
}

But this code cannot be compiled with a standard compiler. So let us see how to work with Standard C.

Console operations in Standard C
The problem with the above code is that it is not compatible with Standard C. No standard libraries provide conio.h. Using the void type for the main function itself is an error. The int type may be used and some value returned, normally zero (return 0;).
Console handling in Standard C is done using escape sequences. Escape sequences use \n for a newline, \t for a horizontal tab, and so on. In Standard C, there are escape sequences that can do many operations on the console. First, let’s use these escape sequences. Since they look rough, we will write our own code for the functions clrscr, getch, gotoxy, textcolor, textbackground, etc.
Some important escape sequences are given in Table 1. You can use them inside printf as you use \n and \t.

Escape code Use
\x1b[2J Clears the console
\x1bn;mH or \x1bn;mf Moves the cursor to row n, column m. The values are 1-based, and default to 1 (top left corner) if omitted
\x1b?25l Hides the cursor (Note: the last character is lowercase 'L')
\x1b?25h Shows the cursor.
\x1b[;km Where k is the colour (text colours are from 30 to 37 and background colours are from 40 to 47). For the colour codes, see Table 2.
\x1b[5m Blinks slowly
\x1b[6m Blinks rapidly

Table 1: Some important ANSI escape codes

As shown in Table 1, you may use printf(\x1b[2J); to clear the console, instead of clrscr();. You may use printf(\x1b10;20H); instead of gotoxy(20,10); or printf(\x1b%d;%dH, a, b); instead of gotoxy(a, b);.
But while using colours, with \x1b[;km, you have to replace k with 30+colour_code in the case of foreground colouring and 40+colour_code in the case of background colouring. Refer to Table 2 for the colour codes.

0 1 2 3 4 5 6 7
Black Red Green Yellow Blue Magenta Cyan White

Table 2: Colour codes

From Table 2, you can use printf(\x1b[31m); instead of textcolor(RED); and printf(\x1b[41m); instead of textbackground(RED);. You can cancel the colouring using \x1b[0m.

To learn more about ANSI escape codes, visit: http://www.en.wikipedia.org/wiki/ANSI_escape_code
These escape codes are used in other languages too, like in Python, when using the print() function; e.g.: print("\x1b[32m") for a green foreground.

Typical Turbo C programmers start their programs with clrscr() to clear the screen and end with getch() to wait for a keystroke before the program terminates. Both are meaningless in most cases. If you are familiar with CLI, you might have noticed the irritation while the console clears with every command that you give. A Turbo C programmer gives the getch() command. Otherwise the program will disappear suddenly and the result of the program will not be visible. In a standard console, the result stays there for a long time without getch(). The extra keystroke is an additional irritation.

However, these two functions are useful in some cases. We have replaced clrscr() with an escape code, \x1b[2J. But there is no such code for getch() since it is a function with return type char.

Actually, getch() can be replaced with getchar() from stdio.h. The problem, however, is that getchar() waits for the user to press the 'Enter' key. It echoes what was typed, too. We'd like to write our own function that waits only for a single keystroke, which will not echo the keystroke. Here we need the help of an external CLI program, stty, which is shipped with almost all GNU/Linux distros.
The code given below shows the combination of escape codes and stty to create a program that clears the screen, prints 'Hello, World! in white with a blue background, waits for a keystroke and resets the video.

#include <stdio.h>
#include <stdlib.h>
void clrscr()
{
       printf("\x1b[2J");
}
 char getch()
{
      char c; // This function should return the keystroke
      system("stty raw");    // Raw input - wait for only a single keystroke
      system("stty -echo");  // Echo off
      c = getchar();
      system("stty cooked"); // Cooked input - reset
      system("stty echo");   // Echo on - Reset
      return c;
}
int main()
{
    printf("\x1b[34m"); // Blue background
    clrscr();       // Clear the screen with blue bg
    printf("\x1b[47m"); // White foreground
    printf("Hello, World!\n");
    getch();
    printf("\x1b[0m");   // Reset the console
    return 0;
}

Now we have replaced all the important functions of conio.h. But think about the complexity of the code above- this long code snippet was the replacement of short Code 1! Here arises the need to write our own conio.h.

Figure-1Our own conio.h!
Let's combine all our techniques in our own conio library. To keep things simple, let's not create a .so shared library, but write conio.c and conio.h separately. Here are the codes, with some additional functions from our earlier discussion (such as nocursor() and showcursor()) also:

conio.c:

// conio.c for ANSI C and C++
// Extra functions are also provided.
// (C) 2013 Nandakumar <[email protected]>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "conio.h"

// General Utility Functions

void cagxy(unsigned int x, unsigned int y) // Clear and Goto X,Y
{
printf("%s\x1b[%d;%df", CLEAR, y, x);
}

void clrscr() // Clear the Screen
{
printf("%s",CLEAR);
}

char getch()
{
char c;
system("stty raw -echo");
c=getchar();
system("stty cooked echo");

return c;
}

void gotox(unsigned int x)
{
printf("\x1b[%dG", x);
}

void gotoxy(unsigned int x, unsigned int y)
{
printf("\x1b[%d;%df", y, x);
}

void nocursor()
{
printf("\x1b[?25l");
}

void reset_video()
{
printf("\x1b[0m");
}

void showcursor()
{
printf("\x1b[?25h");
}

void textcolor(char *color)
{
printf("%s",color);
}

void textbackground(char color[11])
{
char col[11];
strcpy(col,color);
col[2]=’4′; // The given color will be fg color. Replace ’3′ with ’4′.
printf(“%s”,col);
}
conio.h:

// conio.h for ANSI C and C++
// Extra functions are also provided.
// (C) 2013 Nandakumar <[email protected]>

#ifndef CONIO_H
#define CONIO_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// General Utility

#define CLEAR “\x1b[2J"
#define SET11 "\x1b[1;1f"  // Set the Cursor at 1,1

// Text Modification

#define BLINK_SLOW "\x1b[5m"
#define BLINK_RAPID "\x1b[6m"

// Colors

#define CC_CLEAR "\x1b[0m" // Console Color CLEAR

// FG Colours
#define BLACK "\x1b[30m"
#define RED "\x1b[31m"
#define GREEN "\x1b[32m"
#define YELLOW "\x1b[33m"
#define BLUE "\x1b[34m"
#define MAGENTA "\x1b[35m"
#define CYAN "\x1b[36m"
#define WHITE "\x1b[37m"

// FG Intense Colors
#define IBLACK "\x1b[30;1m"
#define IRED "\x1b[31;1m"
#define IGREEN "\x1b[32;1m"
#define IYELLOW "\x1b[33;1m"
#define IBLUE "\x1b[34;1m"
#define IMAGENTA "\x1b[35;1m"
#define ICYAN "\x1b[36;1m"
#define IWHITE "\x1b[37;1m"

// BG Colors
#define BGC_BLACK "\x1b[40m"
#define BGC_RED "\x1b[41m"
#define BGC_GREEN "\x1b[42m"
#define BGC_YELLOW "\x1b[43m"
#define BGC_BLUE "\x1b[44m"
#define BGC_MAGENTA "\x1b[45m"
#define BGC_CYAN "\x1b[46m"
#define BGC_WHITE "\x1b[47m"

// BG Intense Colors
#define BGC_IBLACK "\x1b[40;1m"
#define BGC_IRED "\x1b[41;1m"
#define BGC_IGREEN "\x1b[42;1m"
#define BGC_IYELLOW "\x1b[43;1m"
#define BGC_IBLUE "\x1b[44;1m"
#define BGC_IMAGENTA "\x1b[45;1m"
#define BGC_ICYAN "\x1b[46;1m"
#define BGC_IWHITE "\x1b[47;1m"

// General Utility Functions

void cagxy(unsigned int x, unsigned int y); // Clear and Goto X,Y

void clrscr(); // Clear the Screen

char getch();

void gotox(unsigned int x);

void gotoxy(unsigned int x, unsigned int y);

void nocursor();

void reset_video();

void showcursor();

void textcolor(char *color);

void textbackground(char color[11]);

#endif
Example program
The code for the program that illustrates the use of our conio is given below:

test.c:

#include <stdio.h>
#include “conio.h”

int main()
{
textbackground(BLUE);
textcolor(WHITE);
clrscr();
printf(“Hello, World!\n”);
getch();

return 0;
}
See how short test.c is compared to Code 2!
Now, to compile this code,
1)    Keep both conio.c and conio.h in the same directory where test.c exists.
2)    Compile using the following command:

gcc test.c conio.c -o test

Now, you can use conio.c and conio.h for any program.

Try it out
Create a program especially using gotoxy(x,y) to input a table and print it with different colours.
Copy conio.h into /usr/include to use with <conio.h> instead of ‘conio.h’. Create a shared library from conio.c (.so extension) and find its usage. You may also try to create a ready-to-install package.

Disclaimer
These escape codes and tricks are given to help readers and are tested with gnome-terminal, xterm and Linux tty text console. But incompatibilities may occur. So always use a graphical console like GNOME Terminal, which can be closed easily with the mouse and keyboard when you notice improper working.
Amateur hacking can destroy a system, for which the author is not responsible. So always be careful.

  • http://totaki.com/poesiabinaria Siempre Makinando

    Some routines may be slow using system(), let’s have a look at this: http://binaryprose.com/2013/10/stermp-h-trying-to-port-conio-h-to-linux/ to get getch() without system, wherexy(), kbhit(), getche() and a way to get screen width and height, we don’t care about it in DOS or Windows but in Linux it’s very important.

    • Nandakumar Edamana

      It is true, thank you. But the article had to become simpler.

  • Reggie

    is this code covered by any license

    • Nandakumar Edamana

      The whole article is under creative commons and you are free to use it.

All published articles are released under Creative Commons Attribution-NonCommercial 3.0 Unported License, unless otherwise noted.
Open Source For You is powered by WordPress, which gladly sits on top of a CentOS-based LEMP stack.

Creative Commons License.