#include "carr.h"
/* this example code demonstrates how to implement a virtual array that
manipulates a C array. The code aims for simplicity so there's no
locking of the C array, which is obviously common for any mawk instance:
the code assumes a single thread.
Index is integer between 0 and CARR_SIZE-1. Delete only sets value to 0.
The iterator always goes between 0 and CARR_SIZE-1.
*/
char carr[CARR_SIZE];
/* lookup: copy a cell of a member if res != NULL; if create_flag is non-zero,
the index should be created. If result is non-NULL, it must be destroyed.
Result can be the same as cidx!
return:
-1 on error
0 if index does not exist
1 if it does exist
Because we have a static array, we won't ever return 0; also ignore the
create flag. Return -1 for boundary error.
*/
int carr_find(mawk_state_t *MAWK, mawk_array_t A, const mawk_cell_t *cidx, mawk_cell_t *res, int create_flag)
{
int idx;
idx = libmawk_cell2int(MAWK, cidx);
if ((idx < 0) || (idx >= CARR_SIZE))
return -1;
if (res != NULL) {
mawk_cell_destroy(MAWK, res);
res->type = C_NUM;
res->d.dval = carr[idx];
}
return 1;
}
/* set the value of an element of the array. The val cell may have any type! */
void carr_set(mawk_state_t *MAWK, mawk_array_t A, const mawk_cell_t *cidx, mawk_cell_t *val)
{
int idx;
char cval;
idx = libmawk_cell2int(MAWK, cidx);
if ((idx < 0) || (idx >= CARR_SIZE))
return;
switch(val->type) {
case C_NUM:
case C_STRNUM:
case C_MBSTRN:
carr[idx] = libmawk_cell2int(MAWK, val);
break;
case C_STRING:
{
char buff[2];
libmawk_print_cell(MAWK, val, buff, 2);
carr[idx] = buff[0];
}
break;
default:
carr[idx] = 0;
}
}
/* delete a cell (since our array is static, set the value to 0) */
static void carr_delete(mawk_state_t *MAWK, mawk_array_t A, const mawk_cell_t *idx)
{
mawk_cell_t zero;
zero.type = C_NUM;
zero.d.dval = 0;
carr_set(MAWK, A, idx, &zero);
}
/* set up an iterator; the iterator state is just an integer index */
typedef struct {
int idx;
mawk_cell_t cidx;
} carr_it_t;
void *carr_it_start(mawk_state_t *MAWK, mawk_array_t A)
{
carr_it_t *i;
i = malloc(sizeof(carr_it_t));
i->idx = -1;
i->cidx.type = C_NUM;
return i;
}
/* return next element using an iterator (thread safe) */
const mawk_cell_t *carr_it_next(mawk_state_t *MAWK, mawk_array_t A, void *iterator)
{
carr_it_t *i = iterator;
i->idx++;
if (i->idx >= CARR_SIZE)
return NULL;
i->cidx.d.dval = i->idx;
return &i->cidx;
}
/* finish iteration */
void carr_it_stop(mawk_state_t *MAWK, mawk_array_t A, void *iterator)
{
/* no need to destroy iterator->cidx as it was a number all the time */
free(iterator);
}
/* NOTE: the above code tries to be readable, thus there's a separate
integer index an a cell for sotring the return-cell are in the iterator.
The code could be shorter taking less ram if the iterator was a cell
whose (int)d.dval stored the index. */
/* the implementation struct that describes how the array is implemented */
array_imp_t carr_imp = {
/* low level access: find an index, set and delete members */
carr_find,
carr_set,
carr_delete,
/* use the generic implementation for high level calls, because... */
mawk_array_clear_generic,
mawk_array_loop_vector_generic,
mawk_array_load_generic,
/* ... the low level iterator is implemented: */
carr_it_start,
carr_it_next,
carr_it_stop
};
/* set up the array as a built-in */
void custom_array_init(mawk_state_t *m)
{
/* register the new array */
libmawk_register_array(m, "CARR", &carr_imp);
/* globals should be zero'd, but to make it absolutely clear: */
memset(carr, 0, sizeof(carr));
}