23
23
static bool cmd_if_generate
24
24
(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd);
26
const struct sieve_command_def cmd_if = {
26
const struct sieve_command_def cmd_if = {
62
62
(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd);
64
64
const struct sieve_command_def cmd_else = {
75
75
* Context management
78
78
struct cmd_if_context_data {
79
79
struct cmd_if_context_data *previous;
80
80
struct cmd_if_context_data *next;
82
82
bool jump_generated;
83
83
sieve_size_t exit_jump;
86
86
static void cmd_if_initialize_context_data
87
(struct sieve_command *cmd, struct cmd_if_context_data *previous)
87
(struct sieve_command *cmd, struct cmd_if_context_data *previous)
89
89
struct cmd_if_context_data *cmd_data;
91
91
/* Assign context */
96
96
/* Update linked list of contexts */
97
97
cmd_data->previous = previous;
98
cmd_data->next = NULL;
98
cmd_data->next = NULL;
99
99
if ( previous != NULL )
100
100
previous->next = cmd_data;
102
102
/* Assign to command context */
103
103
cmd->data = cmd_data;
110
110
static bool cmd_if_validate
111
(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_command *cmd)
111
(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_command *cmd)
113
113
/* Start if-command structure */
114
114
cmd_if_initialize_context_data(cmd, NULL);
124
124
/* Check valid command placement */
125
125
if ( prev == NULL ||
126
( !sieve_command_is(prev, cmd_if) && !sieve_command_is(prev, cmd_elsif) ) )
128
sieve_command_validate_error(valdtr, cmd,
129
"the %s command must follow an if or elseif command",
126
( !sieve_command_is(prev, cmd_if) && !sieve_command_is(prev, cmd_elsif) ) )
128
sieve_command_validate_error(valdtr, cmd,
129
"the %s command must follow an if or elseif command",
130
130
sieve_command_identifier(cmd));
134
/* Previous command in this block is 'if' or 'elsif', so we can safely refer
135
* to its context data
134
/* Previous command in this block is 'if' or 'elsif', so we can safely refer
135
* to its context data
137
137
cmd_if_initialize_context_data(cmd, prev->data);
146
146
/* The if command does not generate specific IF-ELSIF-ELSE opcodes, but only uses
147
* JMP instructions. This is why the implementation of the if command does not
147
* JMP instructions. This is why the implementation of the if command does not
148
148
* include an opcode implementation.
151
151
static void cmd_if_resolve_exit_jumps
152
(struct sieve_binary *sbin, struct cmd_if_context_data *cmd_data)
152
(struct sieve_binary *sbin, struct cmd_if_context_data *cmd_data)
154
154
struct cmd_if_context_data *if_ctx = cmd_data->previous;
156
/* Iterate backwards through all if-command contexts and resolve the
156
/* Iterate backwards through all if-command contexts and resolve the
157
157
* exit jumps to the current code position.
159
159
while ( if_ctx != NULL ) {
160
if ( if_ctx->jump_generated )
160
if ( if_ctx->jump_generated )
161
161
sieve_binary_resolve_offset(sbin, if_ctx->exit_jump);
162
if_ctx = if_ctx->previous;
162
if_ctx = if_ctx->previous;
167
167
(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
169
169
struct sieve_binary *sbin = cgenv->sbin;
170
struct cmd_if_context_data *cmd_data =
170
struct cmd_if_context_data *cmd_data =
171
171
(struct cmd_if_context_data *) cmd->data;
172
172
struct sieve_ast_node *test;
173
173
struct sieve_jumplist jmplist;
175
175
/* Prepare jumplist */
176
176
sieve_jumplist_init_temp(&jmplist, sbin);
178
178
/* Generate test condition */
179
179
test = sieve_ast_test_first(cmd->ast_node);
180
180
if ( !sieve_generate_test(cgenv, test, &jmplist, FALSE) )
183
183
/* Case true { */
184
if ( !sieve_generate_block(cgenv, cmd->ast_node) )
184
if ( !sieve_generate_block(cgenv, cmd->ast_node) )
187
187
/* Are we the final command in this if-elsif-else structure? */
188
188
if ( cmd_data->next != NULL ) {
189
/* No, generate jump to end of if-elsif-else structure (resolved later)
190
* This of course is not necessary if the {} block contains a command
189
/* No, generate jump to end of if-elsif-else structure (resolved later)
190
* This of course is not necessary if the {} block contains a command
191
191
* like stop at top level that unconditionally exits the block already
194
194
if ( !sieve_command_block_exits_unconditionally(cmd) ) {
195
195
sieve_operation_emit(sbin, NULL, &sieve_jmp_operation);
200
200
/* Yes, Resolve previous exit jumps to this point */
201
201
cmd_if_resolve_exit_jumps(sbin, cmd_data);
204
204
/* Case false ... (subsequent elsif/else commands might generate more) */
205
sieve_jumplist_resolve(&jmplist);
205
sieve_jumplist_resolve(&jmplist);
213
213
struct cmd_if_context_data *cmd_data =
214
214
(struct cmd_if_context_data *) cmd->data;
217
if ( !sieve_generate_block(cgenv, cmd->ast_node) )
217
if ( !sieve_generate_block(cgenv, cmd->ast_node) )
220
/* } End: resolve all exit blocks */
220
/* } End: resolve all exit blocks */
221
221
cmd_if_resolve_exit_jumps(cgenv->sbin, cmd_data);