NeoMutt  2025-12-11-911-gd8d604
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
node_condition.c
Go to the documentation of this file.
1
23
29
30#include "config.h"
31#include <stdbool.h>
32#include <stdio.h>
33#include <string.h>
34#include "mutt/lib.h"
35#include "node_condition.h"
36#include "definition.h"
37#include "format.h"
38#include "helpers.h"
39#include "node.h"
40#include "node_condbool.h"
41#include "node_container.h"
42#include "node_expando.h"
43#include "node_text.h"
44#include "parse.h"
45#include "render.h"
46
50static int node_condition_render(const struct ExpandoNode *node,
51 const struct ExpandoRenderCallback *erc,
52 struct Buffer *buf, int max_cols, void *data,
53 MuttFormatFlags flags)
54{
55 ASSERT(node->type == ENT_CONDITION);
56
57 const struct ExpandoNode *node_cond = node_get_child(node, ENC_CONDITION);
58
59 // Discard any text returned, just use the return value as a bool
60 struct Buffer *buf_cond = buf_pool_get();
61 int rc_cond = node_cond->render(node_cond, erc, buf_cond, max_cols, data, flags);
62
63 int rc = 0;
64 buf_reset(buf_cond);
65
66 if (rc_cond == true)
67 {
68 const struct ExpandoNode *node_true = node_get_child(node, ENC_TRUE);
69 rc = node_render(node_true, erc, buf_cond, max_cols, data, flags);
70 }
71 else
72 {
73 const struct ExpandoNode *node_false = node_get_child(node, ENC_FALSE);
74 rc = node_render(node_false, erc, buf_cond, max_cols, data, flags);
75 }
76
77 const struct ExpandoFormat *fmt = node->format;
78 if (!fmt)
79 {
80 buf_addstr(buf, buf_string(buf_cond));
81 buf_pool_release(&buf_cond);
82 return rc;
83 }
84
85 struct Buffer *tmp = buf_pool_get();
86
87 int min_cols = MAX(fmt->min_cols, fmt->max_cols);
88 min_cols = MIN(min_cols, max_cols);
89 if (fmt->max_cols >= 0)
90 max_cols = MIN(max_cols, fmt->max_cols);
91 rc = format_string(tmp, min_cols, max_cols, fmt->justification, ' ',
92 buf_string(buf_cond), buf_len(buf_cond), true);
93 if (fmt->lower)
95
96 buf_addstr(buf, buf_string(tmp));
97 buf_pool_release(&tmp);
98 buf_pool_release(&buf_cond);
99
100 return rc;
101}
102
112 struct ExpandoNode *node_true,
113 struct ExpandoNode *node_false,
114 struct ExpandoFormat *fmt)
115{
116 ASSERT(node_cond);
117
118 struct ExpandoNode *node = node_new();
119
120 node->type = ENT_CONDITION;
122
123 ARRAY_SET(&node->children, ENC_CONDITION, node_cond);
124 ARRAY_SET(&node->children, ENC_TRUE, node_true);
125 ARRAY_SET(&node->children, ENC_FALSE, node_false);
126
127 node->format = fmt;
128
129 return node;
130}
131
141struct ExpandoNode *node_condition_parse(const char *str, NodeTextTermFlags term_chars,
142 const struct ExpandoDefinition *defs,
143 const char **parsed_until,
144 struct ExpandoParseError *err)
145{
146 if (!str || (str[0] != '%'))
147 return NULL;
148
149 str++; // Skip %
150
151 struct ExpandoFormat *fmt = NULL;
152 struct ExpandoNode *node_cond = NULL;
153 struct ExpandoNode *node_true = NULL;
154 struct ExpandoNode *node_false = NULL;
155
156 //----------------------------------------------------------------------------
157 // Parse the format (optional)
158 fmt = parse_format(str, parsed_until, err);
159 if (err->position)
160 goto fail;
161
162 str = *parsed_until;
163
164 if ((str[0] != '<') && (str[0] != '?'))
165 goto fail;
166
167 const bool old_style = (str[0] == '?'); // %?X?...&...?
168 str++;
169
170 //----------------------------------------------------------------------------
171 // Parse the condition
172 // Try long name first if it looks like %<{NAME}?...>
173 if (str[0] == '{')
174 {
175 node_cond = parse_long_name(str + 1, defs, EP_CONDITIONAL, NULL, parsed_until, err);
176 if (node_cond)
177 {
178 if ((*parsed_until)[0] != '}')
179 {
180 err->position = *parsed_until;
181 snprintf(err->message, sizeof(err->message), _("Expando is missing closing '}'"));
182 goto fail;
183 }
184 (*parsed_until)++; // Skip the '}'
185 }
186 else if (err->position)
187 {
188 goto fail;
189 }
190 else
191 {
192 // Report an error if the content looks like a long name
193 const char *name_start = str + 1;
194 const char *end = name_start + strspn(name_start, "abcdefghijklmnopqrstuvwxyz0123456789-");
195 if (end != name_start)
196 {
197 err->position = name_start;
198 if (*end != '}')
199 snprintf(err->message, sizeof(err->message), _("Expando is missing closing '}'"));
200 else
201 // L10N: e.g. "Unknown expando: %{bad}"
202 snprintf(err->message, sizeof(err->message), _("Unknown expando: %%{%.*s}"),
203 (int) (end - name_start), name_start);
204 goto fail;
205 }
206 // Doesn't look like a long name, fall through to parse_short_name
207 }
208 }
209
210 if (!node_cond)
211 {
212 node_cond = parse_short_name(str, defs, EP_CONDITIONAL, NULL, parsed_until, err);
213 if (!node_cond)
214 goto fail;
215 }
216
217 if (node_cond->type == ENT_EXPANDO)
218 {
219 node_cond->type = ENT_CONDBOOL;
220 node_cond->render = node_condbool_render;
221 }
222
223 str = *parsed_until; // Skip the expando
224 if (str[0] != '?')
225 {
226 err->position = str;
227 snprintf(err->message, sizeof(err->message),
228 // L10N: Expando is missing a terminator character
229 // e.g. "%[..." is missing the final ']'
230 _("Conditional expando is missing '%c'"), '?');
231 goto fail;
232 }
233 str++; // Skip the '?'
234
235 //----------------------------------------------------------------------------
236 // Parse the 'true' clause (optional)
237 const NodeTextTermFlags term_true = term_chars | NTE_AMPERSAND |
238 (old_style ? NTE_QUESTION : NTE_GREATER);
239
240 node_true = node_container_new();
241 node_parse_many(node_true, str, term_true, defs, parsed_until, err);
242 if (err->position)
243 goto fail;
244
245 str = *parsed_until;
246
247 //----------------------------------------------------------------------------
248 // Parse the 'false' clause (optional)
249
250 node_false = NULL;
251 if (str[0] == '&')
252 {
253 str++;
254 const NodeTextTermFlags term_false = term_chars | (old_style ? NTE_QUESTION : NTE_GREATER);
255
256 node_false = node_container_new();
257 node_parse_many(node_false, str, term_false, defs, parsed_until, err);
258 if (err->position)
259 goto fail;
260
261 str = *parsed_until;
262 }
263
264 //----------------------------------------------------------------------------
265 // Check for the terminator character
266 const char terminator = old_style ? '?' : '>';
267
268 if (str[0] != terminator)
269 {
270 err->position = str;
271 snprintf(err->message, sizeof(err->message),
272 // L10N: Expando is missing a terminator character
273 // e.g. "%[..." is missing the final ']'
274 _("Conditional expando is missing '%c'"), '?');
275 goto fail;
276 }
277
278 *parsed_until = str + 1;
279
280 return node_condition_new(node_cond, node_true, node_false, fmt);
281
282fail:
283 FREE(&fmt);
284 node_free(&node_cond);
285 node_free(&node_true);
286 node_free(&node_false);
287 return NULL;
288}
#define ARRAY_SET(head, idx, elem)
Set an element in the array.
Definition array.h:123
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition buffer.c:491
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:76
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:226
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
Define an Expando format string.
@ EP_CONDITIONAL
Expando is being used as a condition.
Definition definition.h:39
void buf_lower_special(struct Buffer *buf)
Convert to lowercase, excluding special characters.
Definition helpers.c:92
Shared code.
bool node_parse_many(struct ExpandoNode *node_cont, const char *str, NodeTextTermFlags term_chars, const struct ExpandoDefinition *defs, const char **parsed_until, struct ExpandoParseError *err)
Parse a format string.
Definition parse.c:83
Expando Parsing.
int format_string(struct Buffer *buf, int min_cols, int max_cols, enum FormatJustify justify, char pad_char, const char *str, size_t n, bool arboreal)
Format a string, like snprintf()
Definition format.c:108
Simple string formatting.
static int node_condition_render(const struct ExpandoNode *node, const struct ExpandoRenderCallback *erc, struct Buffer *buf, int max_cols, void *data, MuttFormatFlags flags)
Render a Conditional Node - Implements ExpandoNode::render() -.
int node_condbool_render(const struct ExpandoNode *node, const struct ExpandoRenderCallback *erc, struct Buffer *buf, int max_cols, void *data, MuttFormatFlags flags)
Callback for every bool node - Implements ExpandoNode::render() -.
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#define MIN(a, b)
Return the minimum of two values.
Definition memory.h:40
#define MAX(a, b)
Return the maximum of two values.
Definition memory.h:38
Convenience wrapper for the library headers.
#define _(a)
Definition message.h:28
struct ExpandoNode * node_new(void)
Create a new empty ExpandoNode.
Definition node.c:39
struct ExpandoNode * node_get_child(const struct ExpandoNode *node, int index)
Get a child of an ExpandoNode.
Definition node.c:91
void node_free(struct ExpandoNode **ptr)
Free an ExpandoNode and its private data.
Definition node.c:48
Basic Expando Node.
@ ENT_EXPANDO
Expando, e.g. 'n'.
Definition node.h:39
@ ENT_CONDITION
True/False condition.
Definition node.h:41
@ ENT_CONDBOOL
True/False boolean condition.
Definition node.h:42
Expando Node for a Conditional Boolean.
struct ExpandoNode * node_condition_new(struct ExpandoNode *node_cond, struct ExpandoNode *node_true, struct ExpandoNode *node_false, struct ExpandoFormat *fmt)
Create a new Condition Expando Node.
struct ExpandoNode * node_condition_parse(const char *str, NodeTextTermFlags term_chars, const struct ExpandoDefinition *defs, const char **parsed_until, struct ExpandoParseError *err)
Parse a conditional Expando.
Expando Node for a Condition.
@ ENC_CONDITION
Index of Condition Node.
@ ENC_FALSE
Index of False Node.
@ ENC_TRUE
Index of True Node.
struct ExpandoNode * node_container_new(void)
Create a new Container ExpandoNode.
Expando Node for a Container.
struct ExpandoNode * parse_long_name(const char *str, const struct ExpandoDefinition *defs, ExpandoParserFlags flags, struct ExpandoFormat *fmt, const char **parsed_until, struct ExpandoParseError *err)
Create an expando by its long name.
struct ExpandoNode * parse_short_name(const char *str, const struct ExpandoDefinition *defs, ExpandoParserFlags flags, struct ExpandoFormat *fmt, const char **parsed_until, struct ExpandoParseError *err)
Create an expando by its short name.
struct ExpandoFormat * parse_format(const char *str, const char **parsed_until, struct ExpandoParseError *err)
Parse a format string.
Expando Node for an Expando.
Expando Node for Text.
uint8_t NodeTextTermFlags
Definition node_text.h:39
@ NTE_AMPERSAND
'&' Ampersand
Definition node_text.h:35
@ NTE_GREATER
'>' Greater than
Definition node_text.h:36
@ NTE_QUESTION
'?' Question mark
Definition node_text.h:37
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
int node_render(const struct ExpandoNode *node, const struct ExpandoRenderCallback *erc, struct Buffer *buf, int max_cols, void *data, MuttFormatFlags flags)
Render a tree of ExpandoNodes into a string.
Definition render.c:45
Render Expandos using Data.
uint8_t MuttFormatFlags
Definition render.h:45
#define ASSERT(COND)
Definition signal2.h:59
String manipulation buffer.
Definition buffer.h:36
char * data
Pointer to data.
Definition buffer.h:37
Definition of a format string.
Definition definition.h:49
Formatting information for an Expando.
Definition node.h:53
enum FormatJustify justification
Justification: left, centre, right.
Definition node.h:56
int min_cols
Minimum number of screen columns.
Definition node.h:54
int max_cols
Maximum number of screen columns.
Definition node.h:55
bool lower
Display in lower case.
Definition node.h:58
Basic Expando Node.
Definition node.h:67
struct ExpandoFormat * format
Formatting info.
Definition node.h:72
int(* render)(const struct ExpandoNode *node, const struct ExpandoRenderCallback *erc, struct Buffer *buf, int max_cols, void *data, MuttFormatFlags flags)
Definition node.h:92
enum ExpandoNodeType type
Type of Node, e.g. ENT_EXPANDO.
Definition node.h:68
struct ExpandoNodeArray children
Children nodes.
Definition node.h:75
Buffer for parsing errors.
Definition parse.h:37
char message[1024]
Error message.
Definition parse.h:38
const char * position
Position of error in original string.
Definition parse.h:39