* New version 2.26
[alpine.git] / pith / color.c
blobb110d7c7ca12e8d6ded462a7b01c045f932a035e
1 /*
2 * ========================================================================
3 * Copyright 2013-2022 Eduardo Chappa
4 * Copyright 2006-2007 University of Washington
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
15 #include "../pith/headers.h"
16 #include "../pith/color.h"
17 #include "../pith/state.h"
18 #include "../pith/conf.h"
19 #include "../pith/filter.h"
22 char *
23 color_embed(char *fg, char *bg)
25 static char buf[(2 * RGBLEN) + 5], *p;
27 p = buf;
28 if(fg){
29 if(sizeof(buf)-(p-buf) > 1){
30 *p++ = TAG_EMBED;
31 *p++ = TAG_FGCOLOR;
34 sstrncpy(&p, color_to_asciirgb(fg), sizeof(buf)-(p-buf));
37 if(bg){
38 if(sizeof(buf)-(p-buf) > 1){
39 *p++ = TAG_EMBED;
40 *p++ = TAG_BGCOLOR;
43 sstrncpy(&p, color_to_asciirgb(bg), sizeof(buf)-(p-buf));
46 buf[sizeof(buf)-1] = '\0';
48 return(buf);
52 int
53 colorcmp(char *color1, char *color2)
55 if(color1 && color2)
56 return(strcmp(color_to_asciirgb(color1), color_to_asciirgb(color2)));
58 /* if both NULL they're the same? */
59 return(!(color1 || color2));
64 struct quote_colors {
65 COLOR_PAIR *color;
66 struct quote_colors *next;
70 int
71 color_a_quote(long int linenum, char *line, LT_INS_S **ins, void *is_flowed_msg)
73 int countem = 0;
74 struct variable *vars = ps_global->vars;
75 char *p;
76 struct quote_colors *colors = NULL, *cp, *next;
77 COLOR_PAIR *col = NULL;
78 int is_flowed = is_flowed_msg ? *((int *)is_flowed_msg) : 0;
80 p = line;
81 if(!is_flowed)
82 while(isspace((unsigned char)*p))
83 p++;
85 if(p[0] == '>'){
86 struct quote_colors *c;
89 * We have a fixed number of quote level colors (3). If there are
90 * more levels of quoting than are defined, they repeat.
92 if(VAR_QUOTE1_FORE_COLOR && VAR_QUOTE1_BACK_COLOR &&
93 (col = new_color_pair(VAR_QUOTE1_FORE_COLOR,
94 VAR_QUOTE1_BACK_COLOR)) &&
95 pico_is_good_colorpair(col)){
96 c = (struct quote_colors *)fs_get(sizeof(*c));
97 memset(c, 0, sizeof(*c));
98 c->color = col;
99 col = NULL;
100 colors = c;
101 cp = c;
102 countem++;
103 if(VAR_QUOTE2_FORE_COLOR && VAR_QUOTE2_BACK_COLOR &&
104 (col = new_color_pair(VAR_QUOTE2_FORE_COLOR,
105 VAR_QUOTE2_BACK_COLOR)) &&
106 pico_is_good_colorpair(col)){
107 c = (struct quote_colors *)fs_get(sizeof(*c));
108 memset(c, 0, sizeof(*c));
109 c->color = col;
110 col = NULL;
111 cp->next = c;
112 cp = c;
113 countem++;
114 if(VAR_QUOTE3_FORE_COLOR && VAR_QUOTE3_BACK_COLOR &&
115 (col = new_color_pair(VAR_QUOTE3_FORE_COLOR,
116 VAR_QUOTE3_BACK_COLOR)) &&
117 pico_is_good_colorpair(col)){
118 c = (struct quote_colors *)fs_get(sizeof(*cp));
119 memset(c, 0, sizeof(*c));
120 c->color = col;
121 col = NULL;
122 cp->next = c;
123 cp = c;
124 countem++;
130 if(col)
131 free_color_pair(&col);
133 cp = NULL;
134 while(*p == '>'){
135 cp = (cp && cp->next) ? cp->next : colors;
137 if(countem > 0)
138 ins = gf_line_test_new_ins(ins, p,
139 color_embed(cp->color->fg, cp->color->bg),
140 (2 * RGBLEN) + 4);
142 countem = (countem == 1) ? 0 : countem;
144 p++;
145 if(!is_flowed)
146 for(; isspace((unsigned char)*p); p++)
150 if(colors){
151 char fg[RGBLEN + 1], bg[RGBLEN + 1], rgbbuf[RGBLEN + 1];
153 strncpy(fg, color_to_asciirgb(VAR_NORM_FORE_COLOR), sizeof(fg));
154 strncpy(bg, color_to_asciirgb(VAR_NORM_BACK_COLOR), sizeof(bg));
155 fg[sizeof(fg)-1] = '\0';
156 bg[sizeof(bg)-1] = '\0';
159 * Loop watching colors, and override with most recent
160 * quote color whenever the normal foreground and background
161 * colors are in force.
163 while(*p)
164 if(*p++ == TAG_EMBED){
166 switch(*p++){
167 case TAG_HANDLE :
168 p += *p + 1; /* skip handle key */
169 break;
171 case TAG_FGCOLOR :
172 snprintf(rgbbuf, sizeof(rgbbuf), "%s", p);
173 p += RGBLEN; /* advance past color value */
175 if(!colorcmp(rgbbuf, VAR_NORM_FORE_COLOR)
176 && !colorcmp(bg, VAR_NORM_BACK_COLOR))
177 ins = gf_line_test_new_ins(ins, p,
178 color_embed(cp->color->fg,NULL),
179 RGBLEN + 2);
180 break;
182 case TAG_BGCOLOR :
183 snprintf(rgbbuf, sizeof(rgbbuf), "%s", p);
184 p += RGBLEN; /* advance past color value */
186 if(!colorcmp(rgbbuf, VAR_NORM_BACK_COLOR)
187 && !colorcmp(fg, VAR_NORM_FORE_COLOR))
188 ins = gf_line_test_new_ins(ins, p,
189 color_embed(NULL,cp->color->bg),
190 RGBLEN + 2);
192 break;
194 default :
195 break;
199 ins = gf_line_test_new_ins(ins, line + strlen(line),
200 color_embed(VAR_NORM_FORE_COLOR,
201 VAR_NORM_BACK_COLOR),
202 (2 * RGBLEN) + 4);
203 for(cp = colors; cp && cp->color; cp = next){
204 free_color_pair(&cp->color);
205 next = cp->next;
206 fs_give((void **)&cp);
210 return(0);
214 void
215 free_spec_colors(SPEC_COLOR_S **colors)
217 if(colors && *colors){
218 free_spec_colors(&(*colors)->next);
219 if((*colors)->spec)
220 fs_give((void **)&(*colors)->spec);
221 if((*colors)->fg)
222 fs_give((void **)&(*colors)->fg);
223 if((*colors)->bg)
224 fs_give((void **)&(*colors)->bg);
225 if((*colors)->val)
226 free_pattern(&(*colors)->val);
228 fs_give((void **)colors);