-
Notifications
You must be signed in to change notification settings - Fork 1
/
color.c
339 lines (308 loc) · 8.43 KB
/
color.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
/* color.c - Color handling for trn 4.0.
*/
/* This software is copyrighted as detailed in the LICENSE file, and
* this file is also Copyright 1995 by Gran Larsson <[email protected]>. */
/*
** The color handling is implemented as an attribute stack containing
** foreground color, background color, and video attribute for an object.
** Objects are screen features like "thread tree", "header lines",
** "subject line", and "command prompt". The intended use is something
** like this:
**
** color_object(COLOR_HEADER, 1);
** fputs(header_string, stdout);
** color_pop();
**
** The color_pop function will take care of restoring all colors and
** attribute to the state before the color_object function was called.
**
** Colors and attributes are parsed from the [attribute] section
** in the trnrc file. Escape sequences for the colors are picked up
** from term.c by calling the function tc_color_capability.
**
** If colors were specified in the [attribute] section, then colors
** are used, otherwise only normal monochrome video attributes.
*/
#include "EXTERN.h"
#include "common.h"
#include "term.h"
#include "util.h"
#include "final.h"
#include "INTERN.h"
#include "color.h"
#include "color.ih"
/*
** Object properties.
**
** Give default attributes that are used if the trnrc file has no,
** or just a few, lines in the [attribute] section.
*/
static COLOR_OBJ objects[MAX_COLORS] = {
{ "default", nullstr, nullstr, NOMARKING },
{ "ngname", nullstr, nullstr, STANDOUT },
{ "plus", nullstr, nullstr, LASTMARKING },
{ "minus", nullstr, nullstr, LASTMARKING },
{ "star", nullstr, nullstr, LASTMARKING },
{ "header", nullstr, nullstr, LASTMARKING },
{ "subject", nullstr, nullstr, UNDERLINE },
{ "tree", nullstr, nullstr, LASTMARKING },
{ "tree marker", nullstr, nullstr, STANDOUT },
{ "more", nullstr, nullstr, STANDOUT },
{ "heading", nullstr, nullstr, STANDOUT },
{ "command", nullstr, nullstr, STANDOUT },
{ "mouse bar", nullstr, nullstr, STANDOUT },
{ "notice", nullstr, nullstr, STANDOUT },
{ "score", nullstr, nullstr, STANDOUT },
{ "art heading", nullstr, nullstr, LASTMARKING },
{ "mime separator", nullstr, nullstr, STANDOUT },
{ "mime description",nullstr,nullstr, UNDERLINE },
{ "cited text", nullstr, nullstr, LASTMARKING },
{ "body text", nullstr, nullstr, NOMARKING },
};
/* The attribute stack. The 0th element is always the "normal" object. */
static struct {
COLOR_OBJ object;
} color_stack[STACK_SIZE];
static int stack_pointer = 0;
/* Initialize color support after trnrc is read. */
void
color_init()
{
if (use_colors) {
char* fg;
char* bg;
int i;
/* Get default capabilities. */
if ((fg = tc_color_capability("fg default")) == NULL) {
fprintf(stderr,"trn: you need a 'fg default' definition in the [termcap] section.\n");
finalize(1);
}
if ((bg = tc_color_capability("bg default")) == NULL) {
fprintf(stderr,"trn: you need a 'bg default' definition in the [termcap] section.\n");
finalize(1);
}
if (strEQ(fg, bg))
bg = nullstr;
for (i = 0; i < MAX_COLORS; i++) {
if (objects[i].fg == nullstr)
objects[i].fg = fg;
if (objects[i].bg == nullstr)
objects[i].bg = bg;
}
}
if (objects[COLOR_DEFAULT].attr == LASTMARKING)
objects[COLOR_DEFAULT].attr = NOMARKING;
/* Set color to default. */
color_default();
}
/* Parse a line from the [attribute] section of trnrc. */
void
color_rc_attribute(object, value)
char* object;
char* value;
{
char* s;
char* t;
char* n = NULL;
int i;
/* Find the specified object. */
for (i = 0; i < MAX_COLORS; i++) {
if (strcaseEQ(object, objects[i].name))
break;
}
if (i >= MAX_COLORS) {
fprintf(stderr,"trn: unknown object '%s' in [attribute] section.\n",
object);
finalize(1);
}
/* Parse the video attribute. */
if (*value == 's' || *value == 'S')
objects[i].attr = STANDOUT;
else if (*value == 'u' || *value == 'U')
objects[i].attr = UNDERLINE;
else if (*value == 'n' || *value == 'N')
objects[i].attr = NOMARKING;
else if (*value == '-')
objects[i].attr = LASTMARKING;
else {
fprintf(stderr,"trn: bad attribute '%s' for %s in [attribute] section.\n",
value, object);
finalize(1);
}
/* See if they specified a color */
for (s = value; *s && !isspace(*s); s++) ;
while (isspace(*s)) s++;
if (!*s) {
objects[i].fg = nullstr;
objects[i].bg = nullstr;
return;
}
for (t = s; *t && !isspace(*t); t++) ;
if (*t) {
*(n = t++) = '\0';
while (isspace(*t)) t++;
}
/* We have both colors and attributes, so turn colors on. */
use_colors = TRUE;
/* Parse the foreground color. */
if (*s == '-')
objects[i].fg = NULL;
else {
sprintf(buf, "fg %s", s);
objects[i].fg = tc_color_capability(buf);
if (objects[i].fg == NULL) {
fprintf(stderr,"trn: no color '%s' for %s in [attribute] section.\n",
buf, object);
finalize(1);
}
}
if (n) {
*n = ' ';
n = NULL;
}
/* Make sure we have one more parameter. */
for (s = t; *t && !isspace(*t); t++) ;
if (*t) {
*(n = t++) = '\0';
while (isspace(*t)) t++;
}
if (!*s || *t) {
fprintf(stderr,"trn: wrong number of parameters for %s in [attribute] section.\n",
object);
finalize(1);
}
/* Parse the background color. */
if (*s == '-')
objects[i].bg = NULL;
else {
sprintf(buf, "bg %s", s);
objects[i].bg = tc_color_capability(buf);
if (objects[i].bg == NULL) {
fprintf(stderr,"trn: no color '%s' for %s in [attribute] section.\n",
buf, object);
finalize(1);
}
}
if (n)
*n = ' ';
}
/* Turn on color attribute for an object. */
void
color_object(object, push)
int object;
bool_int push;
{
COLOR_OBJ merged;
/* Merge in the colors/attributes that we are not setting
* from the current object. */
merged = color_stack[stack_pointer].object;
/* Merge in the new colors/attributes. */
if (objects[object].fg)
merged.fg = objects[object].fg;
if (objects[object].bg)
merged.bg = objects[object].bg;
if (objects[object].attr != LASTMARKING)
merged.attr = objects[object].attr;
/* Push onto stack. */
if (push && ++stack_pointer >= STACK_SIZE) {
/* error reporting? $$ */
stack_pointer = 0; /* empty stack */
color_default(); /* and set normal colors */
return;
}
color_stack[stack_pointer].object = merged;
/* Set colors/attributes. */
output_color();
}
/* Pop the color/attribute stack. */
void
color_pop()
{
/* Trying to pop an empty stack? */
if (--stack_pointer < 0)
stack_pointer = 0;
else
output_color();
}
/* Color a string with the given object's color/attribute. */
void
color_string(object, str)
int object;
char* str;
{
int len = strlen(str);
if (str[len-1] == '\n') {
strcpy(msg, str);
msg[len-1] = '\0';
str = msg;
len = 0;
}
if (!use_colors && *tc_UC && objects[object].attr == UNDERLINE)
underprint(str); /* hack for stupid terminals */
else {
color_object(object, 1);
fputs(str, stdout);
color_pop();
}
if (!len)
putchar('\n');
}
/* Turn off color attribute. */
void
color_default()
{
color_stack[stack_pointer].object = objects[COLOR_DEFAULT];
output_color();
}
/* Set colors/attribute for an object. */
static void
output_color()
{
static COLOR_OBJ prior = { nullstr, NULL, NULL, NOMARKING };
COLOR_OBJ* op = &color_stack[stack_pointer].object;
/* If no change, just return. */
if (op->attr == prior.attr && op->fg == prior.fg && op->bg == prior.bg)
return;
/* Start by turning off any existing colors and/or attributes. */
if (use_colors) {
if (objects[COLOR_DEFAULT].fg != prior.fg
|| objects[COLOR_DEFAULT].bg != prior.bg) {
fputs(prior.fg = objects[COLOR_DEFAULT].fg, stdout);
fputs(prior.bg = objects[COLOR_DEFAULT].bg, stdout);
}
}
switch (prior.attr) {
case NOMARKING:
break;
case STANDOUT:
un_standout();
break;
case UNDERLINE:
un_underline();
break;
}
/* For color terminals we set the foreground and background color. */
if (use_colors) {
if (op->fg != prior.fg)
fputs(prior.fg = op->fg, stdout);
if (op->bg != prior.bg)
fputs(prior.bg = op->bg, stdout);
}
/* For both monochrome and color terminals we set the video attribute. */
switch (prior.attr = op->attr) {
case NOMARKING:
break;
case STANDOUT:
#ifdef NOFIREWORKS
no_sofire();
#endif
standout();
break;
case UNDERLINE:
#ifdef NOFIREWORKS
no_ulfire();
#endif
underline();
break;
}
}