Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/ksh93/sh/array.c
1810 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1982-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
#pragma prototyped
21
/*
22
* Array processing routines
23
*
24
* David Korn
25
* AT&T Labs
26
* [email protected]
27
*
28
*/
29
30
#include "defs.h"
31
#include <stak.h>
32
#include "name.h"
33
34
#define NUMSIZE 11
35
#define is_associative(ap) array_assoc((Namarr_t*)(ap))
36
#define array_setbit(cp, n, b) (cp[n] |= (b))
37
#define array_clrbit(cp, n, b) (cp[n] &= ~(b))
38
#define array_isbit(cp, n, b) (cp[n] & (b))
39
#define NV_CHILD NV_EXPORT
40
#define ARRAY_CHILD 1
41
#define ARRAY_NOFREE 2
42
43
struct index_array
44
{
45
Namarr_t header;
46
void *xp; /* if set, subscripts will be converted */
47
int cur; /* index of current element */
48
int maxi; /* maximum index for array */
49
unsigned char *bits; /* bit array for child subscripts */
50
union Value val[1]; /* array of value holders */
51
};
52
53
struct assoc_array
54
{
55
Namarr_t header;
56
Namval_t *pos;
57
Namval_t *nextpos;
58
Namval_t *cur;
59
};
60
61
#if SHOPT_FIXEDARRAY
62
struct fixed_array
63
{
64
unsigned char ndim;
65
unsigned char dim;
66
unsigned char level;
67
unsigned char ptr;
68
short size;
69
int nelem;
70
int curi;
71
int *max;
72
int *incr;
73
int *cur;
74
char *data;
75
};
76
# define array_fixed_data(ap) ((ap)?((struct fixed_array*)((ap)->fixed))->data:0)
77
static void array_fixed_setdata(Namval_t*,Namarr_t*,struct fixed_array*);
78
#endif /* SHOPT_FIXEDARRAY */
79
80
static Namarr_t *array_scope(Namval_t *np, Namarr_t *ap, int flags)
81
{
82
Namarr_t *aq;
83
#if SHOPT_FIXEDARRAY
84
struct fixed_array *fp;
85
#endif /* SHOPT_FIXEDARRAY */
86
struct index_array *ar;
87
size_t size = ap->hdr.dsize;
88
if(size==0)
89
size = ap->hdr.disc->dsize;
90
if(!(aq=newof(NIL(Namarr_t*),Namarr_t,1,size-sizeof(Namarr_t))))
91
return(0);
92
memcpy(aq,ap,size);
93
aq->hdr.nofree &= ~1;
94
aq->hdr.nofree |= (flags&NV_RDONLY)?1:0;
95
if(is_associative(aq))
96
{
97
aq->scope = (void*)dtopen(&_Nvdisc,Dtoset);
98
dtview((Dt_t*)aq->scope,aq->table);
99
aq->table = (Dt_t*)aq->scope;
100
return(aq);
101
}
102
#if SHOPT_FIXEDARRAY
103
else if(fp = (struct fixed_array*)ap->fixed)
104
{
105
aq->scope = (void*)ap;
106
fp = (struct fixed_array*)(aq+1);
107
aq->fixed = (void*)fp;
108
fp->max = (int*)(fp+1);
109
fp->incr = fp->max+fp->ndim;
110
fp->cur = fp->incr+fp->ndim;
111
return(aq);
112
}
113
#endif /* SHOPT_FIXEDARRAY */
114
aq->scope = (void*)ap;
115
ar = (struct index_array*)aq;
116
memset(ar->val, 0, ar->maxi*sizeof(char*));
117
ar->bits = (unsigned char*)&ar->val[ar->maxi];
118
return(aq);
119
}
120
121
static int array_unscope(Namval_t *np,Namarr_t *ap)
122
{
123
Namfun_t *fp;
124
if(!ap->scope)
125
return(0);
126
if(is_associative(ap))
127
(*ap->fun)(np, NIL(char*), NV_AFREE);
128
if((fp = nv_disc(np,(Namfun_t*)ap,NV_POP)) && !(fp->nofree&1))
129
free((void*)fp);
130
nv_delete(np,(Dt_t*)0,0);
131
return(1);
132
}
133
134
static void array_syncsub(Namarr_t *ap, Namarr_t *aq)
135
{
136
((struct index_array*)ap)->cur = ((struct index_array*)aq)->cur;
137
}
138
139
static int array_covered(Namval_t *np, struct index_array *ap)
140
{
141
struct index_array *aq = (struct index_array*)ap->header.scope;
142
if(!ap->header.fun && aq)
143
#if SHOPT_FIXEDARRAY
144
return (ap->header.fixed || ((ap->cur<aq->maxi) && aq->val[ap->cur].cp));
145
#else
146
return ((ap->cur<aq->maxi) && aq->val[ap->cur].cp);
147
#endif /* SHOPT_FIXEDARRAY */
148
return(0);
149
}
150
151
/*
152
* replace discipline with new one
153
*/
154
static void array_setptr(register Namval_t *np, struct index_array *old, struct index_array *new)
155
{
156
register Namfun_t **fp = &np->nvfun;
157
while(*fp && *fp!= &old->header.hdr)
158
fp = &((*fp)->next);
159
if(*fp)
160
{
161
new->header.hdr.next = (*fp)->next;
162
*fp = &new->header.hdr;
163
}
164
else sfprintf(sfstderr,"discipline not replaced\n");
165
}
166
167
/*
168
* Calculate the amount of space to be allocated to hold an
169
* indexed array into which <maxi> is a legal index. The number of
170
* elements that will actually fit into the array (> <maxi>
171
* but <= ARRAY_MAX) is returned.
172
*
173
*/
174
static int arsize(struct index_array *ap, register int maxi)
175
{
176
if(ap && maxi < 2*ap->maxi)
177
maxi = 2*ap->maxi;
178
maxi = roundof(maxi,ARRAY_INCR);
179
return (maxi>ARRAY_MAX?ARRAY_MAX:maxi);
180
}
181
182
static struct index_array *array_grow(Namval_t*, struct index_array*,int);
183
184
/* return index of highest element of an array */
185
int array_maxindex(Namval_t *np)
186
{
187
register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
188
register int i = ap->maxi;
189
if(is_associative(ap))
190
return(-1);
191
while(i>0 && ap->val[--i].cp==0);
192
return(i+1);
193
}
194
195
static union Value *array_getup(Namval_t *np, Namarr_t *arp, int update)
196
{
197
register struct index_array *ap = (struct index_array*)arp;
198
register union Value *up;
199
#if SHOPT_FIXEDARRAY
200
struct fixed_array *fp;
201
#endif /* SHOPT_FIXEDARRAY */
202
int nofree=0;
203
if(!arp)
204
return(&np->nvalue);
205
if(is_associative(ap))
206
{
207
Namval_t *mp;
208
mp = (Namval_t*)((*arp->fun)(np,NIL(char*),NV_ACURRENT));
209
if(mp)
210
{
211
nofree = nv_isattr(mp,NV_NOFREE);
212
up = &mp->nvalue;
213
}
214
else
215
return((union Value*)((*arp->fun)(np,NIL(char*),0)));
216
}
217
#if SHOPT_FIXEDARRAY
218
else if(fp = (struct fixed_array*)arp->fixed)
219
{
220
if(!fp->data)
221
array_fixed_setdata(np,arp,fp);
222
up = &np->nvalue;
223
if(fp->ptr)
224
up->cp = *(((char**)fp->data)+fp->curi);
225
else
226
up->cp = fp->data+fp->size*fp->curi;
227
}
228
#endif /* SHOPT_FIXEDARRAY */
229
else
230
{
231
if(ap->cur >= ap->maxi)
232
errormsg(SH_DICT,ERROR_exit(1),e_subscript,nv_name(np));
233
up = &(ap->val[ap->cur]);
234
nofree = array_isbit(ap->bits,ap->cur,ARRAY_NOFREE);
235
}
236
if(update)
237
{
238
if(nofree)
239
nv_onattr(np,NV_NOFREE);
240
else
241
nv_offattr(np,NV_NOFREE);
242
}
243
return(up);
244
}
245
246
int nv_arrayisset(Namval_t *np, Namarr_t *arp)
247
{
248
register struct index_array *ap = (struct index_array*)arp;
249
union Value *up;
250
if(is_associative(ap))
251
return((np = nv_opensub(np)) && !nv_isnull(np));
252
if(ap->cur >= ap->maxi)
253
return(0);
254
up = &(ap->val[ap->cur]);
255
if(up->cp==Empty)
256
{
257
Namfun_t *fp = &arp->hdr;
258
for(fp=fp->next; fp; fp = fp->next)
259
{
260
if(fp->disc && (fp->disc->getnum || fp->disc->getval))
261
return(1);
262
}
263
}
264
return(up->cp && up->cp!=Empty);
265
}
266
267
/*
268
* Get the Value pointer for an array.
269
* Delete space as necessary if flag is ARRAY_DELETE
270
* After the lookup is done the last @ or * subscript is incremented
271
*/
272
static Namval_t *array_find(Namval_t *np,Namarr_t *arp, int flag)
273
{
274
register struct index_array *ap = (struct index_array*)arp;
275
register union Value *up;
276
Namval_t *mp;
277
int wasundef;
278
#if SHOPT_FIXEDARRAY
279
struct fixed_array *fp=(struct fixed_array*)(arp->fixed);
280
#endif /* SHOPT_FIXEDARRAY */
281
if(flag&ARRAY_LOOKUP)
282
ap->header.nelem &= ~ARRAY_NOSCOPE;
283
else
284
ap->header.nelem |= ARRAY_NOSCOPE;
285
if(wasundef = ap->header.nelem&ARRAY_UNDEF)
286
{
287
ap->header.nelem &= ~ARRAY_UNDEF;
288
/* delete array is the same as delete array[@] */
289
if(flag&ARRAY_DELETE)
290
{
291
#if SHOPT_FIXEDARRAY
292
nv_putsub(np, NIL(char*), ARRAY_SCAN|ARRAY_NOSCOPE|(ap->header.fixed?(ARRAY_UNDEF|ARRAY_FIXED):0));
293
#else
294
nv_putsub(np, NIL(char*), ARRAY_SCAN|ARRAY_NOSCOPE);
295
#endif /* SHOPT_FIXEDARRAY */
296
ap->header.nelem |= ARRAY_SCAN;
297
}
298
else /* same as array[0] */
299
{
300
if(is_associative(ap))
301
(*ap->header.fun)(np,"0",flag==ARRAY_ASSIGN?NV_AADD:0);
302
#if SHOPT_FIXEDARRAY
303
else if(fp)
304
{
305
int n=fp->ndim;
306
fp->curi = 0;
307
while(--n>=0)
308
fp->cur[n] = 0;
309
}
310
#endif /* SHOPT_FIXEDARRAY */
311
else
312
ap->cur = 0;
313
}
314
}
315
if(is_associative(ap))
316
{
317
mp = (Namval_t*)((*arp->fun)(np,NIL(char*),NV_ACURRENT));
318
if(!mp)
319
up = (union Value*)&mp;
320
else if(nv_isarray(mp))
321
{
322
if(wasundef)
323
nv_putsub(mp,NIL(char*),ARRAY_UNDEF);
324
return(mp);
325
}
326
else
327
{
328
up = &mp->nvalue;
329
if(nv_isvtree(mp))
330
{
331
if(!up->cp && flag==ARRAY_ASSIGN)
332
{
333
nv_arraychild(np,mp,0);
334
ap->header.nelem++;
335
}
336
return(mp);
337
}
338
}
339
}
340
#if SHOPT_FIXEDARRAY
341
else if(fp)
342
{
343
char *data = array_fixed_data((Namarr_t*)ap->header.scope);
344
if(flag==ARRAY_ASSIGN && data==fp->data)
345
{
346
if(data)
347
{
348
fp->data = (char*)malloc(fp->nelem*fp->size);
349
memcpy(fp->data,data,fp->nelem*fp->size);
350
}
351
else
352
array_fixed_setdata(np,&ap->header,fp);
353
}
354
if(fp->ptr)
355
{
356
if(!fp->data)
357
array_fixed_setdata(np,&ap->header,fp);
358
np->nvalue.cp = *(((char**)fp->data)+fp->curi);
359
}
360
else
361
np->nvalue.cp = fp->data+fp->size*fp->curi;
362
return(np);
363
}
364
#endif /* SHOPT_FIXEDARRAY */
365
else
366
{
367
if(!(ap->header.nelem&ARRAY_SCAN) && ap->cur >= ap->maxi)
368
ap = array_grow(np, ap, (int)ap->cur);
369
if(ap->cur>=ap->maxi)
370
errormsg(SH_DICT,ERROR_exit(1),e_subscript,nv_name(np));
371
up = &(ap->val[ap->cur]);
372
if((!up->cp||up->cp==Empty) && nv_type(np) && nv_isvtree(np))
373
{
374
char *cp;
375
if(!ap->header.table)
376
ap->header.table = dtopen(&_Nvdisc,Dtoset);
377
sfprintf(sh.strbuf,"%d",ap->cur);
378
cp = sfstruse(sh.strbuf);
379
mp = nv_search(cp, ap->header.table, NV_ADD);
380
mp->nvenv = (char*)np;
381
nv_arraychild(np,mp,0);
382
}
383
if(up->np && array_isbit(ap->bits,ap->cur,ARRAY_CHILD))
384
{
385
if(wasundef && nv_isarray(up->np))
386
nv_putsub(up->np,NIL(char*),ARRAY_UNDEF);
387
return(up->np);
388
}
389
}
390
np->nvalue.cp = up->cp;
391
if(!up->cp)
392
{
393
char *xp = nv_setdisc(np,"get",np,(Namfun_t*)np);
394
if(flag!=ARRAY_ASSIGN)
395
return(xp && xp!=(char*)np?np:0);
396
if(!array_covered(np,ap))
397
ap->header.nelem++;
398
}
399
return(np);
400
}
401
402
#if SHOPT_TYPEDEF
403
int nv_arraysettype(Namval_t *np, Namval_t *tp, const char *sub, int flags)
404
{
405
Namval_t *nq;
406
char *av[2];
407
int rdonly = nv_isattr(np,NV_RDONLY);
408
int xtrace = sh_isoption(SH_XTRACE);
409
Namarr_t *ap = nv_arrayptr(np);
410
av[1] = 0;
411
sh.last_table = 0;
412
if(!ap->table)
413
ap->table = dtopen(&_Nvdisc,Dtoset);
414
if(nq = nv_search(sub, ap->table, NV_ADD))
415
{
416
if(!nq->nvfun && nq->nvalue.cp && *nq->nvalue.cp==0)
417
_nv_unset(nq,NV_RDONLY);
418
nv_arraychild(np,nq,0);
419
if(!nv_isattr(tp,NV_BINARY))
420
{
421
sfprintf(sh.strbuf,"%s=%s",nv_name(nq),nv_getval(np));
422
av[0] = strdup(sfstruse(sh.strbuf));
423
}
424
if(!nv_clone(tp,nq,flags|NV_NOFREE))
425
return(0);
426
ap->nelem |= ARRAY_SCAN;
427
if(!rdonly)
428
nv_offattr(nq,NV_RDONLY);
429
if(!nv_isattr(tp,NV_BINARY))
430
{
431
if(xtrace)
432
sh_offoption(SH_XTRACE);
433
ap->nelem &= ~ARRAY_SCAN;
434
sh_eval(sh_sfeval(av),0);
435
ap->nelem |= ARRAY_SCAN;
436
free((void*)av[0]);
437
if(xtrace)
438
sh_onoption(SH_XTRACE);
439
}
440
return(1);
441
}
442
return(0);
443
}
444
#endif /* SHOPT_TYPEDEF */
445
446
447
static Namfun_t *array_clone(Namval_t *np, Namval_t *mp, int flags, Namfun_t *fp)
448
{
449
Namarr_t *ap = (Namarr_t*)fp;
450
Namval_t *nq, *mq;
451
char *name, *sub=0;
452
int nelem, skipped=0;
453
Dt_t *otable=ap->table;
454
struct index_array *aq = (struct index_array*)ap, *ar;
455
Shell_t *shp = sh_getinterp();
456
if(flags&NV_MOVE)
457
{
458
if((flags&NV_COMVAR) && nv_putsub(np,NIL(char*),ARRAY_SCAN))
459
{
460
do
461
{
462
if(nq=nv_opensub(np))
463
nq->nvenv = (void*)mp;
464
}
465
while(nv_nextsub(np));
466
}
467
return(fp);
468
}
469
nelem = ap->nelem;
470
if(nelem&ARRAY_NOCLONE)
471
return(0);
472
if((flags&NV_TYPE) && !ap->scope)
473
{
474
ap = array_scope(np,ap,flags);
475
return(&ap->hdr);
476
}
477
ap = (Namarr_t*)nv_clone_disc(fp,0);
478
if(flags&NV_COMVAR)
479
{
480
ap->scope = 0;
481
ap->nelem = 0;
482
sh.prev_table = sh.last_table;
483
sh.prev_root = sh.last_root;
484
}
485
if(ap->table)
486
{
487
ap->table = dtopen(&_Nvdisc,Dtoset);
488
if(ap->scope && !(flags&NV_COMVAR))
489
{
490
ap->scope = ap->table;
491
dtview(ap->table, otable->view);
492
}
493
}
494
mp->nvfun = (Namfun_t*)ap;
495
mp->nvflag &= NV_MINIMAL;
496
mp->nvflag |= (np->nvflag&~(NV_MINIMAL|NV_NOFREE));
497
if(!(nelem&(ARRAY_SCAN|ARRAY_UNDEF)) && (sub=nv_getsub(np)))
498
sub = strdup(sub);
499
ar = (struct index_array*)ap;
500
if(!is_associative(ap))
501
ar->bits = (unsigned char*)&ar->val[ar->maxi];
502
if(!nv_putsub(np,NIL(char*),ARRAY_SCAN|((flags&NV_COMVAR)?0:ARRAY_NOSCOPE)))
503
{
504
if(ap->fun)
505
(*ap->fun)(np,(char*)np,0);
506
skipped=1;
507
goto skip;
508
}
509
do
510
{
511
name = nv_getsub(np);
512
nv_putsub(mp,name,ARRAY_ADD|ARRAY_NOSCOPE);
513
mq = 0;
514
if(nq=nv_opensub(np))
515
mq = nv_search(name,ap->table,NV_ADD);
516
if(nq && (((flags&NV_COMVAR) && nv_isvtree(nq)) || nv_isarray(nq)))
517
{
518
mq->nvalue.cp = 0;
519
if(!is_associative(ap))
520
ar->val[ar->cur].np = mq;
521
nv_clone(nq,mq,flags);
522
}
523
else if(flags&NV_ARRAY)
524
{
525
if((flags&NV_NOFREE) && !is_associative(ap))
526
array_setbit(aq->bits,aq->cur,ARRAY_NOFREE);
527
else if(nq && (flags&NV_NOFREE))
528
{
529
mq->nvalue = nq->nvalue;
530
nv_onattr(nq,NV_NOFREE);
531
}
532
}
533
else if(nv_isattr(np,NV_INTEGER))
534
{
535
Sfdouble_t d= nv_getnum(np);
536
if(!is_associative(ap))
537
ar->val[ar->cur].cp = 0;
538
nv_putval(mp,(char*)&d,NV_LDOUBLE);
539
}
540
else
541
{
542
if(!is_associative(ap))
543
ar->val[ar->cur].cp = 0;
544
nv_putval(mp,nv_getval(np),NV_RDONLY);
545
}
546
aq->header.nelem |= ARRAY_NOSCOPE;
547
}
548
while(nv_nextsub(np));
549
skip:
550
if(sub)
551
{
552
if(!skipped)
553
nv_putsub(np,sub,0L);
554
free((void*)sub);
555
}
556
aq->header.nelem = ap->nelem = nelem;
557
return(&ap->hdr);
558
}
559
560
static char *array_getval(Namval_t *np, Namfun_t *disc)
561
{
562
register Namarr_t *aq,*ap = (Namarr_t*)disc;
563
register Namval_t *mp;
564
register char *cp=0;
565
if((mp=array_find(np,ap,ARRAY_LOOKUP))!=np)
566
{
567
if(!mp && !is_associative(ap) && (aq=(Namarr_t*)ap->scope))
568
{
569
array_syncsub(aq,ap);
570
if((mp=array_find(np,aq,ARRAY_LOOKUP))==np)
571
return(nv_getv(np,&aq->hdr));
572
}
573
if(mp)
574
{
575
cp = nv_getval(mp);
576
nv_offattr(mp,NV_EXPORT);
577
}
578
return(cp);
579
}
580
#if SHOPT_FIXEDARRAY
581
if(ap->fixed && nv_isattr(np,NV_INT16P) == NV_INT16)
582
np->nvalue.s = *np->nvalue.sp;
583
#endif /* SHOPT_FIXEDARRAY */
584
return(nv_getv(np,&ap->hdr));
585
}
586
587
static Sfdouble_t array_getnum(Namval_t *np, Namfun_t *disc)
588
{
589
register Namarr_t *aq,*ap = (Namarr_t*)disc;
590
register Namval_t *mp;
591
if((mp=array_find(np,ap,ARRAY_LOOKUP))!=np)
592
{
593
if(!mp && !is_associative(ap) && (aq=(Namarr_t*)ap->scope))
594
{
595
array_syncsub(aq,ap);
596
if((mp=array_find(np,aq,ARRAY_LOOKUP))==np)
597
return(nv_getn(np,&aq->hdr));
598
}
599
return(mp?nv_getnum(mp):0);
600
}
601
return(nv_getn(np,&ap->hdr));
602
}
603
604
static void array_putval(Namval_t *np, const char *string, int flags, Namfun_t *dp)
605
{
606
register Namarr_t *ap = (Namarr_t*)dp;
607
register union Value *up;
608
register Namval_t *mp;
609
register struct index_array *aq = (struct index_array*)ap;
610
int scan,nofree = nv_isattr(np,NV_NOFREE);
611
#if SHOPT_FIXEDARRAY
612
struct fixed_array *fp;
613
#endif /* SHOPT_FIXEDARRAY */
614
do
615
{
616
int xfree = (ap->fixed||is_associative(ap))?0:array_isbit(aq->bits,aq->cur,ARRAY_NOFREE);
617
mp = array_find(np,ap,string?ARRAY_ASSIGN:ARRAY_DELETE);
618
scan = ap->nelem&ARRAY_SCAN;
619
if(mp && mp!=np)
620
{
621
if(!is_associative(ap) && string && !(flags&NV_APPEND) && !nv_type(np) && nv_isvtree(mp) && !(ap->nelem&ARRAY_TREE))
622
623
{
624
if(!nv_isattr(np,NV_NOFREE))
625
_nv_unset(mp,flags&NV_RDONLY);
626
array_clrbit(aq->bits,aq->cur,ARRAY_CHILD);
627
aq->val[aq->cur].cp = 0;
628
if(!nv_isattr(mp,NV_NOFREE))
629
nv_delete(mp,ap->table,0);
630
goto skip;
631
}
632
if(!xfree)
633
nv_putval(mp, string, flags);
634
if(string)
635
{
636
#if SHOPT_TYPEDEF
637
if(ap->hdr.type && ap->hdr.type!=nv_type(mp))
638
nv_arraysettype(np,ap->hdr.type,nv_getsub(np),0);
639
#endif /* SHOPT_TYPEDEF */
640
continue;
641
}
642
ap->nelem |= scan;
643
}
644
if(!string)
645
{
646
if(mp)
647
{
648
if(is_associative(ap))
649
{
650
(*ap->fun)(np,NIL(char*),NV_ADELETE);
651
np->nvalue.cp = 0;
652
}
653
else
654
{
655
if(mp!=np)
656
{
657
array_clrbit(aq->bits,aq->cur,ARRAY_CHILD);
658
aq->val[aq->cur].cp = 0;
659
if(!xfree)
660
nv_delete(mp,ap->table,0);
661
}
662
if(!array_covered(np,(struct index_array*)ap))
663
{
664
if(array_elem(ap))
665
ap->nelem--;
666
}
667
#if SHOPT_FIXEDARRAY
668
else if(fp=(struct fixed_array*)ap->fixed)
669
{
670
char *data = array_fixed_data((Namarr_t*)ap->scope);
671
int n = fp->size*fp->curi;
672
if(data)
673
{
674
memcpy(fp->data+n,data+n,fp->size);
675
continue;
676
}
677
}
678
#endif /* SHOPT_FIXEDARRAY */
679
}
680
}
681
if(array_elem(ap)==0 && (ap->nelem&ARRAY_SCAN))
682
{
683
if(is_associative(ap))
684
(*ap->fun)(np, NIL(char*), NV_AFREE);
685
else if(ap->table)
686
dtclose(ap->table);
687
nv_offattr(np,NV_ARRAY);
688
}
689
if(!mp || mp!=np || is_associative(ap))
690
continue;
691
}
692
skip:
693
/* prevent empty string from being deleted */
694
up = array_getup(np,ap,!nofree);
695
if(up->cp == Empty)
696
up->cp = 0;
697
#if SHOPT_FIXEDARRAY
698
if(nv_isarray(np) && !ap->fixed)
699
#else
700
if(nv_isarray(np))
701
#endif /* SHOPT_FIXEDARRAY */
702
np->nvalue.up = up;
703
nv_putv(np,string,flags,&ap->hdr);
704
#if SHOPT_FIXEDARRAY
705
if(fp = (struct fixed_array*)ap->fixed)
706
{
707
if(fp->ptr)
708
{
709
char **cp = (char**)fp->data;
710
cp[fp->curi] = (char*)(np->nvalue.cp?np->nvalue.cp:Empty);
711
}
712
}
713
else
714
#endif /* SHOPT_FIXEDARRAY */
715
if(!is_associative(ap))
716
{
717
if(string)
718
array_clrbit(aq->bits,aq->cur,ARRAY_NOFREE);
719
else if(mp==np)
720
aq->val[aq->cur].cp = 0;
721
}
722
#if SHOPT_TYPEDEF
723
if(string && ap->hdr.type && nv_isvtree(np))
724
nv_arraysettype(np,ap->hdr.type,nv_getsub(np),0);
725
#endif /* SHOPT_TYPEDEF */
726
}
727
while(!string && nv_nextsub(np));
728
if(ap)
729
ap->nelem &= ~ARRAY_NOSCOPE;
730
if(nofree)
731
nv_onattr(np,NV_NOFREE);
732
else
733
nv_offattr(np,NV_NOFREE);
734
if(!string && !nv_isattr(np,NV_ARRAY))
735
{
736
Namfun_t *nfp;
737
#if SHOPT_FIXEDARRAY
738
char *data = array_fixed_data((Namarr_t*)ap->scope);
739
fp = (struct fixed_array*)ap->fixed;
740
if(fp && (!ap->scope || data!=fp->data))
741
{
742
if(fp->ptr)
743
{
744
int n = fp->nelem;
745
char **cp = (char**)fp->data;
746
while(n-->0)
747
{
748
if(cp && *cp!=Empty)
749
free(*cp);
750
cp++;
751
}
752
}
753
free((void*)fp->data);
754
if(data)
755
fp->data = data;
756
}
757
else
758
#endif /* SHOPT_FIXEDARRAY */
759
if(!is_associative(ap) && aq->xp)
760
{
761
_nv_unset(nv_namptr(aq->xp,0),NV_RDONLY);
762
free((void*)aq->xp);
763
}
764
if((nfp = nv_disc(np,(Namfun_t*)ap,NV_POP)) && !(nfp->nofree&1))
765
free((void*)nfp);
766
if(!nv_isnull(np))
767
{
768
if(!np->nvfun)
769
nv_onattr(np,NV_NOFREE);
770
_nv_unset(np,flags);
771
}
772
else
773
nv_offattr(np,NV_NOFREE);
774
if(np->nvalue.cp==Empty)
775
np->nvalue.cp = 0;
776
}
777
if(!string && (flags&NV_TYPE))
778
array_unscope(np,ap);
779
}
780
781
static const Namdisc_t array_disc =
782
{
783
sizeof(Namarr_t),
784
array_putval,
785
array_getval,
786
array_getnum,
787
0,
788
0,
789
array_clone
790
};
791
792
static void array_copytree(Namval_t *np, Namval_t *mp)
793
{
794
Namfun_t *fp = nv_disc(np,NULL,NV_POP);
795
nv_offattr(np,NV_ARRAY);
796
nv_clone(np,mp,0);
797
if(np->nvalue.cp && !nv_isattr(np,NV_NOFREE))
798
free((void*)np->nvalue.cp);
799
np->nvalue.cp = 0;
800
np->nvalue.up = &mp->nvalue;
801
fp->nofree &= ~1;
802
nv_disc(np,(Namfun_t*)fp, NV_FIRST);
803
fp->nofree |= 1;
804
nv_onattr(np,NV_ARRAY);
805
mp->nvenv = (char*)np;
806
}
807
808
/*
809
* Increase the size of the indexed array of elements in <arp>
810
* so that <maxi> is a legal index. If <arp> is 0, an array
811
* of the required size is allocated. A pointer to the
812
* allocated Namarr_t structure is returned.
813
* <maxi> becomes the current index of the array.
814
*/
815
static struct index_array *array_grow(Namval_t *np, register struct index_array *arp,int maxi)
816
{
817
register struct index_array *ap;
818
register int i;
819
register int newsize = arsize(arp,maxi+1);
820
if (maxi >= ARRAY_MAX)
821
errormsg(SH_DICT,ERROR_exit(1),e_subscript, fmtbase((long)maxi,10,0));
822
i = (newsize-1)*sizeof(union Value*)+newsize;
823
ap = new_of(struct index_array,i);
824
memset((void*)ap,0,sizeof(*ap)+i);
825
ap->maxi = newsize;
826
ap->cur = maxi;
827
ap->bits = (unsigned char*)&ap->val[newsize];
828
memset(ap->bits, 0, newsize);
829
if(arp)
830
{
831
ap->header = arp->header;
832
ap->header.hdr.dsize = sizeof(*ap) + i;
833
for(i=0;i < arp->maxi;i++)
834
{
835
ap->bits[i] = arp->bits[i];
836
ap->val[i].cp = arp->val[i].cp;
837
}
838
memcpy(ap->bits, arp->bits, arp->maxi);
839
array_setptr(np,arp,ap);
840
free((void*)arp);
841
}
842
else
843
{
844
Namval_t *mp=0;
845
ap->header.hdr.dsize = sizeof(*ap) + i;
846
i = 0;
847
ap->header.fun = 0;
848
if((nv_isnull(np)||np->nvalue.cp==Empty) && nv_isattr(np,NV_NOFREE))
849
{
850
i = ARRAY_TREE;
851
nv_offattr(np,NV_NOFREE);
852
}
853
if(np->nvalue.cp==Empty)
854
np->nvalue.cp=0;
855
if(nv_hasdisc(np,&array_disc) || (nv_type(np) && nv_isvtree(np)))
856
{
857
ap->header.table = dtopen(&_Nvdisc,Dtoset);
858
mp = nv_search("0", ap->header.table,NV_ADD);
859
if(mp && nv_isnull(mp))
860
{
861
Namfun_t *fp;
862
ap->val[0].np = mp;
863
array_setbit(ap->bits,0,ARRAY_CHILD);
864
for(fp=np->nvfun; fp && !fp->disc->readf; fp=fp->next);
865
if(fp && fp->disc && fp->disc->readf)
866
(*fp->disc->readf)(mp,(Sfio_t*)0,0,fp);
867
i++;
868
}
869
}
870
else
871
if((ap->val[0].cp=np->nvalue.cp))
872
i++;
873
else if(nv_isattr(np,NV_INTEGER) && !nv_isnull(np))
874
{
875
Sfdouble_t d= nv_getnum(np);
876
i++;
877
}
878
ap->header.nelem = i;
879
ap->header.hdr.disc = &array_disc;
880
nv_disc(np,(Namfun_t*)ap, NV_FIRST);
881
nv_onattr(np,NV_ARRAY);
882
if(mp)
883
{
884
array_copytree(np,mp);
885
ap->header.hdr.nofree &= ~1;
886
}
887
}
888
for(;i < newsize;i++)
889
ap->val[i].cp = 0;
890
return(ap);
891
}
892
893
int nv_atypeindex(Namval_t *np, const char *tname)
894
{
895
Namval_t *tp;
896
int offset = staktell();
897
size_t n = strlen(tname)-1;
898
sfprintf(stkstd,"%s.%.*s%c",NV_CLASS,n,tname,0);
899
tp = nv_open(stakptr(offset), sh.var_tree, NV_NOADD|NV_VARNAME);
900
stakseek(offset);
901
if(tp)
902
{
903
struct index_array *ap = (struct index_array*)nv_arrayptr(np);
904
if(!nv_hasdisc(tp,&ENUM_disc))
905
errormsg(SH_DICT,ERROR_exit(1),e_notenum,tp->nvname);
906
if(!ap)
907
ap = array_grow(np,ap,1);
908
ap->xp = calloc(NV_MINSZ,1);
909
np = nv_namptr(ap->xp,0);
910
np->nvname = tp->nvname;
911
nv_onattr(np,NV_MINIMAL);
912
nv_clone(tp,np,NV_NOFREE);
913
nv_offattr(np,NV_RDONLY);
914
return(1);
915
}
916
errormsg(SH_DICT,ERROR_exit(1),e_unknowntype, n,tname);
917
return(0);
918
}
919
920
Namarr_t *nv_arrayptr(register Namval_t *np)
921
{
922
if(nv_isattr(np,NV_ARRAY))
923
return((Namarr_t*)nv_hasdisc(np, &array_disc));
924
return(0);
925
}
926
927
/*
928
* Verify that argument is an indexed array and convert to associative,
929
* freeing relevant storage
930
*/
931
static Namarr_t *nv_changearray(Namval_t *np, void *(*fun)(Namval_t*,const char*,int))
932
{
933
register Namarr_t *ap;
934
char numbuff[NUMSIZE+1];
935
unsigned dot, digit, n;
936
union Value *up;
937
struct index_array *save_ap;
938
register char *string_index=&numbuff[NUMSIZE];
939
numbuff[NUMSIZE]='\0';
940
941
if(!fun || !(ap = nv_arrayptr(np)) || is_associative(ap))
942
return(NIL(Namarr_t*));
943
944
nv_stack(np,&ap->hdr);
945
save_ap = (struct index_array*)nv_stack(np,0);
946
ap = (Namarr_t*)((*fun)(np, NIL(char*), NV_AINIT));
947
ap->nelem = 0;
948
ap->fun = fun;
949
nv_onattr(np,NV_ARRAY);
950
951
for(dot = 0; dot < (unsigned)save_ap->maxi; dot++)
952
{
953
if(save_ap->val[dot].cp)
954
{
955
if ((digit = dot)== 0)
956
*--string_index = '0';
957
else while( n = digit )
958
{
959
digit /= 10;
960
*--string_index = '0' + (n-10*digit);
961
}
962
nv_putsub(np, string_index, ARRAY_ADD);
963
up = (union Value*)((*ap->fun)(np,NIL(char*),0));
964
up->cp = save_ap->val[dot].cp;
965
save_ap->val[dot].cp = 0;
966
}
967
string_index = &numbuff[NUMSIZE];
968
}
969
free((void*)save_ap);
970
return(ap);
971
}
972
973
/*
974
* set the associative array processing method for node <np> to <fun>
975
* The array pointer is returned if sucessful.
976
*/
977
Namarr_t *nv_setarray(Namval_t *np, void *(*fun)(Namval_t*,const char*,int))
978
{
979
register Namarr_t *ap;
980
char *value=0;
981
Namfun_t *fp;
982
int nelem = 0;
983
if(fun && (ap = nv_arrayptr(np)))
984
{
985
/*
986
* if it's already an indexed array, convert to
987
* associative structure
988
*/
989
if(!is_associative(ap))
990
ap = nv_changearray(np, fun);
991
return(ap);
992
}
993
if(nv_isnull(np) && nv_isattr(np,NV_NOFREE))
994
{
995
nelem = ARRAY_TREE;
996
nv_offattr(np,NV_NOFREE);
997
}
998
if(!(fp=nv_isvtree(np)))
999
value = nv_getval(np);
1000
if(fun && !ap && (ap = (Namarr_t*)((*fun)(np, NIL(char*), NV_AINIT))))
1001
{
1002
/* check for preexisting initialization and save */
1003
ap->nelem = nelem;
1004
ap->fun = fun;
1005
nv_onattr(np,NV_ARRAY);
1006
if(fp || value)
1007
{
1008
nv_putsub(np, "0", ARRAY_ADD);
1009
if(value)
1010
nv_putval(np, value, 0);
1011
else
1012
{
1013
Namval_t *mp = (Namval_t*)((*fun)(np,NIL(char*),NV_ACURRENT));
1014
array_copytree(np,mp);
1015
}
1016
}
1017
return(ap);
1018
}
1019
return(NIL(Namarr_t*));
1020
}
1021
1022
/*
1023
* move parent subscript into child
1024
*/
1025
Namval_t *nv_arraychild(Namval_t *np, Namval_t *nq, int c)
1026
{
1027
Namfun_t *fp;
1028
register Namarr_t *ap = nv_arrayptr(np);
1029
union Value *up;
1030
Namval_t *tp;
1031
if(!nq)
1032
return(ap?array_find(np,ap, ARRAY_LOOKUP):0);
1033
if(!ap)
1034
{
1035
nv_putsub(np, NIL(char*), ARRAY_FILL);
1036
ap = nv_arrayptr(np);
1037
}
1038
if(!(up = array_getup(np,ap,0)))
1039
return((Namval_t*)0);
1040
np->nvalue.cp = up->cp;
1041
if((tp=nv_type(np)) || c)
1042
{
1043
ap->nelem |= ARRAY_NOCLONE;
1044
nq->nvenv = (char*)np;
1045
if(c=='t')
1046
nv_clone(tp,nq, 0);
1047
else
1048
nv_clone(np, nq, NV_NODISC);
1049
nv_offattr(nq,NV_ARRAY);
1050
ap->nelem &= ~ARRAY_NOCLONE;
1051
}
1052
nq->nvenv = (char*)np;
1053
if((fp=nq->nvfun) && fp->disc && fp->disc->setdisc && (fp = nv_disc(nq,fp,NV_POP)))
1054
free((void*)fp);
1055
if(!ap->fun)
1056
{
1057
struct index_array *aq = (struct index_array*)ap;
1058
array_setbit(aq->bits,aq->cur,ARRAY_CHILD);
1059
if(c=='.' && !nq->nvalue.cp)
1060
ap->nelem++;
1061
up->np = nq;
1062
}
1063
if(c=='.')
1064
nv_setvtree(nq);
1065
return(nq);
1066
}
1067
1068
/*
1069
* This routine sets subscript of <np> to the next element, if any.
1070
* The return value is zero, if there are no more elements
1071
* Otherwise, 1 is returned.
1072
*/
1073
int nv_nextsub(Namval_t *np)
1074
{
1075
register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
1076
register unsigned dot;
1077
struct index_array *aq=0, *ar=0;
1078
#if SHOPT_FIXEDARRAY
1079
struct fixed_array *fp;
1080
#endif /* SHOPT_FIXEDARRAY */
1081
if(!ap || !(ap->header.nelem&ARRAY_SCAN))
1082
return(0);
1083
if(is_associative(ap))
1084
{
1085
if((*ap->header.fun)(np,NIL(char*),NV_ANEXT))
1086
return(1);
1087
ap->header.nelem &= ~(ARRAY_SCAN|ARRAY_NOCHILD);
1088
return(0);
1089
}
1090
#if SHOPT_FIXEDARRAY
1091
else if(fp = (struct fixed_array*)ap->header.fixed)
1092
{
1093
if(ap->header.nelem&ARRAY_FIXED)
1094
{
1095
while(++fp->curi < fp->nelem)
1096
{
1097
nv_putsub(np,0,fp->curi|ARRAY_FIXED|ARRAY_SCAN);
1098
if(fp->ptr && *(((char**)fp->data)+fp->curi))
1099
return(1);
1100
}
1101
ap->header.nelem &= ~ARRAY_FIXED;
1102
return(0);
1103
}
1104
dot = fp->dim;
1105
if((fp->cur[dot]+1) < fp->max[dot])
1106
{
1107
fp->cur[dot]++;
1108
for(fp->curi=0,dot=0; dot < fp->ndim; dot++)
1109
fp->curi += fp->incr[dot]*fp->cur[dot];
1110
return(1);
1111
}
1112
if(fp->level)
1113
{
1114
dot= --fp->dim;
1115
while((dot+1) < fp->ndim)
1116
fp->cur[++dot] = 0;
1117
fp->level--;
1118
fp->curi = 0;
1119
}
1120
else
1121
ap->header.nelem &= ~(ARRAY_SCAN|ARRAY_NOCHILD);
1122
return(0);
1123
}
1124
#endif /* SHOPT_FIXEDARRAY */
1125
if(!(ap->header.nelem&ARRAY_NOSCOPE))
1126
ar = (struct index_array*)ap->header.scope;
1127
for(dot=ap->cur+1; dot < (unsigned)ap->maxi; dot++)
1128
{
1129
aq = ap;
1130
if(!ap->val[dot].cp && !(ap->header.nelem&ARRAY_NOSCOPE))
1131
{
1132
if(!(aq=ar) || dot>=(unsigned)aq->maxi)
1133
continue;
1134
}
1135
if(aq->val[dot].cp==Empty && array_elem(&aq->header) < nv_aimax(np)+1) {
1136
ap->cur = dot;
1137
if(nv_getval(np)==Empty)
1138
continue;
1139
}
1140
if(aq->val[dot].cp)
1141
{
1142
ap->cur = dot;
1143
if(array_isbit(aq->bits, dot,ARRAY_CHILD))
1144
{
1145
Namval_t *mp = aq->val[dot].np;
1146
if((aq->header.nelem&ARRAY_NOCHILD) && nv_isvtree(mp) && !mp->nvfun->dsize)
1147
continue;
1148
if(nv_isarray(mp))
1149
nv_putsub(mp,NIL(char*),ARRAY_SCAN);
1150
}
1151
return(1);
1152
}
1153
}
1154
ap->header.nelem &= ~(ARRAY_SCAN|ARRAY_NOCHILD);
1155
ap->cur = 0;
1156
return(0);
1157
}
1158
1159
/*
1160
* Set an array subscript for node <np> given the subscript <sp>
1161
* An array is created if necessary.
1162
* <mode> can be a number, plus or more of symbolic constants
1163
* ARRAY_SCAN, ARRAY_UNDEF, ARRAY_ADD
1164
* The node pointer is returned which can be NULL if <np> is
1165
* not already array and the ARRAY_ADD bit of <mode> is not set.
1166
* ARRAY_FILL sets the specified subscript to the empty string when
1167
* ARRAY_ADD is specified and there is no value or sets all
1168
* the elements up to the number specified if ARRAY_ADD is not specified
1169
*/
1170
Namval_t *nv_putsub(Namval_t *np,register char *sp,register long mode)
1171
{
1172
register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
1173
register int size = (mode&ARRAY_MASK);
1174
#if SHOPT_FIXEDARRAY
1175
struct fixed_array *fp;
1176
if(!ap || (!ap->header.fixed && !ap->header.fun))
1177
#else
1178
if(!ap || !ap->header.fun)
1179
#endif /* SHOPT_FIXEDARRAY */
1180
{
1181
if(sp)
1182
{
1183
Shell_t *shp = sh_getinterp();
1184
if(ap && ap->xp && !strmatch(sp,"+([0-9])"))
1185
{
1186
Namval_t *mp = nv_namptr(ap->xp,0);
1187
nv_putval(mp, sp,0);
1188
size = nv_getnum(mp);
1189
}
1190
else
1191
size = (int)sh_arith(shp,(char*)sp);
1192
}
1193
if(size <0 && ap)
1194
size += array_maxindex(np);
1195
if(size >= ARRAY_MAX || (size < 0))
1196
{
1197
errormsg(SH_DICT,ERROR_exit(1),e_subscript, nv_name(np));
1198
return(NIL(Namval_t*));
1199
}
1200
if(!ap || size>=ap->maxi)
1201
{
1202
if(size==0 && !(mode&ARRAY_FILL))
1203
return(NIL(Namval_t*));
1204
if(sh.subshell)
1205
np = sh_assignok(np,1);
1206
ap = array_grow(np, ap,size);
1207
}
1208
ap->header.nelem &= ~ARRAY_UNDEF;
1209
ap->header.nelem |= (mode&(ARRAY_SCAN|ARRAY_NOCHILD|ARRAY_UNDEF|ARRAY_NOSCOPE));
1210
#if 0
1211
if(array_isbit(ap->bits,oldsize,ARRAY_CHILD))
1212
mp = ap->val[oldsize].np;
1213
if(size != oldsize && mp->nvalue.cp)
1214
{
1215
Namfun_t *nfp;
1216
for(nfp=np->nvfun; nfp; nfp=nfp->next)
1217
{
1218
if(nfp->disc && nfp->disc->readf)
1219
{
1220
(*nfp->disc->readf)(mp,(Sfio_t*)0,0,nfp);
1221
break;
1222
}
1223
}
1224
}
1225
#endif
1226
ap->cur = size;
1227
if((mode&ARRAY_SCAN) && (ap->cur--,!nv_nextsub(np)))
1228
np = 0;
1229
if(mode&(ARRAY_FILL|ARRAY_ADD))
1230
{
1231
if(!(mode&ARRAY_ADD))
1232
{
1233
int n;
1234
if(mode&ARRAY_SETSUB)
1235
{
1236
for(n=0; n <= ap->maxi; n++)
1237
ap->val[n].cp = 0;
1238
ap->header.nelem = 0;
1239
}
1240
for(n=0; n <= size; n++)
1241
{
1242
if(!ap->val[n].cp)
1243
{
1244
ap->val[n].cp = Empty;
1245
if(!array_covered(np,ap))
1246
ap->header.nelem++;
1247
}
1248
}
1249
if(n=ap->maxi-ap->maxi)
1250
memset(&ap->val[size],0,n*sizeof(union Value));
1251
}
1252
else if(!(sp=(char*)ap->val[size].cp) || sp==Empty)
1253
{
1254
if(sh.subshell)
1255
np = sh_assignok(np,1);
1256
if(ap->header.nelem&ARRAY_TREE)
1257
{
1258
char *cp;
1259
Namval_t *mp;
1260
if(!ap->header.table)
1261
ap->header.table = dtopen(&_Nvdisc,Dtoset);
1262
sfprintf(sh.strbuf,"%d",ap->cur);
1263
cp = sfstruse(sh.strbuf);
1264
mp = nv_search(cp, ap->header.table, NV_ADD);
1265
mp->nvenv = (char*)np;
1266
nv_arraychild(np,mp,0);
1267
nv_setvtree(mp);
1268
}
1269
else
1270
ap->val[size].cp = Empty;
1271
if(!sp && !array_covered(np,ap))
1272
ap->header.nelem++;
1273
}
1274
}
1275
else if(!(mode&ARRAY_SCAN))
1276
{
1277
ap->header.nelem &= ~ARRAY_SCAN;
1278
if(array_isbit(ap->bits,size,ARRAY_CHILD))
1279
nv_putsub(ap->val[size].np,NIL(char*),ARRAY_UNDEF);
1280
if(sp && !(mode&ARRAY_ADD) && !ap->val[size].cp)
1281
np = 0;
1282
}
1283
return((Namval_t*)np);
1284
}
1285
#if SHOPT_FIXEDARRAY
1286
if(fp=(struct fixed_array*)ap->header.fixed)
1287
{
1288
if(!fp->data)
1289
return(np);
1290
if(mode&ARRAY_UNDEF)
1291
{
1292
fp->dim = 0;
1293
fp->curi = 0;
1294
for(size=fp->ndim;--size>=0;)
1295
fp->cur[size] = 0;
1296
ap->header.nelem &= ~ARRAY_MASK;
1297
if(mode&ARRAY_FIXED)
1298
{
1299
mode &= ~ARRAY_UNDEF;
1300
ap->header.nelem |= (ARRAY_FIXED|fp->nelem);
1301
}
1302
else
1303
ap->header.nelem |= fp->max[0];
1304
}
1305
else if(mode&ARRAY_FIXED)
1306
{
1307
size = (mode&ARRAY_MASK)&~(ARRAY_FIXED);
1308
fp->curi = size;
1309
for(fp->dim=0;size>0 && fp->dim<fp->ndim; fp->dim++)
1310
{
1311
fp->cur[fp->dim] = size/fp->incr[fp->dim];
1312
size -= fp->incr[fp->dim]*fp->cur[fp->dim];
1313
}
1314
while(fp->dim < fp->ndim)
1315
fp->cur[fp->dim++] = 0;
1316
fp->dim = ap->header.nelem;
1317
ap->header.nelem |= ARRAY_FIXED;
1318
}
1319
else if(fp->dim< fp->ndim)
1320
{
1321
fp->curi += (size-fp->cur[fp->dim])*fp->incr[fp->dim];
1322
fp->cur[fp->dim] = size;
1323
}
1324
}
1325
#endif /* SHOPT_FIXEDARRAY */
1326
ap->header.nelem &= ~ARRAY_UNDEF;
1327
if(!(mode&ARRAY_FILL))
1328
ap->header.nelem &= ~ARRAY_SCAN;
1329
ap->header.nelem |= (mode&(ARRAY_SCAN|ARRAY_NOCHILD|ARRAY_UNDEF|ARRAY_NOSCOPE));
1330
#if SHOPT_FIXEDARRAY
1331
if(fp)
1332
return(np);
1333
else
1334
#endif /* SHOPT_FIXEDARRAY */
1335
if(sp)
1336
{
1337
if(mode&ARRAY_SETSUB)
1338
{
1339
(*ap->header.fun)(np, sp, NV_ASETSUB);
1340
return(np);
1341
}
1342
(*ap->header.fun)(np, sp, (mode&ARRAY_ADD)?NV_AADD:0);
1343
if(!(mode&(ARRAY_SCAN|ARRAY_ADD)) && !(*ap->header.fun)(np,NIL(char*),NV_ACURRENT))
1344
np = 0;
1345
}
1346
else if(mode&ARRAY_SCAN)
1347
(*ap->header.fun)(np,(char*)np,0);
1348
else if(mode&ARRAY_UNDEF)
1349
(*ap->header.fun)(np, "",0);
1350
if((mode&ARRAY_SCAN) && !nv_nextsub(np))
1351
np = 0;
1352
return(np);
1353
}
1354
1355
#if SHOPT_FIXEDARRAY
1356
int nv_arrfixed(Namval_t *np, Sfio_t *out, int flag, char *dim)
1357
{
1358
Namarr_t *ap = nv_arrayptr(np);
1359
struct fixed_array *fp = (struct fixed_array*)ap->fixed;
1360
int n;
1361
if(flag)
1362
{
1363
if(out)
1364
{
1365
for(n=0; n < fp->dim; n++)
1366
sfprintf(out,"[%d]",fp->cur[n]);
1367
}
1368
if(dim)
1369
*dim = fp->dim;
1370
return(fp->curi);
1371
}
1372
if(out)
1373
{
1374
for(n=0; n < fp->ndim; n++)
1375
sfprintf(out,"[%d]",fp->max[n]);
1376
}
1377
fp->dim = 0;
1378
return(fp->curi);
1379
}
1380
1381
static void array_fixed_setdata(Namval_t *np,Namarr_t* ap,struct fixed_array* fp)
1382
{
1383
int n = ap->nelem;
1384
ap->nelem = 1;
1385
fp->size = fp->ptr?sizeof(void*):nv_datasize(np,0);
1386
ap->nelem = n;
1387
fp->data = (char*)calloc(fp->nelem,fp->size);
1388
if(fp->ptr)
1389
{
1390
char **cp = (char**)fp->data;
1391
for(n=fp->nelem; n-->0;)
1392
*cp++ = Empty;
1393
}
1394
}
1395
1396
static int array_fixed_init(Namval_t *np, char *sub, char *cp)
1397
{
1398
Shell_t *shp=sh_getinterp();
1399
Namarr_t *ap;
1400
struct fixed_array *fp;
1401
int n=1,sz;
1402
char *ep=cp;
1403
while(*ep=='[')
1404
{
1405
ep = nv_endsubscript(np,ep,0);
1406
n++;
1407
}
1408
if(*ep)
1409
return(0);
1410
sz = sizeof(struct fixed_array)+ 3*n*sizeof(int);
1411
if(!(ap=newof(NIL(Namarr_t*),Namarr_t,1,sz)))
1412
return(0);
1413
ap->hdr.disc = &array_disc;
1414
ap->hdr.dsize = sizeof(Namarr_t)+sz;
1415
ap->hdr.nofree &= ~1;
1416
fp = (struct fixed_array*)(ap+1);
1417
ap->fixed = (void*)fp;
1418
fp->ndim = n;
1419
fp->max = (int*)(fp+1);
1420
fp->incr = fp->max+n;
1421
fp->cur = fp->incr+n;
1422
fp->max[0] = (int)sh_arith(shp,(char*)sub);
1423
for(n=1,ep=cp;*ep=='['; ep=cp)
1424
{
1425
cp = nv_endsubscript(np,ep,0);
1426
cp[-1]=0;
1427
fp->max[n++] = sz = (int)sh_arith(shp,(char*)ep+1);
1428
if(sz<0)
1429
{
1430
free((void*)ap);
1431
errormsg(SH_DICT,ERROR_exit(1),e_subscript, nv_name(np));
1432
}
1433
cp[-1] = ']';
1434
}
1435
nv_disc(np,(Namfun_t*)ap, NV_FIRST);
1436
fp->ptr = !np->nvsize;
1437
nv_onattr(np,NV_ARRAY|(fp->ptr?0:NV_NOFREE));
1438
fp->incr[n=fp->ndim-1] = 1;
1439
for(sz=1; --n>=0;)
1440
sz = fp->incr[n] = sz*fp->max[n+1];
1441
fp->nelem = sz*fp->max[0];
1442
ap->nelem = fp->max[0];
1443
return(1);
1444
}
1445
1446
static char *array_fixed(Namval_t *np, char *sub, char *cp,int mode)
1447
{
1448
Shell_t *shp=sh_getinterp();
1449
Namarr_t *ap = nv_arrayptr(np);
1450
struct fixed_array *fp = (struct fixed_array*)ap->fixed;
1451
char *ep;
1452
int size,n=0,sz;
1453
if(!fp->data)
1454
array_fixed_setdata(np,ap,fp);
1455
ap->nelem &= ~ARRAY_UNDEF;
1456
if(ap->nelem&ARRAY_FIXED)
1457
{
1458
ap->nelem &= ~ARRAY_FIXED;
1459
n = fp->dim;
1460
sz = fp->curi;
1461
if(*sub==0)
1462
goto skip;
1463
}
1464
else
1465
fp->curi = 0;
1466
size = (int)sh_arith(shp,(char*)sub);
1467
fp->cur[n] = size;
1468
if(size >= fp->max[n] || (size < 0))
1469
errormsg(SH_DICT,ERROR_exit(1),e_subscript, nv_name(np));
1470
*cp++ = ']';
1471
sz = fp->curi + fp->cur[n]*fp->incr[n];
1472
for(n++,ep=cp;*ep=='['; ep=cp,n++)
1473
{
1474
if(n >= fp->ndim)
1475
errormsg(SH_DICT,ERROR_exit(1),e_subscript, nv_name(np));
1476
cp = nv_endsubscript(np,ep,0);
1477
cp[-1]=0;
1478
size = (int)sh_arith(shp,(char*)ep+1);
1479
if(size >= fp->max[n] || (size < 0))
1480
errormsg(SH_DICT,ERROR_exit(1),e_subscript, nv_name(np));
1481
fp->cur[n] = size;
1482
cp[-1] = ']';
1483
sz += fp->cur[n]*fp->incr[n];
1484
}
1485
skip:
1486
fp->dim = n;
1487
ap->nelem &= ~ARRAY_MASK;
1488
ap->nelem |= fp->max[n];
1489
while(n < fp->ndim)
1490
fp->cur[n++] = 0;
1491
fp->curi = sz;
1492
return(cp-1);
1493
}
1494
#endif /* SHOPT_FIXEDARRAY */
1495
1496
/*
1497
* process an array subscript for node <np> given the subscript <cp>
1498
* returns pointer to character after the subscript
1499
*/
1500
char *nv_endsubscript(Namval_t *np, register char *cp, int mode)
1501
{
1502
register int count=1, quoted=0, c;
1503
register char *sp = cp+1;
1504
/* first find matching ']' */
1505
while(count>0 && (c= *++cp))
1506
{
1507
if(c=='\\' && (!(mode&NV_SUBQUOTE) || (c=cp[1])=='[' || c==']' || c=='\\' || c=='*' || c=='@'))
1508
{
1509
quoted=1;
1510
cp++;
1511
}
1512
else if(c=='[')
1513
count++;
1514
else if(c==']')
1515
count--;
1516
}
1517
*cp = 0;
1518
if(quoted)
1519
{
1520
/* strip escape characters */
1521
count = staktell();
1522
stakwrite(sp,1+cp-sp);
1523
sh_trim(sp=stakptr(count));
1524
}
1525
if(mode && np)
1526
{
1527
Namarr_t *ap = nv_arrayptr(np);
1528
int scan = 0;
1529
#if SHOPT_FIXEDARRAY
1530
if((mode&NV_FARRAY) && !nv_isarray(np))
1531
{
1532
if(array_fixed_init(np,sp,cp+1))
1533
{
1534
*cp++ = c;
1535
return(strchr(cp,0));
1536
}
1537
}
1538
#endif /* SHOPT_FIXEDARRAY */
1539
if(ap)
1540
scan = ap->nelem&ARRAY_SCAN;
1541
if((mode&NV_ASSIGN) && (cp[1]=='=' || cp[1]=='+'))
1542
mode |= NV_ADD;
1543
else if(ap && cp[1]=='.' && (mode&NV_FARRAY))
1544
mode |= NV_ADD;
1545
#if SHOPT_FIXEDARRAY
1546
if(ap && ap->fixed)
1547
cp = array_fixed(np,sp,cp,mode);
1548
else
1549
#endif /* SHOPT_FIXEDARRAY */
1550
nv_putsub(np, sp, ((mode&NV_ADD)?ARRAY_ADD:0)|(cp[1]&&(mode&NV_ADD)?ARRAY_FILL:mode&ARRAY_FILL));
1551
if(scan)
1552
ap->nelem |= scan;
1553
}
1554
if(quoted)
1555
stakseek(count);
1556
*cp++ = c;
1557
return(cp);
1558
}
1559
1560
1561
Namval_t *nv_opensub(Namval_t* np)
1562
{
1563
register struct index_array *ap = (struct index_array*)nv_arrayptr(np);
1564
#if SHOPT_FIXEDARRAY
1565
struct fixed_array *fp;
1566
#endif /* SHOPT_FIXEDARRAY */
1567
if(ap)
1568
{
1569
if(is_associative(ap))
1570
return((Namval_t*)((*ap->header.fun)(np,NIL(char*),NV_ACURRENT)));
1571
#if SHOPT_FIXEDARRAY
1572
else if(!(fp=(struct fixed_array*)ap->header.fixed) && array_isbit(ap->bits,ap->cur,ARRAY_CHILD))
1573
#else
1574
else if(array_isbit(ap->bits,ap->cur,ARRAY_CHILD))
1575
#endif /* SHOPT_FIXEDARRAY */
1576
{
1577
return(ap->val[ap->cur].np);
1578
}
1579
#if SHOPT_FIXEDARRAY
1580
else if(fp)
1581
{
1582
int n = fp->dim;
1583
if((fp->dim+1) < fp->ndim)
1584
{
1585
fp->dim++;
1586
if(ap->header.nelem&ARRAY_SCAN)
1587
{
1588
while(++n < fp->ndim)
1589
fp->cur[n] = 0;
1590
fp->level++;
1591
}
1592
return(np);
1593
}
1594
}
1595
#endif /* SHOPT_FIXEDARRAY */
1596
}
1597
return(NIL(Namval_t*));
1598
}
1599
1600
char *nv_getsub(Namval_t* np)
1601
{
1602
static char numbuff[NUMSIZE+1];
1603
register struct index_array *ap;
1604
register unsigned dot, n;
1605
register char *cp = &numbuff[NUMSIZE];
1606
if(!np || !(ap = (struct index_array*)nv_arrayptr(np)))
1607
return(NIL(char*));
1608
if(is_associative(ap))
1609
return((char*)((*ap->header.fun)(np,NIL(char*),NV_ANAME)));
1610
if(ap->xp)
1611
{
1612
np = nv_namptr(ap->xp,0);
1613
np->nvalue.s = ap->cur;
1614
return(nv_getval(np));
1615
}
1616
if((dot = ap->cur)==0)
1617
*--cp = '0';
1618
else while(n=dot)
1619
{
1620
dot /= 10;
1621
*--cp = '0' + (n-10*dot);
1622
}
1623
return(cp);
1624
}
1625
1626
/*
1627
* If <np> is an indexed array node, the current subscript index
1628
* returned, otherwise returns -1
1629
*/
1630
int nv_aindex(register Namval_t* np)
1631
{
1632
Namarr_t *ap = nv_arrayptr(np);
1633
if(!ap)
1634
return(0);
1635
else if(is_associative(ap))
1636
return(-1);
1637
#if SHOPT_FIXEDARRAY
1638
else if(ap->fixed)
1639
return(-1);
1640
#endif /* SHOPT_FIXEDARRAY */
1641
return(((struct index_array*)(ap))->cur&ARRAY_MASK);
1642
}
1643
1644
int nv_arraynsub(register Namarr_t* ap)
1645
{
1646
return(array_elem(ap));
1647
}
1648
1649
int nv_aimax(register Namval_t* np)
1650
{
1651
struct index_array *ap = (struct index_array*)nv_arrayptr(np);
1652
int sub = -1;
1653
#if SHOPT_FIXEDARRAY
1654
if(!ap || is_associative(&ap->header) || ap->header.fixed)
1655
#else
1656
if(!ap || is_associative(&ap->header))
1657
#endif /* SHOPT_FIXEDARRAY */
1658
return(-1);
1659
sub = ap->maxi;
1660
while(--sub>0 && ap->val[sub].cp==0);
1661
return(sub);
1662
}
1663
1664
/*
1665
* This is the default implementation for associative arrays
1666
*/
1667
void *nv_associative(register Namval_t *np,const char *sp,int mode)
1668
{
1669
register struct assoc_array *ap = (struct assoc_array*)nv_arrayptr(np);
1670
register int type;
1671
switch(mode)
1672
{
1673
case NV_AINIT:
1674
if(ap = (struct assoc_array*)calloc(1,sizeof(struct assoc_array)))
1675
{
1676
ap->header.table = dtopen(&_Nvdisc,Dtoset);
1677
ap->cur = 0;
1678
ap->pos = 0;
1679
ap->header.hdr.disc = &array_disc;
1680
nv_disc(np,(Namfun_t*)ap, NV_FIRST);
1681
ap->header.hdr.dsize = sizeof(struct assoc_array);
1682
ap->header.hdr.nofree &= ~1;
1683
}
1684
return((void*)ap);
1685
case NV_ADELETE:
1686
if(ap->cur)
1687
{
1688
if(!ap->header.scope || (Dt_t*)ap->header.scope==ap->header.table || !nv_search(ap->cur->nvname,(Dt_t*)ap->header.scope,0))
1689
ap->header.nelem--;
1690
_nv_unset(ap->cur,NV_RDONLY);
1691
nv_delete(ap->cur,ap->header.table,0);
1692
ap->cur = 0;
1693
}
1694
return((void*)ap);
1695
case NV_AFREE:
1696
ap->pos = 0;
1697
if(ap->header.scope)
1698
{
1699
ap->header.table = dtview(ap->header.table,(Dt_t*)0);
1700
dtclose(ap->header.scope);
1701
ap->header.scope = 0;
1702
}
1703
else
1704
dtclose(ap->header.table);
1705
return((void*)ap);
1706
case NV_ANEXT:
1707
if(!ap->pos)
1708
{
1709
if((ap->header.nelem&ARRAY_NOSCOPE) && ap->header.scope && dtvnext(ap->header.table))
1710
{
1711
ap->header.scope = dtvnext(ap->header.table);
1712
ap->header.table->view = 0;
1713
}
1714
if(!(ap->pos=ap->cur))
1715
ap->pos = (Namval_t*)dtfirst(ap->header.table);
1716
}
1717
else
1718
ap->pos = ap->nextpos;
1719
for(;ap->cur=ap->pos; ap->pos=ap->nextpos)
1720
{
1721
ap->nextpos = (Namval_t*)dtnext(ap->header.table,ap->pos);
1722
if(!nv_isnull(ap->cur))
1723
{
1724
if((ap->header.nelem&ARRAY_NOCHILD) && nv_isattr(ap->cur,NV_CHILD))
1725
continue;
1726
return((void*)ap);
1727
}
1728
}
1729
if((ap->header.nelem&ARRAY_NOSCOPE) && ap->header.scope && !dtvnext(ap->header.table))
1730
{
1731
ap->header.table->view = (Dt_t*)ap->header.scope;
1732
ap->header.scope = ap->header.table;
1733
}
1734
return(NIL(void*));
1735
case NV_ASETSUB:
1736
ap->cur = (Namval_t*)sp;
1737
return((void*)ap->cur);
1738
case NV_ACURRENT:
1739
if(ap->cur)
1740
ap->cur->nvenv = (char*)np;
1741
return((void*)ap->cur);
1742
case NV_ANAME:
1743
if(ap->cur)
1744
{
1745
Shell_t *shp = sh_getinterp();
1746
if(!shp->instance && nv_isnull(ap->cur))
1747
return(NIL(void*));
1748
return((void*)ap->cur->nvname);
1749
}
1750
return(NIL(void*));
1751
default:
1752
if(sp)
1753
{
1754
Namval_t *mp=0;
1755
ap->cur = 0;
1756
if(sp==(char*)np)
1757
return(0);
1758
type = nv_isattr(np,NV_PUBLIC&~(NV_ARRAY|NV_CHILD|NV_MINIMAL));
1759
if(mode)
1760
mode = NV_ADD|HASH_NOSCOPE;
1761
else if(ap->header.nelem&ARRAY_NOSCOPE)
1762
mode = HASH_NOSCOPE;
1763
if(*sp==0 && sh_isoption(SH_XTRACE) && (mode&NV_ADD))
1764
errormsg(SH_DICT,ERROR_warn(0),"adding empty subscript");
1765
if(sh.subshell && (mp=nv_search(sp,ap->header.table,0)) && nv_isnull(mp))
1766
ap->cur = mp;
1767
if((mp || (mp=nv_search(sp,ap->header.table,mode))) && nv_isnull(mp) && (mode&NV_ADD))
1768
{
1769
nv_onattr(mp,type);
1770
mp->nvenv = (char*)np;
1771
if((mode&NV_ADD) && nv_type(np))
1772
nv_arraychild(np,mp,0);
1773
if(sh.subshell)
1774
np = sh_assignok(np,1);
1775
if(!ap->header.scope || !nv_search(sp,dtvnext(ap->header.table),0))
1776
ap->header.nelem++;
1777
if(nv_isnull(mp))
1778
{
1779
if(ap->header.nelem&ARRAY_TREE)
1780
nv_setvtree(mp);
1781
mp->nvalue.cp = Empty;
1782
}
1783
}
1784
else if(ap->header.nelem&ARRAY_SCAN)
1785
{
1786
Namval_t fake;
1787
fake.nvname = (char*)sp;
1788
ap->pos = mp = (Namval_t*)dtprev(ap->header.table,&fake);
1789
ap->nextpos = (Namval_t*)dtnext(ap->header.table,mp);
1790
}
1791
else if(!mp && *sp && mode==0)
1792
mp = nv_search(sp,ap->header.table,NV_ADD|HASH_NOSCOPE);
1793
np = mp;
1794
if(ap->pos && ap->pos==np)
1795
ap->header.nelem |= ARRAY_SCAN;
1796
else if(!(ap->header.nelem&ARRAY_SCAN))
1797
ap->pos = 0;
1798
ap->cur = np;
1799
}
1800
if(ap->cur)
1801
return((void*)(&ap->cur->nvalue));
1802
else
1803
return((void*)(&ap->cur));
1804
}
1805
}
1806
1807
/*
1808
* Assign values to an array
1809
*/
1810
void nv_setvec(register Namval_t *np,int append,register int argc,register char *argv[])
1811
{
1812
int arg0=0;
1813
struct index_array *ap=0,*aq;
1814
if(nv_isarray(np))
1815
{
1816
ap = (struct index_array*)nv_arrayptr(np);
1817
if(ap && is_associative(ap))
1818
errormsg(SH_DICT,ERROR_exit(1),"cannot append index array to associative array %s",nv_name(np));
1819
}
1820
if(append)
1821
{
1822
if(ap)
1823
{
1824
if(!(aq = (struct index_array*)ap->header.scope))
1825
aq = ap;
1826
arg0 = ap->maxi;
1827
while(--arg0>0 && ap->val[arg0].cp==0 && aq->val[arg0].cp==0);
1828
arg0++;
1829
}
1830
else
1831
{
1832
nv_offattr(np,NV_ARRAY);
1833
if(!nv_isnull(np) && np->nvalue.cp!=Empty)
1834
arg0=1;
1835
}
1836
}
1837
while(--argc >= 0)
1838
{
1839
nv_putsub(np,NIL(char*),(long)argc+arg0|ARRAY_FILL|ARRAY_ADD);
1840
nv_putval(np,argv[argc],0);
1841
}
1842
}
1843
1844
1845