Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
989 views
in Technique[技术] by (71.8m points)

linux - Change text color using C

I've been reading some few articles about changing text color using C, but the problem is they all tend to be related to Turbo C

textcolor(RED);

And I have a need to change the color of variable: value (user input) output similar to what we get when we execute "inxi -S" on terminal program. How do I change the color of my console program?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This question can only be partially answered because doesn't specify colored output, it only knows about text. So solutions are dependent on the target platform and from the comments, it's clear the OP is interested in more than one platform.

I did my own implementation a while back that works in *nix terminals supporting ANSI colors and in a win32 console, which I already referred to in comments, but for an answer, this should be simplified to the bare minimum, so here comes an example:

#ifdef _WIN32
#include <windows.h>    // for win32 API functions
#include <io.h>         // for _get_osfhandle()
#else
#ifndef _POSIX_SOURCE
#define _POSIX_SOURCE   // enable POSIX extensions in standard library headers
#endif
#include <unistd.h>     // for isatty()
#endif

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

// use an enum for platform-independent interface:
typedef enum TextColor
{
    TC_BLACK = 0,
    TC_BLUE = 1,
    TC_GREEN = 2,
    TC_CYAN = 3,
    TC_RED = 4,
    TC_MAGENTA = 5,
    TC_BROWN = 6,
    TC_LIGHTGRAY = 7,
    TC_DARKGRAY = 8,
    TC_LIGHTBLUE = 9,
    TC_LIGHTGREEN = 10,
    TC_LIGHTCYAN = 11,
    TC_LIGHTRED = 12,
    TC_LIGHTMAGENTA = 13,
    TC_YELLOW = 14,
    TC_WHITE = 15
} TextColor;

// set output color on the given stream:
void setTextColor(FILE *stream, TextColor color);

int main(void)
{
    puts("Color test.");
    setTextColor(stdout, TC_GREEN);
    puts("This is green!");
    setTextColor(stdout, TC_LIGHTGRAY);
    puts("back to normal.");
    return EXIT_SUCCESS;
}

#ifdef _WIN32

void setTextColor(FILE *stream, TextColor color)
{
    int outfd = fileno(stream);
    HANDLE out = (HANDLE)_get_osfhandle(outfd);
    DWORD outType = GetFileType(out);
    DWORD mode;
    if (outType == FILE_TYPE_CHAR && GetConsoleMode(out, &mode))
    {
        // we're directly outputting to a win32 console if the file type
        // is FILE_TYPE_CHAR and GetConsoleMode() returns success

        SetConsoleTextAttribute(out, color);
        // the enum constants are defined to the same values
        // SetConsoleTextAttribute() uses, so just pass on.
    }
}

#else

static const char *ansiColorSequences[] =
{
    "x1B[0;30m",
    "x1B[0;34m",
    "x1B[0;32m",
    "x1B[0;36m",
    "x1B[0;31m",
    "x1B[0;35m",
    "x1B[0;33m",
    "x1B[0;37m",
    "x1B[1;30m",
    "x1B[1;34m",
    "x1B[1;32m",
    "x1B[1;36m",
    "x1B[1;31m",
    "x1B[1;35m",
    "x1B[1;33m",
    "x1B[1;37m"
};

static const char *ansiColorTerms[] =
{
    "xterm",
    "rxvt",
    "vt100",
    "linux",
    "screen",
    0
    // there are probably missing a few others
};

// get current terminal and check whether it's in our list of terminals
// supporting ANSI colors:
static int isAnsiColorTerm(void)
{
    char *term = getenv("TERM");
    for (const char **ansiTerm = &ansiColorTerms[0]; *ansiTerm; ++ansiTerm)
    {
        int match = 1;
        const char *t = term;
        const char *a = *ansiTerm;
        while (*a && *t)
        {
            if (*a++ != *t++)
            {
                match = 0;
                break;
            }
        }
        if (match) return 1;
    }
    return 0;
}

void setTextColor(FILE *stream, TextColor color)
{
    int outfd = fileno(stream);
    if (isatty(outfd) && isAnsiColorTerm())
    {
        // we're directly outputting to a terminal supporting ANSI colors,
        // so send the appropriate sequence:
        fputs(ansiColorSequences[color], stream);
    }
}

#endif

Note 1: My original code does a little more, including sending ansi color codes through pipes as well, this might not be what you want, depending on where you expect output to be piped to. It also has a printf() like interface supporting colors. You can find it here, in the "core" library.

Note 2: If you ultimately want to do more with your terminal than just colors, like e.g. controlling the cursor, outputting to a fixed position, etc, I suggest you use curses instead. The default implementation on Linux systems is ncurses, for windows you can use pdcurses -- the same code can be built/linked against ncurses or pdcurses, depending on your target platform.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...