diff options
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | Doc/Zsh/mod_db_gdbm.yo | 40 | ||||
-rw-r--r-- | Src/Modules/db_gdbm.c | 44 |
3 files changed, 70 insertions, 20 deletions
diff --git a/ChangeLog b/ChangeLog index 8b80a7e6f..2e2a014c0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2015-02-01 Barton E. Schaefer <schaefer@zsh.org> + + * 34446: Doc/Zsh/mod_db_gdbm.yo, Src/Modules/db_gdbm.c: add + "ztie -r" and "zuntie -u", update documentation for this and + for 34430,34439. + 2015-02-01 Daniel Shahaf <d.s@daniel.shahaf.name> * 34411: Completion/Unix/Command/_hg: _hg completion: Complete diff --git a/Doc/Zsh/mod_db_gdbm.yo b/Doc/Zsh/mod_db_gdbm.yo index 6065f860e..90974297c 100644 --- a/Doc/Zsh/mod_db_gdbm.yo +++ b/Doc/Zsh/mod_db_gdbm.yo @@ -11,17 +11,41 @@ The builtins in this module are: startitem() findex(ztie) -cindex(tied array, creating) -item(tt(ztie -d db/gdbm -f) var(filename) var(arrayname))( +cindex(database tied array, creating) +item(tt(ztie -d db/gdbm -f) var(filename) [ tt(-r) ] var(arrayname))( Open the GDBM database identified by var(filename) and, if successful, -create the associative array var(arrayname) linked to the file. Note -that var(arrayname) must be unset at the time tt(ztie) is called, and -is always created as a global parameter (as if with `tt(typeset -g)'). +create the associative array var(arrayname) linked to the file. To create +a local tied array, the parameter must first be declared, so commands +similar to the following would be executed inside a function scope: + +example(local -A sampledb +ztie -d db/gdbm -f sample.gdbm sampledb) + +The tt(-r) option opens the database file for reading only, creating a +parameter with the readonly attribute. Without this option, using +`tt(ztie)' on a file for which the user does not have write permission is +an error. If writable, the database is opened synchronously so fields +changed in var(arrayname) are immediately written to var(filename). + +Changes to the file modes var(filename) after it has been opened do not +alter the state of var(arrayname), but `tt(typeset -r) var(arrayname)' +works as expected. ) findex(zuntie) -cindex(tied array, destroying) -item(tt(zuntie) var(arrayname) ...)( +cindex(database tied array, destroying) +item(tt(zuntie) [ tt(-u) ] var(arrayname) ...)( Close the GDBM database associated with each var(arrayname) and then -unset the variable. +unset the parameter. The tt(-u) option forces an unset of parameters +made readonly with `tt(ztie -r)'. + +This happens automatically if the parameter is explicitly unset or its +local scope (function) ends. Note that a readonly parameter may not be +explicitly unset, so the only way to unset a global parameter created with +`tt(ztie -r)' is to use `tt(zuntie -u)'. ) enditem() + +The fields of an associative array tied to GDBM are neither cached nor +otherwise stored in memory, they are read from or written to the database +on each reference. Thus, for example, the values in a readonly array may +be changed by a second writer of the same database file. diff --git a/Src/Modules/db_gdbm.c b/Src/Modules/db_gdbm.c index 9896bb536..a83e32a7b 100644 --- a/Src/Modules/db_gdbm.c +++ b/Src/Modules/db_gdbm.c @@ -48,8 +48,8 @@ static const struct gsu_hash gdbm_hash_gsu = { hashgetfn, hashsetfn, gdbmhashunsetfn }; static struct builtin bintab[] = { - BUILTIN("ztie", 0, bin_ztie, 1, -1, 0, "d:f:", NULL), - BUILTIN("zuntie", 0, bin_zuntie, 1, -1, 0, NULL, NULL), + BUILTIN("ztie", 0, bin_ztie, 1, -1, 0, "d:f:r", NULL), + BUILTIN("zuntie", 0, bin_zuntie, 1, -1, 0, "u", NULL), }; /**/ @@ -58,6 +58,7 @@ bin_ztie(char *nam, char **args, Options ops, UNUSED(int func)) { char *resource_name, *pmname; GDBM_FILE dbf = NULL; + int read_write = GDBM_SYNC, pmflags = PM_REMOVABLE; Param tied_param; if(!OPT_ISSET(ops,'d')) { @@ -68,6 +69,12 @@ bin_ztie(char *nam, char **args, Options ops, UNUSED(int func)) zwarnnam(nam, "you must pass `-f' with a filename", NULL); return 1; } + if (OPT_ISSET(ops,'r')) { + read_write |= GDBM_READER; + pmflags |= PM_READONLY; + } else { + read_write |= GDBM_WRCREAT; + } /* Here should be a lookup of the backend type against * a registry. @@ -79,9 +86,9 @@ bin_ztie(char *nam, char **args, Options ops, UNUSED(int func)) resource_name = OPT_ARG(ops, 'f'); - dbf = gdbm_open(resource_name, 0, GDBM_WRCREAT | GDBM_SYNC, 0666, 0); + dbf = gdbm_open(resource_name, 0, read_write, 0666, 0); if(!dbf) { - zwarnnam(nam, "error opening database file %s", resource_name); + zwarnnam(nam, "error opening database file %s", resource_name); return 1; } @@ -101,7 +108,7 @@ bin_ztie(char *nam, char **args, Options ops, UNUSED(int func)) } } if (!(tied_param = createspecialhash(pmname, &getgdbmnode, &scangdbmkeys, - PM_REMOVABLE))) { + pmflags))) { zwarnnam(nam, "cannot create the requested parameter %s", pmname); gdbm_close(dbf); return 1; @@ -135,6 +142,8 @@ bin_zuntie(char *nam, char **args, Options ops, UNUSED(int func)) } queue_signals(); + if (OPT_ISSET(ops,'u')) + gdbmuntie(pm); /* clear read-only-ness */ if (unsetparam_pm(pm, 0, 1)) { /* assume already reported */ ret = 1; @@ -250,19 +259,30 @@ scangdbmkeys(HashTable ht, ScanFunc func, int flags) /**/ static void -gdbmhashunsetfn(Param pm, UNUSED(int exp)) +gdbmuntie(Param pm) { GDBM_FILE dbf = (GDBM_FILE)(pm->u.hash->tmpdata); + HashTable ht = pm->u.hash; - if (!dbf) /* paranoia */ - return; + if (dbf) /* paranoia */ + gdbm_close(dbf); - gdbm_close(dbf); - pm->u.hash->tmpdata = NULL; + ht->tmpdata = NULL; - /* hash table is now normal, so proceed normally... */ - pm->node.flags &= ~PM_SPECIAL; + /* for completeness ... createspecialhash() should have an inverse */ + ht->getnode = ht->getnode2 = gethashnode2; + ht->scantab = NULL; + + pm->node.flags &= ~(PM_SPECIAL|PM_READONLY); pm->gsu.h = &stdhash_gsu; +} + +/**/ +static void +gdbmhashunsetfn(Param pm, UNUSED(int exp)) +{ + gdbmuntie(pm); + /* hash table is now normal, so proceed normally... */ pm->gsu.h->setfn(pm, NULL); pm->node.flags |= PM_UNSET; } |