Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/kshlib/dbm_t/dbm_t.c
1810 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 2007-2012 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* David Korn <[email protected]> *
18
* *
19
***********************************************************************/
20
#include <shell.h>
21
#include <ast_ndbm.h>
22
23
static const char dbm_usage[] =
24
"[-?@(#)$Id: Dbm_t (AT&T Research) 2008-05-09 $\n]"
25
USAGE_LICENSE
26
"[+NAME?Dbm_t - create an associative array containing contents of a dbm file]"
27
"[+DESCRIPTION?\bDbm_t\b is a declaration command that creates an associative "
28
"array corresponding to the dbm file whose name is the value of the "
29
"variable \avname\a. The variable \avname\a becomes an associative "
30
"array with subscripts corresponding to keys in the dbm file.]"
31
"[+?Unless hte \b-T\b option is specified, the keys in the file cannot contain "
32
"the NUL character, \b\\0\b, except as the last character. In this "
33
" case all keys must have \b\\0\b as the last characer. The \b-z\b "
34
"option adds a trailing NUL to each key.]"
35
"[+?If no options are specified, \bDbm_t\b defaults to \b-r\b.]"
36
"[T]:[tname?The type of each element will be \atname\a.]"
37
"[c:create?Clear the dbm file if it already exists or create it.]"
38
"[e:exclusive?Open for exclusive access.]"
39
"[r:read?Open for read access only. \avname\a becomes a readonly variable.]"
40
"[w:write?Open for read and write access.]"
41
"[z:zero?When used with \b-c\b, a \b\\0\b byte is appended to each key.]"
42
"\n"
43
"\nvarname\n"
44
"\n"
45
"[+EXIT STATUS]"
46
"{"
47
"[+0?Successful completion.]"
48
"[+>0?An error occurred.]"
49
"}"
50
"[+SEE ALSO?\bksh\b(1), \bdbm\b(3)]"
51
;
52
53
struct dbm_array
54
{
55
Namarr_t header;
56
Shell_t *shp;
57
DBM *dbm;
58
Sfio_t *strbuf;
59
Namval_t *cur;
60
Namval_t *pos;
61
char *val;
62
char *name;
63
size_t namlen;
64
size_t vallen;
65
Namval_t node;
66
datum key;
67
char addzero;
68
char modified;
69
char init;
70
71
};
72
73
extern Namarr_t *nv_arrayptr(Namval_t*);
74
#ifndef NV_ASETSUB
75
# define NV_ASETSUB 8
76
#endif
77
78
static const Namdisc_t *array_disc(Namval_t *np)
79
{
80
Namarr_t *ap;
81
const Namdisc_t *dp;
82
nv_putsub(np, (char*)0, 1);
83
ap = nv_arrayptr(np);
84
dp = ap->hdr.disc;
85
nv_disc(np,&ap->hdr,NV_POP);
86
return(dp);
87
}
88
89
static size_t check_size(char **buff, size_t olds, size_t news)
90
{
91
if(news>=olds)
92
{
93
if(olds)
94
{
95
while((olds*=2) <= news);
96
*buff = (char*)realloc(*buff,olds);
97
98
}
99
else
100
*buff = (char*)malloc(olds=news+1);
101
}
102
return(olds);
103
}
104
105
static void dbm_setname(struct dbm_array *ap)
106
{
107
if(((char*)ap->key.dptr)[ap->key.dsize-ap->addzero])
108
{
109
ap->namlen = check_size(&ap->name,ap->namlen, ap->key.dsize);
110
memcpy(ap->name,ap->key.dptr,ap->key.dsize);
111
ap->name[ap->key.dsize] = 0;
112
ap->node.nvname = ap->name;
113
}
114
else
115
ap->node.nvname = ap->key.dptr;
116
}
117
118
static void dbm_get(struct dbm_array *ap)
119
{
120
char *val;
121
datum data;
122
dbm_clearerr(ap->dbm);
123
data = dbm_fetch(ap->dbm,ap->key);
124
if(data.dsize && (val = (char*)data.dptr))
125
{
126
if(!ap->header.hdr.type && data.dsize>1 && *val==0 && val[1])
127
{
128
*val = '(';
129
if(!ap->strbuf)
130
ap->strbuf = sfstropen();
131
ap->node.nvname = ap->key.dptr;
132
sfprintf(ap->strbuf,"%s=%s\0",nv_name(&ap->node),val);
133
val = sfstruse(ap->strbuf);
134
sh_trap(val,0);
135
}
136
else
137
{
138
ap->vallen = check_size(&ap->node.nvalue,ap->vallen,data.dsize);
139
memcpy(ap->node.nvalue,data.dptr,data.dsize);
140
ap->node.nvalue[data.dsize] = 0;
141
}
142
ap->cur = &ap->node;
143
if(ap->header.hdr.type)
144
nv_setsize(ap->cur,data.dsize);
145
}
146
else
147
{
148
int err;
149
ap->cur = 0;
150
if(err=dbm_error(ap->dbm))
151
{
152
dbm_clearerr(ap->dbm);
153
error(ERROR_system(err),"Unable to get key %.*s",ap->key.dsize-ap->addzero,ap->key.dptr);
154
}
155
}
156
}
157
158
static void dbm_put(struct dbm_array *ap)
159
{
160
datum data;
161
if(ap->node.nvsize)
162
{
163
data.dsize = ap->node.nvsize;
164
data.dptr = ap->node.nvalue;
165
}
166
else
167
{
168
char *val = nv_getval(&ap->node);
169
data.dsize = strlen(val)+ap->addzero;
170
if(nv_isvtree(&ap->node) && *val=='(')
171
*val = 0;
172
data.dptr=(char*)val;
173
}
174
dbm_store(ap->dbm,ap->key,data,DBM_REPLACE);
175
ap->modified = 0;
176
}
177
178
static void *dbm_associative(register Namval_t *np,const char *sp,int mode)
179
{
180
register struct dbm_array *ap = (struct dbm_array*)nv_arrayptr(np);
181
register int keylen;
182
switch(mode)
183
{
184
case NV_AINIT:
185
{
186
if(ap = (struct dbm_array*)calloc(1,sizeof(struct dbm_array)))
187
{
188
Namfun_t *fp = nv_disc(np,NULL,NV_POP);
189
ap->header.hdr.disc = array_disc(np);
190
if(fp)
191
nv_disc(np,fp, NV_FIRST);
192
nv_disc(np,(Namfun_t*)ap, NV_FIRST);
193
ap->header.hdr.nofree = 0;
194
ap->header.hdr.dsize = sizeof(struct dbm_array);
195
ap->val = (char*)malloc(ap->vallen=40);
196
if(nv_isattr(np, NV_ZFILL))
197
{
198
nv_offattr(np,NV_ZFILL);
199
ap->addzero=1;
200
}
201
}
202
return((void*)ap);
203
}
204
case NV_ADELETE:
205
if(ap->modified)
206
dbm_put(ap);
207
if(ap->pos)
208
ap->header.nelem = 1;
209
else if(ap->cur)
210
dbm_delete(ap->dbm,ap->key);
211
ap->pos = ap->cur = 0;
212
return((void*)ap);
213
case NV_AFREE:
214
if(ap->modified)
215
dbm_put(ap);
216
ap->cur = ap->pos = 0;
217
if(ap->name)
218
{
219
free((void*)ap->name);
220
ap->namlen = 0;
221
}
222
if(ap->vallen)
223
free((void*)ap->val);
224
ap->node.nvalue = 0;
225
ap->node.nvsize = 0;
226
dbm_close(ap->dbm);
227
ap->dbm = 0;
228
return((void*)ap);
229
case NV_ANEXT:
230
if(ap->modified)
231
dbm_put(ap);
232
if(!ap->pos)
233
{
234
ap->pos = &ap->node;
235
ap->key = dbm_firstkey(ap->dbm);
236
}
237
else
238
ap->key = dbm_nextkey(ap->dbm);
239
if(ap->key.dptr)
240
{
241
ap->cur = ap->pos;
242
dbm_setname(ap);
243
return((void*)ap->cur);
244
}
245
else
246
ap->pos = 0;
247
return((void*)0);
248
case NV_ASETSUB:
249
if(ap->modified)
250
dbm_put(ap);
251
if(sp)
252
{
253
ap->key.dsize = strlen(sp)+ap->addzero;
254
ap->namlen = check_size(&ap->name,ap->namlen, ap->key.dsize);
255
ap->key.dptr = memcpy(ap->name,sp,ap->key.dsize+1);
256
ap->node.nvname = ap->key.dptr;
257
}
258
ap->cur = (Namval_t*)sp;
259
ap->pos = 0;
260
/* FALL THROUGH*/
261
case NV_ACURRENT:
262
if(ap->pos)
263
dbm_get(ap);
264
if(ap->cur)
265
ap->cur->nvprivate = (char*)np;
266
return((void*)ap->cur);
267
case NV_ANAME:
268
if(ap->cur && ap->cur!= &ap->node)
269
ap->cur = &ap->node;
270
if(ap->cur)
271
return((void*)ap->cur->nvname);
272
return((void*)0);
273
default:
274
if(sp)
275
{
276
if(sp==(char*)np)
277
{
278
ap->cur = 0;
279
return(0);
280
}
281
keylen = strlen(sp)+ap->addzero;
282
if(!ap->init)
283
{
284
ap->init = 1;
285
ap->node.nvprivate = (char*)np;
286
if(ap->node.nvsize==0)
287
ap->node.nvalue = ap->val;
288
ap->key = dbm_firstkey(ap->dbm);
289
if(ap->key.dptr && ((char*)ap->key.dptr)[ap->key.dsize-1]==0)
290
ap->addzero = 1;
291
while(ap->key.dptr)
292
{
293
ap->header.nelem++;
294
ap->key = dbm_nextkey(ap->dbm);
295
}
296
}
297
if(keylen!=ap->key.dsize || !ap->key.dptr || strcmp(sp,ap->key.dptr))
298
{
299
if(ap->modified)
300
dbm_put(ap);
301
ap->key.dsize = keylen;
302
ap->namlen = check_size(&ap->name,ap->namlen, ap->key.dsize);
303
ap->key.dptr = memcpy(ap->name,sp,ap->key.dsize+1);
304
dbm_get(ap);
305
}
306
if(ap->cur)
307
dbm_setname(ap);
308
if(mode&NV_AADD)
309
{
310
if(ap->shp->subshell)
311
sfprintf(sfstderr,"subshell=%d subscript=%s will be modified, need to save \n",ap->shp->subshell,sp);
312
ap->modified = 1;
313
if(!ap->cur)
314
{
315
ap->header.nelem++;
316
ap->cur = &ap->node;
317
dbm_setname(ap);
318
}
319
}
320
if(ap->pos != &ap->node && !(ap->header.nelem&ARRAY_SCAN))
321
ap->pos = 0;
322
}
323
if(ap->cur)
324
{
325
ap->cur = &ap->node;
326
return((void*)(&ap->cur->nvalue));
327
}
328
else
329
return((void*)(&ap->cur));
330
}
331
}
332
333
static int dbm_create(int argc, char** argv, Shbltin_t* context)
334
{
335
int oflags = 0, zflag=0;
336
Namval_t *np;
337
struct dbm_array *ap;
338
char *dbfile, *tname=0;
339
DBM *db;
340
int fds[10],n=0;
341
342
cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_NOTIFY);
343
#if _use_ndbm
344
for (;;)
345
{
346
switch (optget(argv, dbm_usage))
347
{
348
case 'T':
349
tname = opt_info.arg;
350
continue;
351
case 'c':
352
oflags |= O_CREAT|O_TRUNC|O_RDWR;
353
continue;
354
case 'e':
355
oflags |= O_EXCL;
356
continue;
357
case 'r':
358
continue;
359
case 'w':
360
oflags |= O_RDWR;
361
continue;
362
case 'z':
363
zflag = 1;
364
continue;
365
case '?':
366
error(ERROR_USAGE|4, "%s", opt_info.arg);
367
break;
368
case ':':
369
error(2, "%s", opt_info.arg);
370
break;
371
}
372
break;
373
}
374
argv += opt_info.index;
375
if (error_info.errors || !*argv || *(argv + 1))
376
{
377
error(ERROR_USAGE|2, "%s", optusage(NiL));
378
return 1;
379
}
380
if(oflags==0)
381
oflags = O_RDONLY;
382
if(!(np = nv_open(*argv, (void*)0, NV_VARNAME|NV_NOADD)) || !(dbfile=nv_getval(np)))
383
error(3, "%s must contain the name of a dbm file");
384
while((fds[n] = open("/dev/null",NV_RDONLY)) < 10)
385
n++;
386
if (!error_info.errors && !(db=dbm_open(dbfile, oflags, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)))
387
{
388
error(ERROR_SYSTEM|3, "%s: cannot open db",dbfile);
389
return 1;
390
}
391
while(n>0)
392
close(fds[--n]);
393
nv_unset(np);
394
if(zflag && (oflags&O_CREAT))
395
nv_onattr(np,NV_ZFILL);
396
if(ap=(struct dbm_array*)nv_setarray(np, dbm_associative))
397
ap->dbm = db;
398
else
399
error(ERROR_exit(1),"%s: unable to create array",nv_name(np));
400
ap->shp = context->shp;
401
if(tname)
402
{
403
Namval_t *tp;
404
char *tmp = (char*)malloc(n=sizeof(NV_CLASS)+strlen(tname)+2);
405
sfsprintf(tmp, n, "%s.%s", NV_CLASS,tname);
406
tp = nv_open(tmp,0,NV_VARNAME|NV_NOARRAY|NV_NOASSIGN|NV_NOADD);
407
free(tmp);
408
if(!tp)
409
error(ERROR_exit(1),"%s: unknown type",tname);
410
nv_settype(np,tp,0);
411
nv_settype(&ap->node, ap->header.hdr.type,0);
412
ap->node.nvsize = tp->nvsize;
413
}
414
if(!(oflags&O_RDWR))
415
nv_onattr(np,NV_RDONLY);
416
return error_info.errors != 0;
417
#else
418
error(2, "ndbm library required");
419
return 1;
420
#endif
421
}
422
423
void lib_init(int flag, void* context)
424
{
425
Shell_t *shp = ((Shbltin_t*)context)->shp;
426
Namval_t *mp,*bp;
427
428
if (!flag &&
429
(bp = sh_addbuiltin("Dbm_t", dbm_create, (void*)0)) &&
430
(mp = nv_search("typeset", shp->bltin_tree, 0)))
431
nv_onattr(bp, nv_isattr(mp, NV_PUBLIC));
432
}
433
434
SHLIB(dbm_t)
435
436