Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/ksh93/sh/parse.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
* UNIX shell
23
*
24
* S. R. Bourne
25
* Rewritten by David Korn
26
* AT&T Labs
27
*
28
* This is the parser for a shell language
29
*/
30
31
#if KSHELL
32
#include "defs.h"
33
#else
34
#include <shell.h>
35
#include <ctype.h>
36
#endif
37
#include <fcin.h>
38
#include <error.h>
39
#include "shlex.h"
40
#include "history.h"
41
#include "builtins.h"
42
#include "test.h"
43
#include "history.h"
44
45
#define HERE_MEM SF_BUFSIZE /* size of here-docs kept in memory */
46
47
#if CDT_VERSION < 20111111L
48
#define hash nvlink.hl._hash
49
#else
50
#define hash nvlink.lh.__hash
51
#endif
52
53
/* These routines are local to this module */
54
55
static Shnode_t *makeparent(Lex_t*, int, Shnode_t*);
56
static Shnode_t *makelist(Lex_t*, int, Shnode_t*, Shnode_t*);
57
static struct argnod *qscan(struct comnod*, int);
58
static struct ionod *inout(Lex_t*,struct ionod*, int);
59
static Shnode_t *sh_cmd(Lex_t*,int,int);
60
static Shnode_t *term(Lex_t*,int);
61
static Shnode_t *list(Lex_t*,int);
62
static struct regnod *syncase(Lex_t*,int);
63
static Shnode_t *item(Lex_t*,int);
64
static Shnode_t *simple(Lex_t*,int, struct ionod*);
65
static int skipnl(Lex_t*,int);
66
static Shnode_t *test_expr(Lex_t*,int);
67
static Shnode_t *test_and(Lex_t*);
68
static Shnode_t *test_or(Lex_t*);
69
static Shnode_t *test_primary(Lex_t*);
70
71
#define sh_getlineno(lp) (lp->lastline)
72
73
#ifndef NIL
74
# define NIL(type) ((type)0)
75
#endif /* NIL */
76
#define CNTL(x) ((x)&037)
77
78
79
#if !KSHELL
80
static struct stdata
81
{
82
struct slnod *staklist;
83
int cmdline;
84
} st;
85
#endif
86
87
static int opt_get;
88
static int loop_level;
89
static struct argnod *label_list;
90
static struct argnod *label_last;
91
92
#define getnode(type) ((Shnode_t*)stakalloc(sizeof(struct type)))
93
94
#if SHOPT_KIA
95
#include "path.h"
96
/*
97
* write out entities for each item in the list
98
* type=='V' for variable assignment lists
99
* Otherwise type is determined by the command */
100
static unsigned long writedefs(Lex_t *lexp,struct argnod *arglist, int line, int type, struct argnod *cmd)
101
{
102
register struct argnod *argp = arglist;
103
register char *cp;
104
register int n,eline;
105
int width=0;
106
unsigned long r=0;
107
static char atbuff[20];
108
int justify=0;
109
char *attribute = atbuff;
110
unsigned long parent=lexp->script;
111
if(type==0)
112
{
113
parent = lexp->current;
114
type = 'v';
115
switch(*argp->argval)
116
{
117
case 'a':
118
type='p';
119
justify = 'a';
120
break;
121
case 'e':
122
*attribute++ = 'x';
123
break;
124
case 'r':
125
*attribute++ = 'r';
126
break;
127
case 'l':
128
break;
129
}
130
while(argp = argp->argnxt.ap)
131
{
132
if((n= *(cp=argp->argval))!='-' && n!='+')
133
break;
134
if(cp[1]==n)
135
break;
136
while((n= *++cp))
137
{
138
if(isdigit(n))
139
width = 10*width + n-'0';
140
else if(n=='L' || n=='R' || n =='Z')
141
justify=n;
142
else
143
*attribute++ = n;
144
}
145
}
146
}
147
else if(cmd)
148
parent=kiaentity(lexp,sh_argstr(cmd),-1,'p',-1,-1,lexp->unknown,'b',0,"");
149
*attribute = 0;
150
while(argp)
151
{
152
if((cp=strchr(argp->argval,'='))||(cp=strchr(argp->argval,'?')))
153
n = cp-argp->argval;
154
else
155
n = strlen(argp->argval);
156
eline = lexp->sh->inlineno-(lexp->token==NL);
157
r=kiaentity(lexp,argp->argval,n,type,line,eline,parent,justify,width,atbuff);
158
sfprintf(lexp->kiatmp,"p;%..64d;v;%..64d;%d;%d;s;\n",lexp->current,r,line,eline);
159
argp = argp->argnxt.ap;
160
}
161
return(r);
162
}
163
#endif /* SHOPT_KIA */
164
165
static void typeset_order(const char *str,int line)
166
{
167
register int c,n=0;
168
unsigned const char *cp=(unsigned char*)str;
169
static unsigned char *table;
170
if(*cp!='+' && *cp!='-')
171
return;
172
if(!table)
173
{
174
table = calloc(1,256);
175
for(cp=(unsigned char*)"bflmnprstuxACHS";c = *cp; cp++)
176
table[c] = 1;
177
for(cp=(unsigned char*)"aiEFLRXhTZ";c = *cp; cp++)
178
table[c] = 2;
179
for(c='0'; c <='9'; c++)
180
table[c] = 3;
181
}
182
for(cp=(unsigned char*)str; c= *cp++; n=table[c])
183
{
184
if(table[c] < n)
185
errormsg(SH_DICT,ERROR_warn(0),e_lextypeset,line,str);
186
}
187
}
188
189
/*
190
* add type definitions when compiling with -n
191
*/
192
static void check_typedef(struct comnod *tp)
193
{
194
char *cp=0;
195
if(tp->comtyp&COMSCAN)
196
{
197
struct argnod *ap = tp->comarg;
198
while(ap = ap->argnxt.ap)
199
{
200
if(!(ap->argflag&ARG_RAW) || memcmp(ap->argval,"--",2))
201
break;
202
if(sh_isoption(SH_NOEXEC))
203
typeset_order(ap->argval,tp->comline);
204
if(memcmp(ap->argval,"-T",2)==0)
205
{
206
if(ap->argval[2])
207
cp = ap->argval+2;
208
else if((ap->argnxt.ap)->argflag&ARG_RAW)
209
cp = (ap->argnxt.ap)->argval;
210
if(cp)
211
break;
212
}
213
}
214
}
215
else
216
{
217
struct dolnod *dp = (struct dolnod*)tp->comarg;
218
char **argv = dp->dolval + dp->dolbot+1;
219
while((cp= *argv++) && memcmp(cp,"--",2))
220
{
221
if(sh_isoption(SH_NOEXEC))
222
typeset_order(cp,tp->comline);
223
if(memcmp(cp,"-T",2)==0)
224
{
225
if(cp[2])
226
cp = cp+2;
227
else
228
cp = *argv;
229
break;
230
}
231
}
232
}
233
if(cp)
234
{
235
Namval_t *mp=(Namval_t*)tp->comnamp ,*bp;
236
bp = sh_addbuiltin(cp, (Shbltin_f)mp->nvalue.bfp, (void*)0);
237
nv_onattr(bp,nv_isattr(mp,NV_PUBLIC));
238
}
239
}
240
241
/*
242
* Make a parent node for fork() or io-redirection
243
*/
244
static Shnode_t *makeparent(Lex_t *lp, int flag, Shnode_t *child)
245
{
246
register Shnode_t *par = getnode(forknod);
247
par->fork.forktyp = flag;
248
par->fork.forktre = child;
249
par->fork.forkio = 0;
250
par->fork.forkline = sh_getlineno(lp)-1;
251
return(par);
252
}
253
254
static int paramsub(const char *str)
255
{
256
register int c,sub=0,lit=0;
257
while(c= *str++)
258
{
259
if(c=='$' && !lit)
260
{
261
if(*str=='(')
262
return(0);
263
if(sub)
264
continue;
265
if(*str=='{')
266
str++;
267
if(!isdigit(*str) && strchr("?#@*!$ ",*str)==0)
268
return(1);
269
}
270
else if(c=='`')
271
return(0);
272
else if(c=='[' && !lit)
273
sub++;
274
else if(c==']' && !lit)
275
sub--;
276
else if(c=='\'')
277
lit = !lit;
278
}
279
return(0);
280
}
281
282
static Shnode_t *getanode(Lex_t *lp, struct argnod *ap)
283
{
284
register Shnode_t *t = getnode(arithnod);
285
t->ar.artyp = TARITH;
286
t->ar.arline = sh_getlineno(lp);
287
t->ar.arexpr = ap;
288
if(ap->argflag&ARG_RAW)
289
t->ar.arcomp = sh_arithcomp(lp->sh,ap->argval);
290
else
291
{
292
if(sh_isoption(SH_NOEXEC) && (ap->argflag&ARG_MAC) && paramsub(ap->argval))
293
errormsg(SH_DICT,ERROR_warn(0),e_lexwarnvar,lp->sh->inlineno);
294
t->ar.arcomp = 0;
295
}
296
return(t);
297
}
298
299
/*
300
* Make a node corresponding to a command list
301
*/
302
static Shnode_t *makelist(Lex_t *lexp, int type, Shnode_t *l, Shnode_t *r)
303
{
304
register Shnode_t *t;
305
if(!l || !r)
306
sh_syntax(lexp);
307
else
308
{
309
if((type&COMMSK) == TTST)
310
t = getnode(tstnod);
311
else
312
t = getnode(lstnod);
313
t->lst.lsttyp = type;
314
t->lst.lstlef = l;
315
t->lst.lstrit = r;
316
}
317
return(t);
318
}
319
320
/*
321
* entry to shell parser
322
* Flag can be the union of SH_EOF|SH_NL
323
*/
324
325
void *sh_parse(Shell_t *shp, Sfio_t *iop, int flag)
326
{
327
register Shnode_t *t;
328
Lex_t *lexp = (Lex_t*)shp->lex_context;
329
Fcin_t sav_input;
330
struct argnod *sav_arg = lexp->arg;
331
int sav_prompt = shp->nextprompt;
332
if(shp->binscript && (sffileno(iop)==shp->infd || (flag&SH_FUNEVAL)))
333
return((void*)sh_trestore(shp,iop));
334
fcsave(&sav_input);
335
shp->st.staklist = 0;
336
lexp->noreserv = 0;
337
lexp->heredoc = 0;
338
lexp->inlineno = shp->inlineno;
339
lexp->firstline = shp->st.firstline;
340
shp->nextprompt = 1;
341
loop_level = 0;
342
label_list = label_last = 0;
343
if(sh_isoption(SH_INTERACTIVE))
344
sh_onstate(SH_INTERACTIVE);
345
if(sh_isoption(SH_VERBOSE))
346
sh_onstate(SH_VERBOSE);
347
sh_lexopen(lexp,shp,0);
348
if(fcfopen(iop) < 0)
349
return(NIL(void*));
350
if(fcfile())
351
{
352
char *cp = fcfirst();
353
if( cp[0]==CNTL('k') && cp[1]==CNTL('s') && cp[2]==CNTL('h') && cp[3]==0)
354
{
355
int version;
356
fcseek(4);
357
fcgetc(version);
358
fcclose();
359
fcrestore(&sav_input);
360
lexp->arg = sav_arg;
361
if(version > 3)
362
errormsg(SH_DICT,ERROR_exit(1),e_lexversion);
363
if(sffileno(iop)==shp->infd || (flag&SH_FUNEVAL))
364
shp->binscript = 1;
365
sfgetc(iop);
366
t = sh_trestore(shp,iop);
367
if(flag&SH_NL)
368
{
369
Shnode_t *tt;
370
while(1)
371
{
372
if(!(tt = sh_trestore(shp,iop)))
373
break;
374
t =makelist(lexp,TLST, t, tt);
375
}
376
}
377
return((void*)t);
378
}
379
}
380
flag &= ~SH_FUNEVAL;
381
if((flag&SH_NL) && (shp->inlineno=error_info.line+shp->st.firstline)==0)
382
shp->inlineno=1;
383
#if KSHELL
384
shp->nextprompt = 2;
385
#endif
386
t = sh_cmd(lexp,(flag&SH_EOF)?EOFSYM:'\n',SH_SEMI|SH_EMPTY|(flag&SH_NL));
387
fcclose();
388
fcrestore(&sav_input);
389
lexp->arg = sav_arg;
390
/* unstack any completed alias expansions */
391
if((sfset(iop,0,0)&SF_STRING) && !sfreserve(iop,0,-1))
392
{
393
Sfio_t *sp = sfstack(iop,NULL);
394
if(sp)
395
sfclose(sp);
396
}
397
shp->nextprompt = sav_prompt;
398
if(flag&SH_NL)
399
{
400
shp->st.firstline = lexp->firstline;
401
shp->inlineno = lexp->inlineno;
402
}
403
stkseek(shp->stk,0);
404
return((void*)t);
405
}
406
407
/*
408
* This routine parses up the matching right parenthesis and returns
409
* the parse tree
410
*/
411
Shnode_t *sh_dolparen(Lex_t* lp)
412
{
413
register Shnode_t *t=0;
414
Sfio_t *sp = fcfile();
415
int line = lp->sh->inlineno;
416
lp->sh->inlineno = error_info.line+lp->sh->st.firstline;
417
sh_lexopen(lp,lp->sh,1);
418
lp->comsub = 1;
419
switch(sh_lex(lp))
420
{
421
/* ((...)) arithmetic expression */
422
case EXPRSYM:
423
t = getanode(lp,lp->arg);
424
break;
425
case LPAREN:
426
t = sh_cmd(lp,RPAREN,SH_NL|SH_EMPTY);
427
break;
428
case LBRACE:
429
t = sh_cmd(lp,RBRACE,SH_NL|SH_EMPTY);
430
break;
431
}
432
lp->comsub = 0;
433
if(!sp && (sp=fcfile()))
434
{
435
/*
436
* This code handles the case where string has been converted
437
* to a file by an alias setup
438
*/
439
register int c;
440
char *cp;
441
if(fcgetc(c) > 0)
442
fcseek(-1);
443
cp = fcseek(0);
444
fcclose();
445
fcsopen(cp);
446
sfclose(sp);
447
}
448
lp->sh->inlineno = line;
449
return(t);
450
}
451
452
/*
453
* remove temporary files and stacks
454
*/
455
456
void sh_freeup(Shell_t *shp)
457
{
458
if(shp->st.staklist)
459
sh_funstaks(shp->st.staklist,-1);
460
shp->st.staklist = 0;
461
}
462
463
/*
464
* increase reference count for each stack in function list when flag>0
465
* decrease reference count for each stack in function list when flag<=0
466
* stack is freed when reference count is zero
467
*/
468
469
void sh_funstaks(register struct slnod *slp,int flag)
470
{
471
register struct slnod *slpold;
472
while(slpold=slp)
473
{
474
if(slp->slchild)
475
sh_funstaks(slp->slchild,flag);
476
slp = slp->slnext;
477
if(flag<=0)
478
stakdelete(slpold->slptr);
479
else
480
staklink(slpold->slptr);
481
}
482
}
483
/*
484
* cmd
485
* empty
486
* list
487
* list & [ cmd ]
488
* list [ ; cmd ]
489
*/
490
491
static Shnode_t *sh_cmd(Lex_t *lexp, register int sym, int flag)
492
{
493
register Shnode_t *left, *right;
494
register int type = FINT|FAMP;
495
if(sym==NL)
496
lexp->lasttok = 0;
497
left = list(lexp,flag);
498
if(lexp->token==NL)
499
{
500
if(flag&SH_NL)
501
lexp->token=';';
502
}
503
else if(!left && !(flag&SH_EMPTY))
504
sh_syntax(lexp);
505
switch(lexp->token)
506
{
507
case COOPSYM: /* set up a cooperating process */
508
type |= (FPIN|FPOU|FPCL|FCOOP);
509
/* FALL THRU */
510
case '&':
511
if(left)
512
{
513
/* (...)& -> {...;} & */
514
if(left->tre.tretyp==TPAR)
515
left = left->par.partre;
516
left = makeparent(lexp,TFORK|type, left);
517
}
518
/* FALL THRU */
519
case ';':
520
if(!left)
521
sh_syntax(lexp);
522
if(right=sh_cmd(lexp,sym,flag|SH_EMPTY))
523
left=makelist(lexp,TLST, left, right);
524
break;
525
case EOFSYM:
526
if(sym==NL)
527
break;
528
default:
529
if(sym && sym!=lexp->token)
530
{
531
if(sym!=ELSESYM || (lexp->token!=ELIFSYM && lexp->token!=FISYM))
532
sh_syntax(lexp);
533
}
534
}
535
return(left);
536
}
537
538
/*
539
* list
540
* term
541
* list && term
542
* list || term
543
* unfortunately, these are equal precedence
544
*/
545
static Shnode_t *list(Lex_t *lexp, register int flag)
546
{
547
register Shnode_t *t = term(lexp,flag);
548
register int token;
549
while(t && ((token=lexp->token)==ANDFSYM || token==ORFSYM))
550
t = makelist(lexp,(token==ANDFSYM?TAND:TORF), t, term(lexp,SH_NL|SH_SEMI));
551
return(t);
552
}
553
554
/*
555
* term
556
* item
557
* item | term
558
*/
559
static Shnode_t *term(Lex_t *lexp,register int flag)
560
{
561
register Shnode_t *t;
562
register int token;
563
if(flag&SH_NL)
564
token = skipnl(lexp,flag);
565
else
566
token = sh_lex(lexp);
567
/* check to see if pipeline is to be timed */
568
if(token==TIMESYM || token==NOTSYM)
569
{
570
t = getnode(parnod);
571
t->par.partyp=TTIME;
572
if(lexp->token==NOTSYM)
573
t->par.partyp |= COMSCAN;
574
t->par.partre = term(lexp,0);
575
}
576
#if SHOPT_COSHELL
577
else if((t=item(lexp,SH_NL|SH_EMPTY|(flag&SH_SEMI))) && (lexp->token=='|' || lexp->token==PIPESYM2))
578
#else
579
else if((t=item(lexp,SH_NL|SH_EMPTY|(flag&SH_SEMI))) && lexp->token=='|')
580
#endif /* SHOPT_COSHELL */
581
{
582
register Shnode_t *tt;
583
int showme = t->tre.tretyp&FSHOWME;
584
t = makeparent(lexp,TFORK|FPOU,t);
585
#if SHOPT_COSHELL
586
if(lexp->token==PIPESYM2)
587
t->tre.tretyp |= FALTPIPE;
588
#endif /* SHOPT_COSHELL */
589
if(tt=term(lexp,SH_NL))
590
{
591
switch(tt->tre.tretyp&COMMSK)
592
{
593
case TFORK:
594
tt->tre.tretyp |= FPIN|FPCL;
595
break;
596
case TFIL:
597
tt->lst.lstlef->tre.tretyp |= FPIN|FPCL;
598
break;
599
default:
600
tt= makeparent(lexp,TSETIO|FPIN|FPCL,tt);
601
}
602
t=makelist(lexp,TFIL,t,tt);
603
t->tre.tretyp |= showme;
604
}
605
else if(lexp->token)
606
sh_syntax(lexp);
607
}
608
return(t);
609
}
610
611
/*
612
* case statement
613
*/
614
static struct regnod* syncase(Lex_t *lexp,register int esym)
615
{
616
register int tok = skipnl(lexp,0);
617
register struct regnod *r;
618
if(tok==esym)
619
return(NIL(struct regnod*));
620
r = (struct regnod*)stakalloc(sizeof(struct regnod));
621
r->regptr=0;
622
r->regflag=0;
623
if(tok==LPAREN)
624
skipnl(lexp,0);
625
while(1)
626
{
627
if(!lexp->arg)
628
sh_syntax(lexp);
629
lexp->arg->argnxt.ap=r->regptr;
630
r->regptr = lexp->arg;
631
if((tok=sh_lex(lexp))==RPAREN)
632
break;
633
else if(tok=='|')
634
sh_lex(lexp);
635
else
636
sh_syntax(lexp);
637
}
638
r->regcom=sh_cmd(lexp,0,SH_NL|SH_EMPTY|SH_SEMI);
639
if((tok=lexp->token)==BREAKCASESYM)
640
r->regnxt=syncase(lexp,esym);
641
else if(tok==FALLTHRUSYM)
642
{
643
r->regflag++;
644
r->regnxt=syncase(lexp,esym);
645
}
646
else
647
{
648
if(tok!=esym && tok!=EOFSYM)
649
sh_syntax(lexp);
650
r->regnxt=0;
651
}
652
if(lexp->token==EOFSYM)
653
return(NIL(struct regnod*));
654
return(r);
655
}
656
657
/*
658
* This routine creates the parse tree for the arithmetic for
659
* When called, shlex.arg contains the string inside ((...))
660
* When the first argument is missing, a while node is returned
661
* Otherise a list containing an arithmetic command and a while
662
* is returned.
663
*/
664
static Shnode_t *arithfor(Lex_t *lexp,register Shnode_t *tf)
665
{
666
register Shnode_t *t, *tw = tf;
667
register int offset;
668
register struct argnod *argp;
669
register int n;
670
Stk_t *stkp = lexp->sh->stk;
671
int argflag = lexp->arg->argflag;
672
/* save current input */
673
Fcin_t sav_input;
674
fcsave(&sav_input);
675
fcsopen(lexp->arg->argval);
676
/* split ((...)) into three expressions */
677
for(n=0; ; n++)
678
{
679
register int c;
680
argp = (struct argnod*)stkseek(stkp,ARGVAL);
681
argp->argnxt.ap = 0;
682
argp->argchn.cp = 0;
683
argp->argflag = argflag;
684
if(n==2)
685
break;
686
/* copy up to ; onto the stack */
687
sh_lexskip(lexp,';',1,ST_NESTED);
688
offset = stktell(stkp)-1;
689
if((c=fcpeek(-1))!=';')
690
break;
691
/* remove trailing white space */
692
while(offset>ARGVAL && ((c= *stkptr(stkp,offset-1)),isspace(c)))
693
offset--;
694
/* check for empty initialization expression */
695
if(offset==ARGVAL && n==0)
696
continue;
697
stkseek(stkp,offset);
698
/* check for empty condition and treat as while((1)) */
699
if(offset==ARGVAL)
700
sfputc(stkp,'1');
701
argp = (struct argnod*)stkfreeze(stkp,1);
702
t = getanode(lexp,argp);
703
if(n==0)
704
tf = makelist(lexp,TLST,t,tw);
705
else
706
tw->wh.whtre = t;
707
}
708
while((offset=fcpeek(0)) && isspace(offset))
709
fcseek(1);
710
stakputs(fcseek(0));
711
argp = (struct argnod*)stakfreeze(1);
712
fcrestore(&sav_input);
713
if(n<2)
714
{
715
lexp->token = RPAREN|SYMREP;
716
sh_syntax(lexp);
717
}
718
/* check whether the increment is present */
719
if(*argp->argval)
720
{
721
t = getanode(lexp,argp);
722
tw->wh.whinc = (struct arithnod*)t;
723
}
724
else
725
tw->wh.whinc = 0;
726
sh_lexopen(lexp, lexp->sh,1);
727
if((n=sh_lex(lexp))==NL)
728
n = skipnl(lexp,0);
729
else if(n==';')
730
n = sh_lex(lexp);
731
if(n!=DOSYM && n!=LBRACE)
732
sh_syntax(lexp);
733
tw->wh.dotre = sh_cmd(lexp,n==DOSYM?DONESYM:RBRACE,SH_NL|SH_SEMI);
734
tw->wh.whtyp = TWH;
735
return(tf);
736
737
}
738
739
static Shnode_t *funct(Lex_t *lexp)
740
{
741
Shell_t *shp = lexp->sh;
742
register Shnode_t *t;
743
register int flag;
744
struct slnod *volatile slp=0;
745
Stak_t *savstak;
746
Sfoff_t first, last;
747
struct functnod *volatile fp;
748
Sfio_t *iop;
749
#if SHOPT_KIA
750
unsigned long current = lexp->current;
751
#endif /* SHOPT_KIA */
752
int nargs=0,size=0,jmpval, saveloop=loop_level;
753
struct argnod *savelabel = label_last;
754
struct checkpt buff;
755
int save_optget = opt_get;
756
void *in_mktype = shp->mktype;
757
shp->mktype = 0;
758
opt_get = 0;
759
t = getnode(functnod);
760
t->funct.functline = shp->inlineno;
761
t->funct.functtyp=TFUN;
762
t->funct.functargs = 0;
763
if(!(flag = (lexp->token==FUNCTSYM)))
764
t->funct.functtyp |= FPOSIX;
765
else if(sh_lex(lexp))
766
sh_syntax(lexp);
767
if(!(iop=fcfile()))
768
{
769
iop = sfopen(NIL(Sfio_t*),fcseek(0),"s");
770
fcclose();
771
fcfopen(iop);
772
}
773
t->funct.functloc = first = fctell();
774
if(!shp->st.filename || sffileno(iop)<0)
775
{
776
if(fcfill() >= 0)
777
fcseek(-1);
778
if(sh_isstate(SH_HISTORY) && shp->gd->hist_ptr)
779
t->funct.functloc = sfseek(shp->gd->hist_ptr->histfp,(off_t)0,SEEK_CUR);
780
else
781
{
782
/* copy source to temporary file */
783
t->funct.functloc = 0;
784
if(lexp->sh->heredocs)
785
t->funct.functloc = sfseek(lexp->sh->heredocs,(Sfoff_t)0, SEEK_END);
786
else
787
lexp->sh->heredocs = sftmp(HERE_MEM);
788
lexp->sh->funlog = lexp->sh->heredocs;
789
t->funct.functtyp |= FPIN;
790
}
791
}
792
t->funct.functnam= (char*)lexp->arg->argval;
793
#if SHOPT_KIA
794
if(lexp->kiafile)
795
lexp->current = kiaentity(lexp,t->funct.functnam,-1,'p',-1,-1,lexp->script,'p',0,"");
796
#endif /* SHOPT_KIA */
797
if(flag)
798
{
799
lexp->token = sh_lex(lexp);
800
#if SHOPT_BASH
801
if(lexp->token == LPAREN)
802
{
803
if((lexp->token = sh_lex(lexp)) == RPAREN)
804
t->funct.functtyp |= FPOSIX;
805
else
806
sh_syntax(lexp);
807
}
808
#endif
809
}
810
if(t->funct.functtyp&FPOSIX)
811
skipnl(lexp,0);
812
else
813
{
814
if(lexp->token==0)
815
{
816
struct comnod *ac;
817
char *cp, **argv, **argv0;
818
int c;
819
t->funct.functargs = ac = (struct comnod*)simple(lexp,SH_NOIO|SH_FUNDEF,NIL(struct ionod*));
820
if(ac->comset || (ac->comtyp&COMSCAN))
821
errormsg(SH_DICT,ERROR_exit(3),e_lexsyntax4,lexp->sh->inlineno);
822
argv0 = argv = ((struct dolnod*)ac->comarg)->dolval+ARG_SPARE;
823
while(cp= *argv++)
824
{
825
size += strlen(cp)+1;
826
if((c = mbchar(cp)) && isaletter(c))
827
while(c=mbchar(cp), isaname(c));
828
}
829
if(c)
830
errormsg(SH_DICT,ERROR_exit(3),e_lexsyntax4,lexp->sh->inlineno);
831
nargs = argv-argv0;
832
size += sizeof(struct dolnod)+(nargs+ARG_SPARE)*sizeof(char*);
833
if(shp->shcomp && memcmp(".sh.math.",t->funct.functnam,9)==0)
834
{
835
Namval_t *np= nv_open(t->funct.functnam,shp->fun_tree,NV_ADD|NV_VARNAME);
836
np->nvalue.rp = new_of(struct Ufunction,shp->funload?sizeof(Dtlink_t):0);
837
memset((void*)np->nvalue.rp,0,sizeof(struct Ufunction));
838
np->nvalue.rp->argc = ((struct dolnod*)ac->comarg)->dolnum;
839
}
840
}
841
while(lexp->token==NL)
842
lexp->token = sh_lex(lexp);
843
}
844
if((flag && lexp->token!=LBRACE) || lexp->token==EOFSYM)
845
sh_syntax(lexp);
846
sh_pushcontext(shp,&buff,1);
847
jmpval = sigsetjmp(buff.buff,0);
848
if(jmpval == 0)
849
{
850
/* create a new stak frame to compile the command */
851
savstak = stakcreate(STAK_SMALL);
852
savstak = stakinstall(savstak, 0);
853
slp = (struct slnod*)stakalloc(sizeof(struct slnod)+sizeof(struct functnod));
854
slp->slchild = 0;
855
slp->slnext = shp->st.staklist;
856
shp->st.staklist = 0;
857
t->funct.functstak = (struct slnod*)slp;
858
/*
859
* store the pathname of function definition file on stack
860
* in name field of fake for node
861
*/
862
fp = (struct functnod*)(slp+1);
863
fp->functtyp = TFUN|FAMP;
864
fp->functnam = 0;
865
fp->functargs = 0;
866
fp->functline = t->funct.functline;
867
if(shp->st.filename)
868
fp->functnam = stakcopy(shp->st.filename);
869
loop_level = 0;
870
label_last = label_list;
871
if(size)
872
{
873
struct dolnod *dp = (struct dolnod*)stakalloc(size);
874
char *cp, *sp, **argv, **old = ((struct dolnod*)t->funct.functargs->comarg)->dolval+1;
875
argv = ((char**)(dp->dolval))+1;
876
dp->dolnum = ((struct dolnod*)t->funct.functargs->comarg)->dolnum;
877
t->funct.functargs->comarg = (struct argnod*)dp;
878
for(cp=(char*)&argv[nargs]; sp= *old++; cp++)
879
{
880
*argv++ = cp;
881
cp = strcopy(cp,sp);
882
}
883
*argv = 0;
884
}
885
if(!flag && lexp->token==0)
886
{
887
/* copy current word token to current stak frame */
888
struct argnod *ap;
889
flag = ARGVAL + strlen(lexp->arg->argval);
890
ap = (struct argnod*)stakalloc(flag);
891
memcpy(ap,lexp->arg,flag);
892
lexp->arg = ap;
893
}
894
t->funct.functtre = item(lexp,SH_NOIO);
895
}
896
else if(shp->shcomp)
897
exit(1);
898
sh_popcontext(shp,&buff);
899
loop_level = saveloop;
900
label_last = savelabel;
901
/* restore the old stack */
902
if(slp)
903
{
904
slp->slptr = stakinstall(savstak,0);
905
slp->slchild = shp->st.staklist;
906
}
907
#if SHOPT_KIA
908
lexp->current = current;
909
#endif /* SHOPT_KIA */
910
if(jmpval)
911
{
912
if(slp && slp->slptr)
913
{
914
shp->st.staklist = slp->slnext;
915
stakdelete(slp->slptr);
916
}
917
siglongjmp(*shp->jmplist,jmpval);
918
}
919
shp->st.staklist = (struct slnod*)slp;
920
last = fctell();
921
fp->functline = (last-first);
922
fp->functtre = t;
923
shp->mktype = in_mktype;
924
if(lexp->sh->funlog)
925
{
926
if(fcfill()>0)
927
fcseek(-1);
928
lexp->sh->funlog = 0;
929
}
930
#if SHOPT_KIA
931
if(lexp->kiafile)
932
kiaentity(lexp,t->funct.functnam,-1,'p',t->funct.functline,shp->inlineno-1,lexp->current,'p',0,"");
933
#endif /* SHOPT_KIA */
934
t->funct.functtyp |= opt_get;
935
opt_get = save_optget;
936
return(t);
937
}
938
939
/*
940
* Compound assignment
941
*/
942
static struct argnod *assign(Lex_t *lexp, register struct argnod *ap, int type)
943
{
944
register int n;
945
register Shnode_t *t, **tp;
946
register struct comnod *ac;
947
Stk_t *stkp = lexp->sh->stk;
948
int array=0, index=0;
949
Namval_t *np;
950
n = strlen(ap->argval)-1;
951
if(ap->argval[n]!='=')
952
sh_syntax(lexp);
953
if(ap->argval[n-1]=='+')
954
{
955
ap->argval[n--]=0;
956
array = ARG_APPEND;
957
type |= NV_APPEND;
958
}
959
/* shift right */
960
while(n > 0)
961
{
962
ap->argval[n] = ap->argval[n-1];
963
n--;
964
}
965
*ap->argval=0;
966
t = getnode(fornod);
967
t->for_.fornam = (char*)(ap->argval+1);
968
t->for_.fortyp = sh_getlineno(lexp);
969
tp = &t->for_.fortre;
970
ap->argchn.ap = (struct argnod*)t;
971
ap->argflag &= ARG_QUOTED;
972
ap->argflag |= array;
973
lexp->assignok = SH_ASSIGN;
974
if(type==NV_ARRAY)
975
{
976
lexp->noreserv = 1;
977
lexp->assignok = 0;
978
}
979
else
980
lexp->aliasok = 2;
981
array= (type==NV_ARRAY)?SH_ARRAY:0;
982
if((n=skipnl(lexp,0))==RPAREN || n==LPAREN)
983
{
984
struct argnod *ar,*aq,**settail;
985
ac = (struct comnod*)getnode(comnod);
986
memset((void*)ac,0,sizeof(*ac));
987
comarray:
988
settail= &ac->comset;
989
ac->comline = sh_getlineno(lexp);
990
while(n==LPAREN)
991
{
992
ar = (struct argnod*)stkseek(stkp,ARGVAL);
993
ar->argflag= ARG_ASSIGN;
994
sfprintf(stkp,"[%d]=",index++);
995
if(aq=ac->comarg)
996
{
997
ac->comarg = aq->argnxt.ap;
998
sfprintf(stkp,"%s",aq->argval);
999
ar->argflag |= aq->argflag;
1000
}
1001
ar = (struct argnod*)stkfreeze(stkp,1);
1002
ar->argnxt.ap = 0;
1003
if(!aq)
1004
ar = assign(lexp,ar,0);
1005
ar->argflag |= ARG_MESSAGE;
1006
*settail = ar;
1007
settail = &(ar->argnxt.ap);
1008
if(aq)
1009
continue;
1010
while((n = skipnl(lexp,0))==0)
1011
{
1012
ar = (struct argnod*)stkseek(stkp,ARGVAL);
1013
ar->argflag= ARG_ASSIGN;
1014
sfprintf(stkp,"[%d]=",index++);
1015
stakputs(lexp->arg->argval);
1016
ar = (struct argnod*)stkfreeze(stkp,1);
1017
ar->argnxt.ap = 0;
1018
ar->argflag = lexp->arg->argflag;
1019
*settail = ar;
1020
settail = &(ar->argnxt.ap);
1021
}
1022
}
1023
}
1024
else if(n && n!=FUNCTSYM)
1025
sh_syntax(lexp);
1026
else if(type!=NV_ARRAY && n!=FUNCTSYM && !(lexp->arg->argflag&ARG_ASSIGN) && !((np=nv_search(lexp->arg->argval,lexp->sh->fun_tree,0)) && (nv_isattr(np,BLT_DCL)|| np==SYSDOT)))
1027
{
1028
array=SH_ARRAY;
1029
if(fcgetc(n)==LPAREN)
1030
{
1031
int c;
1032
if(fcgetc(c)==RPAREN)
1033
{
1034
lexp->token = SYMRES;
1035
array = 0;
1036
}
1037
else
1038
fcseek(-2);
1039
}
1040
else if(n>0)
1041
fcseek(-1);
1042
if(array && type==NV_TYPE)
1043
{
1044
struct argnod *arg = lexp->arg;
1045
n = lexp->token;
1046
if(path_search(lexp->sh,lexp->arg->argval,NIL(Pathcomp_t**),1) && (np=nv_search(lexp->arg->argval,lexp->sh->fun_tree,0)) && nv_isattr(np,BLT_DCL))
1047
{
1048
lexp->token = n;
1049
lexp->arg = arg;
1050
array = 0;
1051
}
1052
else
1053
sh_syntax(lexp);
1054
}
1055
}
1056
lexp->noreserv = 0;
1057
while(1)
1058
{
1059
if((n=lexp->token)==RPAREN)
1060
break;
1061
if(n==FUNCTSYM || n==SYMRES)
1062
ac = (struct comnod*)funct(lexp);
1063
else
1064
ac = (struct comnod*)simple(lexp,SH_NOIO|SH_ASSIGN|type|array,NIL(struct ionod*));
1065
if((n=lexp->token)==RPAREN)
1066
break;
1067
if(n!=NL && n!=';')
1068
{
1069
if(array && n==LPAREN)
1070
goto comarray;
1071
sh_syntax(lexp);
1072
}
1073
lexp->assignok = SH_ASSIGN;
1074
if((n=skipnl(lexp,0)) || array)
1075
{
1076
if(n==RPAREN)
1077
break;
1078
if(array || n!=FUNCTSYM)
1079
sh_syntax(lexp);
1080
}
1081
if((n!=FUNCTSYM) && !(lexp->arg->argflag&ARG_ASSIGN) && !((np=nv_search(lexp->arg->argval,lexp->sh->fun_tree,0)) && (nv_isattr(np,BLT_DCL)||np==SYSDOT)))
1082
{
1083
struct argnod *arg = lexp->arg;
1084
if(n!=0)
1085
sh_syntax(lexp);
1086
/* check for sys5 style function */
1087
if(sh_lex(lexp)!=LPAREN || sh_lex(lexp)!=RPAREN)
1088
{
1089
lexp->arg = arg;
1090
lexp->token = 0;
1091
sh_syntax(lexp);
1092
}
1093
lexp->arg = arg;
1094
lexp->token = SYMRES;
1095
}
1096
t = makelist(lexp,TLST,(Shnode_t*)ac,t);
1097
*tp = t;
1098
tp = &t->lst.lstrit;
1099
}
1100
*tp = (Shnode_t*)ac;
1101
lexp->assignok = 0;
1102
return(ap);
1103
}
1104
1105
/*
1106
* item
1107
*
1108
* ( cmd ) [ < in ] [ > out ]
1109
* word word* [ < in ] [ > out ]
1110
* if ... then ... else ... fi
1111
* for ... while ... do ... done
1112
* case ... in ... esac
1113
* begin ... end
1114
*/
1115
1116
static Shnode_t *item(Lex_t *lexp,int flag)
1117
{
1118
register Shnode_t *t;
1119
register struct ionod *io;
1120
register int tok = (lexp->token&0xff);
1121
int savwdval = lexp->lasttok;
1122
int savline = lexp->lastline;
1123
int showme=0, comsub;
1124
if(!(flag&SH_NOIO) && (tok=='<' || tok=='>' || lexp->token==IOVNAME))
1125
io=inout(lexp,NIL(struct ionod*),1);
1126
else
1127
io=0;
1128
if((tok=lexp->token) && tok!=EOFSYM && tok!=FUNCTSYM)
1129
{
1130
lexp->lastline = sh_getlineno(lexp);
1131
lexp->lasttok = lexp->token;
1132
}
1133
switch(tok)
1134
{
1135
/* [[ ... ]] test expression */
1136
case BTESTSYM:
1137
t = test_expr(lexp,ETESTSYM);
1138
t->tre.tretyp &= ~TTEST;
1139
break;
1140
/* ((...)) arithmetic expression */
1141
case EXPRSYM:
1142
t = getanode(lexp,lexp->arg);
1143
sh_lex(lexp);
1144
goto done;
1145
1146
/* case statement */
1147
case CASESYM:
1148
{
1149
int savetok = lexp->lasttok;
1150
int saveline = lexp->lastline;
1151
t = getnode(swnod);
1152
if(sh_lex(lexp))
1153
sh_syntax(lexp);
1154
t->sw.swarg=lexp->arg;
1155
t->sw.swtyp=TSW;
1156
t->sw.swio = 0;
1157
t->sw.swtyp |= FLINENO;
1158
t->sw.swline = lexp->sh->inlineno;
1159
if((tok=skipnl(lexp,0))!=INSYM && tok!=LBRACE)
1160
sh_syntax(lexp);
1161
if(!(t->sw.swlst=syncase(lexp,tok==INSYM?ESACSYM:RBRACE)) && lexp->token==EOFSYM)
1162
{
1163
lexp->lasttok = savetok;
1164
lexp->lastline = saveline;
1165
sh_syntax(lexp);
1166
}
1167
break;
1168
}
1169
1170
/* if statement */
1171
case IFSYM:
1172
{
1173
register Shnode_t *tt;
1174
t = getnode(ifnod);
1175
t->if_.iftyp=TIF;
1176
t->if_.iftre=sh_cmd(lexp,THENSYM,SH_NL);
1177
t->if_.thtre=sh_cmd(lexp,ELSESYM,SH_NL|SH_SEMI);
1178
tok = lexp->token;
1179
t->if_.eltre=(tok==ELSESYM?sh_cmd(lexp,FISYM,SH_NL|SH_SEMI):
1180
(tok==ELIFSYM?(lexp->token=IFSYM, tt=item(lexp,SH_NOIO)):0));
1181
if(tok==ELIFSYM)
1182
{
1183
if(!tt || tt->tre.tretyp!=TSETIO)
1184
goto done;
1185
t->if_.eltre = tt->fork.forktre;
1186
tt->fork.forktre = t;
1187
t = tt;
1188
goto done;
1189
}
1190
break;
1191
}
1192
1193
/* for and select statement */
1194
case FORSYM:
1195
case SELECTSYM:
1196
{
1197
t = getnode(fornod);
1198
t->for_.fortyp=(lexp->token==FORSYM?TFOR:TSELECT);
1199
t->for_.forlst=0;
1200
t->for_.forline = lexp->sh->inlineno;
1201
if(sh_lex(lexp))
1202
{
1203
if(lexp->token!=EXPRSYM || t->for_.fortyp!=TFOR)
1204
sh_syntax(lexp);
1205
/* arithmetic for */
1206
t = arithfor(lexp,t);
1207
break;
1208
}
1209
t->for_.fornam=(char*) lexp->arg->argval;
1210
t->for_.fortyp |= FLINENO;
1211
#if SHOPT_KIA
1212
if(lexp->kiafile)
1213
writedefs(lexp,lexp->arg,lexp->sh->inlineno,'v',NIL(struct argnod*));
1214
#endif /* SHOPT_KIA */
1215
while((tok=sh_lex(lexp))==NL);
1216
if(tok==INSYM)
1217
{
1218
if(sh_lex(lexp))
1219
{
1220
if(lexp->token != NL && lexp->token !=';')
1221
sh_syntax(lexp);
1222
/* some Linux scripts assume this */
1223
if(sh_isoption(SH_NOEXEC))
1224
errormsg(SH_DICT,ERROR_warn(0),e_lexemptyfor,lexp->sh->inlineno-(lexp->token=='\n'));
1225
t->for_.forlst = (struct comnod*)getnode(comnod);
1226
(t->for_.forlst)->comarg = 0;
1227
(t->for_.forlst)->comset = 0;
1228
(t->for_.forlst)->comnamp = 0;
1229
(t->for_.forlst)->comnamq = 0;
1230
(t->for_.forlst)->comstate = 0;
1231
(t->for_.forlst)->comio = 0;
1232
(t->for_.forlst)->comtyp = 0;
1233
}
1234
else
1235
t->for_.forlst=(struct comnod*)simple(lexp,SH_NOIO,NIL(struct ionod*));
1236
if(lexp->token != NL && lexp->token !=';')
1237
sh_syntax(lexp);
1238
tok = skipnl(lexp,0);
1239
}
1240
/* 'for i;do cmd' is valid syntax */
1241
else if(tok==';')
1242
while((tok=sh_lex(lexp))==NL);
1243
if(tok!=DOSYM && tok!=LBRACE)
1244
sh_syntax(lexp);
1245
loop_level++;
1246
t->for_.fortre=sh_cmd(lexp,tok==DOSYM?DONESYM:RBRACE,SH_NL|SH_SEMI);
1247
if(--loop_level==0)
1248
label_last = label_list;
1249
break;
1250
}
1251
1252
/* This is the code for parsing function definitions */
1253
case FUNCTSYM:
1254
return(funct(lexp));
1255
1256
#if SHOPT_NAMESPACE
1257
case NSPACESYM:
1258
t = getnode(functnod);
1259
t->funct.functtyp=TNSPACE;
1260
t->funct.functargs = 0;
1261
t->funct.functloc = 0;
1262
if(sh_lex(lexp))
1263
sh_syntax(lexp);
1264
t->funct.functnam=(char*) lexp->arg->argval;
1265
while((tok=sh_lex(lexp))==NL);
1266
if(tok!=LBRACE)
1267
sh_syntax(lexp);
1268
t->funct.functtre = sh_cmd(lexp,RBRACE,SH_NL);
1269
break;
1270
#endif /* SHOPT_NAMESPACE */
1271
1272
/* while and until */
1273
case WHILESYM:
1274
case UNTILSYM:
1275
t = getnode(whnod);
1276
t->wh.whtyp=(lexp->token==WHILESYM ? TWH : TUN);
1277
loop_level++;
1278
t->wh.whtre = sh_cmd(lexp,DOSYM,SH_NL);
1279
t->wh.dotre = sh_cmd(lexp,DONESYM,SH_NL|SH_SEMI);
1280
if(--loop_level==0)
1281
label_last = label_list;
1282
t->wh.whinc = 0;
1283
break;
1284
1285
case LABLSYM:
1286
{
1287
register struct argnod *argp = label_list;
1288
while(argp)
1289
{
1290
if(strcmp(argp->argval,lexp->arg->argval)==0)
1291
errormsg(SH_DICT,ERROR_exit(3),e_lexsyntax3,lexp->sh->inlineno,argp->argval);
1292
argp = argp->argnxt.ap;
1293
}
1294
lexp->arg->argnxt.ap = label_list;
1295
label_list = lexp->arg;
1296
label_list->argchn.len = sh_getlineno(lexp);
1297
label_list->argflag = loop_level;
1298
skipnl(lexp,flag);
1299
if(!(t = item(lexp,SH_NL)))
1300
sh_syntax(lexp);
1301
tok = (t->tre.tretyp&(COMSCAN|COMSCAN-1));
1302
if(sh_isoption(SH_NOEXEC) && tok!=TWH && tok!=TUN && tok!=TFOR && tok!=TSELECT)
1303
errormsg(SH_DICT,ERROR_warn(0),e_lexlabignore,label_list->argchn.len,label_list->argval);
1304
return(t);
1305
}
1306
1307
/* command group with {...} */
1308
case LBRACE:
1309
comsub = lexp->comsub;
1310
lexp->comsub = 0;
1311
t = sh_cmd(lexp,RBRACE,SH_NL|SH_SEMI);
1312
lexp->comsub = comsub;
1313
break;
1314
1315
case LPAREN:
1316
t = getnode(parnod);
1317
t->par.partre=sh_cmd(lexp,RPAREN,SH_NL|SH_SEMI);
1318
t->par.partyp=TPAR;
1319
break;
1320
1321
#if SHOPT_COSHELL
1322
case '&':
1323
if(tok=sh_lex(lexp))
1324
{
1325
if(tok!=NL)
1326
sh_syntax(lexp);
1327
t = getnode(comnod);
1328
memset(t,0,sizeof(struct comnod));
1329
t->com.comline = sh_getlineno(lexp);
1330
}
1331
else
1332
t = (Shnode_t*)simple(lexp,SH_NOIO,NIL(struct ionod*));
1333
t->com.comtyp |= FAMP;
1334
if(lexp->token=='&' || lexp->token=='|')
1335
sh_syntax(lexp);
1336
return(t);
1337
break;
1338
#endif /* SHOPT_COSHELL */
1339
default:
1340
if(io==0)
1341
return(0);
1342
1343
case ';':
1344
if(io==0)
1345
{
1346
if(!(flag&SH_SEMI))
1347
return(0);
1348
if(sh_lex(lexp)==';')
1349
sh_syntax(lexp);
1350
showme = FSHOWME;
1351
}
1352
/* simple command */
1353
case 0:
1354
t = (Shnode_t*)simple(lexp,flag,io);
1355
if(t->com.comarg && lexp->intypeset)
1356
check_typedef(&t->com);
1357
lexp->intypeset = 0;
1358
lexp->inexec = 0;
1359
t->tre.tretyp |= showme;
1360
return(t);
1361
}
1362
sh_lex(lexp);
1363
if(io=inout(lexp,io,0))
1364
{
1365
if((tok=t->tre.tretyp&COMMSK) != TFORK)
1366
tok = TSETIO;
1367
t=makeparent(lexp,tok,t);
1368
t->tre.treio=io;
1369
}
1370
done:
1371
lexp->lasttok = savwdval;
1372
lexp->lastline = savline;
1373
return(t);
1374
}
1375
1376
static struct argnod *process_sub(Lex_t *lexp,int tok)
1377
{
1378
struct argnod *argp;
1379
Shnode_t *t;
1380
int mode = (tok==OPROCSYM);
1381
t = sh_cmd(lexp,RPAREN,SH_NL);
1382
argp = (struct argnod*)stkalloc(lexp->sh->stk,sizeof(struct argnod));
1383
*argp->argval = 0;
1384
argp->argchn.ap = (struct argnod*)makeparent(lexp,mode?TFORK|FPIN|FAMP|FPCL:TFORK|FPOU,t);
1385
argp->argflag = (ARG_EXP|mode);
1386
return(argp);
1387
}
1388
1389
1390
/*
1391
* This is for a simple command, for list, or compound assignment
1392
*/
1393
static Shnode_t *simple(Lex_t *lexp,int flag, struct ionod *io)
1394
{
1395
register struct comnod *t;
1396
register struct argnod *argp;
1397
register int tok;
1398
Stk_t *stkp = lexp->sh->stk;
1399
struct argnod **argtail;
1400
struct argnod **settail;
1401
int cmdarg=0;
1402
int argno = 0;
1403
int assignment = 0;
1404
int key_on = (!(flag&SH_NOIO) && sh_isoption(SH_KEYWORD));
1405
int associative=0;
1406
if((argp=lexp->arg) && (argp->argflag&ARG_ASSIGN) && argp->argval[0]=='[')
1407
{
1408
flag |= SH_ARRAY;
1409
associative = 1;
1410
}
1411
t = (struct comnod*)getnode(comnod);
1412
t->comio=io; /*initial io chain*/
1413
/* set command line number for error messages */
1414
t->comline = sh_getlineno(lexp);
1415
argtail = &(t->comarg);
1416
t->comset = 0;
1417
t->comnamp = 0;
1418
t->comnamq = 0;
1419
t->comstate = 0;
1420
settail = &(t->comset);
1421
while(lexp->token==0)
1422
{
1423
argp = lexp->arg;
1424
if(*argp->argval==LBRACE && (flag&SH_FUNDEF) && argp->argval[1]==0)
1425
{
1426
lexp->token = LBRACE;
1427
break;
1428
}
1429
if(associative && argp->argval[0]!='[')
1430
sh_syntax(lexp);
1431
/* check for assignment argument */
1432
if((argp->argflag&ARG_ASSIGN) && assignment!=2)
1433
{
1434
*settail = argp;
1435
settail = &(argp->argnxt.ap);
1436
lexp->assignok = (flag&SH_ASSIGN)?SH_ASSIGN:1;
1437
if(assignment)
1438
{
1439
struct argnod *ap=argp;
1440
char *last, *cp;
1441
if(assignment==1)
1442
{
1443
last = strchr(argp->argval,'=');
1444
if(last && (last[-1]==']'|| (last[-1]=='+' && last[-2]==']')) && (cp=strchr(argp->argval,'[')) && (cp < last) && cp[-1]!='.')
1445
last = cp;
1446
stkseek(stkp,ARGVAL);
1447
sfwrite(stkp,argp->argval,last-argp->argval);
1448
ap=(struct argnod*)stkfreeze(stkp,1);
1449
ap->argflag = ARG_RAW;
1450
ap->argchn.ap = 0;
1451
}
1452
*argtail = ap;
1453
argtail = &(ap->argnxt.ap);
1454
if(argno>=0)
1455
argno++;
1456
}
1457
else /* alias substitutions allowed */
1458
lexp->aliasok = 1;
1459
}
1460
else
1461
{
1462
if(!(argp->argflag&ARG_RAW))
1463
argno = -1;
1464
if(argno>=0 && argno++==cmdarg && !(flag&SH_ARRAY) && *argp->argval!='/')
1465
{
1466
/* check for builtin command */
1467
Namval_t *np=nv_bfsearch(argp->argval,lexp->sh->fun_tree, (Namval_t**)&t->comnamq,(char**)0);
1468
if(cmdarg==0)
1469
t->comnamp = (void*)np;
1470
if(np && is_abuiltin(np))
1471
{
1472
if(nv_isattr(np,BLT_DCL))
1473
{
1474
assignment = 1+(*argp->argval=='a');
1475
if(np==SYSTYPESET)
1476
lexp->intypeset = 1;
1477
key_on = 1;
1478
}
1479
else if(np==SYSCOMMAND)
1480
cmdarg++;
1481
else if(np==SYSEXEC)
1482
lexp->inexec = 1;
1483
else if(np->nvalue.bfp==(Nambfp_f)b_getopts)
1484
opt_get |= FOPTGET;
1485
}
1486
}
1487
if((flag&NV_COMVAR) && !assignment)
1488
sh_syntax(lexp);
1489
*argtail = argp;
1490
argtail = &(argp->argnxt.ap);
1491
if(!(lexp->assignok=key_on) && !(flag&SH_NOIO) && sh_isoption(SH_NOEXEC))
1492
lexp->assignok = SH_COMPASSIGN;
1493
lexp->aliasok = 0;
1494
}
1495
retry:
1496
tok = sh_lex(lexp);
1497
if(tok==LABLSYM && (flag&SH_ASSIGN))
1498
lexp->token = tok = 0;
1499
if((tok==IPROCSYM || tok==OPROCSYM))
1500
{
1501
argp = process_sub(lexp,tok);
1502
argno = -1;
1503
*argtail = argp;
1504
argtail = &(argp->argnxt.ap);
1505
goto retry;
1506
}
1507
if(tok==LPAREN)
1508
{
1509
if(argp->argflag&ARG_ASSIGN)
1510
{
1511
int intypeset = lexp->intypeset;
1512
int type = 0;
1513
lexp->intypeset = 0;
1514
if(t->comnamp==SYSTYPESET)
1515
{
1516
struct argnod *ap;
1517
for(ap=t->comarg->argnxt.ap;ap;ap=ap->argnxt.ap)
1518
{
1519
if(*ap->argval!='-')
1520
break;
1521
if(strchr(ap->argval,'T'))
1522
type = NV_TYPE;
1523
else if(strchr(ap->argval,'a'))
1524
type = NV_ARRAY;
1525
else if(strchr(ap->argval,'C'))
1526
type = NV_COMVAR;
1527
else
1528
continue;
1529
break;
1530
}
1531
}
1532
argp = assign(lexp,argp,type);
1533
lexp->intypeset = intypeset;
1534
if(associative)
1535
lexp->assignok |= SH_ASSIGN;
1536
goto retry;
1537
}
1538
else if(argno==1 && !t->comset)
1539
{
1540
/* SVR2 style function */
1541
if(!(flag&SH_ARRAY) && sh_lex(lexp) == RPAREN)
1542
{
1543
lexp->arg = argp;
1544
return(funct(lexp));
1545
}
1546
lexp->token = LPAREN;
1547
}
1548
}
1549
else if(flag&SH_ASSIGN)
1550
{
1551
if(tok==RPAREN)
1552
break;
1553
else if(tok==NL && (flag&SH_ARRAY))
1554
{
1555
lexp->comp_assign = 2;
1556
goto retry;
1557
}
1558
1559
}
1560
if(!(flag&SH_NOIO))
1561
{
1562
if(io)
1563
{
1564
while(io->ionxt)
1565
io = io->ionxt;
1566
io->ionxt = inout(lexp,(struct ionod*)0,0);
1567
}
1568
else
1569
t->comio = io = inout(lexp,(struct ionod*)0,0);
1570
}
1571
}
1572
*argtail = 0;
1573
t->comtyp = TCOM;
1574
#if SHOPT_KIA
1575
if(lexp->kiafile && !(flag&SH_NOIO))
1576
{
1577
register Namval_t *np=(Namval_t*)t->comnamp;
1578
unsigned long r=0;
1579
int line = t->comline;
1580
argp = t->comarg;
1581
if(np)
1582
r = kiaentity(lexp,nv_name(np),-1,'p',-1,0,lexp->unknown,'b',0,"");
1583
else if(argp)
1584
r = kiaentity(lexp,sh_argstr(argp),-1,'p',-1,0,lexp->unknown,'c',0,"");
1585
if(r>0)
1586
sfprintf(lexp->kiatmp,"p;%..64d;p;%..64d;%d;%d;c;\n",lexp->current,r,line,line);
1587
if(t->comset && argno==0)
1588
writedefs(lexp,t->comset,line,'v',t->comarg);
1589
else if(np && nv_isattr(np,BLT_DCL))
1590
writedefs(lexp,argp,line,0,NIL(struct argnod*));
1591
else if(argp && strcmp(argp->argval,"read")==0)
1592
writedefs(lexp,argp,line,0,NIL(struct argnod*));
1593
#if 0
1594
else if(argp && strcmp(argp->argval,"unset")==0)
1595
writedefs(lexp,argp,line,'u',NIL(struct argnod*));
1596
#endif
1597
else if(argp && *argp->argval=='.' && argp->argval[1]==0 && (argp=argp->argnxt.ap))
1598
{
1599
r = kiaentity(lexp,sh_argstr(argp),-1,'p',0,0,lexp->script,'d',0,"");
1600
sfprintf(lexp->kiatmp,"p;%..64d;p;%..64d;%d;%d;d;\n",lexp->current,r,line,line);
1601
}
1602
}
1603
#endif /* SHOPT_KIA */
1604
if(t->comnamp && (argp=t->comarg->argnxt.ap))
1605
{
1606
Namval_t *np=(Namval_t*)t->comnamp;
1607
if((np==SYSBREAK || np==SYSCONT) && (argp->argflag&ARG_RAW) && !isdigit(*argp->argval))
1608
{
1609
register char *cp = argp->argval;
1610
/* convert break/continue labels to numbers */
1611
tok = 0;
1612
for(argp=label_list;argp!=label_last;argp=argp->argnxt.ap)
1613
{
1614
if(strcmp(cp,argp->argval))
1615
continue;
1616
tok = loop_level-argp->argflag;
1617
if(tok>=1)
1618
{
1619
argp = t->comarg->argnxt.ap;
1620
if(tok>9)
1621
{
1622
argp->argval[1] = '0'+tok%10;
1623
argp->argval[2] = 0;
1624
tok /= 10;
1625
}
1626
else
1627
argp->argval[1] = 0;
1628
*argp->argval = '0'+tok;
1629
}
1630
break;
1631
}
1632
if(sh_isoption(SH_NOEXEC) && tok==0)
1633
errormsg(SH_DICT,ERROR_warn(0),e_lexlabunknown,lexp->sh->inlineno-(lexp->token=='\n'),cp);
1634
}
1635
else if(sh_isoption(SH_NOEXEC) && np==SYSSET && ((tok= *argp->argval)=='-'||tok=='+') &&
1636
(argp->argval[1]==0||strchr(argp->argval,'k')))
1637
errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete5,lexp->sh->inlineno-(lexp->token=='\n'),argp->argval);
1638
}
1639
/* expand argument list if possible */
1640
if(argno>0 && !(flag&(SH_ARRAY|NV_APPEND)))
1641
t->comarg = qscan(t,argno);
1642
else if(t->comarg)
1643
t->comtyp |= COMSCAN;
1644
lexp->aliasok = 0;
1645
return((Shnode_t*)t);
1646
}
1647
1648
/*
1649
* skip past newlines but issue prompt if interactive
1650
*/
1651
static int skipnl(Lex_t *lexp,int flag)
1652
{
1653
register int token;
1654
while((token=sh_lex(lexp))==NL);
1655
if(token==';' && !(flag&SH_SEMI))
1656
sh_syntax(lexp);
1657
return(token);
1658
}
1659
1660
/*
1661
* check for and process and i/o redirections
1662
* if flag>0 then an alias can be in the next word
1663
* if flag<0 only one redirection will be processed
1664
*/
1665
static struct ionod *inout(Lex_t *lexp,struct ionod *lastio,int flag)
1666
{
1667
register int iof = lexp->digits, token=lexp->token;
1668
register struct ionod *iop;
1669
Stk_t *stkp = lexp->sh->stk;
1670
char *iovname=0;
1671
register int errout=0;
1672
if(token==IOVNAME)
1673
{
1674
iovname=lexp->arg->argval+1;
1675
token= sh_lex(lexp);
1676
iof = 0;
1677
}
1678
switch(token&0xff)
1679
{
1680
case '<':
1681
if(token==IODOCSYM)
1682
iof |= (IODOC|IORAW);
1683
else if(token==IOMOV0SYM)
1684
iof |= IOMOV;
1685
else if(token==IORDWRSYMT)
1686
iof |= IORDW|IOREWRITE;
1687
else if(token==IORDWRSYM)
1688
iof |= IORDW;
1689
else if((token&SYMSHARP) == SYMSHARP)
1690
{
1691
int n;
1692
iof |= IOLSEEK;
1693
if(fcgetc(n)=='#')
1694
iof |= IOCOPY;
1695
else if(n>0)
1696
fcseek(-1);
1697
}
1698
break;
1699
1700
case '>':
1701
if(iof<0)
1702
{
1703
errout = 1;
1704
iof = 1;
1705
}
1706
iof |= IOPUT;
1707
if(token==IOAPPSYM)
1708
iof |= IOAPP;
1709
else if(token==IOMOV1SYM)
1710
iof |= IOMOV;
1711
else if(token==IOCLOBSYM)
1712
iof |= IOCLOB;
1713
else if((token&SYMSHARP) == SYMSHARP)
1714
iof |= IOLSEEK;
1715
else if((token&SYMSEMI) == SYMSEMI)
1716
iof |= IOREWRITE;
1717
break;
1718
1719
default:
1720
return(lastio);
1721
}
1722
lexp->digits=0;
1723
iop=(struct ionod*) stkalloc(stkp,sizeof(struct ionod));
1724
iop->iodelim = 0;
1725
if(token=sh_lex(lexp))
1726
{
1727
if(token==RPAREN && (iof&IOLSEEK) && lexp->comsub)
1728
{
1729
lexp->arg = (struct argnod*)stkalloc(stkp,sizeof(struct argnod)+3);
1730
strcpy(lexp->arg->argval,"CUR");
1731
lexp->arg->argflag = ARG_RAW;
1732
iof |= IOARITH;
1733
fcseek(-1);
1734
}
1735
else if(token==EXPRSYM && (iof&IOLSEEK))
1736
iof |= IOARITH;
1737
else if(((token==IPROCSYM && !(iof&IOPUT)) || (token==OPROCSYM && (iof&IOPUT))) && !(iof&(IOLSEEK|IOREWRITE|IOMOV|IODOC)))
1738
{
1739
lexp->arg = process_sub(lexp,token);
1740
iof |= IOPROCSUB;
1741
}
1742
else
1743
sh_syntax(lexp);
1744
}
1745
if( (iof&IOPROCSUB) && !(iof&IOLSEEK))
1746
iop->ioname= (char*)lexp->arg->argchn.ap;
1747
else
1748
iop->ioname=lexp->arg->argval;
1749
iop->iovname = iovname;
1750
if(iof&IODOC)
1751
{
1752
if(lexp->digits==2)
1753
{
1754
iof |= IOSTRG;
1755
if(!(lexp->arg->argflag&ARG_RAW))
1756
iof &= ~IORAW;
1757
}
1758
else
1759
{
1760
if(!lexp->sh->heredocs)
1761
lexp->sh->heredocs = sftmp(HERE_MEM);
1762
iop->iolst=lexp->heredoc;
1763
lexp->heredoc=iop;
1764
if(lexp->arg->argflag&ARG_QUOTED)
1765
iof |= IOQUOTE;
1766
if(lexp->digits==3)
1767
iof |= IOLSEEK;
1768
if(lexp->digits)
1769
iof |= IOSTRIP;
1770
}
1771
}
1772
else
1773
{
1774
iop->iolst = 0;
1775
if(lexp->arg->argflag&ARG_RAW)
1776
iof |= IORAW;
1777
}
1778
iop->iofile=iof;
1779
if(flag>0)
1780
/* allow alias substitutions and parameter assignments */
1781
lexp->aliasok = lexp->assignok = 1;
1782
#if SHOPT_KIA
1783
if(lexp->kiafile)
1784
{
1785
int n = lexp->sh->inlineno-(lexp->token=='\n');
1786
if(!(iof&IOMOV))
1787
{
1788
unsigned long r=kiaentity(lexp,(iof&IORAW)?sh_fmtq(iop->ioname):iop->ioname,-1,'f',0,0,lexp->script,'f',0,"");
1789
sfprintf(lexp->kiatmp,"p;%..64d;f;%..64d;%d;%d;%c;%d\n",lexp->current,r,n,n,(iof&IOPUT)?((iof&IOAPP)?'a':'w'):((iof&IODOC)?'h':'r'),iof&IOUFD);
1790
}
1791
}
1792
#endif /* SHOPT_KIA */
1793
if(flag>=0)
1794
{
1795
struct ionod *ioq=iop;
1796
sh_lex(lexp);
1797
if(errout)
1798
{
1799
/* redirect standard output to standard error */
1800
ioq = (struct ionod*)stkalloc(stkp,sizeof(struct ionod));
1801
memset(ioq,0,sizeof(*ioq));
1802
ioq->ioname = "1";
1803
ioq->iolst = 0;
1804
ioq->iodelim = 0;
1805
ioq->iofile = IORAW|IOPUT|IOMOV|2;
1806
iop->ionxt=ioq;
1807
}
1808
ioq->ionxt=inout(lexp,lastio,flag);
1809
}
1810
else
1811
iop->ionxt=0;
1812
return(iop);
1813
}
1814
1815
/*
1816
* convert argument chain to argument list when no special arguments
1817
*/
1818
1819
static struct argnod *qscan(struct comnod *ac,int argn)
1820
{
1821
register char **cp;
1822
register struct argnod *ap;
1823
register struct dolnod* dp;
1824
register int special=0;
1825
/* special hack for test -t compatibility */
1826
if((Namval_t*)ac->comnamp==SYSTEST)
1827
special = 2;
1828
else if(*(ac->comarg->argval)=='[' && ac->comarg->argval[1]==0)
1829
special = 3;
1830
if(special)
1831
{
1832
ap = ac->comarg->argnxt.ap;
1833
if(argn==(special+1) && ap->argval[1]==0 && *ap->argval=='!')
1834
ap = ap->argnxt.ap;
1835
else if(argn!=special)
1836
special=0;
1837
}
1838
if(special)
1839
{
1840
const char *message;
1841
if(strcmp(ap->argval,"-t"))
1842
{
1843
message = "line %d: Invariant test";
1844
special=0;
1845
}
1846
else
1847
{
1848
message = "line %d: -t requires argument";
1849
argn++;
1850
}
1851
if(sh_isoption(SH_NOEXEC))
1852
errormsg(SH_DICT,ERROR_warn(0),message,ac->comline);
1853
}
1854
/* leave space for an extra argument at the front */
1855
dp = (struct dolnod*)stakalloc((unsigned)sizeof(struct dolnod) + ARG_SPARE*sizeof(char*) + argn*sizeof(char*));
1856
cp = dp->dolval+ARG_SPARE;
1857
dp->dolnum = argn;
1858
dp->dolbot = ARG_SPARE;
1859
ap = ac->comarg;
1860
while(ap)
1861
{
1862
*cp++ = ap->argval;
1863
ap = ap->argnxt.ap;
1864
}
1865
if(special==3)
1866
{
1867
cp[0] = cp[-1];
1868
cp[-1] = "1";
1869
cp++;
1870
}
1871
else if(special)
1872
*cp++ = "1";
1873
*cp = 0;
1874
return((struct argnod*)dp);
1875
}
1876
1877
static Shnode_t *test_expr(Lex_t *lp,int sym)
1878
{
1879
register Shnode_t *t = test_or(lp);
1880
if(lp->token!=sym)
1881
sh_syntax(lp);
1882
return(t);
1883
}
1884
1885
static Shnode_t *test_or(Lex_t *lp)
1886
{
1887
register Shnode_t *t = test_and(lp);
1888
while(lp->token==ORFSYM)
1889
t = makelist(lp,TORF|TTEST,t,test_and(lp));
1890
return(t);
1891
}
1892
1893
static Shnode_t *test_and(Lex_t *lp)
1894
{
1895
register Shnode_t *t = test_primary(lp);
1896
while(lp->token==ANDFSYM)
1897
t = makelist(lp,TAND|TTEST,t,test_primary(lp));
1898
return(t);
1899
}
1900
1901
/*
1902
* convert =~ into == ~(E)
1903
*/
1904
static void ere_match(void)
1905
{
1906
Sfio_t *base, *iop = sfopen((Sfio_t*)0," ~(E)","s");
1907
register int c;
1908
while( fcgetc(c),(c==' ' || c=='\t'));
1909
if(c)
1910
fcseek(-1);
1911
if(!(base=fcfile()))
1912
base = sfopen(NIL(Sfio_t*),fcseek(0),"s");
1913
fcclose();
1914
sfstack(base,iop);
1915
fcfopen(base);
1916
}
1917
1918
static Shnode_t *test_primary(Lex_t *lexp)
1919
{
1920
register struct argnod *arg;
1921
register Shnode_t *t;
1922
register int num,token;
1923
token = skipnl(lexp,0);
1924
num = lexp->digits;
1925
switch(token)
1926
{
1927
case '(':
1928
t = test_expr(lexp,')');
1929
t = makelist(lexp,TTST|TTEST|TPAREN ,t, (Shnode_t*)pointerof(lexp->sh->inlineno));
1930
break;
1931
case '!':
1932
if(!(t = test_primary(lexp)))
1933
sh_syntax(lexp);
1934
t->tre.tretyp |= TNEGATE;
1935
return(t);
1936
case TESTUNOP:
1937
if(sh_lex(lexp))
1938
sh_syntax(lexp);
1939
#if SHOPT_KIA
1940
if(lexp->kiafile && !strchr("sntzoOG",num))
1941
{
1942
int line = lexp->sh->inlineno- (lexp->token==NL);
1943
unsigned long r;
1944
r=kiaentity(lexp,sh_argstr(lexp->arg),-1,'f',0,0,lexp->script,'t',0,"");
1945
sfprintf(lexp->kiatmp,"p;%..64d;f;%..64d;%d;%d;t;\n",lexp->current,r,line,line);
1946
}
1947
#endif /* SHOPT_KIA */
1948
t = makelist(lexp,TTST|TTEST|TUNARY|(num<<TSHIFT),
1949
(Shnode_t*)lexp->arg,(Shnode_t*)lexp->arg);
1950
t->tst.tstline = lexp->sh->inlineno;
1951
break;
1952
/* binary test operators */
1953
case 0:
1954
arg = lexp->arg;
1955
if((token=sh_lex(lexp))==TESTBINOP)
1956
{
1957
num = lexp->digits;
1958
if(num==TEST_REP)
1959
{
1960
ere_match();
1961
num = TEST_PEQ;
1962
}
1963
}
1964
else if(token=='<')
1965
num = TEST_SLT;
1966
else if(token=='>')
1967
num = TEST_SGT;
1968
else if(token==ANDFSYM||token==ORFSYM||token==ETESTSYM||token==RPAREN)
1969
{
1970
t = makelist(lexp,TTST|TTEST|TUNARY|('n'<<TSHIFT),
1971
(Shnode_t*)arg,(Shnode_t*)arg);
1972
t->tst.tstline = lexp->sh->inlineno;
1973
return(t);
1974
}
1975
else
1976
sh_syntax(lexp);
1977
#if SHOPT_KIA
1978
if(lexp->kiafile && (num==TEST_EF||num==TEST_NT||num==TEST_OT))
1979
{
1980
int line = lexp->sh->inlineno- (lexp->token==NL);
1981
unsigned long r;
1982
r=kiaentity(lexp,sh_argstr(lexp->arg),-1,'f',0,0,lexp->current,'t',0,"");
1983
sfprintf(lexp->kiatmp,"p;%..64d;f;%..64d;%d;%d;t;\n",lexp->current,r,line,line);
1984
}
1985
#endif /* SHOPT_KIA */
1986
if(sh_lex(lexp))
1987
sh_syntax(lexp);
1988
if(num&TEST_PATTERN)
1989
{
1990
if(lexp->arg->argflag&(ARG_EXP|ARG_MAC))
1991
num &= ~TEST_PATTERN;
1992
}
1993
t = getnode(tstnod);
1994
t->lst.lsttyp = TTST|TTEST|TBINARY|(num<<TSHIFT);
1995
t->lst.lstlef = (Shnode_t*)arg;
1996
t->lst.lstrit = (Shnode_t*)lexp->arg;
1997
t->tst.tstline = lexp->sh->inlineno;
1998
#if SHOPT_KIA
1999
if(lexp->kiafile && (num==TEST_EF||num==TEST_NT||num==TEST_OT))
2000
{
2001
int line = lexp->sh->inlineno-(lexp->token==NL);
2002
unsigned long r;
2003
r=kiaentity(lexp,sh_argstr(lexp->arg),-1,'f',0,0,lexp->current,'t',0,"");
2004
sfprintf(lexp->kiatmp,"p;%..64d;f;%..64d;%d;%d;t;\n",lexp->current,r,line,line);
2005
}
2006
#endif /* SHOPT_KIA */
2007
break;
2008
default:
2009
return(0);
2010
}
2011
skipnl(lexp,0);
2012
return(t);
2013
}
2014
2015
#if SHOPT_KIA
2016
/*
2017
* return an entity checksum
2018
* The entity is created if it doesn't exist
2019
*/
2020
unsigned long kiaentity(Lex_t *lexp,const char *name,int len,int type,int first,int last,unsigned long parent, int pkind, int width, const char *attr)
2021
{
2022
Stk_t *stkp = lexp->sh->stk;
2023
Namval_t *np;
2024
long offset = stktell(stkp);
2025
sfputc(stkp,type);
2026
if(len>0)
2027
sfwrite(stkp,name,len);
2028
else
2029
{
2030
if(type=='p')
2031
sfputr(stkp,path_basename(name),0);
2032
else
2033
sfputr(stkp,name,0);
2034
}
2035
np = nv_search(stakptr(offset),lexp->entity_tree,NV_ADD);
2036
stkseek(stkp,offset);
2037
np->nvalue.i = pkind;
2038
nv_setsize(np,width);
2039
if(!nv_isattr(np,NV_TAGGED) && first>=0)
2040
{
2041
nv_onattr(np,NV_TAGGED);
2042
if(!pkind)
2043
pkind = '0';
2044
if(len>0)
2045
sfprintf(lexp->kiafile,"%..64d;%c;%.*s;%d;%d;%..64d;%..64d;%c;%d;%s\n",np->hash,type,len,name,first,last,parent,lexp->fscript,pkind,width,attr);
2046
else
2047
sfprintf(lexp->kiafile,"%..64d;%c;%s;%d;%d;%..64d;%..64d;%c;%d;%s\n",np->hash,type,name,first,last,parent,lexp->fscript,pkind,width,attr);
2048
}
2049
return(np->hash);
2050
}
2051
2052
static void kia_add(register Namval_t *np, void *data)
2053
{
2054
char *name = nv_name(np);
2055
Lex_t *lp = (Lex_t*)data;
2056
NOT_USED(data);
2057
kiaentity(lp,name+1,-1,*name,0,-1,(*name=='p'?lp->unknown:lp->script),np->nvalue.i,nv_size(np),"");
2058
}
2059
2060
int kiaclose(Lex_t *lexp)
2061
{
2062
register off_t off1,off2;
2063
register int n;
2064
if(lexp->kiafile)
2065
{
2066
unsigned long r = kiaentity(lexp,lexp->scriptname,-1,'p',-1,lexp->sh->inlineno-1,0,'s',0,"");
2067
kiaentity(lexp,lexp->scriptname,-1,'p',1,lexp->sh->inlineno-1,r,'s',0,"");
2068
kiaentity(lexp,lexp->scriptname,-1,'f',1,lexp->sh->inlineno-1,r,'s',0,"");
2069
nv_scan(lexp->entity_tree,kia_add,(void*)lexp,NV_TAGGED,0);
2070
off1 = sfseek(lexp->kiafile,(off_t)0,SEEK_END);
2071
sfseek(lexp->kiatmp,(off_t)0,SEEK_SET);
2072
sfmove(lexp->kiatmp,lexp->kiafile,SF_UNBOUND,-1);
2073
off2 = sfseek(lexp->kiafile,(off_t)0,SEEK_END);
2074
#ifdef SF_BUFCONST
2075
if(off2==off1)
2076
n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%lld;%d\nDIRECTORY;",(Sflong_t)lexp->kiabegin,(size_t)(off1-lexp->kiabegin));
2077
else
2078
n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%lld;%d\nRELATIONSHIP;%lld;%d\nDIRECTORY;",(Sflong_t)lexp->kiabegin,(size_t)(off1-lexp->kiabegin),(Sflong_t)off1,(size_t)(off2-off1));
2079
if(off2 >= INT_MAX)
2080
off2 = -(n+12);
2081
sfprintf(lexp->kiafile,"%010.10lld;%010d\n",(Sflong_t)off2+10, n+12);
2082
#else
2083
if(off2==off1)
2084
n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%d;%d\nDIRECTORY;",lexp->kiabegin,off1-lexp->kiabegin);
2085
else
2086
n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%d;%d\nRELATIONSHIP;%d;%d\nDIRECTORY;",lexp->kiabegin,off1-lexp->kiabegin,off1,off2-off1);
2087
sfprintf(lexp->kiafile,"%010d;%010d\n",off2+10, n+12);
2088
#endif
2089
}
2090
return(sfclose(lexp->kiafile));
2091
}
2092
#endif /* SHOPT_KIA */
2093
2094