NeoMutt  2025-09-05-55-g97fc89
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
parse_ansi.h File Reference

Parse ANSI Sequences. More...

#include <stdbool.h>
+ Include dependency graph for parse_ansi.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

int ansi_color_parse_single (const char *buf, struct AnsiColor *ansi, bool dry_run)
 Parse a single ANSI escape sequence.
 
int ansi_color_seq_length (const char *str)
 Is this an ANSI escape sequence?
 

Detailed Description

Parse ANSI Sequences.

Authors
  • Richard Russon

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file parse_ansi.h.

Function Documentation

◆ ansi_color_parse_single()

int ansi_color_parse_single ( const char * buf,
struct AnsiColor * ansi,
bool dry_run )

Parse a single ANSI escape sequence.

Parameters
bufString to parse
ansiAnsiColor for the result
dry_runDon't parse anything, just skip over
Return values
numLength of the escape sequence

Parse an ANSI escape sequence into ansi. Calling this function repeatedly, will accumulate sequences in ansi.

Definition at line 107 of file parse_ansi.c.

108{
109 int seq_len = ansi_color_seq_length(buf);
110 if (seq_len == 0)
111 return 0;
112
113 if (dry_run || !ansi)
114 return seq_len;
115
116 int pos = 2; // Skip '<esc>['
117
118 while (pos < seq_len)
119 {
120 if ((buf[pos] == '0') && mutt_isdigit(buf[pos + 1]))
121 {
122 pos++; // Skip the leading zero
123 }
124 else if ((buf[pos] == '0') && ansi_is_end_char(buf[pos + 1]))
125 {
126 ansi_color_reset(ansi);
127 pos += 2;
128 }
129 else if ((buf[pos] == '1') && ansi_is_end_char(buf[pos + 1]))
130 {
131 ansi->attrs |= A_BOLD;
132 pos += 2;
133 }
134 else if ((buf[pos] == '2') && mutt_isdigit(buf[pos + 1]) &&
135 ansi_is_end_char(buf[pos + 2]))
136 {
137 char digit = buf[pos + 1];
138 pos += 3;
139 if (digit == '2')
140 {
141 ansi->attrs &= ~A_BOLD; // Clear the flag
142 }
143 else if (digit == '3')
144 {
145 ansi->attrs &= ~A_ITALIC; // Clear the flag
146 }
147 else if (digit == '4')
148 {
149 ansi->attrs &= ~A_UNDERLINE; // Clear the flag
150 }
151 else if (digit == '5')
152 {
153 ansi->attrs &= ~A_BLINK; // Clear the flag
154 }
155 else if (digit == '7')
156 {
157 ansi->attrs &= ~A_REVERSE; // Clear the flag
158 }
159 }
160 else if ((buf[pos] == '3') && ansi_is_end_char(buf[pos + 1]))
161 {
162 ansi->attrs |= A_ITALIC;
163 pos += 2;
164 }
165 else if (buf[pos] == '3')
166 {
167 struct ColorElement *elem = &ansi->fg;
168
169 // 30-37 basic foreground
170 if ((buf[pos + 1] >= '0') && (buf[pos + 1] < '8') && ansi_is_end_char(buf[pos + 2]))
171 {
172 elem->color = buf[pos + 1] - '0';
173 elem->type = CT_SIMPLE;
174 pos += 3;
175 }
176 else if (buf[pos + 1] == '8')
177 {
178 if (mutt_str_startswith(buf + pos, "38;5;") && mutt_isdigit(buf[pos + 5]))
179 {
180 // 38;5;n palette foreground
181 char *end = NULL;
182 unsigned long value = strtoul(buf + pos + 5, &end, 10);
183 if ((value < 256) && end && ansi_is_end_char(end[0]))
184 {
185 elem->color = value;
186 elem->type = CT_PALETTE;
187 pos += end - &buf[pos];
188 }
189 else
190 {
191 return 0;
192 }
193 }
194 else if (mutt_str_startswith(buf + pos, "38;2;") && mutt_isdigit(buf[pos + 5]))
195 {
196 // 38;2;R;G;B true colour foreground
197 long r = -1;
198 long g = -1;
199 long b = -1;
200 char *end = NULL;
201 unsigned long value = 0;
202 pos += 5; // Skip 38;2;
203
204 value = strtoul(buf + pos, &end, 10);
205 if ((value > 255) || !end || (end[0] != ';'))
206 {
207 return 0;
208 }
209 r = value;
210 pos += end - &buf[pos] + 1;
211
212 value = strtoul(buf + pos, &end, 10);
213 if ((value > 255) || !end || (end[0] != ';'))
214 {
215 return 0;
216 }
217 g = value;
218 pos += end - &buf[pos] + 1;
219
220 value = strtoul(buf + pos, &end, 10);
221 if ((value > 255) || !end || (end[0] != 'm'))
222 {
223 return 0;
224 }
225 b = value;
226 pos += end - &buf[pos] + 1;
227
228 elem->color = (r << 16) + (g << 8) + (b << 0);
229 elem->type = CT_RGB;
230 }
231 else
232 {
233 return pos; // LCOV_EXCL_LINE
234 }
235 }
236 else if ((buf[pos + 1] == '9') && ansi_is_end_char(buf[pos + 2]))
237 {
238 // default foreground
239 elem->color = COLOR_DEFAULT;
240 elem->type = CT_SIMPLE;
241 pos += 2;
242 }
243 else
244 {
245 return 0; // LCOV_EXCL_LINE
246 }
247 }
248 else if ((buf[pos] == '4') && ansi_is_end_char(buf[pos + 1]))
249 {
250 ansi->attrs |= A_UNDERLINE;
251 pos += 2;
252 }
253 else if (buf[pos] == '4')
254 {
255 struct ColorElement *elem = &ansi->bg;
256
257 // 40-47 basic background
258 if ((buf[pos + 1] >= '0') && (buf[pos + 1] < '8') && ansi_is_end_char(buf[pos + 2]))
259 {
260 elem->color = buf[pos + 1] - '0';
261 elem->type = CT_SIMPLE;
262 pos += 3;
263 }
264 else if (buf[pos + 1] == '8')
265 {
266 if (mutt_str_startswith(buf + pos, "48;5;") && mutt_isdigit(buf[pos + 5]))
267 {
268 // 48;5;n palette background
269 char *end = NULL;
270 unsigned long value = strtoul(buf + pos + 5, &end, 10);
271 if ((value < 256) && end && ansi_is_end_char(end[0]))
272 {
273 elem->color = value;
274 elem->type = CT_PALETTE;
275 pos += end - &buf[pos];
276 }
277 else
278 {
279 return 0;
280 }
281 }
282 else if (mutt_str_startswith(buf + pos, "48;2;") && mutt_isdigit(buf[pos + 5]))
283 {
284 // 48;2;R;G;B true colour background
285 long r = -1;
286 long g = -1;
287 long b = -1;
288 char *end = NULL;
289 unsigned long value = 0;
290 pos += 5; // Skip 48;2;
291
292 value = strtoul(buf + pos, &end, 10);
293 if ((value > 255) || !end || (end[0] != ';'))
294 {
295 return 0;
296 }
297 r = value;
298 pos += end - &buf[pos] + 1;
299
300 value = strtoul(buf + pos, &end, 10);
301 if ((value > 255) || !end || (end[0] != ';'))
302 {
303 return 0;
304 }
305 g = value;
306 pos += end - &buf[pos] + 1;
307
308 value = strtoul(buf + pos, &end, 10);
309 if ((value > 255) || !end || (end[0] != 'm'))
310 {
311 return 0;
312 }
313 b = value;
314 pos += end - &buf[pos] + 1;
315
316 elem->color = (r << 16) + (g << 8) + (b << 0);
317 elem->type = CT_RGB;
318 }
319 else
320 {
321 return pos; // LCOV_EXCL_LINE
322 }
323 }
324 else if ((buf[pos + 1] == '9') && ansi_is_end_char(buf[pos + 2]))
325 {
326 // default background
327 elem->color = COLOR_DEFAULT;
328 elem->type = CT_SIMPLE;
329 pos += 2;
330 }
331 else
332 {
333 return 0; // LCOV_EXCL_LINE
334 }
335 }
336 else if ((buf[pos] == '5') && ansi_is_end_char(buf[pos + 1]))
337 {
338 ansi->attrs |= A_BLINK;
339 pos += 2;
340 }
341 else if ((buf[pos] == '7') && ansi_is_end_char(buf[pos + 1]))
342 {
343 ansi->attrs |= A_REVERSE;
344 pos += 2;
345 }
346 else if (buf[pos] == ';')
347 {
348 pos++; // LCOV_EXCL_LINE
349 }
350 else
351 {
352 while ((pos < seq_len) && (buf[pos] != ';'))
353 pos++;
354 }
355 }
356
357 return pos;
358}
@ CT_SIMPLE
Simple colour, e.g. "Red".
Definition attr.h:36
@ CT_PALETTE
Palette colour, e.g. "color207".
Definition attr.h:37
@ CT_RGB
True colour, e.g. "#11AAFF".
Definition attr.h:38
#define COLOR_DEFAULT
Definition color.h:103
int digit(const char *s)
bool mutt_isdigit(int arg)
Wrapper for isdigit(3)
Definition ctype.c:65
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition string.c:232
#define A_ITALIC
Definition mutt_curses.h:49
void ansi_color_reset(struct AnsiColor *ansi)
Reset an AnsiColor to uncoloured.
Definition parse_ansi.c:43
static bool ansi_is_end_char(char c)
Is this the end of a sequence?
Definition parse_ansi.c:63
int ansi_color_seq_length(const char *str)
Is this an ANSI escape sequence?
Definition parse_ansi.c:77
int attrs
Text attributes, e.g. A_BOLD.
Definition ansi.h:38
struct ColorElement bg
Background colour.
Definition ansi.h:37
struct ColorElement fg
Foreground colour.
Definition ansi.h:36
One element of a Colour.
Definition attr.h:56
enum ColorType type
Type of Colour.
Definition attr.h:58
color_t color
Colour.
Definition attr.h:57
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ ansi_color_seq_length()

int ansi_color_seq_length ( const char * str)

Is this an ANSI escape sequence?

Parameters
strString to test
Return values
0No, not an ANSI sequence
>0Length of the ANSI sequence

Match ANSI escape sequences of type 'm', e.g.

  • <esc>[1;32m

Definition at line 77 of file parse_ansi.c.

78{
79 if (!str || !*str)
80 return 0;
81
82 if ((str[0] != '\033') || (str[1] != '[')) // Escape
83 return 0;
84
85 int i = 2;
86 while ((str[i] != '\0') && (mutt_isdigit(str[i]) || (str[i] == ';')))
87 {
88 i++;
89 }
90
91 if (str[i] == 'm')
92 return i + 1;
93
94 return 0;
95}
+ Here is the call graph for this function:
+ Here is the caller graph for this function: