diff options
author | john haque <j.eh@mchsi.com> | 2012-05-02 08:05:43 -0500 |
---|---|---|
committer | john haque <j.eh@mchsi.com> | 2012-05-02 08:05:43 -0500 |
commit | 3a8c139d1a28651bf222b05cb0895bf5066bb9f9 (patch) | |
tree | cbe9b6c918bef7439f6c321925c30066e6103771 | |
parent | 50c2afd6433f1c4407b04d2f75e536da7c94fe74 (diff) | |
download | egawk-3a8c139d1a28651bf222b05cb0895bf5066bb9f9.tar.gz egawk-3a8c139d1a28651bf222b05cb0895bf5066bb9f9.tar.bz2 egawk-3a8c139d1a28651bf222b05cb0895bf5066bb9f9.zip |
Fix memory corruption in copying an array, add another array extension.
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | extension/ChangeLog | 5 | ||||
-rw-r--r-- | extension/bindarr.c | 339 | ||||
-rw-r--r-- | extension/dbarray.awk | 222 | ||||
-rwxr-xr-x | extension/steps | 2 | ||||
-rw-r--r-- | extension/testdbarray.awk | 21 | ||||
-rw-r--r-- | int_array.c | 1 | ||||
-rw-r--r-- | po/da.gmo | bin | 46123 -> 46123 bytes | |||
-rw-r--r-- | po/da.po | 6 | ||||
-rw-r--r-- | po/de.gmo | bin | 49358 -> 49358 bytes | |||
-rw-r--r-- | po/de.po | 26 | ||||
-rw-r--r-- | po/es.gmo | bin | 48746 -> 48746 bytes | |||
-rw-r--r-- | po/es.po | 14 | ||||
-rw-r--r-- | po/fi.gmo | bin | 48930 -> 48930 bytes | |||
-rw-r--r-- | po/fi.po | 2 | ||||
-rw-r--r-- | str_array.c | 1 |
16 files changed, 619 insertions, 26 deletions
@@ -1,3 +1,9 @@ +2012-05-02 John Haque <j.eh@mchsi.com> + + * str_array.c (str_copy): Initialize next pointer in the linked list + to avoid memory corruption. + * int_array.c (int_copy): Ditto. + 2012-04-21 John Haque <j.eh@mchsi.com> Shutdown routine for a dynamic extension. diff --git a/extension/ChangeLog b/extension/ChangeLog index 75dc66a4..6fdd40e5 100644 --- a/extension/ChangeLog +++ b/extension/ChangeLog @@ -1,3 +1,8 @@ +2011-05-02 John Haque <j.eh@mchsi.com> + + * bindarr.c, dbarray.awk, testdbarray.awk: New files. + * steps: Updated. + 2011-04-24 John Haque <j.eh@mchsi.com> * spec_array.c, spec_array.h, sparr.c, testsparr.awk: New files. diff --git a/extension/bindarr.c b/extension/bindarr.c new file mode 100644 index 00000000..f500b748 --- /dev/null +++ b/extension/bindarr.c @@ -0,0 +1,339 @@ +/* + * 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) array_func_call(symbol, NULL, CLEAR); + return xn->aclear(xn, 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) array_func_call(symbol, subs, DELETE); + return xn->aremove(xn, subs); +} + +/* 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) + fatal(ERRNO_node->var_value->stlen > 0 ? + _("%s"), ERRNO_node->var_value->stptr : + _("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); + 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_builtin("bind_array", do_bind_array, 2); + make_builtin("unbind_array", do_unbind_array, 1); + return make_number((AWKNUM) 0); +} diff --git a/extension/dbarray.awk b/extension/dbarray.awk new file mode 100644 index 00000000..e0a3c093 --- /dev/null +++ b/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/extension/steps b/extension/steps index 0cd0042a..1abab9d2 100755 --- a/extension/steps +++ b/extension/steps @@ -15,6 +15,7 @@ gcc -fPIC -shared -Wall -DHAVE_CONFIG_H -c -O -g -I.. testarg.c gcc -fPIC -shared -Wall -DHAVE_CONFIG_H -c -O -g -I.. rwarray.c gcc -fPIC -shared -Wall -DHAVE_CONFIG_H -c -O -g -I.. spec_array.c gcc -fPIC -shared -Wall -DHAVE_CONFIG_H -c -O -g -I.. sparr.c +gcc -fPIC -shared -Wall -DHAVE_CONFIG_H -c -O -g -I.. bindarr.c ld -o dl.so -shared dl.o ld -o filefuncs.so -shared filefuncs.o ld -o fork.so -shared fork.o @@ -24,3 +25,4 @@ ld -o readfile.so -shared readfile.o ld -o testarg.so -shared testarg.o ld -o rwarray.so -shared rwarray.o ld -o sparr.so -shared sparr.o spec_array.o +ld -o bindarr.so -shared bindarr.o diff --git a/extension/testdbarray.awk b/extension/testdbarray.awk new file mode 100644 index 00000000..fd7fd595 --- /dev/null +++ b/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/int_array.c b/int_array.c index 7b8b261a..1f19b14f 100644 --- a/int_array.c +++ b/int_array.c @@ -425,6 +425,7 @@ int_copy(NODE *symbol, NODE *newsymb) } *pnew = newchain; + newchain->ainext = NULL; pnew = & newchain->ainext; } } Binary files differ@@ -14,10 +14,10 @@ msgstr "" "PO-Revision-Date: 2012-02-06 10:37+0100\n" "Last-Translator: Keld Simonsen <keld@keldix.com>\n" "Language-Team: Danish <dansk@dansk-gruppen.dk>\n" -"Language: da\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-1\n" "Content-Transfer-Encoding: 8bit\n" +"Language: da\n" "X-Generator: Lokalize 1.0\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -1032,8 +1032,8 @@ msgstr "atalt: extension: kan ikke åbne '%s' (%s)\n" msgid "" "extension: library `%s': does not define `plugin_is_GPL_compatible' (%s)\n" msgstr "" -"fatalt: extension: bibliotek '%s': definer ikke " -"'plugin_is_GPL_compatible' (%s)\n" +"fatalt: extension: bibliotek '%s': definer ikke 'plugin_is_GPL_compatible' (%" +"s)\n" #: ext.c:91 #, fuzzy, c-format Binary files differ@@ -12,10 +12,10 @@ msgstr "" "PO-Revision-Date: 2012-01-30 16:21+0100\n" "Last-Translator: Philipp Thomas <pth@suse.de>\n" "Language-Team: German <translation-team-de@lists.sourceforge.net>\n" -"Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: de\n" #: array.c:267 #, c-format @@ -129,8 +129,8 @@ msgstr "»%s« ist eine eingebaute Funktion und kann nicht umdefiniert werden" #: awkgram.y:389 msgid "regexp constant `//' looks like a C++ comment, but is not" msgstr "" -"Die Regulärer-Ausdruck-Konstante »//« sieht wie ein C-Kommentar aus, ist " -"aber keiner" +"Die Regulärer-Ausdruck-Konstante »//« sieht wie ein C-Kommentar aus, ist aber " +"keiner" #: awkgram.y:393 #, c-format @@ -467,8 +467,8 @@ msgstr "Funktion »%s«: Funktionsnamen können nicht als Parameternamen benutze #, c-format msgid "function `%s': can't use special variable `%s' as a function parameter" msgstr "" -"Funktion »%s«: die spezielle Variable »%s« kann nicht als Parameter " -"verwendet werden" +"Funktion »%s«: die spezielle Variable »%s« kann nicht als Parameter verwendet " +"werden" #: awkgram.y:4055 #, c-format @@ -538,8 +538,7 @@ msgstr "" #, c-format msgid "fflush: cannot flush: file `%s' opened for reading, not writing" msgstr "" -"fflush: Leeren der Puffer nicht möglich, Datei »%s« ist nur zum Lesen " -"geöffnet" +"fflush: Leeren der Puffer nicht möglich, Datei »%s« ist nur zum Lesen geöffnet" #: builtin.c:217 #, c-format @@ -1283,8 +1282,7 @@ msgstr "%s: Die Option »-W %s« erfordert ein Argument\n" #: io.c:315 #, c-format msgid "command line argument `%s' is a directory: skipped" -msgstr "" -"das Kommandozeilen-Argument »%s« ist ein Verzeichnis: wird übersprungen" +msgstr "das Kommandozeilen-Argument »%s« ist ein Verzeichnis: wird übersprungen" #: io.c:318 io.c:421 #, c-format @@ -1383,8 +1381,8 @@ msgstr "»close« für eine Umlenkung, die nie geöffnet wurde" #, c-format msgid "close: redirection `%s' not opened with `|&', second argument ignored" msgstr "" -"close: Umlenkung »%s« wurde nicht mit »[&« geöffnet, das zweite Argument " -"wird ignoriert" +"close: Umlenkung »%s« wurde nicht mit »[&« geöffnet, das zweite Argument wird " +"ignoriert" #: io.c:1105 #, c-format @@ -2036,14 +2034,12 @@ msgstr "redir2str: unbekannter Umlenkungstyp %d" #: re.c:573 #, c-format msgid "range of the form `[%c-%c]' is locale dependent" -msgstr "" -"Ein Bereich in der Form »[%c-%c]« ist abhängig von der gesetzten Locale" +msgstr "Ein Bereich in der Form »[%c-%c]« ist abhängig von der gesetzten Locale" #: re.c:600 #, c-format msgid "regexp component `%.*s' should probably be `[%.*s]'" -msgstr "" -"Regulärer-Ausdruck-Komponente »%.*s« sollte wahrscheinlich »[%.*s]« sein" +msgstr "Regulärer-Ausdruck-Komponente »%.*s« sollte wahrscheinlich »[%.*s]« sein" #: regcomp.c:131 msgid "Success" Binary files differ@@ -11,10 +11,10 @@ msgstr "" "PO-Revision-Date: 2012-01-30 07:42-0600\n" "Last-Translator: Cristian Othón MartÃnez Vera <cfuga@cfuga.mx>\n" "Language-Team: Spanish <es@li.org>\n" -"Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: es\n" #: array.c:267 #, c-format @@ -1053,15 +1053,15 @@ msgstr "fatal: extension: no se puede abrir `%s' (%s)\n" msgid "" "extension: library `%s': does not define `plugin_is_GPL_compatible' (%s)\n" msgstr "" -"fatal: extension: la biblioteca `%s': no define " -"`plugin_is_GPL_compatible' (%s)\n" +"fatal: extension: la biblioteca `%s': no define `plugin_is_GPL_compatible' (%" +"s)\n" #: ext.c:91 #, fuzzy, c-format msgid "extension: library `%s': cannot call function `%s' (%s)\n" msgstr "" -"fatal: extension: la biblioteca `%s': no puede llamar a la función `" -"%s' (%s)\n" +"fatal: extension: la biblioteca `%s': no puede llamar a la función `%s' (%" +"s)\n" #: ext.c:119 msgid "extension: missing function name" @@ -1494,8 +1494,8 @@ msgstr "falló al cerrar la entrada estándar en el hijo (%s)" #, c-format msgid "moving slave pty to stdin in child failed (dup: %s)" msgstr "" -"falló el movimiento del pty esclavo a la entrada estándar en el hijo (dup: " -"%s)" +"falló el movimiento del pty esclavo a la entrada estándar en el hijo (dup: %" +"s)" #: io.c:1795 io.c:1816 #, c-format Binary files differ@@ -11,10 +11,10 @@ msgstr "" "PO-Revision-Date: 2012-03-13 18:00+0200\n" "Last-Translator: Jorma Karvonen <karvonen.jorma@gmail.com>\n" "Language-Team: Finnish <translation-team-fi@lists.sourceforge.net>\n" -"Language: fi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: fi\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: array.c:267 diff --git a/str_array.c b/str_array.c index c6b33c6d..a38562cd 100644 --- a/str_array.c +++ b/str_array.c @@ -332,6 +332,7 @@ str_copy(NODE *symbol, NODE *newsymb) newchain->ahcode = chain->ahcode; *pnew = newchain; + newchain->ahnext = NULL; pnew = & newchain->ahnext; } } |