diff options
author | Arnold D. Robbins <arnold@skeeve.com> | 2013-01-06 17:36:58 +0200 |
---|---|---|
committer | Arnold D. Robbins <arnold@skeeve.com> | 2013-01-06 17:36:58 +0200 |
commit | 6b4dccf6db4dcaaff9f5a58baeee21329635ec18 (patch) | |
tree | 057f9b6d5c02ad8338c7f5cb71ca6cb295de3fbe /old-extension | |
parent | cccfa4aac8863671e7215877f9d582d7c6c63753 (diff) | |
download | gawk-6b4dccf6db4dcaaff9f5a58baeee21329635ec18.tar.gz |
Move old extension stuff into a separate directory.
Diffstat (limited to 'old-extension')
-rw-r--r-- | old-extension/ChangeLog | 6 | ||||
-rw-r--r-- | old-extension/bindarr.c | 347 | ||||
-rw-r--r-- | old-extension/dbarray.awk | 222 | ||||
-rw-r--r-- | old-extension/fileop.c | 394 | ||||
-rw-r--r-- | old-extension/record.awk | 252 | ||||
-rw-r--r-- | old-extension/sparr.c | 163 | ||||
-rw-r--r-- | old-extension/spec_array.c | 416 | ||||
-rw-r--r-- | old-extension/spec_array.h | 28 | ||||
-rwxr-xr-x | old-extension/steps | 10 | ||||
-rw-r--r-- | old-extension/testdbarray.awk | 21 | ||||
-rwxr-xr-x | old-extension/testrecord.sh | 19 | ||||
-rw-r--r-- | old-extension/testsparr.awk | 18 |
12 files changed, 1896 insertions, 0 deletions
diff --git a/old-extension/ChangeLog b/old-extension/ChangeLog new file mode 100644 index 00000000..a25295a6 --- /dev/null +++ b/old-extension/ChangeLog @@ -0,0 +1,6 @@ +2013-01-06 Arnold D. Robbins <arnold@skeeve.com> + + * bindarr.c, dbarray.awk, fileop.c, record.awk, sparr.c, + spec_array.c, spec_array.h, steps, testdbarray.awk, testrecord.sh, + testsparr.awk: Moved here from extension directory, since they + use the old mechanism. diff --git a/old-extension/bindarr.c b/old-extension/bindarr.c new file mode 100644 index 00000000..60959903 --- /dev/null +++ b/old-extension/bindarr.c @@ -0,0 +1,347 @@ +/* + * bindarr.c - routines for binding (attaching) user-defined functions + * to array and array elements. + */ + +/* + * Copyright (C) 1986, 1988, 1989, 1991-2011 the Free Software Foundation, Inc. + * + * This file is part of GAWK, the GNU implementation of the + * AWK Programming Language. + * + * GAWK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GAWK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "awk.h" + +/* + * Binding an array is basically the binding of functions to the internal + * triggers for reading and writing that array or an element of that array. + * This allows the user to define the set of behaviors for gawk arrays + * using gawk functions. With arrays you can assign and read values of + * specific elements, provide list of indices and values, and tell if a + * certain index exists or not. A variable can be "tied" by including + * code which overrides any or all of the standard behaviors of awk arrays. + * + * See dbarray.awk and testdbarray.awk to learn how to bind an array + * to an external database for persistent storage. + */ + +int plugin_is_GPL_compatible; + +static NODE **bind_array_lookup(NODE *, NODE *); +static NODE **bind_array_exists(NODE *, NODE *); +static NODE **bind_array_clear(NODE *, NODE *); +static NODE **bind_array_remove(NODE *, NODE *); +static NODE **bind_array_list(NODE *, NODE *); +static NODE **bind_array_store(NODE *, NODE *); +static NODE **bind_array_length(NODE *, NODE *); + +static afunc_t bind_array_func[] = { + (afunc_t) 0, + (afunc_t) 0, + bind_array_length, + bind_array_lookup, + bind_array_exists, + bind_array_clear, + bind_array_remove, + bind_array_list, + null_afunc, /* copy */ + null_afunc, /* dump */ + bind_array_store, +}; + +enum { INIT, FINI, COUNT, EXISTS, LOOKUP, + STORE, DELETE, CLEAR, FETCHALL +}; + +static const char *const bfn[] = { + "init", "fini", "count", "exists", "lookup", + "store", "delete", "clear", "fetchall", +}; + +typedef struct { + NODE *func[sizeof(bfn)/sizeof(char *)]; + NODE *arg0; +} array_t; + +static NODE *call_func(NODE *func, NODE **arg, int arg_count); +static long array_func_call(NODE *, NODE *, int); + + +/* bind_array_length -- find the number of elements in the array */ + +static NODE ** +bind_array_length(NODE *symbol, NODE *subs ATTRIBUTE_UNUSED) +{ + static NODE *length_node; + + symbol->table_size = array_func_call(symbol, NULL, COUNT); + length_node = symbol; + return & length_node; +} + +/* bind_array_lookup --- find element in the array; return a pointer to value. */ + +static NODE ** +bind_array_lookup(NODE *symbol, NODE *subs) +{ + NODE *xn = symbol->xarray; + (void) array_func_call(symbol, subs, LOOKUP); + return xn->alookup(xn, subs); +} + +/* + * bind_array_exists --- test whether the array element symbol[subs] exists or not, + * return pointer to value if it does. + */ + +static NODE ** +bind_array_exists(NODE *symbol, NODE *subs) +{ + NODE *xn = symbol->xarray; + (void) array_func_call(symbol, subs, EXISTS); + return xn->aexists(xn, subs); +} + +/* bind_array_clear --- flush all the values in symbol[] */ + +static NODE ** +bind_array_clear(NODE *symbol, NODE *subs ATTRIBUTE_UNUSED) +{ + NODE *xn = symbol->xarray; + (void) xn->aclear(xn, NULL); + (void) array_func_call(symbol, NULL, CLEAR); + return NULL; +} + +/* bind_array_remove --- if subs is already in the table, remove it. */ + +static NODE ** +bind_array_remove(NODE *symbol, NODE *subs) +{ + NODE *xn = symbol->xarray; + (void) xn->aremove(xn, subs); + (void) array_func_call(symbol, subs, DELETE); + return NULL; +} + +/* bind_array_store --- update the value for the SUBS */ + +static NODE ** +bind_array_store(NODE *symbol, NODE *subs) +{ + (void) array_func_call(symbol, subs, STORE); + return NULL; +} + +/* bind_array_list --- return a list of array items */ + +static NODE** +bind_array_list(NODE *symbol, NODE *akind) +{ + NODE *xn = symbol->xarray; + (void) array_func_call(symbol, NULL, FETCHALL); + return xn->alist(xn, akind); +} + + +/* array_func_call --- call user-defined array routine */ + +static long +array_func_call(NODE *symbol, NODE *arg1, int fi) +{ + NODE *argp[3]; + NODE *retval; + long ret; + int i = 0; + array_t *aq; + + aq = symbol->a_opaque; + if (! aq) /* an array routine invoked from the same or another routine */ + fatal(_("bind_array: cannot access bound array, operation not allowed")); + symbol->a_opaque = NULL; /* avoid infinite recursion */ + + argp[i++] = symbol->xarray; + argp[i++] = aq->arg0; + if (arg1 != NULL) + argp[i++] = arg1; + + retval = call_func(aq->func[fi], argp, i); + symbol->a_opaque = aq; + force_number(retval); + ret = get_number_si(retval); + unref(retval); + if (ret < 0) { + if (ERRNO_node->var_value->stlen > 0) + fatal(_("%s"), ERRNO_node->var_value->stptr); + else + fatal(_("unknown reason")); + } + return ret; +} + +/* do_bind_array --- bind an array to user-defined functions */ + +static NODE * +do_bind_array(int nargs) +{ + NODE *symbol, *xn, *t, *td; + int i; + array_t *aq; + char *aname; + + symbol = get_array_argument(0, false); + if (symbol->array_funcs == bind_array_func) + fatal(_("bind_array: array `%s' already bound"), array_vname(symbol)); + + assoc_clear(symbol); + + emalloc(aq, array_t *, sizeof(array_t), "do_bind_array"); + memset(aq, '\0', sizeof(array_t)); + + t = get_array_argument(1, false); + + for (i = 0; i < sizeof(bfn)/sizeof(char *); i++) { + NODE *subs, *val, *f; + + subs = make_string(bfn[i], strlen(bfn[i])); + val = in_array(t, subs); + unref(subs); + if (val == NULL) { + if (i != INIT && i != FINI) + fatal(_("bind_array: array element `%s[\"%s\"]' not defined"), + t->vname, bfn[i]); + continue; + } + + force_string(val); + f = lookup(val->stptr); + if (f == NULL || f->type != Node_func) + fatal(_("bind_array: function `%s' is not defined"), val->stptr); + aq->func[i] = f; + } + + /* copy the array -- this is passed as the second argument to the functions */ + emalloc(aname, char *, strlen(t->vname) + 2, "do_bind_array"); + aname[0] = '~'; /* any illegal character */ + strcpy(& aname[1], symbol->vname); + td = make_array(); + td->vname = aname; + assoc_copy(t, td); + aq->arg0 = td; + + /* internal array for the actual storage */ + xn = make_array(); + xn->vname = symbol->vname; /* shallow copy */ + xn->flags |= XARRAY; + symbol->a_opaque = aq; + symbol->array_funcs = bind_array_func; + symbol->xarray = xn; + + if (aq->func[INIT] != NULL) + (void) array_func_call(symbol, NULL, INIT); + + return make_number(0); +} + +/* do_unbind_array --- unbind an array */ + +static NODE * +do_unbind_array(int nargs) +{ + NODE *symbol, *xn, *td; + array_t *aq; + + symbol = get_array_argument(0, false); + if (symbol->array_funcs != bind_array_func) + fatal(_("unbind_array: `%s' is not a bound array"), array_vname(symbol)); + + aq = symbol->a_opaque; + if (aq->func[FINI] != NULL) + (void) array_func_call(symbol, NULL, FINI); + + td = aq->arg0; + assoc_clear(td); + efree(td->vname); + freenode(td); + efree(aq); + + /* promote xarray to symbol */ + xn = symbol->xarray; + xn->flags &= ~XARRAY; + xn->parent_array = symbol->parent_array; + *symbol = *xn; + freenode(xn); + + return make_number(0); +} + + +/* call_func --- call a user-defined gawk function */ + +static NODE * +call_func(NODE *func, NODE **arg, int arg_count) +{ + NODE *ret; + INSTRUCTION *code; + extern int currule; + int i, save_rule = 0; + + if (arg_count > func->param_cnt) + fatal(_("function `%s' called with too many parameters"), func->vname); + + /* make function call instructions */ + code = bcalloc(Op_func_call, 2, 0); + code->func_body = func; + code->func_name = NULL; /* not needed, func_body already assigned */ + (code + 1)->expr_count = arg_count; + code->nexti = bcalloc(Op_stop, 1, 0); + + save_rule = currule; /* save current rule */ + currule = 0; + + /* push arguments onto stack */ + for (i = 0; i < arg_count; i++) { + if (arg[i]->type == Node_val) + UPREF(arg[i]); + PUSH(arg[i]); + } + + /* execute the function */ + (void) interpret(code); + + ret = POP_SCALAR(); /* the return value of the function */ + + /* restore current rule */ + currule = save_rule; + + /* free code */ + bcfree(code->nexti); + bcfree(code); + + return ret; +} + + +/* dlload --- load this library */ + +NODE * +dlload(NODE *obj, void *dl) +{ + make_old_builtin("bind_array", do_bind_array, 2); + make_old_builtin("unbind_array", do_unbind_array, 1); + return make_number((AWKNUM) 0); +} diff --git a/old-extension/dbarray.awk b/old-extension/dbarray.awk new file mode 100644 index 00000000..e0a3c093 --- /dev/null +++ b/old-extension/dbarray.awk @@ -0,0 +1,222 @@ +# dbarray.awk -- persistent array with sqlite database backend + +# @load "bindarr" + +BEGIN { + extension("bindarr") +} + +function _db_count(symbol, sq, + sth, ret, count) +{ + sth = sq["sqlc"] + printf "SELECT count(col1) FROM %s;\n", sq["table"] |& sth + close(sth, "to") + ret = (sth |& getline count) + if (close(sth) != 0 || ret <= 0) + return -1 + return count +} + +function _db_exists(symbol, sq, subs, + sth, ret, row, qsubs) +{ + if (! (subs in symbol)) { + sth = sq["sqlc"] + + # double up single quotes + qsubs = gensub(/'/, "''", "g", subs) + + printf "SELECT col2 FROM %s WHERE col1='%s';\n", sq["table"], qsubs |& sth + close(sth, "to") + ret = (sth |& getline row) + if (close(sth) != 0 || ret < 0) + return -1 + if (ret == 0) # non-existent row + return 0 + if (row == sq["null"]) + symbol[subs] # install null string as value + else + symbol[subs] = row + } + return 0 +} + +function _db_lookup(symbol, sq, subs, + sth, ret, row, qsubs) +{ + if (! (subs in symbol)) { + sth = sq["sqlc"] + + # double up single quotes + qsubs = gensub(/'/, "''", "g", subs) + + printf "SELECT col2 FROM %s WHERE col1='%s';\n", sq["table"], qsubs |& sth + close(sth, "to") + ret = (sth |& getline row) + if (close(sth) != 0 || ret < 0) + return -1 + + if (ret > 0) { + if (row == sq["null"]) + symbol[subs] # install null string as value + else + symbol[subs] = row + } else { + # Not there, install it with NULL as value + printf "INSERT INTO %s (col1) VALUES('%s');\n", sq["table"], qsubs |& sth + close(sth, "to") + ret = (sth |& getline) + if (close(sth) != 0 || ret < 0) + return -1 + } + } + return 0 +} + +function _db_clear(symbol, sq, + sth, ret) +{ + sth = sq["sqlc"] + printf "DELETE FROM %s;\n", sq["table"] |& sth + close(sth, "to") + ret = (sth |& getline) + if (close(sth) != 0 || ret < 0) + return -1 + return 0 +} + +function _db_delete(symbol, sq, subs, + sth, ret, qsubs) +{ + sth = sq["sqlc"] + qsubs = gensub(/'/, "''", "g", subs) + printf "DELETE FROM %s WHERE col1='%s';\n", sq["table"], qsubs |& sth + close(sth, "to") + ret = (sth |& getline) + if (close(sth) != 0 || ret < 0) + return -1 + return 0 +} + +function _db_store(symbol, sq, subs, + sth, ret, qsubs, qval) +{ + sth = sq["sqlc"] + + qval = gensub(/'/, "''", "g", symbol[subs]) + qsubs = gensub(/'/, "''", "g", subs) + printf "UPDATE %s SET col2='%s' WHERE col1='%s';\n", \ + sq["table"], qval, qsubs |& sth + close(sth, "to") + ret = (sth |& getline) + if (close(sth) != 0 || ret < 0) + return -1 + return 0 +} + +function _db_fetchall(symbol, sq, + sth, ret, save_RS, save_FS) +{ + sth = sq["sqlc2"] + + if (! sq["loaded"]) { + printf "SELECT col1, col2 FROM %s;\n", sq["table"] |& sth + close(sth, "to") + save_RS = RS + save_FS = FS + RS = "\n\n" + FS = "\n" + while ((ret = (sth |& getline)) > 0) { + sub(/^ *col1 = /, "", $1) + sub(/^ *col2 = /, "", $2) + if ($2 == sq["null"]) + symbol[$1] # install null string as value + else + symbol[$1] = $2 + } + RS = save_RS + FS = save_FS + if (ret < 0 || close(sth) != 0) + return -1 + sq["loaded"] = 1 + } +} + + +function _db_init(symbol, sq, + sth, table, ret) +{ + sth = sq["sqlc"] + table = sq["table"] + + # check if table exists + printf ".tables %s\n", table |& sth + close(sth, "to") + ret = (sth |& getline) + if (close(sth) != 0 || ret < 0) + return -1 + if (ret > 0 && $0 == table) { + # verify schema + printf ".schema %s\n", table |& sth + close(sth, "to") + ret = (sth |& getline) + if (close(sth) != 0 || ret <= 0) + return -1 + if ($0 !~ /\(col1 TEXT PRIMARY KEY, col2 TEXT\)/) { + printf "table %s: Invalid column name or type(s)\n", table > "/dev/stderr" + return -1 + } + } else { + # table does not exist, create it. + printf "CREATE TABLE %s (col1 TEXT PRIMARY KEY, col2 TEXT);\n", table |& sth + close(sth, "to") + ret = (sth |& getline) + if (close(sth) != 0 || ret < 0) + return -1 + } + return 0 +} + +#function _db_fini(tie, a, subs) {} + +function db_bind(arr, database, table, sq) +{ + if (! database) { + print "db_bind: must specify a database name" > "/dev/stderr" + exit(1) + } + + if (! table) { + print "db_bind: must specify a table name" > "/dev/stderr" + exit(1) + } + + # string used by the sqlite3 client to represent NULL + sq["null"] = "(null)" + + sq["sqlc"] = sprintf("sqlite3 -nullvalue '%s' %s", sq["null"], database) + # sqlite command used in _db_fetchall + sq["sqlc2"] = sprintf("sqlite3 -line -nullvalue '%s' %s", sq["null"], database) + + sq["table"] = table + + # register our array routines + sq["init"] = "_db_init" + sq["count"] = "_db_count" + sq["exists"] = "_db_exists" + sq["lookup"] = "_db_lookup" + sq["delete"] = "_db_delete" + sq["store"] = "_db_store" + sq["clear"] = "_db_clear" + sq["fetchall"] = "_db_fetchall" + +# sq["fini"] = "_db_fini"; + + bind_array(arr, sq) +} + +function db_unbind(arr) +{ + unbind_array(arr) +} diff --git a/old-extension/fileop.c b/old-extension/fileop.c new file mode 100644 index 00000000..86f62576 --- /dev/null +++ b/old-extension/fileop.c @@ -0,0 +1,394 @@ +/* + * fileop.c -- Builtin functions for binary I/O and other interfaces to + * the filesystem. + */ + +/* + * Copyright (C) 2012 the Free Software Foundation, Inc. + * + * This file is part of GAWK, the GNU implementation of the + * AWK Programming Language. + * + * GAWK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GAWK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "awk.h" + +int plugin_is_GPL_compatible; + +typedef struct file_struct { + struct file_struct *next; + FILE *fp; + int flags; + char path[1]; +} file_t; + +static file_t *files; +static file_t *file_open(const char *builtin_name, int nargs, int do_open); +static int mode2flags(const char *mode); + +/* do_fread --- read from file */ + +static NODE * +do_fread(int nargs) +{ + NODE *arg; + size_t rlen, count; + file_t *f; + char *rbuf; + + f = file_open("fread", nargs, true); + + arg = get_scalar_argument(2, false); + force_number(arg); + rlen = get_number_ui(arg); + + emalloc(rbuf, char *, rlen + 2, "do_fread"); + if ((count = fread(rbuf, 1, rlen, f->fp)) < rlen) { + if (! feof(f->fp)) + update_ERRNO_int(errno); + } + return make_str_node(rbuf, count, ALREADY_MALLOCED); +} + +/* do_fwrite --- write to file */ + +static NODE * +do_fwrite(int nargs) +{ + NODE *arg; + file_t *f; + size_t count = 0; + + f = file_open("fwrite", nargs, true); + + arg = get_scalar_argument(2, false); + force_string(arg); + if (arg->stlen > 0) { + count = fwrite(arg->stptr, 1, arg->stlen, f->fp); + if (count < arg->stlen) + update_ERRNO_int(errno); + } + return make_number(count); +} + +/* do_fseek --- set the file position indicator */ + +static NODE * +do_fseek(int nargs) +{ + NODE *arg; + long offset; + file_t *f; + int whence = 0, ret = 0; + + f = file_open("fseek", nargs, true); + + arg = get_scalar_argument(2, false); + force_number(arg); + offset = get_number_si(arg); + + arg = get_scalar_argument(3, false); + force_string(arg); + if (strcasecmp(arg->stptr, "SEEK_SET") == 0) + whence = SEEK_SET; + else if (strcasecmp(arg->stptr, "SEEK_CUR") == 0) + whence = SEEK_CUR; + else if (strcasecmp(arg->stptr, "SEEK_END") == 0) + whence = SEEK_END; + else + fatal(_("fseek: `%.*s' is not a valid 4th argument"), + (int) arg->stlen, arg->stptr); + + if (fseek(f->fp, offset, whence) < 0) { + update_ERRNO_int(errno); + ret = -1; + } + return make_number(ret); +} + +/* do_ftruncate --- truncate the file to a specified length */ + +static NODE * +do_ftruncate(int nargs) +{ + NODE *arg; + file_t *f; + off_t len; + int ret = 0; + + f = file_open("ftruncate", nargs, true); + arg = get_scalar_argument(2, false); + force_number(arg); + len = (off_t) get_number_si(arg); + if (ftruncate(fileno(f->fp), len) < 0) { + update_ERRNO_int(errno); + ret = -1; + } + return make_number(ret); +} + +/* do_unlink --- delete the name from the filesystem */ + +static NODE * +do_unlink(int nargs) +{ + NODE *file; + int ret = 0; + + file = get_scalar_argument(0, false); + force_string(file); + if (file->stlen == 0) + fatal(_("unlink: filename has empty string value")); + if (unlink(file->stptr) < 0) { + update_ERRNO_int(errno); + ret = -1; + } + return make_number(ret); +} + +/* do_flush --- flush buffered data to file */ + +static NODE * +do_flush(int nargs) +{ + file_t *f; + int status = -1; + + f = file_open("flush", nargs, false); + if (f != NULL) { + status = fflush(f->fp); + if (status != 0) + update_ERRNO_int(errno); + } + return make_number(status); +} + +/* do_fclose --- close an open file */ + +static NODE * +do_fclose(int nargs) +{ + file_t *f; + int status = -1; + + f = file_open("fclose", nargs, false); + if (f != NULL) { + status = fclose(f->fp); + if (status != 0) + update_ERRNO_int(errno); + assert(files == f); + files = f->next; + efree(f); + } + return make_number(status); +} + +/* do_filesize --- return the size of the file */ + +static NODE * +do_filesize(int nargs) +{ + NODE *file; + struct stat sbuf; + AWKNUM d = -1.0; + + file = get_scalar_argument(0, false); + force_string(file); + if (file->stlen == 0) + fatal(_("filesize: filename has empty string value")); + + if (stat(file->stptr, & sbuf) < 0) { + update_ERRNO_int(errno); + goto ferror; + } + if ((sbuf.st_mode & S_IFMT) != S_IFREG) { + errno = EINVAL; + update_ERRNO_int(errno); + goto ferror; + } + d = sbuf.st_size; + +ferror: + return make_number(d); +} + +/* do_file_exists --- check if path exists in the filesystem */ + +static NODE * +do_file_exists(int nargs) +{ + NODE *file; + struct stat sbuf; + int ret = 1; + + file = get_scalar_argument(0, false); + force_string(file); + if (file->stlen == 0) + fatal(_("file_exists: filename has empty string value")); + + if (stat(file->stptr, & sbuf) < 0) { + if (errno != ENOENT) + update_ERRNO_int(errno); + ret = 0; + } + return make_number(ret); +} + + +/* file_open --- open a file or find an already opened file */ + +static file_t * +file_open(const char *builtin_name, int nargs, int do_open) +{ + NODE *file, *mode; + file_t *f, *prev; + FILE *fp; + int flags; + char *path; + + if (nargs < 2) + cant_happen(); + + file = get_scalar_argument(0, false); + force_string(file); + mode = get_scalar_argument(1, true); + force_string(mode); + + if (file->stlen == 0) + fatal(_("%s: filename has empty string value"), builtin_name); + if (mode->stlen == 0) + fatal(_("%s: mode has empty string value"), builtin_name); + + flags = mode2flags(mode->stptr); + if (flags < 0) + fatal(_("%s: invalid mode `%.*s'"), builtin_name, + (int) mode->stlen, mode->stptr); + + path = file->stptr; + for (prev = NULL, f = files; f != NULL; prev = f, f = f->next) { + if (strcmp(f->path, path) == 0 && f->flags == flags) { + /* Move to the head of the list */ + if (prev != NULL) { + prev->next = f->next; + f->next = files; + files = f; + } + return f; + } + } + + if (! do_open) { + if (do_lint) + lintwarn(_("%s: `%.*s' is not an open file"), + builtin_name, (int) file->stlen, file->stptr); + return NULL; + } + + fp = fopen(path, mode->stptr); + if (fp == NULL) + fatal(_("%s: cannot open file `%.*s'"), + builtin_name, (int) file->stlen, file->stptr); + + os_close_on_exec(fileno(fp), path, "", ""); + + emalloc(f, file_t *, sizeof(file_t) + file->stlen + 1, "file_open"); + memcpy(f->path, path, file->stlen + 1); + f->fp = fp; + f->flags = flags; + f->next = files; + files = f; + return f; +} + + +/* + * mode2flags --- convert a string mode to an integer flag; + * modified from str2mode in io.c. + */ + +static int +mode2flags(const char *mode) +{ + int ret = -1; + const char *second; + + if (mode == NULL || mode[0] == '\0') + return -1; + + second = & mode[1]; + + if (*second == 'b') + second++; + + switch(mode[0]) { + case 'r': + ret = O_RDONLY; + if (*second == '+' || *second == 'w') + ret = O_RDWR; + break; + + case 'w': + ret = O_WRONLY|O_CREAT|O_TRUNC; + if (*second == '+' || *second == 'r') + ret = O_RDWR|O_CREAT|O_TRUNC; + break; + + case 'a': + ret = O_WRONLY|O_APPEND|O_CREAT; + if (*second == '+') + ret = O_RDWR|O_APPEND|O_CREAT; + break; + + default: + ret = -1; + } + if (ret != -1 && strchr(mode, 'b') != NULL) + ret |= O_BINARY; + return ret; +} + + +/* dlload --- load new builtins in this library */ + +NODE * +dlload(NODE *tree, void *dl) +{ + make_old_builtin("fseek", do_fseek, 4); + make_old_builtin("fread", do_fread, 3); + make_old_builtin("fwrite", do_fwrite, 3); + make_old_builtin("flush", do_flush, 2); + make_old_builtin("filesize", do_filesize, 1); + make_old_builtin("file_exists", do_file_exists, 1); + make_old_builtin("fclose", do_fclose, 2); + make_old_builtin("ftruncate", do_ftruncate, 3); + make_old_builtin("unlink", do_unlink, 1); + return make_number((AWKNUM) 0); +} + + +/* dlunload --- routine called when exiting */ + +void +dlunload() +{ + file_t *f; + for (f = files; f != NULL; f = f->next) { + if (f->fp != NULL) { + fclose(f->fp); + f->fp = NULL; + } + } +} diff --git a/old-extension/record.awk b/old-extension/record.awk new file mode 100644 index 00000000..18a3ce48 --- /dev/null +++ b/old-extension/record.awk @@ -0,0 +1,252 @@ +# record.awk -- represent fixed-length records in a file as an array. +# Each element in the array corresponds to a record in the file. +# The records are numbered starting from 1, and each record read in +# from the file is cached. If opened using mode "r+", +# changes to the array are reflected in the file immediately i.e. +# writing to an element writes the data into the file. +# +# Usage: +# record(r, path [, reclen [, mode]]) +# r -- array to bind +# path -- filename +# reclen -- length of each record +# mode -- "r" for reading (default), "r+" for reading and writing +# +# With reclen <= 0, entire file is treated as one record #1. +# +# record(r, "data.in", 80, "r+") +# r[10] = r[1] +# for (i = 1; i in r; i++) +# print r[i] +# delete r[1] +# +# See Also: testrecord.sh +# +# +# TODO: +# * implement deferred writing +# * limit memory usage for read cache +# * use fixed size buffer when deleting a record +# + +BEGIN { + extension("fileop.so") + extension("bindarr.so") +} + +# _record_count --- return the number of records in file + +function _record_count(symbol, rd) +{ + if (! ("rectot" in rd)) + rd["rectot"] = ("reclen" in rd) ? + int(filesize(rd["path"]) / rd["reclen"]) : 1 + return rd["rectot"] +} + +# _record_exists --- check if record exists + +function _record_exists(symbol, rd, recnum, + path, mode, reclen, rectot) +{ + path = rd["path"] + reclen = ("reclen" in rd) ? rd["reclen"] : filesize(path) + mode = rd["mode"] + rectot = _record_count(symbol, rd) + + recnum = int(recnum) + if (recnum <= 0 || recnum > rectot) + return 0 + + if (! (recnum in symbol)) { + fseek(path, mode, (recnum - 1) * reclen, "SEEK_SET") + symbol[recnum] = fread(path, mode, reclen) + } + return 0 +} + +# _record_lookup --- lookup a record + +function _record_lookup(symbol, rd, recnum, + path, mode, reclen, rectot) +{ + path = rd["path"] + reclen = ("reclen" in rd) ? rd["reclen"] : filesize(path) + mode = rd["mode"] + rectot = _record_count(symbol, rd) + + recnum = int(recnum) + if (recnum <= 0 || recnum > rectot) { + ERRNO = sprintf("record: %s: reference to non-existent record #%d", path, recnum) + return -1 + } + + if (! (recnum in symbol)) { + fseek(path, mode, (recnum - 1) * reclen, "SEEK_SET") + symbol[recnum] = fread(path, mode, reclen) + } + return 0 +} + +# _record_clear --- remove all records + +function _record_clear(symbol, rd, + path, mode) +{ + path = rd["path"] + mode = rd["mode"] + if (mode == "r") { + ERRNO = sprintf("record: cannot delete record from file `%s' opened only for reading", path) + return -1 + } + ftruncate(path, mode, 0) + delete rd["reclen"] + return 0 +} + +# _record_delete --- delete a record from the file + +function _record_delete(symbol, rd, recnum, + path, mode, reclen, rectot) +{ + path = rd["path"] + reclen = ("reclen" in rd) ? rd["reclen"] : filesize(path) + mode = rd["mode"] + + if (mode == "r") { + ERRNO = sprintf("record: cannot delete record from file `%s' opened only for reading", path) + return -1 + } + + recnum = int(recnum) + if (! ("reclen" in rd)) { + # entire file is record #1 + ftruncate(path, mode, 0) + delete rd["reclen"] + return 0 + } + + sz = filesize(path) + rectot = int(sz / reclen) + + recstart = (recnum - 1) * reclen + off = sz - (recstart + reclen) + + fseek(path, mode, -off, "SEEK_END") + tmp = fread(path, mode, off) + fseek(path, mode, recstart, "SEEK_SET") + if (fwrite(path, mode, tmp) != length(tmp)) + return -1 + flush(path, mode) + ftruncate(path, mode, sz - reclen) + + rd["rectot"] = rectot - 1 + for (i = recnum + 1; i <= rectot; i++) { + if (i in symbol) { + symbol[i - 1] = symbol[i] + delete symbol[i] + } + } + return 0 +} + +# _record_store --- write a record to file + +function _record_store(symbol, rd, recnum, + path, mode, reclen, val) +{ + path = rd["path"] + reclen = ("reclen" in rd) ? rd["reclen"] : filesize(path) + mode = rd["mode"] + + if (mode == "r") { + ERRNO = sprintf("record: cannot write to file `%s' opened only for reading", path) + return -1 + } + + recnum = int(recnum) + val = symbol[recnum] + if (! ("reclen" in rd)) { + # the entire file is record #1 + if (reclen != 0) + ftruncate(path, mode, 0) + } else if (length(val) != reclen) { + ERRNO = sprintf("record: %s: invalid length for record #%d", path, recnum) + return -1 + } + + fseek(path, mode, (recnum - 1) * reclen, "SEEK_SET") + if (fwrite(path, mode, val) != length(val)) + return -1 + flush(path, mode) + return 0 +} + +# _record_fetchall --- retrieve all the records + +function _record_fetchall(symbol, rd, + path, mode, reclen, rectot, recnum) +{ + path = rd["path"] + reclen = ("reclen" in rd) ? rd["reclen"] : filesize(path) + mode = rd["mode"] + rectot = _record_count(symbol, rd) + + if (rd["loaded"]) + return 0 + for (recnum = 1; recnum <= rectot; recnum++) { + if (! (recnum in symbol)) { + fseek(path, mode, (recnum - 1) * reclen, "SEEK_SET") + symbol[recnum] = fread(path, mode, reclen) + } + } + rd["loaded"] = 1 + return 0 +} + +# _record_init --- initialization routine + +function _record_init(symbol, rd) +{ + if (! file_exists(rd["path"])) { + ERRNO = sprintf("record: cannot open file `%s' for reading", rd["path"]) + return -1 + } + return 0 +} + +# _record_fini --- cleanup routine + +function _record_fini(symbol, rd) +{ + fclose(rd["path"], rd["mode"]) +} + +# record --- bind an array to a file with fixed-length records + +function record(array, path, reclen, mode, rd) +{ + if (path == "") { + print "fatal: record: empty string value for filename" > "/dev/stderr" + exit(1) + } + + # register our array routines + rd["init"] = "_record_init" + rd["fini"] = "_record_fini" + rd["count"] = "_record_count" + rd["exists"] = "_record_exists" + rd["lookup"] = "_record_lookup" + rd["delete"] = "_record_delete" + rd["store"] = "_record_store" + rd["clear"] = "_record_clear" + rd["fetchall"] = "_record_fetchall" + + rd["path"] = path + if (reclen > 0) + rd["reclen"] = reclen + rd["mode"] = mode == "r+" ? "r+" : "r" + + delete array + bind_array(array, rd) +} diff --git a/old-extension/sparr.c b/old-extension/sparr.c new file mode 100644 index 00000000..a3d06e66 --- /dev/null +++ b/old-extension/sparr.c @@ -0,0 +1,163 @@ +/* + * sparr.c - Example of changing behavior of arrays in gawk. + * See testsparr.awk for usage. + */ + +/* + * Copyright (C) 2012 the Free Software Foundation, Inc. + * + * This file is part of GAWK, the GNU implementation of the + * AWK Programming Language. + * + * GAWK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GAWK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#include "awk.h" +#include "spec_array.h" + +int plugin_is_GPL_compatible; + +typedef struct { + int load_file; + NODE *filename; +} sdata_t; + +/* install_array --- install an array in the symbol table */ + +static NODE * +install_array(const char *name) +{ + NODE *r; + + r = lookup(name); + if (r == NULL) + r = install_symbol(estrdup(name, strlen(name)), Node_var_array); + switch (r->type) { + case Node_var_new: + r = force_array(r, false); + /* fall through */ + case Node_var_array: + assoc_clear(r); + break; + default: + fatal(_("`%s' is not an array"), name); + } + return r; +} + +/* fetch_SYS --- fetch routine for the array `SYS' */ + +static NODE * +fetch_SYS(NODE *symbol, NODE *subs, void *data) +{ + force_string(subs); + if (strcmp(subs->stptr, "time") == 0) + return do_strftime(0); + return NULL; +} + +/* store_SYS --- store routine for the array `SYS' */ + +static void +store_SYS(NODE *symbol, NODE *subs, NODE *val, void *data) +{ + sdata_t *sd = (sdata_t *) data; + + if (subs != NULL && val != NULL && val->type == Node_val) { + force_string(subs); + if (strcmp(subs->stptr, "readline") == 0) { + sd->load_file = true; + unref(sd->filename); + sd->filename = dupnode(val); + } + } +} + +/* load_READLINE --- load routine for the array `READLINE' */ + +static void +load_READLINE(NODE *symbol, void *data) +{ + sdata_t *sd = (sdata_t *) data; + NODE *file, *tmp; + FILE *fp; + static char linebuf[BUFSIZ]; + int i; + bool long_line = false; + + if (! sd->load_file) /* non-existent SYS["readline"] or already loaded */ + return; + + file = sd->filename; + force_string(file); + + if (file->stlen == 0) + return; + + assoc_clear(symbol); + + if ((fp = fopen(file->stptr, "r" )) == NULL) { + warning(_("READLINE (%s): %s"), file->stptr, strerror(errno)); + return; + } + + for (i = 1; fgets(linebuf, sizeof(linebuf), fp ) != NULL; i++) { + NODE **lhs; + size_t sz; + + sz = strlen(linebuf); + if (sz > 0 && linebuf[sz - 1] == '\n') { + linebuf[sz - 1] = '\0'; + sz--; + if (long_line) { + long_line = false; + i--; + continue; + } + } else if (long_line) { + i--; + continue; + } else { + if (do_lint) + lintwarn(_("file `%s' does not end in newline or line # `%d' is too long"), + file->stptr, i); + long_line = true; + } + + tmp = make_number(i); + lhs = assoc_lookup(symbol, tmp); + unref(tmp); + unref(*lhs); + *lhs = make_string(linebuf, sz); + } + fclose(fp); + sd->load_file = false; /* don't load this file again */ +} + +/* dlload --- load this library */ + +NODE * +dlload(NODE *obj, void *dl) +{ + NODE *a1, *a2; + static sdata_t data; + + a1 = install_array("SYS"); + register_dyn_array(a1, fetch_SYS, store_SYS, & data); + a2 = install_array("READLINE"); + register_deferred_array(a2, load_READLINE, & data); + return make_number((AWKNUM) 0); +} diff --git a/old-extension/spec_array.c b/old-extension/spec_array.c new file mode 100644 index 00000000..78b24018 --- /dev/null +++ b/old-extension/spec_array.c @@ -0,0 +1,416 @@ +/* + * spec_array.c - Support for specialized associative arrays. + */ + +/* + * Copyright (C) 2012 the Free Software Foundation, Inc. + * + * This file is part of GAWK, the GNU implementation of the + * AWK Programming Language. + * + * GAWK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GAWK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "awk.h" +#include "spec_array.h" + +typedef struct spec_array { + Fetch_func_t fetch_func; + Store_func_t store_func; + Load_func_t load_func; + void *data; +} array_t; + +/* + * The array_t structure is attached to the array itself without + * the necessity to maintain a list of symbols; this works only + * because there is just enough free space in the NODE strcture when + * the base array is str_array. + */ + +#define SUPER(F) (*str_array_func[AFUNC(F)]) + + +/* + * deferred_array --- Deferred loading of array at run-time. + * + * The load routine takes two arguments, the array and + * a void * data: + * + * void load_func(NODE *array, void *data) + * + * Use register_deferred_array(array, load_func, void *data) to + * bind an array to the load routine. + */ + +static NODE **deferred_array_init(NODE *, NODE *); +static NODE **deferred_array_lookup(NODE *, NODE *); +static NODE **deferred_array_exists(NODE *, NODE *); +static NODE **deferred_array_remove(NODE *, NODE *); +static NODE **deferred_array_clear(NODE *, NODE *); +static NODE **deferred_array_list(NODE *, NODE *); +static NODE **deferred_array_copy(NODE *, NODE *); +static NODE **deferred_array_length(NODE *, NODE *); + +static afunc_t deferred_array_func[] = { + deferred_array_init, + (afunc_t) 0, /* typeof */ + deferred_array_length, + deferred_array_lookup, + deferred_array_exists, + deferred_array_clear, + deferred_array_remove, + deferred_array_list, + deferred_array_copy, + null_afunc, /* dump */ + (afunc_t) 0, /* store */ +}; + + +/* deferred_array_init --- called when array becomes empty, e.g: delete BOUND_ARRAY */ + +static NODE ** +deferred_array_init(NODE *symbol, NODE *subs) +{ + if (symbol != NULL) { + array_t *av = (array_t *) symbol->xarray; + symbol->xarray = NULL; /* this is to avoid an assertion failure in null_array */ + null_array(symbol); /* typeless empty array */ + if (symbol->parent_array == NULL) { + /* main array */ + symbol->array_funcs = deferred_array_func; /* restore type */ + symbol->xarray = (NODE *) av; + } else if (av) /* sub-array */ + efree(av); + } + return NULL; +} + +/* deferred_array_length --- get the length of the array */ + +static NODE ** +deferred_array_length(NODE *symbol, NODE *subs) +{ + static NODE *length_node; + array_t *av = (array_t *) symbol->xarray; + if (av) { + symbol->xarray = NULL; + (*av->load_func)(symbol, av->data); + symbol->xarray = (NODE *) av; + } + length_node = symbol; + return & length_node; +} + +#define DEF_ARR(F) static NODE ** \ +deferred_array_##F(NODE *symbol, NODE *subs) \ +{ \ + array_t *av = (array_t *) symbol->xarray; \ + if (av) { \ + symbol->xarray = NULL; \ + (*av->load_func)(symbol, av->data); \ + symbol->xarray = (NODE *) av; \ + } \ + return SUPER(a##F)(symbol, subs); \ +} + +/* the rest of the routines */ + +DEF_ARR(exists) +DEF_ARR(lookup) +DEF_ARR(list) +DEF_ARR(copy) + +#undef DEF_ARR + +/* deferred_array_remove --- remove the index from the array */ + +static NODE ** +deferred_array_remove(NODE *symbol, NODE *subs) +{ + array_t *av = (array_t *) symbol->xarray; + + (void) SUPER(aremove)(symbol, subs); + if (av) { + symbol->xarray = NULL; + (*av->load_func)(symbol, av->data); + symbol->xarray = (NODE *) av; + } + return NULL; +} + +/* deferred_array_clear --- flush all the values in symbol[] */ + +static NODE ** +deferred_array_clear(NODE *symbol, NODE *subs) +{ + array_t *av = (array_t *) symbol->xarray; + + (void) SUPER(aclear)(symbol, subs); + if (av) { + symbol->xarray = NULL; + (*av->load_func)(symbol, av->data); + symbol->xarray = (NODE *) av; + } + return NULL; +} + + +/* + * dyn_array --- array with triggers for reading and writing + * an element. + * + * The fetch routine should expect three arguments, the array, + * the subscript and optional void * data. It should return the value + * if it exists or NULL otherwise. + * + * NODE *fetch_func(NODE *array, NODE *subs, void *data) + * + * The store routine must take an additional argument for the + * value. The value can be NULL if the specific element is + * removed from the array. The subscript (and the value) is NULL + * when the entire array is deleted. + * + * void store_func(NODE *array, NODE *subs, NODE *value, void *data) + * + * Use register_dyn_array(array, fetch_func, store_func, void *data) to + * bind an array to the fetch/store routine. + */ + + +static NODE **dyn_array_init(NODE *, NODE *); +static NODE **dyn_array_lookup(NODE *, NODE *); +static NODE **dyn_array_exists(NODE *, NODE *); +static NODE **dyn_array_remove(NODE *, NODE *); +static NODE **dyn_array_clear(NODE *, NODE *); +static NODE **dyn_array_list(NODE *, NODE *); +static NODE **dyn_array_copy(NODE *, NODE *); +static NODE **dyn_array_store(NODE *, NODE *); + +static afunc_t dyn_array_func[] = { + dyn_array_init, + (afunc_t) 0, /* typeof */ + null_length, /* length */ + dyn_array_lookup, + dyn_array_exists, + dyn_array_clear, + dyn_array_remove, + dyn_array_list, + dyn_array_copy, + null_afunc, /* dump */ + dyn_array_store, +}; + +/* dyn_array_init --- called when array becomes empty */ + +static NODE ** +dyn_array_init(NODE *symbol, NODE *subs) +{ + if (symbol != NULL) { + array_t *av = (array_t *) symbol->xarray; + symbol->xarray = NULL; + null_array(symbol); /* typeless empty array */ + if (symbol->parent_array == NULL) { + /* main array */ + symbol->array_funcs = dyn_array_func; /* restore type */ + symbol->xarray = (NODE *) av; + } else if (av) /* sub-array */ + efree(av); + } + return NULL; +} + +/* dyn_array_exists --- check if the SUBS exists */ + +static NODE ** +dyn_array_exists(NODE *symbol, NODE *subs) +{ + NODE *r; + array_t *av = (array_t *) symbol->xarray; + + if (av && av->fetch_func) { + symbol->xarray = NULL; + r = (*av->fetch_func)(symbol, subs, av->data); + symbol->xarray = (NODE *) av; + if (r != NULL) { + NODE **lhs; + lhs = SUPER(alookup)(symbol, subs); + unref(*lhs); + *lhs = r; + return lhs; + } + } + + return SUPER(aexists)(symbol, subs); +} + +/* dyn_array_lookup --- lookup SUBS and return a pointer to store its value */ + +static NODE ** +dyn_array_lookup(NODE *symbol, NODE *subs) +{ + NODE **lhs; + NODE *r; + array_t *av = (array_t *) symbol->xarray; + + lhs = SUPER(alookup)(symbol, subs); + if (av && av->fetch_func) { + symbol->xarray = NULL; + r = (*av->fetch_func)(symbol, subs, av->data); + symbol->xarray = (NODE *) av; + if (r != NULL) { + unref(*lhs); + *lhs = r; + } + } + return lhs; +} + +/* dyn_array_store --- call the store routine after an assignment */ + +static NODE ** +dyn_array_store(NODE *symbol, NODE *subs) +{ + array_t *av = (array_t *) symbol->xarray; + + if (av && av->store_func) { + NODE **lhs; + lhs = SUPER(aexists)(symbol, subs); + symbol->xarray = NULL; + (*av->store_func)(symbol, subs, *lhs, av->data); + symbol->xarray = (NODE *) av; + } + return NULL; +} + +/* dyn_array_remove --- remove the index from the array */ + +static NODE ** +dyn_array_remove(NODE *symbol, NODE *subs) +{ + array_t *av = (array_t *) symbol->xarray; + + (void) SUPER(aremove)(symbol, subs); + if (av && av->store_func) { + symbol->xarray = NULL; + (*av->store_func)(symbol, subs, NULL, av->data); + symbol->xarray = (NODE *) av; + } + return NULL; +} + +/* dyn_array_clear --- flush all the values in symbol[] */ + +static NODE ** +dyn_array_clear(NODE *symbol, NODE *subs) +{ + array_t *av = (array_t *) symbol->xarray; + + (void) SUPER(aclear)(symbol, subs); + if (av && av->store_func) { + symbol->xarray = NULL; + (*av->store_func)(symbol, NULL, NULL, av->data); + symbol->xarray = (NODE *) av; + } + return NULL; +} + +/* dyn_array_list --- return a list of items in symbol[] */ + +static NODE ** +dyn_array_list(NODE *symbol, NODE *subs) +{ + return SUPER(alist)(symbol, subs); +} + +/* dyn_array_copy --- duplicate the array */ + +static NODE ** +dyn_array_copy(NODE *symbol, NODE *subs) +{ + return SUPER(acopy)(symbol, subs); +} + +/* register_array_s --- attach the specified routine(s) to an array */ + +static void +register_array_s(NODE *symbol, Fetch_func_t fetch_func, + Store_func_t store_func, Load_func_t load_func, void *data) +{ + array_t *av; + + if (symbol->type != Node_var_array) + fatal(_("register_array_s: argument is not an array")); + + if (symbol->array_funcs == deferred_array_func + || symbol->array_funcs == dyn_array_func) + fatal(_("register_array_s: `%s' already is a deferred/dyn array"), + array_vname(symbol)); + + assoc_clear(symbol); + assert(symbol->xarray == NULL); + emalloc(av, array_t *, sizeof (array_t), "register_spec_array"); + av->fetch_func = fetch_func; + av->store_func = store_func; + av->load_func = load_func; + av->data = data; + symbol->xarray = (NODE *) av; +} + +/* register_deferred_array --- make the array to be loaded at run-time */ + +void +register_deferred_array(NODE *symbol, Load_func_t load_func, void *dq) +{ + if (! load_func) + fatal(_("register_deferred_array: null load function")); + register_array_s(symbol, 0, 0, load_func, dq); + symbol->array_funcs = deferred_array_func; +} + +/* register_dyn_array --- attach read and write triggers to an array */ + +void +register_dyn_array(NODE *symbol, Fetch_func_t fetch_func, + Store_func_t store_func, void *dq) +{ + register_array_s(symbol, fetch_func, store_func, 0, dq); + symbol->array_funcs = dyn_array_func; +} + +/* unregister_array_s --- un-special the array */ + +void * +unregister_array_s(NODE *symbol) +{ + void *data = NULL; + if (symbol->type != Node_var_array) + fatal(_("unregister_array_s: argument is not an array")); + + if (symbol->array_funcs == dyn_array_func + || symbol->array_funcs == deferred_array_func + ) { + array_t *av; + + av = (array_t *) symbol->xarray; + assert(av != NULL); + data = av->data; + efree(av); + symbol->array_funcs = str_array_func; + symbol->xarray = NULL; + /* FIXME: do we assoc_clear the array ? */ + } + return data; +} diff --git a/old-extension/spec_array.h b/old-extension/spec_array.h new file mode 100644 index 00000000..f75fc7ce --- /dev/null +++ b/old-extension/spec_array.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2012 the Free Software Foundation, Inc. + * + * This file is part of GAWK, the GNU implementation of the + * AWK Programming Language. + * + * GAWK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GAWK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +typedef NODE *(*Fetch_func_t)(NODE *, NODE *, void *); +typedef void(*Store_func_t)(NODE *, NODE *, NODE *, void *); +typedef void(*Load_func_t)(NODE *, void *); +extern void register_dyn_array(NODE *, Fetch_func_t, Store_func_t, void *); +extern void register_deferred_array(NODE *, Load_func_t, void *); +extern void *unregister_array_s(NODE *); diff --git a/old-extension/steps b/old-extension/steps new file mode 100755 index 00000000..3e8070d6 --- /dev/null +++ b/old-extension/steps @@ -0,0 +1,10 @@ +# what to do under linux to make dl.so +# Sun Nov 25 21:40:49 IST 2012 + +gcc -fPIC -shared -Wall -DGAWK -DHAVE_CONFIG_H -c -O -g -I.. spec_array.c +gcc -fPIC -shared -Wall -DGAWK -DHAVE_CONFIG_H -c -O -g -I.. sparr.c +gcc -fPIC -shared -Wall -DGAWK -DHAVE_CONFIG_H -c -O -g -I.. bindarr.c +gcc -fPIC -shared -Wall -DGAWK -DHAVE_CONFIG_H -c -O -g -I.. fileop.c +gcc -o sparr.so -shared sparr.o spec_array.o +gcc -o bindarr.so -shared bindarr.o +gcc -o fileop.so -shared fileop.o diff --git a/old-extension/testdbarray.awk b/old-extension/testdbarray.awk new file mode 100644 index 00000000..fd7fd595 --- /dev/null +++ b/old-extension/testdbarray.awk @@ -0,0 +1,21 @@ +@include "dbarray.awk" + +# $ ../gawk -f testdbarray.awk +# $ ../gawk -f testdbarray.awk +# ... +# $ ../gawk -vINIT=1 -f testdbarray.awk + + +BEGIN { + # bind array 'A' to the table 'table_A' in sqlite3 database 'testdb' + db_bind(A, "testdb", "table_A") + + if (INIT) # detele table and start over + delete A + + lenA = length(A) + A[++lenA] = strftime() + PROCINFO["sorted_in"] = "@ind_num_asc" + for (item in A) + print item, ":", A[item] +} diff --git a/old-extension/testrecord.sh b/old-extension/testrecord.sh new file mode 100755 index 00000000..61d1ba76 --- /dev/null +++ b/old-extension/testrecord.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +AWK=../gawk +$AWK 'BEGIN { OFS = ORS = ""; for (j = 1; j <= 4; j++) for (i = 1; i <= 16; i++) print j}' > _rec.in +for i in 1 2 3 4 5 +do +$AWK -f record.awk -vinfile='_rec.in' -e 'BEGIN { +reclen = 16 +record(r, infile, reclen, "r+") +FIELDWIDTHS="8 4 4" +for (i = 1; i in r; i++) { + $0 = r[i] + print $1 +} +delete r[1] +unbind_array(r) +print "--" }' +done +rm -f _rec.in diff --git a/old-extension/testsparr.awk b/old-extension/testsparr.awk new file mode 100644 index 00000000..648a21a2 --- /dev/null +++ b/old-extension/testsparr.awk @@ -0,0 +1,18 @@ +# ../gawk -lsparr -f testsparr.awk +BEGIN { + extension("sparr") + print SYS["time"] + SYS["readline"] = "sparr.c"; + printf("File %s has %d lines\n", SYS["readline"], length(READLINE)) + SYS["readline"] = "testsparr.awk"; + printf("File %s has %d lines\n", SYS["readline"], length(READLINE)) + for (i = 1; i in READLINE; i++) + print READLINE[i] + + system("sleep 1") + +# PROCINFO["/dev/stdin", "READ_TIMEOUT"] = 1000 +# getline < "/dev/stdin" + + print SYS["time"] +} |