mirror of
https://gitlab.isc.org/isc-projects/dhcp
synced 2025-09-03 15:56:00 +00:00
Add support for function calls and typed variables.
This commit is contained in:
120
common/execute.c
120
common/execute.c
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#ifndef lint
|
#ifndef lint
|
||||||
static char copyright[] =
|
static char copyright[] =
|
||||||
"$Id: execute.c,v 1.28 2000/02/02 20:01:41 mellon Exp $ Copyright (c) 1998, 1999 The Internet Software Consortium. All rights reserved.\n";
|
"$Id: execute.c,v 1.29 2000/02/05 18:07:17 mellon Exp $ Copyright (c) 1998, 1999 The Internet Software Consortium. All rights reserved.\n";
|
||||||
#endif /* not lint */
|
#endif /* not lint */
|
||||||
|
|
||||||
#include "dhcpd.h"
|
#include "dhcpd.h"
|
||||||
@@ -132,51 +132,10 @@ int execute_statements (packet, lease, in_options, out_options, scope,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case eval_statement:
|
case eval_statement:
|
||||||
if (is_boolean_expression (r -> data.eval)) {
|
status = evaluate_expression
|
||||||
status = (evaluate_boolean_expression
|
((struct binding_value **)0,
|
||||||
(&result, packet, lease, in_options,
|
packet, lease, in_options,
|
||||||
out_options, scope,
|
out_options, scope, r -> data.eval);
|
||||||
r -> data.eval));
|
|
||||||
} else if (is_numeric_expression (r -> data.eval)) {
|
|
||||||
status = (evaluate_numeric_expression
|
|
||||||
(&num, packet, lease, in_options,
|
|
||||||
out_options, scope,
|
|
||||||
r -> data.eval));
|
|
||||||
} else if (is_data_expression (r -> data.eval)) {
|
|
||||||
memset (&ds, 0, sizeof ds);
|
|
||||||
status = (evaluate_data_expression
|
|
||||||
(&ds, packet, lease, in_options,
|
|
||||||
out_options, scope,
|
|
||||||
r -> data.eval));
|
|
||||||
if (status && ds.data)
|
|
||||||
data_string_forget (&ds, MDL);
|
|
||||||
} else if (is_dns_expression (r -> data.eval)) {
|
|
||||||
#if defined (NSUPDATE)
|
|
||||||
ns_updrec *nut;
|
|
||||||
nut = 0;
|
|
||||||
status = (evaluate_dns_expression
|
|
||||||
(&nut, packet, lease, in_options,
|
|
||||||
out_options, scope,
|
|
||||||
r -> data.eval));
|
|
||||||
if (status) {
|
|
||||||
if (nut -> r_data) {
|
|
||||||
dfree (nut -> r_data, MDL);
|
|
||||||
nut -> r_data =
|
|
||||||
(unsigned char *)0;
|
|
||||||
}
|
|
||||||
if (nut -> r_dname) {
|
|
||||||
dfree (nut -> r_dname, MDL);
|
|
||||||
nut -> r_dname = (char *)0;
|
|
||||||
}
|
|
||||||
minires_freeupdrec (nut);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
log_error ("%s: invalid expression type: %d",
|
|
||||||
"execute_statements",
|
|
||||||
r -> data.eval -> op);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined (DEBUG_EXPRESSIONS)
|
#if defined (DEBUG_EXPRESSIONS)
|
||||||
log_debug ("exec: evaluate: %s",
|
log_debug ("exec: evaluate: %s",
|
||||||
(status "succeeded" : "failed"));
|
(status "succeeded" : "failed"));
|
||||||
@@ -235,11 +194,6 @@ int execute_statements (packet, lease, in_options, out_options, scope,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case set_statement:
|
case set_statement:
|
||||||
memset (&ds, 0, sizeof ds);
|
|
||||||
status = (evaluate_data_expression
|
|
||||||
(&ds, packet, lease, in_options, out_options,
|
|
||||||
scope, r -> data.set.expr));
|
|
||||||
|
|
||||||
binding = find_binding (scope, r -> data.set.name);
|
binding = find_binding (scope, r -> data.set.name);
|
||||||
if (!binding && status) {
|
if (!binding && status) {
|
||||||
binding = dmalloc (sizeof *binding, MDL);
|
binding = dmalloc (sizeof *binding, MDL);
|
||||||
@@ -268,47 +222,39 @@ int execute_statements (packet, lease, in_options, out_options, scope,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (binding) {
|
if (binding) {
|
||||||
if (binding -> value.data)
|
if (binding -> value)
|
||||||
data_string_forget (&binding -> value,
|
binding_value_dereference
|
||||||
MDL);
|
(&binding -> value, MDL);
|
||||||
if (status)
|
status = (evaluate_expression
|
||||||
data_string_copy (&binding -> value, &ds,
|
(&binding -> value, packet, lease,
|
||||||
MDL);
|
in_options, out_options,
|
||||||
|
scope, r -> data.set.expr));
|
||||||
}
|
}
|
||||||
if (status)
|
|
||||||
data_string_forget (&ds, MDL);
|
|
||||||
#if defined (DEBUG_EXPRESSIONS)
|
#if defined (DEBUG_EXPRESSIONS)
|
||||||
log_debug ("exec: set %s = %s", r -> data.set.name,
|
log_debug ("exec: set %s%s", r -> data.set.name,
|
||||||
(status && binding
|
(binding && status ? "" : " (failed)"));
|
||||||
? print_hex_1 (binding -> value.len,
|
|
||||||
binding -> value.data, 50)
|
|
||||||
: "NULL"));
|
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case unset_statement:
|
case unset_statement:
|
||||||
binding = find_binding (scope, r -> data.unset);
|
binding = find_binding (scope, r -> data.unset);
|
||||||
if (binding) {
|
if (binding) {
|
||||||
if (binding -> value.data)
|
if (binding -> value)
|
||||||
data_string_forget (&binding -> value,
|
binding_value_dereference
|
||||||
MDL);
|
(&binding -> value, MDL);
|
||||||
status = 1;
|
status = 1;
|
||||||
} else
|
} else
|
||||||
status = 0;
|
status = 0;
|
||||||
#if defined (DEBUG_EXPRESSIONS)
|
#if defined (DEBUG_EXPRESSIONS)
|
||||||
log_debug ("exec: unset %s: %s", r -> data.unset,
|
log_debug ("exec: unset %s: %s", r -> data.unset,
|
||||||
(status ? "found" : "NULL"));
|
(status ? "found" : "not found"));
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case let_statement:
|
case let_statement:
|
||||||
memset (&ds, 0, sizeof ds);
|
|
||||||
status = (evaluate_data_expression
|
|
||||||
(&ds, packet, lease, in_options, out_options,
|
|
||||||
scope, r -> data.let.expr));
|
|
||||||
|
|
||||||
ns = (struct binding_scope *)0;
|
ns = (struct binding_scope *)0;
|
||||||
binding_scope_allocate (&ns, MDL);
|
binding_scope_allocate (&ns, MDL);
|
||||||
|
e = r;
|
||||||
|
|
||||||
next_let:
|
next_let:
|
||||||
if (ns) {
|
if (ns) {
|
||||||
@@ -319,11 +265,11 @@ int execute_statements (packet, lease, in_options, out_options, scope,
|
|||||||
} else {
|
} else {
|
||||||
binding -> name =
|
binding -> name =
|
||||||
dmalloc (strlen
|
dmalloc (strlen
|
||||||
(r -> data.let.name + 1),
|
(e -> data.let.name + 1),
|
||||||
MDL);
|
MDL);
|
||||||
if (binding -> name)
|
if (binding -> name)
|
||||||
strcpy (binding -> name,
|
strcpy (binding -> name,
|
||||||
r -> data.let.name);
|
e -> data.let.name);
|
||||||
else {
|
else {
|
||||||
dfree (binding, MDL);
|
dfree (binding, MDL);
|
||||||
binding = (struct binding *)0;
|
binding = (struct binding *)0;
|
||||||
@@ -331,31 +277,29 @@ int execute_statements (packet, lease, in_options, out_options, scope,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ns && binding && status) {
|
if (ns && binding) {
|
||||||
data_string_copy (&binding -> value, &ds, MDL);
|
status = (evaluate_expression
|
||||||
|
(&binding -> value, packet, lease,
|
||||||
|
in_options, out_options,
|
||||||
|
scope, e -> data.set.expr));
|
||||||
binding -> next = ns -> bindings;
|
binding -> next = ns -> bindings;
|
||||||
ns -> bindings = binding;
|
ns -> bindings = binding;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status)
|
|
||||||
data_string_forget (&ds, MDL);
|
|
||||||
#if defined (DEBUG_EXPRESSIONS)
|
#if defined (DEBUG_EXPRESSIONS)
|
||||||
log_debug ("exec: let %s = %s", r -> data.let.name,
|
log_debug ("exec: let %s%s", e -> data.let.name,
|
||||||
(status && binding
|
(binding && status ? "" : "failed"));
|
||||||
? print_hex_1 (binding -> value.len,
|
|
||||||
binding -> value.data, 50)
|
|
||||||
: "NULL"));
|
|
||||||
#endif
|
#endif
|
||||||
if (!r -> data.let.statements) {
|
if (!e -> data.let.statements) {
|
||||||
} else if (r -> data.let.statements -> op ==
|
} else if (e -> data.let.statements -> op ==
|
||||||
let_statement) {
|
let_statement) {
|
||||||
r = r -> data.let.statements;
|
e = e -> data.let.statements;
|
||||||
goto next_let;
|
goto next_let;
|
||||||
} else if (ns) {
|
} else if (ns) {
|
||||||
ns -> outer = scope;
|
ns -> outer = scope;
|
||||||
execute_statements
|
execute_statements
|
||||||
(packet, lease, in_options, out_options,
|
(packet, lease, in_options, out_options,
|
||||||
ns, r -> data.let.statements);
|
ns, e -> data.let.statements);
|
||||||
}
|
}
|
||||||
if (ns)
|
if (ns)
|
||||||
binding_scope_dereference (&ns, MDL);
|
binding_scope_dereference (&ns, MDL);
|
||||||
|
141
common/parse.c
141
common/parse.c
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#ifndef lint
|
#ifndef lint
|
||||||
static char copyright[] =
|
static char copyright[] =
|
||||||
"$Id: parse.c,v 1.62 2000/02/02 17:10:38 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n";
|
"$Id: parse.c,v 1.63 2000/02/05 18:04:47 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n";
|
||||||
#endif /* not lint */
|
#endif /* not lint */
|
||||||
|
|
||||||
#include "dhcpd.h"
|
#include "dhcpd.h"
|
||||||
@@ -1810,7 +1810,9 @@ int parse_boolean_expression (expr, cfile, lose)
|
|||||||
(struct expression **)0, expr_none))
|
(struct expression **)0, expr_none))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!is_boolean_expression (*expr)) {
|
if (!is_boolean_expression (*expr) &&
|
||||||
|
(*expr) -> op != expr_variable_reference &&
|
||||||
|
(*expr) -> op != expr_funcall) {
|
||||||
parse_warn (cfile, "Expecting a boolean expression.");
|
parse_warn (cfile, "Expecting a boolean expression.");
|
||||||
*lose = 1;
|
*lose = 1;
|
||||||
expression_dereference (expr, MDL);
|
expression_dereference (expr, MDL);
|
||||||
@@ -1845,7 +1847,9 @@ int parse_data_expression (expr, cfile, lose)
|
|||||||
(struct expression **)0, expr_none))
|
(struct expression **)0, expr_none))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!is_data_expression (*expr)) {
|
if (!is_data_expression (*expr) &&
|
||||||
|
(*expr) -> op != expr_variable_reference &&
|
||||||
|
(*expr) -> op != expr_funcall) {
|
||||||
parse_warn (cfile, "Expecting a data expression.");
|
parse_warn (cfile, "Expecting a data expression.");
|
||||||
*lose = 1;
|
*lose = 1;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1869,7 +1873,9 @@ int parse_numeric_expression (expr, cfile, lose)
|
|||||||
(struct expression **)0, expr_none))
|
(struct expression **)0, expr_none))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!is_numeric_expression (*expr)) {
|
if (!is_numeric_expression (*expr) &&
|
||||||
|
(*expr) -> op != expr_variable_reference &&
|
||||||
|
(*expr) -> op != expr_funcall) {
|
||||||
parse_warn (cfile, "Expecting a numeric expression.");
|
parse_warn (cfile, "Expecting a numeric expression.");
|
||||||
*lose = 1;
|
*lose = 1;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1901,7 +1907,9 @@ int parse_dns_expression (expr, cfile, lose)
|
|||||||
(struct expression **)0, expr_none))
|
(struct expression **)0, expr_none))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!is_dns_expression (*expr)) {
|
if (!is_dns_expression (*expr) &&
|
||||||
|
(*expr) -> op != expr_variable_reference &&
|
||||||
|
(*expr) -> op != expr_funcall) {
|
||||||
parse_warn (cfile, "Expecting a dns update subexpression.");
|
parse_warn (cfile, "Expecting a dns update subexpression.");
|
||||||
*lose = 1;
|
*lose = 1;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1921,12 +1929,14 @@ int parse_non_binary (expr, cfile, lose, context)
|
|||||||
const char *val;
|
const char *val;
|
||||||
struct collection *col;
|
struct collection *col;
|
||||||
struct option *option;
|
struct option *option;
|
||||||
struct expression *nexp;
|
struct expression *nexp, **ep;
|
||||||
int known;
|
int known;
|
||||||
enum expr_op opcode;
|
enum expr_op opcode;
|
||||||
const char *s;
|
const char *s;
|
||||||
|
char *cptr;
|
||||||
struct executable_statement *stmt;
|
struct executable_statement *stmt;
|
||||||
int i;
|
int i;
|
||||||
|
unsigned long u;
|
||||||
|
|
||||||
token = peek_token (&val, cfile);
|
token = peek_token (&val, cfile);
|
||||||
|
|
||||||
@@ -2274,41 +2284,48 @@ int parse_non_binary (expr, cfile, lose, context)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!strcasecmp (val, "a"))
|
if (!strcasecmp (val, "a"))
|
||||||
i = T_A;
|
u = T_A;
|
||||||
else if (!strcasecmp (val, "ptr"))
|
else if (!strcasecmp (val, "ptr"))
|
||||||
i = T_PTR;
|
u = T_PTR;
|
||||||
else if (!strcasecmp (val, "mx"))
|
else if (!strcasecmp (val, "mx"))
|
||||||
i = T_MX;
|
u = T_MX;
|
||||||
else if (!strcasecmp (val, "cname"))
|
else if (!strcasecmp (val, "cname"))
|
||||||
i = T_CNAME;
|
u = T_CNAME;
|
||||||
else if (!strcasecmp (val, "TXT"))
|
else if (!strcasecmp (val, "TXT"))
|
||||||
i = T_TXT;
|
u = T_TXT;
|
||||||
else {
|
else {
|
||||||
parse_warn (cfile, "unexpected rrtype: %s", val);
|
parse_warn (cfile, "unexpected rrtype: %s", val);
|
||||||
goto badnsupdate;
|
goto badnsupdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s = (opcode == expr_ns_add
|
||||||
|
? "old-dns-update"
|
||||||
|
: "old-dns-delete");
|
||||||
|
cptr = dmalloc (strlen (s) + 1, MDL);
|
||||||
|
if (!cptr)
|
||||||
|
log_fatal ("can't allocate name for %s", s);
|
||||||
|
strcpy (cptr, s);
|
||||||
if (!expression_allocate (expr, MDL))
|
if (!expression_allocate (expr, MDL))
|
||||||
log_fatal ("can't allocate expression");
|
log_fatal ("can't allocate expression");
|
||||||
#if 0
|
|
||||||
(*expr) -> op = expr_funcall;
|
(*expr) -> op = expr_funcall;
|
||||||
(*expr) -> data.funcall.context = context_boolean;
|
(*expr) -> data.funcall.name = cptr;
|
||||||
(*expr) -> data.funcall.name =
|
|
||||||
|
|
||||||
if (!make_let (&(*expr) -> data.funcall.statements, "rrtype"))
|
/* Fake up a function call. */
|
||||||
log_fatal ("can't allocate rrtype let.");
|
ep = &(*expr) -> data.funcall.arglist;
|
||||||
stmt = (*expr) -> data.funcall.statements;
|
if (!expression_allocate (ep, MDL))
|
||||||
if (!make_const_int (stmt -> data.let.value, i))
|
log_fatal ("can't allocate expression");
|
||||||
|
(*ep) -> op = expr_arg;
|
||||||
|
if (!make_const_int (&(*ep) -> data.arg.val, u))
|
||||||
log_fatal ("can't allocate rrtype value.");
|
log_fatal ("can't allocate rrtype value.");
|
||||||
|
|
||||||
token = next_token (&val, cfile);
|
token = next_token (&val, cfile);
|
||||||
if (token != COMMA)
|
if (token != COMMA)
|
||||||
goto nocomma;
|
goto nocomma;
|
||||||
|
ep = &((*ep) -> data.arg.next);
|
||||||
if (!make_let (&stmt -> data.let.statements, "rrname"))
|
if (!expression_allocate (ep, MDL))
|
||||||
log_fatal ("can't allocate rrname let.");
|
log_fatal ("can't allocate expression");
|
||||||
stmt = stmt -> data.let.statements;
|
(*ep) -> op = expr_arg;
|
||||||
if (!(parse_data_expression (&stmt -> data.let.expr,
|
if (!(parse_data_expression (&(*ep) -> data.arg.val,
|
||||||
cfile, lose)))
|
cfile, lose)))
|
||||||
goto nodata;
|
goto nodata;
|
||||||
|
|
||||||
@@ -2316,10 +2333,11 @@ int parse_non_binary (expr, cfile, lose, context)
|
|||||||
if (token != COMMA)
|
if (token != COMMA)
|
||||||
goto nocomma;
|
goto nocomma;
|
||||||
|
|
||||||
if (!make_let (&stmt -> data.let.statements, "rrdata"))
|
ep = &((*ep) -> data.arg.next);
|
||||||
log_fatal ("can't allocate rrname let.");
|
if (!expression_allocate (ep, MDL))
|
||||||
stmt = stmt -> data.let.statements;
|
log_fatal ("can't allocate expression");
|
||||||
if (!(parse_data_expression (&stmt -> data.let.expr,
|
(*ep) -> op = expr_arg;
|
||||||
|
if (!(parse_data_expression (&(*ep) -> data.arg.val,
|
||||||
cfile, lose)))
|
cfile, lose)))
|
||||||
goto nodata;
|
goto nodata;
|
||||||
|
|
||||||
@@ -2328,18 +2346,18 @@ int parse_non_binary (expr, cfile, lose, context)
|
|||||||
if (token != COMMA)
|
if (token != COMMA)
|
||||||
goto nocomma;
|
goto nocomma;
|
||||||
|
|
||||||
if (!make_let (&stmt -> data.let.statements, "ttl"))
|
ep = &((*ep) -> data.arg.next);
|
||||||
log_fatal ("can't allocate rrname let.");
|
if (!expression_allocate (ep, MDL))
|
||||||
stmt = stmt -> data.let.statements;
|
log_fatal ("can't allocate expression");
|
||||||
|
(*ep) -> op = expr_arg;
|
||||||
if (!(parse_numeric_expression
|
if (!(parse_numeric_expression (&(*ep) -> data.arg.val,
|
||||||
(&stmt -> data.let.expr, cfile, lose))) {
|
cfile, lose))) {
|
||||||
parse_warn (cfile,
|
parse_warn (cfile,
|
||||||
"expecting numeric expression.");
|
"expecting numeric expression.");
|
||||||
goto badnsupdate;
|
goto badnsupdate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
token = next_token (&val, cfile);
|
token = next_token (&val, cfile);
|
||||||
if (token != RPAREN)
|
if (token != RPAREN)
|
||||||
goto norparen;
|
goto norparen;
|
||||||
@@ -2885,14 +2903,59 @@ int parse_non_binary (expr, cfile, lose, context)
|
|||||||
if (token != NAME && token != NUMBER_OR_NAME)
|
if (token != NAME && token != NUMBER_OR_NAME)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
token = next_token (&val, cfile);
|
||||||
|
|
||||||
|
/* Save the name of the variable being referenced. */
|
||||||
|
cptr = dmalloc (strlen (val) + 1, MDL);
|
||||||
|
if (!cptr)
|
||||||
|
log_fatal ("can't allocate variable name");
|
||||||
|
strcpy (cptr, val);
|
||||||
|
|
||||||
|
/* Simple variable reference, as far as we can tell. */
|
||||||
|
token = peek_token (&val, cfile);
|
||||||
|
if (token != LPAREN) {
|
||||||
|
if (!expression_allocate (expr, MDL))
|
||||||
|
log_fatal ("can't allocate expression");
|
||||||
|
(*expr) -> op = expr_variable_reference;
|
||||||
|
(*expr) -> data.variable = cptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
token = next_token (&val, cfile);
|
token = next_token (&val, cfile);
|
||||||
if (!expression_allocate (expr, MDL))
|
if (!expression_allocate (expr, MDL))
|
||||||
log_fatal ("can't allocate expression");
|
log_fatal ("can't allocate expression");
|
||||||
(*expr) -> op = expr_variable_reference;
|
(*expr) -> op = expr_funcall;
|
||||||
(*expr) -> data.variable = dmalloc (strlen (val) + 1, MDL);
|
(*expr) -> data.funcall.name = cptr;
|
||||||
if (!(*expr)->data.variable)
|
|
||||||
log_fatal ("can't allocate variable name");
|
/* Now parse the argument list. */
|
||||||
strcpy ((*expr) -> data.variable, val);
|
ep = &(*expr) -> data.funcall.arglist;
|
||||||
|
do {
|
||||||
|
if (!expression_allocate (ep, MDL))
|
||||||
|
log_fatal ("can't allocate expression");
|
||||||
|
(*ep) -> op = expr_arg;
|
||||||
|
if (!parse_expression (&(*ep) -> data.arg.val,
|
||||||
|
cfile, lose, context_any,
|
||||||
|
(struct expression **)0,
|
||||||
|
expr_none)) {
|
||||||
|
if (!*lose) {
|
||||||
|
parse_warn (cfile,
|
||||||
|
"expecting expression.");
|
||||||
|
*lose = 1;
|
||||||
|
}
|
||||||
|
skip_to_semi (cfile);
|
||||||
|
expression_dereference (expr, MDL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ep = &((*ep) -> data.arg.next);
|
||||||
|
token = next_token (&val, cfile);
|
||||||
|
} while (token == COMMA);
|
||||||
|
if (token != RPAREN) {
|
||||||
|
parse_warn (cfile, "Right parenthesis expected.");
|
||||||
|
skip_to_semi (cfile);
|
||||||
|
*lose = 1;
|
||||||
|
expression_dereference (expr, MDL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
Reference in New Issue
Block a user