32

I would like to change a program to automatically detect whether a terminal is color-capable or not, so when I run said program from within a non-color capable terminal (say M-x shell in (X)Emacs), color is automatically turned off.

I don't want to hardcode the program to detect TERM={emacs,dumb}.

I am thinking that termcap/terminfo should be able to help with this, but so far I've only managed to cobble together this (n)curses-using snippet of code, which fails badly when it can't find the terminal:

#include <stdlib.h>
#include <curses.h>

int main(void) {
 int colors=0;

 initscr();
 start_color();
 colors=has_colors() ? 1 : 0;
 endwin();

 printf(colors ? "YES\n" : "NO\n");

 exit(0);
}

I.e. I get this:

$ gcc -Wall -lncurses -o hep hep.c
$ echo $TERM
xterm
$ ./hep
YES
$ export TERM=dumb
$ ./hep           
NO
$ export TERM=emacs
$ ./hep            
Error opening terminal: emacs.
$ 

which is... suboptimal.

asjo
  • 3,084
  • 2
  • 26
  • 20
  • 2
    In the final analysis you can't, because you cannot tell what kind of CRT the terminal is implemented with. –  Mar 17 '10 at 20:01
  • 7
    I am interested in whether the terminal(type) says it is color-capable or not - not in an analysis of the spectrum of the light emanating from a CRT :-) – asjo Mar 17 '10 at 20:10

3 Answers3

24

A friend pointed me towards tput(1), and I cooked up this solution:

#!/bin/sh

# ack-wrapper - use tput to try and detect whether the terminal is
#               color-capable, and call ack-grep accordingly.

OPTION='--nocolor'

COLORS=$(tput colors 2> /dev/null)
if [ $? = 0 ] && [ $COLORS -gt 2 ]; then
    OPTION=''
fi

exec ack-grep $OPTION "$@"

which works for me. It would be great if I had a way to integrate it into ack, though.

asjo
  • 3,084
  • 2
  • 26
  • 20
  • 2
    Note that ncurses's `has_colors()` performs a more comprehensive test than just examining the number of colors, since that's not the only way color support can be expressed in terminfo. – Chris Page Sep 15 '11 at 05:55
  • But... but... the `tput` manual makes no mention of a "colors" command. How did your *friend* find out about this nifty feature??! – Kingsley Aug 08 '19 at 05:30
  • 1
    The tput(1) man page says "tput [-Ttype] capname [parameters]", so "colors" is a "capname", a capability that is defined in the terminfo database, not a command. So I guess look in terminfo(5) to learn about what capabilities there are. – asjo Aug 16 '19 at 20:20
10

You almost had it, except that you need to use the lower-level curses function setupterm instead of initscr. setupterm just performs enough initialization to read terminfo data, and if you pass in a pointer to an error result value (the last argument) it will return an error value instead of emitting error messages and exiting (the default behavior for initscr).

#include <stdlib.h>
#include <curses.h>

int main(void) {
  char *term = getenv("TERM");

  int erret = 0;
  if (setupterm(NULL, 1, &erret) == ERR) {
    char *errmsg = "unknown error";
    switch (erret) {
    case 1: errmsg = "terminal is hardcopy, cannot be used for curses applications"; break;
    case 0: errmsg = "terminal could not be found, or not enough information for curses applications"; break;
    case -1: errmsg = "terminfo entry could not be found"; break;
    }
    printf("Color support for terminal \"%s\" unknown (error %d: %s).\n", term, erret, errmsg);
    exit(1);
  }

  bool colors = has_colors();

  printf("Terminal \"%s\" %s colors.\n", term, colors ? "has" : "does not have");

  return 0;
}

Additional information about using setupterm is available in the curs_terminfo(3X) man page (x-man-page://3x/curs_terminfo) and Writing Programs with NCURSES.

Chris Page
  • 18,263
  • 4
  • 39
  • 47
  • 3
    In C++ on my Mac OSX machine I also need to #include . – Alec Jacobson Oct 24 '12 at 05:58
  • > terminal is hardcopy, cannot be used for curses applications I wonder if there are log-like terminals where neither anything can be erased nor cursor can be moved, but which still support colors and to some extent useful with ncurses? E.g. many CI environments do that. – nponeccop Nov 12 '21 at 16:00
  • @AlecJacobson that's not just for C++ of course .. also C (naturally). – Pryftan Apr 16 '23 at 11:58
5

Look up the terminfo(5) entry for the terminal type and check the Co (max_colors) entry. That's how many colors the terminal supports.

jfawcett
  • 885
  • 7
  • 6