tin  2.6.1
About: TIN is a threaded NNTP and spool based UseNet newsreader.
  Fossies Dox: tin-2.6.1.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

color.c
Go to the documentation of this file.
1/*
2 * Project : tin - a Usenet reader
3 * Module : color.c
4 * Original : Olaf Kaluza <olaf@criseis.ruhr.de>
5 * Author : Roland Rosenfeld <roland@spinnaker.rhein.de>
6 * Giuseppe De Marco <gdm@rebel.net> (light-colors)
7 * Julien Oster <fuzzy@cu8.cum.de> (word highlighting)
8 * T.Dickey <dickey@invisible-island.net> (curses support)
9 * Created : 1995-06-02
10 * Updated : 2021-02-23
11 * Notes : This are the basic function for ansi-color
12 * and word highlighting
13 *
14 * Copyright (c) 1995-2022 Roland Rosenfeld <roland@spinnaker.rhein.de>
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
19 * are met:
20 *
21 * 1. Redistributions of source code must retain the above copyright notice,
22 * this list of conditions and the following disclaimer.
23 *
24 * 2. Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution.
27 *
28 * 3. Neither the name of the copyright holder nor the names of its
29 * contributors may be used to endorse or promote products derived from
30 * this software without specific prior written permission.
31 *
32 * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
36 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
37 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
38 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
39 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
40 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42 * POSSIBILITY OF SUCH DAMAGE.
43 */
44
45#ifndef TIN_H
46# include "tin.h"
47#endif /* !TIN_H */
48#ifndef TCURSES_H
49# include "tcurses.h"
50#endif /* !TCURSES_H */
51#ifndef included_trace_h
52# include "trace.h"
53#endif /* !included_trace_h */
54
55#ifdef HAVE_COLOR
56
57# define MIN_COLOR -1 /* -1 is default, otherwise 0-7 or 0-15 */
58
59int default_fcol = 7;
60int default_bcol = 0;
61
62# ifdef USE_CURSES
63 static int current_fcol = 7;
64 static struct LIST {
65 struct LIST *link;
66 int pair;
67 int fg;
68 int bg;
69 } *list;
70# endif /* USE_CURSES */
71static int current_bcol = 0;
72
73
74/*
75 * local prototypes
76 */
77# ifdef USE_CURSES
78 static void set_colors(int fcolor, int bcolor);
79# endif /* USE_CURSES */
80
81
82# ifdef USE_CURSES
83static void
84set_colors(
85 int fcolor,
86 int bcolor)
87{
88 static int nextpair;
89
90# ifndef HAVE_USE_DEFAULT_COLORS
91 if (fcolor < 0)
92 fcolor = default_fcol;
93 if (bcolor < 0)
94 bcolor = default_bcol;
95# endif /* !HAVE_USE_DEFAULT_COLORS */
96 if (cmd_line || !use_color || !has_colors()) {
97 current_fcol = default_fcol;
98 current_bcol = default_bcol;
99 } else if (COLORS > 1 && COLOR_PAIRS > 1) {
100 chtype attribute = A_NORMAL;
101 int pair = 0;
102
103 TRACE(("set_colors(%d, %d)", fcolor, bcolor));
104
105 /*
106 * fcolor/bcolor may be negative, if we're using ncurses
107 * function use_default_colors().
108 */
109 if (fcolor > COLORS - 1) {
110 attribute |= A_BOLD;
111 fcolor %= COLORS;
112 }
113 if (bcolor > 0)
114 bcolor %= COLORS;
115
116 if (fcolor != default_fcol || bcolor != default_bcol) {
117 struct LIST *p;
118 t_bool found = FALSE;
119
120 for (p = list; p != NULL; p = p->link) {
121 if (p->fg == fcolor && p->bg == bcolor) {
122 found = TRUE;
123 break;
124 }
125 }
126 if (found) {
127 pair = p->pair;
128 } else if (++nextpair < COLOR_PAIRS) {
129 p = my_malloc(sizeof(struct LIST));
130 p->fg = fcolor;
131 p->bg = bcolor;
132 p->pair = pair = nextpair;
133 p->link = list;
134 list = p;
135 init_pair(pair, fcolor, bcolor);
136 } else {
137 pair = 0;
138 }
139 }
140
141 bkgdset(attribute | COLOR_PAIR(pair) | ' ');
142 }
143}
144
145
146void
147refresh_color(
148 void)
149{
150 set_colors(current_fcol, current_bcol);
151}
152
153
154void
155reset_color(
156 void)
157{
158 current_fcol = default_fcol;
159 current_bcol = default_bcol;
160 refresh_color();
161}
162
163
164void
165free_color_pair_arrays(
166 void)
167{
168 struct LIST *p, *q;
169
170 for (p = list; p != NULL; p = q) {
171 q = p->link;
172 free(p);
173 }
174}
175# endif /* USE_CURSES */
176
177
178/* setting foreground-color */
179void
180fcol(
181 int color)
182{
183 if (color < MIN_COLOR || color > MAX_COLOR)
184 color = default_fcol;
185
186 TRACE(("fcol(%d) %s", color, txt_colors[color - MIN_COLOR]));
187
188 if (use_color) {
189# ifdef USE_CURSES
190 set_colors(color, current_bcol);
191 current_fcol = color;
192# else
193 int bold;
194
195 if (cmd_line)
196 return;
197 if (color < 0)
198 color = default_fcol;
199 bold = (color >> 3); /* bitwise operation on signed value? ouch */
200 my_printf("\033[%d;%dm", bold, ((color & 7) + 30));
201 if (!bold)
202 bcol(current_bcol);
203# endif /* USE_CURSES */
204 }
205# ifdef USE_CURSES
206 else
207 set_colors(default_fcol, default_bcol);
208# endif /* USE_CURSES */
209}
210
211
212/* setting background-color */
213void
214bcol(
215 int color)
216{
217 if (color < MIN_COLOR || color > MAX_COLOR)
218 color = default_bcol;
219
220 TRACE(("bcol(%d) %s", color, txt_colors[color - MIN_COLOR]));
221
222 if (use_color) {
223# ifdef USE_CURSES
224 set_colors(current_fcol, color);
225# else
226 if (color < 0)
227 color = default_bcol;
228 my_printf("\033[%dm", (color + 40));
229# endif /* USE_CURSES */
230 current_bcol = color;
231 }
232# ifdef USE_CURSES
233 else
234 set_colors(default_fcol, default_bcol);
235# endif /* USE_CURSES */
236}
237#endif /* HAVE_COLOR */
238
239
240/*
241 * Output a line of text to the screen with colour if needed
242 * word highlights, signatures etc will be highlighted
243 */
244void
246 const char *str,
247 int flags,
248 t_bool raw_data)
249{
250#ifdef HAVE_COLOR
251 if (use_color) {
252 if (flags & C_SIG) {
253 fcol(tinrc.col_signature);
254 } else if (flags & (C_HEADER | C_ATTACH | C_UUE)) {
255 fcol(tinrc.col_newsheaders);
256 } else { /* keep order in sync with cook.c:process_text_body_part() */
257 if (flags & C_VERBATIM) {
258 fcol(tinrc.col_verbatim);
259 } else if (flags & C_QUOTE3) {
260 fcol(tinrc.col_quote3);
261 } else if (flags & C_QUOTE2) {
262 fcol(tinrc.col_quote2);
263 } else if (flags & C_EXTQUOTE) {
264 fcol(tinrc.col_extquote);
265 } else if (flags & C_QUOTE1) {
266 fcol(tinrc.col_quote);
267 } else
268 fcol(tinrc.col_text);
269 }
270 }
271#endif /* HAVE_COLOR */
272
273 if (!raw_data) {
274#if defined(HAVE_LIBICUUC) && defined(MULTIBYTE_ABLE) && defined(HAVE_UNICODE_UBIDI_H) && !defined(NO_LOCALE)
275 /*
276 * BiDi support
277 */
278 /* don't run it on empty lines and lines containing only one char (which must be an ASCII one) */
279 if (tinrc.render_bidi && IS_LOCAL_CHARSET("UTF-8") && strlen(str) > 1) {
280 char *line;
281 t_bool is_rtl;
282
283 if ((line = render_bidi(str, &is_rtl)) != NULL) {
284 if (is_rtl) { /* RTL */
285 /* determine visual length and pad out so that line is right-aligned */
286 wchar_t *wline;
287
288 if ((wline = char2wchar_t(line)) != NULL) {
289 int visual_len;
290
291 wconvert_to_printable(wline, FALSE);
292 visual_len = wcswidth(wline, wcslen(wline) + 1);
293 free(wline);
294
295 if (visual_len > 0) {
296 int i;
297
298 for (i = 0; i < cCOLS - visual_len - 1; i++)
299 my_fputc(' ', stdout);
300 }
301 my_fputs(line, stdout);
302 } else /* fallback */
303 my_fputs(line, stdout);
304
305 } else /* LTR */
306 my_fputs(line, stdout);
307
308 free(line);
309 } else
310 my_fputs(str, stdout);
311 } else
312#endif /* HAVE_LIBICUUC && MULTIBYTE_ABLE && HAVE_UNICODE_UBIDI_H && !NO_LOCALE */
313 my_fputs(str, stdout);
314 } else {
315 /* in RAW-mode (show_all_headers) display non-printable chars as octals */
316 const char *c;
317 char octal[5];
318
319 c = str;
320 while (*c) {
321#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
322 int num_bytes;
323 wchar_t wc;
324
325 num_bytes = mbtowc(&wc, c, MB_CUR_MAX);
326 if (num_bytes != -1 && iswprint((wint_t) wc)) {
327 my_fputwc((wint_t) wc, stdout);
328 c += num_bytes;
329 }
330#else
331 if (my_isprint((unsigned char) *c)) {
332 my_fputc((int) *c, stdout);
333 c++;
334 }
335#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
336 else if (IS_LOCAL_CHARSET("Big5") && (unsigned char) *c >= 0xa1 && (unsigned char) *c <= 0xfe && *(c + 1)) {
337 /*
338 * Big5: ASCII chars are handled by the normal code
339 * check only for 2-byte chars
340 * TODO: should we also check if the second byte is also valid?
341 */
342 my_fputc((int) *c, stdout);
343 c++;
344 my_fputc((int) *c, stdout);
345 c++;
346 } else {
347 /*
348 * non-printable char
349 * print as an octal value
350 */
351 snprintf(octal, sizeof(octal), "\\%03o", (unsigned int) (*c & 0xff));
352 my_fputs(octal, stdout);
353 c++;
354 }
355 }
356 }
357
358#ifndef USE_CURSES
359 my_fputs(cCRLF, stdout);
360#endif /* !USE_CURSES */
361}
unsigned t_bool
Definition: bool.h:77
#define TRUE
Definition: bool.h:74
#define FALSE
Definition: bool.h:70
void draw_pager_line(const char *str, int flags, t_bool raw_data)
Definition: color.c:245
t_bool cmd_line
Definition: init.c:129
int cCOLS
Definition: curses.c:53
struct t_config tinrc
Definition: init.c:192
int my_isprint(int c)
Definition: misc.c:978
#define C_SIG
Definition: rfc2046.h:154
#define C_VERBATIM
Definition: rfc2046.h:167
#define C_QUOTE1
Definition: rfc2046.h:159
#define C_HEADER
Definition: rfc2046.h:152
#define C_QUOTE3
Definition: rfc2046.h:161
#define C_ATTACH
Definition: rfc2046.h:155
#define C_UUE
Definition: rfc2046.h:156
#define C_QUOTE2
Definition: rfc2046.h:160
#define cCRLF
Definition: tcurses.h:156
#define my_fputs(str, stream)
Definition: tcurses.h:159
#define my_printf
Definition: tcurses.h:175
#define my_fputc(ch, stream)
Definition: tcurses.h:158
#define MAX_COLOR
Definition: tin.h:1003
#define IS_LOCAL_CHARSET(c)
Definition: tin.h:782
#define my_malloc(size)
Definition: tin.h:2245
#define snprintf
Definition: tin.h:2464
#define TRACE(p)
Definition: trace.h:65