Fun With Terminal Text in C

On March 8, 2013, in How To, Linux, Programming, by erik

I have always thought it was cool when a program like wget would show you ‘visually’ on a command console how much longer a file would take to download, essentially an ASCII progress bar. The message was ASCII graphics really, and would have some movement to it – I always wondered how you could achieve this using standard out and some simple fprintf commands to modify the text in place. There are a few ways you can achieve some graphics on the console.

  • You can utilize the ncurses library.
  • You can utilize fprintf and the \b (backspace) character to replace some text.

The advantage of ncurses is it can re-draw and clear the entire screen, draw certain aspects of the screen at different points. There is a predefined API for ncurses and is far more powerful than simple fprintf work. Even the common ‘make menuconfig’ directives utilize the ncurses library.

Using the second method is a little mickey mouse but still fun none-the-less. I wrote a little program that will visually give you progress by swapping textual values within two square opening and closing brackets. In this case [w] and [e]. I thought it would be easier to explain to what I mean from an animated gif I created from my terminal window:

Text Replace

This very basic example does not actually take a lot of programming, but I think it may trigger some ideas as to other neat things you could do with it. The code to achieve this is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdlib.h>
#include <stdio.h>
 
int main()
{
	fprintf(stdout, "Writing from a to b ....");
	fprintf(stdout, " [ ]");
 
	for (;;) {
		fprintf(stdout, "\b\b\b   ");
		fprintf(stdout, "\b\b\b[e]");
		usleep(500000);
		fprintf(stdout, "\b\b\b[w]");
		usleep(500000);
	}
 
	return 0;
}

Initially the code writes out the standard line. Then the second fprintf outputs the [ ], then the first line in the ‘for’ loop backspaces three characters, this includes the opening and closing square brackets. The following lines will pause for half a second, remove the [ ] then populate them with the ‘[e]‘ or the ‘[w]‘. This is merely a trick of backspacing at such a rate in which your eyes do not notice.

What cool things have you seen done in a terminal?

I am a huge fan of OpenWRT and have used it for many years. OpenWRT is a complete build environment that includes toolchain and is designed to allow for easy target architecture switching – all modifiable from a standard menuconfig. Quite nice! After using it for so long I have come across a few easy commands for cleaning the environment, building single packages, building packages with debug information among many other things. I hope to cover a few here for ease of use.

Clean whole environment including architecture type:

From the trunk of your checkout type:

$ make distclean

This will remove your .config file as well as the linux kernel build directory and your package directory.

Clean just the packages for the current config file:

From the root of your checkout:

$ make clean

This will keep your .config file in tact.

How to select packages and architecture type:

If you want to modify which packages your image should contain, add a few utilities, or add a few libraries simply use the standard menuconfig.

$ make menuconfig

This will provide a ‘graphical’ interface to select specific packages. If you hit ‘spacebar’ once on an item it will set to M – or module, this builds an ipk file (much like a .deb or .rpm) file which is used by OPKG to install the package. If you hit ‘spacebar’ again it will put a asterisk ‘*’ beside the package, this means it will build it directly into the image (you will still find the *.ipk file in your /bin/packages/arch/ directory).

Modify kernel options:

Sometimes you need to select a specific kernel scheduler or perhaps include some special GPIO interface to turn your LEDs on and off on a hardware type thus there is a command to modify kernel modules:

$ make kernel_menuconfig

How to build a specific package:

On occasion you may be working on a specific package and do not want to compile the whole image just to check a minor modification. Thus, there is a specific way to call only that function:

$ make package/base-files-compile

OR

$ make package/base-files/compile

Compile with error output:

I will always compile an image or package with V=99. This command will ensure that all compilation, environment variables, and errors are displayed to standard output. Therefore, if you care about this data I would suggest setting unlimited history to your terminal window, or redirect the output to a file.

You can append the V=99 to any make step, this include the menuconfig or for the entire build.

$ make package/base-files/compile V=99

OR

$ make V=99

Compile with debug information

Perhaps you are profiling a package using valgrind, it is suggested to compile C programs using -g or -g3 to include symbol information for your binary. If you pass the CONFIG_DEBUG=y at the end of your make command then your binary will be built with debugging data. Be careful though because your IPK will still be stripped, only the binary built in your /build_dir/ will contain the binary not stripped.

$ make V=99 CONFIG_DEBUG=y

Compile with debug information and do not strip binary

To ensure that OpenWRT will build your IPKG with binaries that contain debug information and are not stripped you can pass in CONFIG_NO_STRIP=y. Be warned though, when including debug information and not stripping your binary, the size of your binary and IPKG’s become quite large. If you do a global make with debug information and no stripping you are looking at a massive image size increase, you may even hit partition size limits which OpenWRT will warn you about. The method to utilize this is:

$ make V=99 CONFIG_DEBUG=y CONFIG_NO_STRIP=y

This will produce an image and specific IPKG in your /build_dir/ that contain debug information.

Compile across multiple cores

OpenWRT will pass this information to gcc or g++ during compilation and is really not an OpenWRT commands but here for completeness:

$ make -j 3 V=99 CONFIG_DEBUG=y

The command -j informs gcc or g++ to move compilation tasks across multiple cores. It is always the number of cores + 1. So if you have 2 cores, then -j 3 should suffice. Use this with caution as in some cases there are package dependencies that must be built prior to other packages. I have run into a few instances where the package requiring dependencies is attempting to build prior to the package dependency.

Note:The OpenWRT image is property of OpenWRT.org.