A scalar cookie is an opaque handle that provides access
to a global variable or array. It is an optimization that
avoids looking up variables in gawk
’s symbol table every time
access is needed. This was discussed earlier, in General-Purpose Data Types.
The following functions let you work with scalar cookies:
awk_bool_t sym_lookup_scalar(awk_scalar_t cookie,
awk_valtype_t wanted,
awk_value_t *result);
Retrieve the current value of a scalar cookie.
Once you have obtained a scalar cookie using sym_lookup()
, you can
use this function to get its value more efficiently.
Return false if the value cannot be retrieved.
awk_bool_t sym_update_scalar(awk_scalar_t cookie, awk_value_t *value);
Update the value associated with a scalar cookie. Return false if
the new value is not of type AWK_STRING
, AWK_STRNUM
, AWK_REGEX
, or AWK_NUMBER
.
Here too, the predefined variables may not be updated.
It is not obvious at first glance how to work with scalar cookies or
what their raison d’être really is. In theory, the sym_lookup()
and sym_update()
routines are all you really need to work with
variables. For example, you might have code that looks up the value of
a variable, evaluates a condition, and then possibly changes the value
of the variable based on the result of that evaluation, like so:
/* do_magic --- do something really great */ static awk_value_t * do_magic(int nargs, awk_value_t *result) { awk_value_t value; if ( sym_lookup("MAGIC_VAR", AWK_NUMBER, & value) && some_condition(value.num_value)) { value.num_value += 42; sym_update("MAGIC_VAR", & value); } return make_number(0.0, result); }
This code looks (and is) simple and straightforward. So what’s the problem?
Well, consider what happens if awk
-level code associated
with your extension calls the magic()
function (implemented in
C by do_magic()
), once per record, while processing hundreds
of thousands or millions of records. The MAGIC_VAR
variable is
looked up in the symbol table once or twice per function call!
The symbol table lookup is really pure overhead; it is considerably more efficient to get a cookie that represents the variable, and use that to get the variable’s value and update it as needed.110
Thus, the way to use cookies is as follows. First, install
your extension’s variable in gawk
’s symbol table using
sym_update()
, as usual. Then get a scalar cookie for the variable
using sym_lookup()
:
static awk_scalar_t magic_var_cookie; /* cookie for MAGIC_VAR */ static void my_extension_init() { awk_value_t value;
/* install initial value */ sym_update("MAGIC_VAR", make_number(42.0, & value)); /* get the cookie */ sym_lookup("MAGIC_VAR", AWK_SCALAR, & value); /* save the cookie */ magic_var_cookie = value.scalar_cookie; ... }
Next, use the routines in this section for retrieving and updating
the value through the cookie. Thus, do_magic()
now becomes
something like this:
/* do_magic --- do something really great */ static awk_value_t * do_magic(int nargs, awk_value_t *result) { awk_value_t value; if ( sym_lookup_scalar(magic_var_cookie, AWK_NUMBER, & value) && some_condition(value.num_value)) { value.num_value += 42; sym_update_scalar(magic_var_cookie, & value); } ... return make_number(0.0, result); }
NOTE: The previous code omitted error checking for presentation purposes. Your extension code should be more robust and carefully check the return values from the API functions.