dfilter: Clean up error format and exception code

Misc code cleanups. Add some extra stnode functions for increased type
safety. Fix a constness issue with df_lval_value().
This commit is contained in:
João Valverde 2021-11-08 12:20:40 +00:00
parent 63adcf7fb5
commit e7ecc9b9e5
8 changed files with 124 additions and 114 deletions

View File

@ -64,9 +64,11 @@ df_lval_new(void)
return g_new0(df_lval_t, 1);
}
static inline char *
static inline const char *
df_lval_value(df_lval_t *lval)
{
if (!lval || !lval->value)
return "(fixme: null)";
return lval->value;
}
@ -89,12 +91,17 @@ void Dfilter(void*, int, df_lval_t*, dfwork_t*);
/* Return value for error in scanner. */
#define SCAN_FAILED -1 /* not 0, as that means end-of-input */
/* Set dfw->error_message */
void
dfilter_vfail(dfwork_t *dfw, const char *format, va_list args);
void
dfilter_fail(dfwork_t *dfw, const char *format, ...) G_GNUC_PRINTF(2, 3);
void
dfilter_parse_fail(dfwork_t *dfw, const char *format, ...) G_GNUC_PRINTF(2, 3);
dfilter_fail_throw(dfwork_t *dfw, long code, const char *format, ...) G_GNUC_PRINTF(3, 4);
void
dfilter_fail_parse(dfwork_t *dfw, const char *format, ...) G_GNUC_PRINTF(2, 3);
void
add_deprecated_token(dfwork_t *dfw, const char *token);

View File

@ -18,6 +18,7 @@
#include "semcheck.h"
#include "dfvm.h"
#include <epan/epan_dissect.h>
#include <epan/exceptions.h>
#include "dfilter.h"
#include "dfilter-macro.h"
#include "scanner_lex.h"
@ -40,7 +41,7 @@ static void* ParserObj = NULL;
*/
dfwork_t *global_dfw;
static void
void
dfilter_vfail(dfwork_t *dfw, const char *format, va_list args)
{
/* If we've already reported one error, don't overwite it */
@ -61,7 +62,18 @@ dfilter_fail(dfwork_t *dfw, const char *format, ...)
}
void
dfilter_parse_fail(dfwork_t *dfw, const char *format, ...)
dfilter_fail_throw(dfwork_t *dfw, long code, const char *format, ...)
{
va_list args;
va_start(args, format);
dfilter_vfail(dfw, format, args);
va_end(args);
THROW(code);
}
void
dfilter_fail_parse(dfwork_t *dfw, const char *format, ...)
{
va_list args;

View File

@ -20,6 +20,9 @@
#include <epan/exceptions.h>
#include <wsutil/ws_assert.h>
#define FAIL(dfw, ...) \
dfilter_fail_throw(dfw, TypeError, __VA_ARGS__)
/* Convert an FT_STRING using a callback function */
static gboolean
string_walk(GList* arg1list, GList **retval, gchar(*conv_func)(gchar))
@ -181,8 +184,7 @@ ul_semcheck_is_field_string(dfwork_t *dfw, const char *func_name,
return;
}
}
dfilter_fail(dfw, "Only string type fields can be used as parameter for %s()", func_name);
THROW(TypeError);
FAIL(dfw, "Only string type fields can be used as parameter for %s()", func_name);
}
static void
@ -194,8 +196,7 @@ ul_semcheck_is_field(dfwork_t *dfw, const char *func_name,
if (stnode_type_id(st_node) == STTYPE_FIELD)
return;
dfilter_fail(dfw, "Only fields can be used as parameter for %s()", func_name);
THROW(TypeError);
FAIL(dfw, "Only fields can be used as parameter for %s()", func_name);
}
static void
@ -245,11 +246,9 @@ ul_semcheck_string_param(dfwork_t *dfw, const char *func_name,
default:
break;
}
dfilter_fail(dfw, "String conversion for field \"%s\" is not supported", hfinfo->abbrev);
THROW(TypeError);
FAIL(dfw, "String conversion for field \"%s\" is not supported", hfinfo->abbrev);
}
dfilter_fail(dfw, "Only fields can be used as parameter for %s()", func_name);
THROW(TypeError);
FAIL(dfw, "Only fields can be used as parameter for %s()", func_name);
}
/* The table of all display-filter functions */

View File

@ -85,16 +85,8 @@ new_function(dfwork_t *dfw, df_lval_t *lval);
/* This is called as soon as a syntax error happens. After that,
any "error" symbols are shifted, if possible. */
%syntax_error {
if (!TOKEN) {
dfilter_fail(dfw, "Unexpected end of filter string.");
dfw->syntax_error = TRUE;
return;
}
dfilter_fail(dfw, "\"%s\" was unexpected in this context.",
df_lval_value(TOKEN));
dfw->syntax_error = TRUE;
dfilter_fail_parse(dfw, "\"%s\" was unexpected in this context.",
df_lval_value(TOKEN));
}
/* When a parse fails, mark an error. This occurs after
@ -147,18 +139,18 @@ logical_test(T) ::= entity(E).
/* Entities, or things that can be compared/tested/checked */
entity(E) ::= STRING(S).
{
E = stnode_new(STTYPE_STRING, df_lval_value(S));
E = stnode_new_string(df_lval_value(S));
df_lval_free(S);
}
entity(E) ::= CHARCONST(C).
{
/* A charconst uses "unparsed" semantic rules. */
E = stnode_new(STTYPE_UNPARSED, df_lval_value(C));
E = stnode_new_unparsed(df_lval_value(C));
df_lval_free(C);
}
entity(E) ::= UNPARSED(U).
{
E = stnode_new(STTYPE_UNPARSED, df_lval_value(U));
E = stnode_new_unparsed(df_lval_value(U));
dfilter_resolve_unparsed(dfw, E);
df_lval_free(U);
}
@ -193,7 +185,7 @@ range_node(D) ::= RANGE(R).
D = drange_node_from_str(df_lval_value(R), &err);
if (err != NULL) {
dfilter_parse_fail(dfw, "%s", err);
dfilter_fail_parse(dfw, "%s", err);
g_free(err);
}
@ -294,7 +286,7 @@ set_element(N) ::= entity(X) DOTDOT entity(Y).
const char *name = df_lval_value(lval);
df_func_def_t *def = df_func_lookup(name);
if (!def) {
dfilter_parse_fail(dfw, "Function '%s' does not exist", name);
dfilter_fail_parse(dfw, "Function '%s' does not exist", name);
}
return stnode_new(STTYPE_FUNCTION, def);
}

View File

@ -29,6 +29,9 @@
#include <ftypes/ftypes-int.h>
#define FAIL(dfw, ...) \
dfilter_fail_throw(dfw, TypeError, __VA_ARGS__)
static void
semcheck(dfwork_t *dfw, stnode_t *st_node);
@ -436,9 +439,8 @@ check_exists(dfwork_t *dfw, stnode_t *st_arg1)
break;
case STTYPE_STRING:
case STTYPE_UNPARSED:
dfilter_fail(dfw, "\"%s\" is neither a field nor a protocol name.",
(char *)stnode_data(st_arg1));
THROW(TypeError);
FAIL(dfw, "%s is neither a field nor a protocol name.",
stnode_todisplay(st_arg1));
break;
case STTYPE_RANGE:
@ -448,15 +450,13 @@ check_exists(dfwork_t *dfw, stnode_t *st_arg1)
* has at least 2 bytes starting at an offset of
* 3"?
*/
dfilter_fail(dfw, "You cannot test whether a range is present.");
THROW(TypeError);
FAIL(dfw, "You cannot test whether a range is present.");
break;
case STTYPE_FUNCTION:
/* XXX - Maybe we should change functions so they can return fields,
* in which case the 'exist' should be fine. */
dfilter_fail(dfw, "You cannot test whether a function is present.");
THROW(TypeError);
FAIL(dfw, "You cannot test whether a function is present.");
break;
case STTYPE_UNINITIALIZED:
@ -484,18 +484,16 @@ check_drange_sanity(dfwork_t *dfw, stnode_t *st)
ftype1 = hfinfo1->type;
if (!ftype_can_slice(ftype1)) {
dfilter_fail(dfw, "\"%s\" is a %s and cannot be sliced into a sequence of bytes.",
FAIL(dfw, "\"%s\" is a %s and cannot be sliced into a sequence of bytes.",
hfinfo1->abbrev, ftype_pretty_name(ftype1));
THROW(TypeError);
}
} else if (stnode_type_id(entity1) == STTYPE_FUNCTION) {
df_func_def_t *funcdef = sttype_function_funcdef(entity1);
ftype1 = funcdef->retval_ftype;
if (!ftype_can_slice(ftype1)) {
dfilter_fail(dfw, "Return value of function \"%s\" is a %s and cannot be converted into a sequence of bytes.",
FAIL(dfw, "Return value of function \"%s\" is a %s and cannot be converted into a sequence of bytes.",
funcdef->name, ftype_pretty_name(ftype1));
THROW(TypeError);
}
check_function(dfw, entity1);
@ -503,9 +501,8 @@ check_drange_sanity(dfwork_t *dfw, stnode_t *st)
/* Should this be rejected instead? */
check_drange_sanity(dfw, entity1);
} else {
dfilter_fail(dfw, "Range is not supported for entity %s of type %s",
FAIL(dfw, "Range is not supported for entity %s of type %s",
stnode_todisplay(entity1), stnode_type_name(entity1));
THROW(TypeError);
}
}
@ -537,13 +534,11 @@ check_function(dfwork_t *dfw, stnode_t *st_node)
nparams = g_slist_length(params);
if (nparams < funcdef->min_nargs) {
dfilter_fail(dfw, "Function %s needs at least %u arguments.",
FAIL(dfw, "Function %s needs at least %u arguments.",
funcdef->name, funcdef->min_nargs);
THROW(TypeError);
} else if (nparams > funcdef->max_nargs) {
dfilter_fail(dfw, "Function %s can only accept %u arguments.",
FAIL(dfw, "Function %s can only accept %u arguments.",
funcdef->name, funcdef->max_nargs);
THROW(TypeError);
}
iparam = 0;
@ -569,7 +564,7 @@ check_relation_LHS_FIELD(dfwork_t *dfw, test_op_t st_op,
type2 = stnode_type_id(st_arg2);
hfinfo1 = (header_field_info*)stnode_data(st_arg1);
hfinfo1 = stnode_data(st_arg1);
ftype1 = hfinfo1->type;
if (stnode_type_id(st_node) == STTYPE_TEST) {
@ -579,27 +574,24 @@ check_relation_LHS_FIELD(dfwork_t *dfw, test_op_t st_op,
}
if (!can_func(ftype1)) {
dfilter_fail(dfw, "%s (type=%s) cannot participate in '%s' comparison.",
FAIL(dfw, "%s (type=%s) cannot participate in '%s' comparison.",
hfinfo1->abbrev, ftype_pretty_name(ftype1),
sttype_test_todisplay(st_op));
THROW(TypeError);
}
if (type2 == STTYPE_FIELD) {
hfinfo2 = (header_field_info*)stnode_data(st_arg2);
hfinfo2 = stnode_data(st_arg2);
ftype2 = hfinfo2->type;
if (!compatible_ftypes(ftype1, ftype2)) {
dfilter_fail(dfw, "%s and %s are not of compatible types.",
FAIL(dfw, "%s and %s are not of compatible types.",
hfinfo1->abbrev, hfinfo2->abbrev);
THROW(TypeError);
}
/* Do this check even though you'd think that if
* they're compatible, then can_func() would pass. */
if (!can_func(ftype2)) {
dfilter_fail(dfw, "%s (type=%s) cannot participate in specified comparison.",
FAIL(dfw, "%s (type=%s) cannot participate in specified comparison.",
hfinfo2->abbrev, ftype_pretty_name(ftype2));
THROW(TypeError);
}
}
else if (type2 == STTYPE_STRING || type2 == STTYPE_UNPARSED) {
@ -623,10 +615,9 @@ check_relation_LHS_FIELD(dfwork_t *dfw, test_op_t st_op,
check_drange_sanity(dfw, st_arg2);
if (!is_bytes_type(ftype1)) {
if (!ftype_can_slice(ftype1)) {
dfilter_fail(dfw, "\"%s\" is a %s and cannot be converted into a sequence of bytes.",
FAIL(dfw, "\"%s\" is a %s and cannot be converted into a sequence of bytes.",
hfinfo1->abbrev,
ftype_pretty_name(ftype1));
THROW(TypeError);
}
/* Convert entire field to bytes */
@ -638,16 +629,14 @@ check_relation_LHS_FIELD(dfwork_t *dfw, test_op_t st_op,
ftype2 = funcdef->retval_ftype;
if (!compatible_ftypes(ftype1, ftype2)) {
dfilter_fail(dfw, "%s (type=%s) and return value of %s() (type=%s) are not of compatible types.",
FAIL(dfw, "%s (type=%s) and return value of %s() (type=%s) are not of compatible types.",
hfinfo1->abbrev, ftype_pretty_name(ftype1),
funcdef->name, ftype_pretty_name(ftype2));
THROW(TypeError);
}
if (!can_func(ftype2)) {
dfilter_fail(dfw, "return value of %s() (type=%s) cannot participate in specified comparison.",
FAIL(dfw, "return value of %s() (type=%s) cannot participate in specified comparison.",
funcdef->name, ftype_pretty_name(ftype2));
THROW(TypeError);
}
check_function(dfw, st_arg2);
@ -677,14 +666,13 @@ check_relation_LHS_STRING(dfwork_t *dfw, test_op_t st_op,
ws_debug("5 check_relation_LHS_STRING()");
if (type2 == STTYPE_FIELD) {
hfinfo2 = (header_field_info*)stnode_data(st_arg2);
hfinfo2 = stnode_data(st_arg2);
ftype2 = hfinfo2->type;
if (!can_func(ftype2)) {
dfilter_fail(dfw, "%s (type=%s) cannot participate in '%s' comparison.",
FAIL(dfw, "%s (type=%s) cannot participate in '%s' comparison.",
hfinfo2->abbrev, ftype_pretty_name(ftype2),
sttype_test_todisplay(st_op));
THROW(TypeError);
}
fvalue = dfilter_fvalue_from_string(dfw, ftype2, st_arg1, hfinfo2);
@ -692,10 +680,9 @@ check_relation_LHS_STRING(dfwork_t *dfw, test_op_t st_op,
}
else if (type2 == STTYPE_STRING || type2 == STTYPE_UNPARSED) {
/* Well now that's silly... */
dfilter_fail(dfw, "Neither \"%s\" nor \"%s\" are field or protocol names.",
(char *)stnode_data(st_arg1),
(char *)stnode_data(st_arg2));
THROW(TypeError);
FAIL(dfw, "Neither %s nor %s are field or protocol names.",
stnode_todisplay(st_arg1),
stnode_todisplay(st_arg2));
}
else if (type2 == STTYPE_RANGE) {
check_drange_sanity(dfw, st_arg2);
@ -709,10 +696,9 @@ check_relation_LHS_STRING(dfwork_t *dfw, test_op_t st_op,
ftype2 = funcdef->retval_ftype;
if (!can_func(ftype2)) {
dfilter_fail(dfw, "Return value of function %s (type=%s) cannot participate in '%s' comparison.",
FAIL(dfw, "Return value of function %s (type=%s) cannot participate in '%s' comparison.",
funcdef->name, ftype_pretty_name(ftype2),
sttype_test_todisplay(st_op));
THROW(TypeError);
}
fvalue = dfilter_fvalue_from_string(dfw, ftype2, st_arg1, NULL);
@ -740,14 +726,13 @@ check_relation_LHS_UNPARSED(dfwork_t *dfw, test_op_t st_op,
ws_debug("5 check_relation_LHS_UNPARSED()");
if (type2 == STTYPE_FIELD) {
hfinfo2 = (header_field_info*)stnode_data(st_arg2);
hfinfo2 = stnode_data(st_arg2);
ftype2 = hfinfo2->type;
if (!can_func(ftype2)) {
dfilter_fail(dfw, "%s (type=%s) cannot participate in '%s' comparison.",
FAIL(dfw, "%s (type=%s) cannot participate in '%s' comparison.",
hfinfo2->abbrev, ftype_pretty_name(ftype2),
sttype_test_todisplay(st_op));
THROW(TypeError);
}
fvalue = dfilter_fvalue_from_unparsed(dfw, ftype2, st_arg1, allow_partial_value, hfinfo2);
@ -755,10 +740,9 @@ check_relation_LHS_UNPARSED(dfwork_t *dfw, test_op_t st_op,
}
else if (type2 == STTYPE_STRING || type2 == STTYPE_UNPARSED) {
/* Well now that's silly... */
dfilter_fail(dfw, "Neither \"%s\" nor \"%s\" are field or protocol names.",
(char *)stnode_data(st_arg1),
(char *)stnode_data(st_arg2));
THROW(TypeError);
FAIL(dfw, "Neither %s nor %s are field or protocol names.",
stnode_todisplay(st_arg1),
stnode_todisplay(st_arg2));
}
else if (type2 == STTYPE_RANGE) {
check_drange_sanity(dfw, st_arg2);
@ -772,9 +756,8 @@ check_relation_LHS_UNPARSED(dfwork_t *dfw, test_op_t st_op,
ftype2 = funcdef->retval_ftype;
if (!can_func(ftype2)) {
dfilter_fail(dfw, "return value of function %s() (type=%s) cannot participate in '%s' comparison.",
FAIL(dfw, "return value of function %s() (type=%s) cannot participate in '%s' comparison.",
funcdef->name, ftype_pretty_name(ftype2), sttype_test_todisplay(st_op));
THROW(TypeError);
}
fvalue = dfilter_fvalue_from_unparsed(dfw, ftype2, st_arg1, allow_partial_value, NULL);
@ -804,15 +787,14 @@ check_relation_LHS_RANGE(dfwork_t *dfw, test_op_t st_op,
type2 = stnode_type_id(st_arg2);
if (type2 == STTYPE_FIELD) {
hfinfo2 = (header_field_info*)stnode_data(st_arg2);
hfinfo2 = stnode_data(st_arg2);
ftype2 = hfinfo2->type;
if (!is_bytes_type(ftype2)) {
if (!ftype_can_slice(ftype2)) {
dfilter_fail(dfw, "\"%s\" is a %s and cannot be converted into a sequence of bytes.",
FAIL(dfw, "\"%s\" is a %s and cannot be converted into a sequence of bytes.",
hfinfo2->abbrev,
ftype_pretty_name(ftype2));
THROW(TypeError);
}
/* Convert entire field to bytes */
@ -836,10 +818,9 @@ check_relation_LHS_RANGE(dfwork_t *dfw, test_op_t st_op,
if (!is_bytes_type(ftype2)) {
if (!ftype_can_slice(ftype2)) {
dfilter_fail(dfw, "Return value of function \"%s\" is a %s and cannot be converted into a sequence of bytes.",
FAIL(dfw, "Return value of function \"%s\" is a %s and cannot be converted into a sequence of bytes.",
funcdef->name,
ftype_pretty_name(ftype2));
THROW(TypeError);
}
/* Convert function result to bytes */
@ -881,27 +862,24 @@ check_relation_LHS_FUNCTION(dfwork_t *dfw, test_op_t st_op,
ws_debug("5 check_relation_LHS_FUNCTION(%s)", sttype_test_todisplay(st_op));
if (!can_func(ftype1)) {
dfilter_fail(dfw, "Function %s (type=%s) cannot participate in '%s' comparison.",
FAIL(dfw, "Function %s (type=%s) cannot participate in '%s' comparison.",
funcdef->name, ftype_pretty_name(ftype1),
sttype_test_todisplay(st_op));
THROW(TypeError);
}
if (type2 == STTYPE_FIELD) {
hfinfo2 = (header_field_info*)stnode_data(st_arg2);
hfinfo2 = stnode_data(st_arg2);
ftype2 = hfinfo2->type;
if (!compatible_ftypes(ftype1, ftype2)) {
dfilter_fail(dfw, "Function %s and %s are not of compatible types.",
FAIL(dfw, "Function %s and %s are not of compatible types.",
funcdef->name, hfinfo2->abbrev);
THROW(TypeError);
}
/* Do this check even though you'd think that if
* they're compatible, then can_func() would pass. */
if (!can_func(ftype2)) {
dfilter_fail(dfw, "%s (type=%s) cannot participate in specified comparison.",
FAIL(dfw, "%s (type=%s) cannot participate in specified comparison.",
hfinfo2->abbrev, ftype_pretty_name(ftype2));
THROW(TypeError);
}
}
else if (type2 == STTYPE_STRING) {
@ -916,10 +894,9 @@ check_relation_LHS_FUNCTION(dfwork_t *dfw, test_op_t st_op,
check_drange_sanity(dfw, st_arg2);
if (!is_bytes_type(ftype1)) {
if (!ftype_can_slice(ftype1)) {
dfilter_fail(dfw, "Function \"%s\" is a %s and cannot be converted into a sequence of bytes.",
FAIL(dfw, "Function \"%s\" is a %s and cannot be converted into a sequence of bytes.",
funcdef->name,
ftype_pretty_name(ftype1));
THROW(TypeError);
}
/* Convert function result to bytes */
@ -931,17 +908,15 @@ check_relation_LHS_FUNCTION(dfwork_t *dfw, test_op_t st_op,
ftype2 = funcdef2->retval_ftype;
if (!compatible_ftypes(ftype1, ftype2)) {
dfilter_fail(dfw, "Return values of function %s (type=%s) and function %s (type=%s) are not of compatible types.",
FAIL(dfw, "Return values of function %s (type=%s) and function %s (type=%s) are not of compatible types.",
funcdef->name, ftype_pretty_name(ftype1), funcdef2->name, ftype_pretty_name(ftype2));
THROW(TypeError);
}
/* Do this check even though you'd think that if
* they're compatible, then can_func() would pass. */
if (!can_func(ftype2)) {
dfilter_fail(dfw, "Return value of %s (type=%s) cannot participate in specified comparison.",
FAIL(dfw, "Return value of %s (type=%s) cannot participate in specified comparison.",
funcdef2->name, ftype_pretty_name(ftype2));
THROW(TypeError);
}
check_function(dfw, st_arg2);
@ -1033,7 +1008,7 @@ check_relation_contains(dfwork_t *dfw, stnode_t *st_node,
* functions will take care of it as if it didn't
* match a protocol string.
*/
stnode_replace(st_arg2, STTYPE_UNPARSED, (char *)hfinfo->abbrev);
stnode_replace_unparsed(st_arg2, hfinfo->abbrev);
}
}
@ -1052,8 +1027,7 @@ check_relation_contains(dfwork_t *dfw, stnode_t *st_node,
break;
case STTYPE_STRING:
case STTYPE_UNPARSED:
dfilter_fail(dfw, "%s is not a valid operand for contains.", stnode_todisplay(st_arg1));
THROW(TypeError);
FAIL(dfw, "%s is not a valid operand for contains.", stnode_todisplay(st_arg1));
break;
default:
ws_assert_not_reached();
@ -1074,8 +1048,7 @@ check_relation_matches(dfwork_t *dfw, stnode_t *st_node,
log_stnode(st_arg2);
if (stnode_type_id(st_arg2) != STTYPE_STRING) {
dfilter_fail(dfw, "Expected a double quoted string not %s", stnode_todisplay(st_arg2));
THROW(TypeError);
FAIL(dfw, "Expected a double quoted string not %s", stnode_todisplay(st_arg2));
}
patt = stnode_data(st_arg2);
@ -1105,8 +1078,7 @@ check_relation_matches(dfwork_t *dfw, stnode_t *st_node,
break;
case STTYPE_STRING:
case STTYPE_UNPARSED:
dfilter_fail(dfw, "%s is not a valid operand for matches.", stnode_todisplay(st_arg1));
THROW(TypeError);
FAIL(dfw, "%s is not a valid operand for matches.", stnode_todisplay(st_arg1));
break;
default:
ws_assert_not_reached();
@ -1121,8 +1093,7 @@ check_relation_in(dfwork_t *dfw, stnode_t *st_node _U_,
stnode_t *node, *node_right;
if (stnode_type_id(st_arg1) != STTYPE_FIELD) {
dfilter_fail(dfw, "Only a field may be tested for membership in a set.");
THROW(TypeError);
FAIL(dfw, "Only a field may be tested for membership in a set.");
}
/* Checked in the grammar parser. */
ws_assert(stnode_type_id(st_arg2) == STTYPE_SET);
@ -1137,8 +1108,7 @@ check_relation_in(dfwork_t *dfw, stnode_t *st_node _U_,
/* Don't let a range on the RHS affect the LHS field. */
if (stnode_type_id(node) == STTYPE_RANGE) {
dfilter_fail(dfw, "A range may not appear inside a set.");
THROW(TypeError);
FAIL(dfw, "A range may not appear inside a set.");
break;
}

View File

@ -9,12 +9,6 @@
#include "syntax-tree.h"
static gpointer
string_new(gpointer string)
{
return g_strdup(string);
}
static gpointer
string_dup(gconstpointer string)
{
@ -48,7 +42,7 @@ sttype_register_string(void)
static sttype_t string_type = {
STTYPE_STRING,
"STRING",
string_new,
NULL,
string_free,
string_dup,
string_tostr
@ -57,7 +51,7 @@ sttype_register_string(void)
static sttype_t unparsed_type = {
STTYPE_UNPARSED,
"UNPARSED",
string_new,
NULL,
string_free,
string_dup,
unparsed_tostr

View File

@ -134,6 +134,18 @@ stnode_replace(stnode_t *node, sttype_id_t type_id, gpointer data)
node->flags = flags;
}
void
stnode_replace_string(stnode_t *node, const char *str)
{
stnode_replace(node, STTYPE_STRING, g_strdup(str));
}
void
stnode_replace_unparsed(stnode_t *node, const char *str)
{
stnode_replace(node, STTYPE_UNPARSED, g_strdup(str));
}
stnode_t*
stnode_new(sttype_id_t type_id, gpointer data)
{
@ -160,6 +172,18 @@ stnode_new_test(test_op_t op, stnode_t *val1, stnode_t *val2)
return node;
}
stnode_t *
stnode_new_string(const char *str)
{
return stnode_new(STTYPE_STRING, g_strdup(str));
}
stnode_t *
stnode_new_unparsed(const char *str)
{
return stnode_new(STTYPE_UNPARSED, g_strdup(str));
}
stnode_t*
stnode_dup(const stnode_t *node)
{

View File

@ -104,6 +104,12 @@ stnode_new(sttype_id_t type_id, gpointer data);
stnode_t *
stnode_new_test(test_op_t op, stnode_t *val1, stnode_t *val2);
stnode_t *
stnode_new_string(const char *str);
stnode_t *
stnode_new_unparsed(const char *str);
stnode_t*
stnode_dup(const stnode_t *org);
@ -116,6 +122,12 @@ stnode_init(stnode_t *node, sttype_id_t type_id, gpointer data);
void
stnode_replace(stnode_t *node, sttype_id_t type_id, gpointer data);
void
stnode_replace_string(stnode_t *node, const char *str);
void
stnode_replace_unparsed(stnode_t *node, const char *str);
void
stnode_free(stnode_t *node);