Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/ksh93/sh/macro.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
* Shell macro expander
23
* expands ~
24
* expands ${...}
25
* expands $(...)
26
* expands $((...))
27
* expands `...`
28
*
29
* David Korn
30
* AT&T Labs
31
*
32
*/
33
34
#include "defs.h"
35
#include <fcin.h>
36
#include <pwd.h>
37
#include <ctype.h>
38
#include <regex.h>
39
#include "name.h"
40
#include "variables.h"
41
#include "shlex.h"
42
#include "io.h"
43
#include "jobs.h"
44
#include "shnodes.h"
45
#include "path.h"
46
#include "national.h"
47
#include "streval.h"
48
49
#undef STR_GROUP
50
#ifndef STR_GROUP
51
# define STR_GROUP 0
52
#endif
53
54
#if SHOPT_MULTIBYTE
55
# undef isascii
56
# define isacii(c) ((c)<=UCHAR_MAX)
57
#else
58
# define mbchar(p) (*(unsigned char*)p++)
59
#endif /* SHOPT_MULTIBYTE */
60
61
#if _WINIX
62
static int Skip;
63
#endif /*_WINIX */
64
65
static int _c_;
66
typedef struct _mac_
67
{
68
Shell_t *shp; /* pointer to shell interpreter */
69
Sfio_t *sp; /* stream pointer for here-document */
70
struct argnod **arghead; /* address of head of argument list */
71
char *ifsp; /* pointer to IFS value */
72
int fields; /* number of fields */
73
short quoted; /* set when word has quotes */
74
unsigned char ifs; /* first char of IFS */
75
char atmode; /* when processing $@ */
76
char quote; /* set within double quoted contexts */
77
char lit; /* set within single quotes */
78
char split; /* set when word splittin is possible */
79
char pattern; /* set when file expansion follows */
80
char patfound; /* set if pattern character found */
81
char assign; /* set for assignments */
82
char arith; /* set for ((...)) */
83
char let; /* set when expanding let arguments */
84
char zeros; /* strip leading zeros when set */
85
char arrayok; /* $x[] ok for arrays */
86
char subcopy; /* set when copying subscript */
87
int dotdot; /* set for .. in subscript */
88
void *nvwalk; /* for name space walking*/
89
} Mac_t;
90
91
#undef ESCAPE
92
#define ESCAPE '\\'
93
#define isescchar(s) ((s)>S_QUOTE)
94
#define isqescchar(s) ((s)>=S_QUOTE)
95
#define isbracechar(c) ((c)==RBRACE || (_c_=sh_lexstates[ST_BRACE][c])==S_MOD1 ||_c_==S_MOD2)
96
#define ltos(x) fmtbase((long)(x),0,0)
97
98
/* type of macro expansions */
99
#define M_BRACE 1 /* ${var} */
100
#define M_TREE 2 /* ${var.} */
101
#define M_SIZE 3 /* ${#var} */
102
#define M_VNAME 4 /* ${!var} */
103
#define M_SUBNAME 5 /* ${!var[sub]} */
104
#define M_NAMESCAN 6 /* ${!var*} */
105
#define M_NAMECOUNT 7 /* ${#var*} */
106
#define M_TYPE 8 /* ${@var} */
107
108
static int substring(const char*, const char*, int[], int);
109
static void copyto(Mac_t*, int, int);
110
static void comsubst(Mac_t*, Shnode_t*, int);
111
static int varsub(Mac_t*);
112
static void mac_copy(Mac_t*,const char*, int);
113
static void tilde_expand2(Shell_t*,int);
114
static char *sh_tilde(Shell_t*,const char*);
115
static char *special(Shell_t *,int);
116
static void endfield(Mac_t*,int);
117
static void mac_error(Namval_t*);
118
static char *mac_getstring(char*);
119
static int charlen(const char*,int);
120
#if SHOPT_MULTIBYTE
121
static char *lastchar(const char*,const char*);
122
#endif /* SHOPT_MULTIBYTE */
123
124
void *sh_macopen(Shell_t *shp)
125
{
126
void *addr = newof(0,Mac_t,1,0);
127
Mac_t *mp = (Mac_t*)addr;
128
mp->shp = shp;
129
return(addr);
130
}
131
132
/*
133
* perform only parameter substitution and catch failures
134
*/
135
char *sh_mactry(Shell_t *shp,register char *string)
136
{
137
if(string)
138
{
139
int jmp_val;
140
int savexit = shp->savexit;
141
struct checkpt buff;
142
sh_pushcontext(shp,&buff,SH_JMPSUB);
143
jmp_val = sigsetjmp(buff.buff,0);
144
if(jmp_val == 0)
145
string = sh_mactrim(shp,string,0);
146
sh_popcontext(shp,&buff);
147
shp->savexit = savexit;
148
return(string);
149
}
150
return("");
151
}
152
153
/*
154
* Perform parameter expansion, command substitution, and arithmetic
155
* expansion on <str>.
156
* If <mode> greater than 1 file expansion is performed if the result
157
* yields a single pathname.
158
* If <mode> negative, than expansion rules for assignment are applied.
159
*/
160
char *sh_mactrim(Shell_t *shp, char *str, register int mode)
161
{
162
register Mac_t *mp = (Mac_t*)shp->mac_context;
163
Stk_t *stkp = shp->stk;
164
Mac_t savemac;
165
savemac = *mp;
166
stkseek(stkp,0);
167
mp->arith = (mode==3);
168
mp->let = 0;
169
shp->argaddr = 0;
170
mp->pattern = (mode==1||mode==2);
171
mp->patfound = 0;
172
mp->assign = 0;
173
if(mode<0)
174
mp->assign = -mode;
175
mp->quoted = mp->lit = mp->split = mp->quote = 0;
176
mp->sp = 0;
177
if(mp->ifsp=nv_getval(sh_scoped(shp,IFSNOD)))
178
mp->ifs = *mp->ifsp;
179
else
180
mp->ifs = ' ';
181
stkseek(stkp,0);
182
fcsopen(str);
183
copyto(mp,0,mp->arith);
184
str = stkfreeze(stkp,1);
185
if(mode==2)
186
{
187
/* expand only if unique */
188
struct argnod *arglist=0;
189
if((mode=path_expand(shp,str,&arglist))==1)
190
str = arglist->argval;
191
else if(mode>1)
192
errormsg(SH_DICT,ERROR_exit(1),e_ambiguous,str);
193
sh_trim(str);
194
}
195
*mp = savemac;
196
return(str);
197
}
198
199
/*
200
* Perform all the expansions on the argument <argp>
201
*/
202
int sh_macexpand(Shell_t* shp, register struct argnod *argp, struct argnod **arghead,int flag)
203
{
204
register int flags = argp->argflag;
205
register char *str = argp->argval;
206
register Mac_t *mp = (Mac_t*)shp->mac_context;
207
char **saveargaddr = shp->argaddr;
208
Mac_t savemac;
209
Stk_t *stkp = shp->stk;
210
savemac = *mp;
211
mp->sp = 0;
212
if(mp->ifsp=nv_getval(sh_scoped(shp,IFSNOD)))
213
mp->ifs = *mp->ifsp;
214
else
215
mp->ifs = ' ';
216
if((flag&ARG_OPTIMIZE) && !shp->indebug && !(flags&ARG_MESSAGE))
217
shp->argaddr = (char**)&argp->argchn.ap;
218
else
219
shp->argaddr = 0;
220
mp->arghead = arghead;
221
mp->quoted = mp->lit = mp->quote = 0;
222
mp->arith = ((flag&ARG_ARITH)!=0);
223
mp->let = ((flag&ARG_LET)!=0);
224
mp->split = !(flag&ARG_ASSIGN);
225
mp->assign = !mp->split;
226
mp->pattern = mp->split && !(flag&ARG_NOGLOB) && !sh_isoption(SH_NOGLOB);
227
mp->arrayok = mp->arith || (flag&ARG_ARRAYOK);
228
str = argp->argval;
229
fcsopen(str);
230
mp->fields = 0;
231
mp->atmode = 0;
232
if(!arghead)
233
{
234
mp->split = 0;
235
mp->pattern = ((flag&ARG_EXP)!=0);
236
stkseek(stkp,0);
237
}
238
else
239
{
240
stkseek(stkp,ARGVAL);
241
*stkptr(stkp,ARGVAL-1) = 0;
242
}
243
mp->patfound = 0;
244
if(mp->pattern)
245
mp->arrayok = 0;
246
copyto(mp,0,mp->arith);
247
if(!arghead)
248
{
249
argp->argchn.cp = stkfreeze(stkp,1);
250
if(shp->argaddr)
251
argp->argflag |= ARG_MAKE;
252
}
253
else
254
{
255
endfield(mp,mp->quoted|mp->atmode);
256
flags = mp->fields;
257
if(flags==1 && shp->argaddr)
258
argp->argchn.ap = *arghead;
259
}
260
shp->argaddr = saveargaddr;
261
*mp = savemac;
262
return(flags);
263
}
264
265
/*
266
* Expand here document which is stored in <infile> or <string>
267
* The result is written to <outfile>
268
*/
269
void sh_machere(Shell_t *shp,Sfio_t *infile, Sfio_t *outfile, char *string)
270
{
271
register int c,n;
272
register const char *state = sh_lexstates[ST_QUOTE];
273
register char *cp;
274
register Mac_t *mp = (Mac_t*)shp->mac_context;
275
Lex_t *lp = (Lex_t*)mp->shp->lex_context;
276
Fcin_t save;
277
Mac_t savemac;
278
Stk_t *stkp = shp->stk;
279
savemac = *mp;
280
stkseek(stkp,0);
281
shp->argaddr = 0;
282
mp->sp = outfile;
283
mp->split = mp->assign = mp->pattern = mp->patfound = mp->lit = mp->arith = mp->let = 0;
284
mp->quote = 1;
285
mp->ifsp = nv_getval(sh_scoped(shp,IFSNOD));
286
mp->ifs = ' ';
287
fcsave(&save);
288
if(infile)
289
fcfopen(infile);
290
else
291
fcsopen(string);
292
fcnotify(0,lp);
293
cp = fcseek(0);
294
while(1)
295
{
296
#if SHOPT_MULTIBYTE
297
if(mbwide())
298
{
299
do
300
{
301
ssize_t len;
302
switch(len = mbsize(cp))
303
{
304
case -1: /* illegal multi-byte char */
305
case 0:
306
case 1:
307
n=state[*(unsigned char*)cp++];
308
break;
309
default:
310
/* use state of alpha character */
311
n=state['a'];
312
cp += len;
313
}
314
}
315
while(n == 0);
316
}
317
else
318
#endif /* SHOPT_MULTIBYTE */
319
while((n=state[*(unsigned char*)cp++])==0);
320
if(n==S_NL || n==S_QUOTE || n==S_RBRA)
321
continue;
322
if(c=(cp-1)-fcseek(0))
323
sfwrite(outfile,fcseek(0),c);
324
cp = fcseek(c+1);
325
switch(n)
326
{
327
case S_EOF:
328
if((n=fcfill()) <=0)
329
{
330
/* ignore 0 byte when reading from file */
331
if(n==0 && fcfile())
332
continue;
333
fcrestore(&save);
334
*mp = savemac;
335
return;
336
}
337
cp = fcseek(-1);
338
continue;
339
case S_ESC:
340
fcgetc(c);
341
cp=fcseek(-1);
342
if(c>0)
343
cp++;
344
if(!isescchar(state[c]))
345
sfputc(outfile,ESCAPE);
346
continue;
347
case S_GRAVE:
348
comsubst(mp,(Shnode_t*)0,0);
349
break;
350
case S_DOL:
351
c = fcget();
352
if(c=='.')
353
goto regular;
354
again:
355
switch(n=sh_lexstates[ST_DOL][c])
356
{
357
case S_ALP: case S_SPC1: case S_SPC2:
358
case S_DIG: case S_LBRA:
359
{
360
Fcin_t save2;
361
int offset = stktell(stkp);
362
int offset2;
363
fcnotify(0,lp);
364
sfputc(stkp,c);
365
if(n==S_LBRA)
366
{
367
c = fcget();
368
fcseek(-1);
369
if(sh_lexstates[ST_NORM][c]==S_BREAK)
370
{
371
comsubst(mp,(Shnode_t*)0,2);
372
break;
373
}
374
sh_lexskip(lp,RBRACE,1,ST_BRACE);
375
}
376
else if(n==S_ALP)
377
{
378
while(fcgetc(c),isaname(c))
379
sfputc(stkp,c);
380
fcseek(-1);
381
}
382
sfputc(stkp,0);
383
offset2 = stktell(stkp);
384
fcsave(&save2);
385
fcsopen(stkptr(stkp,offset));
386
varsub(mp);
387
if(c=stktell(stkp)-offset2)
388
sfwrite(outfile,(char*)stkptr(stkp,offset2),c);
389
fcrestore(&save2);
390
stkseek(stkp,offset);
391
break;
392
}
393
case S_PAR:
394
comsubst(mp,(Shnode_t*)0,1);
395
break;
396
case S_EOF:
397
if((c=fcfill()) > 0)
398
goto again;
399
/* FALL THRU */
400
default:
401
regular:
402
sfputc(outfile,'$');
403
fcseek(-1);
404
break;
405
}
406
}
407
cp = fcseek(0);
408
}
409
}
410
411
/*
412
* expand argument but do not trim pattern characters
413
*/
414
char *sh_macpat(Shell_t *shp,register struct argnod *arg, int flags)
415
{
416
register char *sp = arg->argval;
417
if((arg->argflag&ARG_RAW))
418
return(sp);
419
sh_stats(STAT_ARGEXPAND);
420
if(flags&ARG_OPTIMIZE)
421
arg->argchn.ap=0;
422
if(!(sp=arg->argchn.cp))
423
{
424
sh_macexpand(shp,arg,NIL(struct argnod**),flags|ARG_ARRAYOK);
425
sp = arg->argchn.cp;
426
if(!(flags&ARG_OPTIMIZE) || !(arg->argflag&ARG_MAKE))
427
arg->argchn.cp = 0;
428
arg->argflag &= ~ARG_MAKE;
429
}
430
else
431
sh_stats(STAT_ARGHITS);
432
return(sp);
433
}
434
435
/*
436
* Process the characters up to <endch> or end of input string
437
*/
438
static void copyto(register Mac_t *mp,int endch, int newquote)
439
{
440
register int c,n;
441
register const char *state = sh_lexstates[ST_MACRO];
442
register char *cp,*first;
443
Lex_t *lp = (Lex_t*)mp->shp->lex_context;
444
int tilde = -1;
445
int oldquote = mp->quote;
446
int ansi_c = 0;
447
int paren = 0;
448
int ere = 0;
449
int brace = 0;
450
Sfio_t *sp = mp->sp;
451
Stk_t *stkp = mp->shp->stk;
452
char *resume = 0;
453
mp->sp = NIL(Sfio_t*);
454
mp->quote = newquote;
455
first = cp = fcseek(0);
456
if(!mp->quote && *cp=='~' && cp[1]!=LPAREN)
457
tilde = stktell(stkp);
458
/* handle // operator specially */
459
if(mp->pattern==2 && *cp=='/')
460
cp++;
461
while(1)
462
{
463
#if SHOPT_MULTIBYTE
464
if(mbwide())
465
{
466
ssize_t len;
467
do
468
{
469
switch(len = mbsize(cp))
470
{
471
case -1: /* illegal multi-byte char */
472
case 0:
473
len = 1;
474
case 1:
475
n = state[*(unsigned char*)cp++];
476
break;
477
default:
478
/* treat as if alpha */
479
cp += len;
480
n=state['a'];
481
}
482
}
483
while(n == 0);
484
c = (cp-len) - first;
485
}
486
else
487
#endif /* SHOPT_MULTIBYTE */
488
{
489
while((n=state[*(unsigned char*)cp++])==0);
490
c = (cp-1) - first;
491
}
492
switch(n)
493
{
494
case S_ESC:
495
if(ansi_c)
496
{
497
/* process ANSI-C escape character */
498
char *addr= --cp;
499
if(c)
500
sfwrite(stkp,first,c);
501
c = chresc(cp,&addr);
502
cp = addr;
503
first = fcseek(cp-first);
504
#if SHOPT_MULTIBYTE
505
if(c > UCHAR_MAX && mbwide())
506
{
507
int i;
508
unsigned char mb[8];
509
510
n = mbconv((char*)mb, c);
511
for(i=0;i<n;i++)
512
sfputc(stkp,mb[i]);
513
}
514
else
515
#endif /* SHOPT_MULTIBYTE */
516
sfputc(stkp,c);
517
if(c==ESCAPE && mp->pattern)
518
sfputc(stkp,ESCAPE);
519
break;
520
}
521
else if(sh_isoption(SH_BRACEEXPAND) && mp->pattern==4 && (*cp==',' || *cp==LBRACE || *cp==RBRACE || *cp=='.'))
522
break;
523
else if(mp->split && endch && !mp->quote && !mp->lit)
524
{
525
if(c)
526
mac_copy(mp,first,c);
527
cp = fcseek(c+2);
528
if(c= cp[-1])
529
{
530
sfputc(stkp,c);
531
if(c==ESCAPE)
532
sfputc(stkp,ESCAPE);
533
}
534
else
535
cp--;
536
first = cp;
537
break;
538
}
539
n = state[*(unsigned char*)cp];
540
if(n==S_ENDCH && *cp!=endch)
541
n = S_PAT;
542
if(mp->pattern)
543
{
544
/* preserve \digit for pattern matching */
545
/* also \alpha for extended patterns */
546
if(!mp->lit && !mp->quote)
547
{
548
int nc = *(unsigned char*)cp;
549
if((n==S_DIG || ((paren+ere) && (sh_lexstates[ST_DOL][nc]==S_ALP) || nc=='<' || nc=='>')))
550
break;
551
if(ere && mp->pattern==1 && strchr(".[()*+?{|^$&!",*cp))
552
break;
553
}
554
/* followed by file expansion */
555
if(!mp->lit && (n==S_ESC || (!mp->quote &&
556
(n==S_PAT||n==S_ENDCH||n==S_SLASH||n==S_BRACT||*cp=='-'))))
557
{
558
cp += (n!=S_EOF);
559
if(ere && n==S_ESC && *cp =='\\' && cp[1]=='$')
560
{
561
/* convert \\\$ into \$' */
562
sfwrite(stkp,first,c+1);
563
cp = first = fcseek(c+3);
564
}
565
break;
566
}
567
if(!(ere && *cp=='$') && (mp->lit || (mp->quote && !isqescchar(n) && n!=S_ENDCH)))
568
{
569
/* add \ for file expansion */
570
sfwrite(stkp,first,c+1);
571
first = fcseek(c);
572
break;
573
}
574
}
575
if(mp->lit)
576
break;
577
if(!mp->quote || isqescchar(n) || n==S_ENDCH)
578
{
579
/* eliminate \ */
580
if(c)
581
sfwrite(stkp,first,c);
582
/* check new-line joining */
583
first = fcseek(c+1);
584
}
585
cp += (n!=S_EOF);
586
break;
587
case S_GRAVE: case S_DOL:
588
if(mp->lit)
589
break;
590
if(c)
591
{
592
if(mp->split && !mp->quote && endch)
593
mac_copy(mp,first,c);
594
else
595
sfwrite(stkp,first,c);
596
}
597
first = fcseek(c+1);
598
c = mp->pattern;
599
if(n==S_GRAVE)
600
comsubst(mp,(Shnode_t*)0,0);
601
else if((n= *cp) == '"' && !mp->quote)
602
{
603
int off = stktell(stkp);
604
char *dp;
605
cp = first = fcseek(1);
606
mp->quote = 1;
607
if(!ERROR_translating())
608
break;
609
while(n=c, c= *++cp)
610
{
611
if(c=='\\' && n==c)
612
c = 0;
613
else if(c=='"' && n!='\\')
614
break;
615
}
616
n = cp-first;
617
sfwrite(stkp,first,n);
618
sfputc(stkp,0);
619
cp = stkptr(stkp,off);
620
dp = (char*)sh_translate(cp);
621
stkseek(stkp,off);
622
if(dp==cp)
623
{
624
cp = first;
625
break;
626
}
627
resume = fcseek(n);
628
fcclose();
629
fcsopen(dp);
630
cp = first = fcseek(0);
631
break;
632
}
633
else if(n==0 || !varsub(mp))
634
{
635
if(n=='\'' && !mp->quote)
636
ansi_c = 1;
637
else if(mp->quote || n!='"')
638
sfputc(stkp,'$');
639
}
640
cp = first = fcseek(0);
641
if(mp->quote && cp)
642
mp->pattern = c;
643
break;
644
case S_ENDCH:
645
if((mp->lit || cp[-1]!=endch || mp->quote!=newquote))
646
goto pattern;
647
if(endch==RBRACE && mp->pattern && brace)
648
{
649
brace--;
650
if(*cp==LPAREN && mp->pattern!=2)
651
goto pattern;
652
continue;
653
}
654
case S_EOF:
655
if(c)
656
{
657
if(mp->split && !mp->quote && !mp->lit && endch)
658
mac_copy(mp,first,c);
659
else
660
sfwrite(stkp,first,c);
661
}
662
if(n==S_EOF && resume)
663
{
664
fcclose();
665
fcsopen(resume);
666
resume = 0;
667
cp = first = fcseek(0);
668
continue;
669
}
670
c += (n!=S_EOF);
671
first = fcseek(c);
672
if(tilde>=0)
673
tilde_expand2(mp->shp,tilde);
674
goto done;
675
case S_QUOTE:
676
if(mp->lit || mp->arith)
677
break;
678
case S_LIT:
679
if(mp->arith)
680
{
681
if((*cp=='`' || *cp=='[') && cp[1]=='\'')
682
cp +=2;
683
break;
684
}
685
if(n==S_LIT && mp->quote)
686
break;
687
if(c)
688
{
689
if(mp->split && endch && !mp->quote && !mp->lit)
690
mac_copy(mp,first,c);
691
else
692
sfwrite(stkp,first,c);
693
}
694
first = fcseek(c+1);
695
if(n==S_LIT)
696
{
697
if(mp->quote)
698
continue;
699
if(mp->lit)
700
mp->lit = ansi_c = 0;
701
else
702
mp->lit = 1;
703
}
704
else
705
mp->quote = !mp->quote;
706
mp->quoted++;
707
break;
708
case S_BRACT:
709
if(mp->arith || (((mp->assign&1) || endch==RBRACT) &&
710
!(mp->quote || mp->lit)))
711
{
712
int offset=0,oldpat = mp->pattern;
713
int oldarith = mp->arith, oldsub=mp->subcopy;
714
sfwrite(stkp,first,++c);
715
if(mp->assign&1)
716
{
717
if(first[c-2]=='.')
718
offset = stktell(stkp);
719
if(isastchar(*cp) && cp[1]==']')
720
errormsg(SH_DICT,ERROR_exit(1),
721
e_badsubscript,*cp);
722
}
723
first = fcseek(c);
724
mp->pattern = 4;
725
mp->arith = 0;
726
mp->subcopy = 0;
727
copyto(mp,RBRACT,0);
728
mp->subcopy = oldsub;
729
mp->arith = oldarith;
730
mp->pattern = oldpat;
731
sfputc(stkp,RBRACT);
732
if(offset)
733
{
734
cp = stkptr(stkp,stktell(stkp));
735
if(sh_checkid(stkptr(stkp,offset),cp)!=cp)
736
stkseek(stkp,stktell(stkp)-2);
737
}
738
cp = first = fcseek(0);
739
break;
740
}
741
case S_PAT:
742
if(mp->pattern && !(mp->quote || mp->lit))
743
{
744
mp->patfound = mp->pattern;
745
if((n=cp[-1])==LPAREN)
746
{
747
paren++;
748
if((cp-first)>1 && cp[-2]=='~')
749
{
750
char *p = cp;
751
while((c=mbchar(p)) && c!=RPAREN)
752
if(c=='A'||c=='E'||c=='K'||c=='P'||c=='X')
753
{
754
ere = 1;
755
break;
756
}
757
}
758
}
759
else if(n==RPAREN)
760
--paren;
761
}
762
goto pattern;
763
case S_COM:
764
if(mp->pattern==4 && (mp->quote || mp->lit))
765
{
766
if(c)
767
{
768
sfwrite(stkp,first,c);
769
first = fcseek(c);
770
}
771
sfputc(stkp,ESCAPE);
772
}
773
break;
774
case S_BRACE:
775
if(!(mp->quote || mp->lit))
776
{
777
mp->patfound = mp->split && sh_isoption(SH_BRACEEXPAND);
778
brace++;
779
}
780
pattern:
781
if(!mp->pattern || !(mp->quote || mp->lit))
782
{
783
/* mark beginning of {a,b} */
784
if(n==S_BRACE && endch==0 && mp->pattern)
785
mp->pattern=4;
786
if(n==S_SLASH && mp->pattern==2)
787
mp->pattern=3;
788
break;
789
}
790
if(mp->pattern==3)
791
break;
792
if(c)
793
sfwrite(stkp,first,c);
794
first = fcseek(c);
795
sfputc(stkp,ESCAPE);
796
break;
797
case S_EQ:
798
if(mp->assign==1)
799
{
800
if(*cp=='~' && !endch && !mp->quote && !mp->lit)
801
tilde = stktell(stkp)+(c+1);
802
mp->assign = 2;
803
}
804
break;
805
case S_SLASH:
806
case S_COLON:
807
if(tilde >=0)
808
{
809
if(c)
810
sfwrite(stkp,first,c);
811
first = fcseek(c);
812
tilde_expand2(mp->shp,tilde);
813
#if _WINIX
814
if(Skip)
815
{
816
first = cp = fcseek(Skip);
817
Skip = 0;
818
}
819
#endif /*_WINIX */
820
tilde = -1;
821
c=0;
822
}
823
if(n==S_COLON && mp->assign==2 && *cp=='~' && endch==0 && !mp->quote &&!mp->lit)
824
tilde = stktell(stkp)+(c+1);
825
else if(n==S_SLASH && mp->pattern==2)
826
#if 0
827
goto pattern;
828
#else
829
{
830
if(mp->quote || mp->lit)
831
goto pattern;
832
sfwrite(stkp,first,c+1);
833
first = fcseek(c+1);
834
c = stktell(stkp);
835
sh_lexskip(lp,RBRACE,0,ST_NESTED);
836
stkseek(stkp,c);
837
cp = fcseek(-1);
838
sfwrite(stkp,first,cp-first);
839
first=cp;
840
}
841
#endif
842
break;
843
case S_DOT:
844
if(*cp=='.' && mp->subcopy==1)
845
{
846
sfwrite(stkp,first,c);
847
sfputc(stkp,0);
848
mp->dotdot = stktell(stkp);
849
cp = first = fcseek(c+2);
850
}
851
break;
852
}
853
}
854
done:
855
mp->sp = sp;
856
mp->quote = oldquote;
857
}
858
859
/*
860
* copy <str> to stack performing sub-expression substitutions
861
*/
862
static void mac_substitute(Mac_t *mp, register char *cp,char *str,register int subexp[],int subsize)
863
{
864
register int c,n;
865
register char *first=cp;
866
while(1)
867
{
868
while((c= *cp++) && c!=ESCAPE);
869
if(c==0)
870
break;
871
if((n= *cp++)=='\\' || n==RBRACE || (n>='0' && n<='9' && (n-='0')<subsize))
872
{
873
c = cp-first-2;
874
if(c)
875
mac_copy(mp,first,c);
876
first=cp;
877
if(n=='\\' || n==RBRACE)
878
{
879
first--;
880
continue;
881
}
882
if((c=subexp[2*n])>=0)
883
{
884
if((n=subexp[2*n+1]-c)>0)
885
mac_copy(mp,str+c,n);
886
}
887
}
888
else if(n==0)
889
break;
890
}
891
if(n=cp-first-1)
892
mac_copy(mp,first,n);
893
}
894
895
#if SHOPT_FILESCAN
896
#define MAX_OFFSETS (sizeof(shp->offsets)/sizeof(shp->offsets[0]))
897
#define MAX_ARGN (32*1024)
898
899
/*
900
* compute the arguments $1 ... $n and $# from the current line as needed
901
* save line offsets in the offsets array.
902
*/
903
static char *getdolarg(Shell_t *shp, int n, int *size)
904
{
905
register int c=S_DELIM, d=shp->ifstable['\\'];
906
register unsigned char *first,*last,*cp = (unsigned char*)shp->cur_line;
907
register int m=shp->offsets[0],delim=0;
908
if(m==0)
909
return(0);
910
if(m<0)
911
m = 0;
912
else if(n<=m)
913
m = n-1;
914
else
915
m--;
916
if(m >= MAX_OFFSETS-1)
917
m = MAX_OFFSETS-2;
918
cp += shp->offsets[m+1];
919
n -= m;
920
shp->ifstable['\\'] = 0;
921
shp->ifstable[0] = S_EOF;
922
while(1)
923
{
924
if(c==S_DELIM)
925
while(shp->ifstable[*cp++]==S_SPACE);
926
first = --cp;
927
if(++m < MAX_OFFSETS)
928
shp->offsets[m] = (first-(unsigned char*)shp->cur_line);
929
while((c=shp->ifstable[*cp++])==0);
930
last = cp-1;
931
if(c==S_SPACE)
932
while((c=shp->ifstable[*cp++])==S_SPACE);
933
if(--n==0 || c==S_EOF)
934
{
935
if(last==first && c==S_EOF && (!delim || (m>1)))
936
{
937
n++;
938
m--;
939
}
940
break;
941
}
942
delim = (c==S_DELIM);
943
}
944
shp->ifstable['\\'] = d;
945
if(m > shp->offsets[0])
946
shp->offsets[0] = m;
947
if(n)
948
first = last = 0;
949
if(size)
950
*size = last-first;
951
return((char*)first);
952
}
953
#endif /* SHOPT_FILESCAN */
954
955
/*
956
* get the prefix after name reference resolution
957
*/
958
static char *prefix(Shell_t *shp, char *id)
959
{
960
Namval_t *np;
961
register char *sub=0, *cp = strchr(id,'.');
962
if(cp)
963
{
964
*cp = 0;
965
np = nv_search(id, shp->var_tree,0);
966
*cp = '.';
967
if(isastchar(cp[1]))
968
cp[1] = 0;
969
if(np && nv_isref(np))
970
{
971
int n;
972
char *sp;
973
shp->argaddr = 0;
974
while(nv_isref(np) && np->nvalue.cp)
975
{
976
sub = nv_refsub(np);
977
np = nv_refnode(np);
978
if(sub)
979
nv_putsub(np,sub,0L);
980
}
981
id = (char*)malloc(strlen(cp)+1+(n=strlen(sp=nv_name(np)))+ (sub?strlen(sub)+3:1));
982
memcpy(id,sp,n);
983
if(sub)
984
{
985
id[n++] = '[';
986
strcpy(&id[n],sub);
987
n+= strlen(sub)+1;
988
id[n-1] = ']';
989
}
990
strcpy(&id[n],cp);
991
return(id);
992
}
993
}
994
return(strdup(id));
995
}
996
997
/*
998
* copy to ']' onto the stack and return offset to it
999
*/
1000
static int subcopy(Mac_t *mp, int flag)
1001
{
1002
int split = mp->split;
1003
int xpattern = mp->pattern;
1004
int loc = stktell(mp->shp->stk);
1005
int xarith = mp->arith;
1006
int arrayok = mp->arrayok;
1007
mp->split = 0;
1008
mp->arith = 0;
1009
mp->pattern = flag?4:0;
1010
mp->arrayok=1;
1011
mp->subcopy++;
1012
mp->dotdot = 0;
1013
copyto(mp,RBRACT,0);
1014
mp->subcopy = 0;
1015
mp->pattern = xpattern;
1016
mp->split = split;
1017
mp->arith = xarith;
1018
mp->arrayok = arrayok;
1019
return(loc);
1020
}
1021
1022
/*
1023
* if name is a discipline function, run the function and put the results
1024
* on the stack so that ${x.foo} behaves like ${ x.foo;}
1025
*/
1026
int sh_macfun(Shell_t *shp, const char *name, int offset)
1027
{
1028
Namval_t *np, *nq;
1029
np = nv_bfsearch(name,shp->fun_tree,&nq,(char**)0);
1030
if(np)
1031
{
1032
/* treat ${x.foo} as ${x.foo;} */
1033
union
1034
{
1035
struct comnod com;
1036
Shnode_t node;
1037
} t;
1038
union
1039
{
1040
struct argnod arg;
1041
struct dolnod dol;
1042
char buff[sizeof(struct dolnod)+sizeof(char*)];
1043
} d;
1044
memset(&t,0,sizeof(t));
1045
memset(&d,0,sizeof(d));
1046
t.node.com.comarg = &d.arg;
1047
t.node.com.comline = shp->inlineno;
1048
d.dol.dolnum = 1;
1049
d.dol.dolval[0] = strdup(name);
1050
stkseek(shp->stk,offset);
1051
comsubst((Mac_t*)shp->mac_context,&t.node,2);
1052
free(d.dol.dolval[0]);
1053
return(1);
1054
}
1055
return(0);
1056
}
1057
1058
static int namecount(Mac_t *mp,const char *prefix)
1059
{
1060
int count = 0;
1061
mp->nvwalk = nv_diropen((Namval_t*)0,prefix);
1062
while(nv_dirnext(mp->nvwalk))
1063
count++;
1064
nv_dirclose(mp->nvwalk);
1065
return(count);
1066
}
1067
1068
static char *nextname(Mac_t *mp,const char *prefix, int len)
1069
{
1070
char *cp;
1071
if(len==0)
1072
{
1073
mp->nvwalk = nv_diropen((Namval_t*)0,prefix);
1074
return((char*)mp->nvwalk);
1075
}
1076
if(!(cp=nv_dirnext(mp->nvwalk)))
1077
nv_dirclose(mp->nvwalk);
1078
return(cp);
1079
}
1080
1081
/*
1082
* This routine handles $param, ${parm}, and ${param op word}
1083
* The input stream is assumed to be a string
1084
*/
1085
static int varsub(Mac_t *mp)
1086
{
1087
register int c;
1088
register int type=0; /* M_xxx */
1089
register char *v,*argp=0;
1090
register Namval_t *np = NIL(Namval_t*);
1091
register int dolg=0, mode=0;
1092
Lex_t *lp = (Lex_t*)mp->shp->lex_context;
1093
Namarr_t *ap=0;
1094
int dolmax=0, vsize= -1, offset= -1, nulflg, replen=0, bysub=0;
1095
char idbuff[3], *id = idbuff, *pattern=0, *repstr=0, *arrmax=0;
1096
char *idx = 0;
1097
int var=1,addsub=0,oldpat=mp->pattern,idnum=0,flag=0,d;
1098
Stk_t *stkp = mp->shp->stk;
1099
retry1:
1100
mp->zeros = 0;
1101
idbuff[0] = 0;
1102
idbuff[1] = 0;
1103
c = fcmbget(&LEN);
1104
switch(isascii(c)?sh_lexstates[ST_DOL][c]:S_ALP)
1105
{
1106
case S_RBRA:
1107
if(type<M_SIZE)
1108
goto nosub;
1109
/* This code handles ${#} */
1110
c = mode;
1111
mode = type = 0;
1112
/* FALL THRU */
1113
case S_SPC1:
1114
if(type==M_BRACE)
1115
{
1116
if(isaletter(mode=fcpeek(0)) || mode=='.')
1117
{
1118
if(c=='#')
1119
type = M_SIZE;
1120
#ifdef SHOPT_TYPEDEF
1121
else if(c=='@')
1122
{
1123
type = M_TYPE;
1124
goto retry1;
1125
}
1126
#endif /* SHOPT_TYPEDEF */
1127
else
1128
type = M_VNAME;
1129
mode = c;
1130
goto retry1;
1131
}
1132
else if(c=='#' && (isadigit(mode)||fcpeek(1)==RBRACE))
1133
{
1134
type = M_SIZE;
1135
mode = c;
1136
goto retry1;
1137
}
1138
}
1139
/* FALL THRU */
1140
case S_SPC2:
1141
var = 0;
1142
*id = c;
1143
v = special(mp->shp,c);
1144
if(isastchar(c))
1145
{
1146
mode = c;
1147
#if SHOPT_FILESCAN
1148
if(mp->shp->cur_line)
1149
{
1150
v = getdolarg(mp->shp,1,(int*)0);
1151
dolmax = MAX_ARGN;
1152
}
1153
else
1154
#endif /* SHOPT_FILESCAN */
1155
dolmax = mp->shp->st.dolc+1;
1156
mp->atmode = (v && mp->quoted && c=='@');
1157
dolg = (v!=0);
1158
}
1159
break;
1160
case S_LBRA:
1161
if(type)
1162
goto nosub;
1163
type = M_BRACE;
1164
goto retry1;
1165
case S_PAR:
1166
if(type)
1167
goto nosub;
1168
comsubst(mp,(Shnode_t*)0,1);
1169
return(1);
1170
case S_DIG:
1171
var = 0;
1172
c -= '0';
1173
mp->shp->argaddr = 0;
1174
if(type)
1175
{
1176
register int d;
1177
while((d=fcget()),isadigit(d))
1178
c = 10*c + (d-'0');
1179
fcseek(-1);
1180
}
1181
idnum = c;
1182
if(c==0)
1183
v = special(mp->shp,c);
1184
#if SHOPT_FILESCAN
1185
else if(mp->shp->cur_line)
1186
{
1187
mp->shp->used_pos = 1;
1188
v = getdolarg(mp->shp,c,&vsize);
1189
}
1190
#endif /* SHOPT_FILESCAN */
1191
else if(c <= mp->shp->st.dolc)
1192
{
1193
mp->shp->used_pos = 1;
1194
v = mp->shp->st.dolv[c];
1195
}
1196
else
1197
v = 0;
1198
break;
1199
case S_ALP:
1200
if(c=='.' && type==0)
1201
goto nosub;
1202
offset = stktell(stkp);
1203
do
1204
{
1205
register int d;
1206
np = 0;
1207
do
1208
{
1209
if(LEN==1)
1210
sfputc(stkp,c);
1211
else
1212
sfwrite(stkp,fcseek(0)-LEN,LEN);
1213
}
1214
while((d=c,(c=fcmbget(&LEN)),isaname(c))||type && c=='.');
1215
while(c==LBRACT && (type||mp->arrayok))
1216
{
1217
mp->shp->argaddr=0;
1218
if((c=fcmbget(&LEN),isastchar(c)) && fcpeek(0)==RBRACT && d!='.')
1219
{
1220
if(type==M_VNAME)
1221
type = M_SUBNAME;
1222
idbuff[0] = mode = c;
1223
fcget();
1224
c = fcmbget(&LEN);
1225
if(c=='.' || c==LBRACT)
1226
{
1227
sfputc(stkp,LBRACT);
1228
sfputc(stkp,mode);
1229
sfputc(stkp,RBRACT);
1230
}
1231
else
1232
flag = NV_ARRAY;
1233
break;
1234
}
1235
else
1236
{
1237
fcseek(-LEN);
1238
c = stktell(stkp);
1239
if(d!='.')
1240
sfputc(stkp,LBRACT);
1241
v = stkptr(stkp,subcopy(mp,1));
1242
if(type && mp->dotdot)
1243
{
1244
mode = '@';
1245
v[-1] = 0;
1246
if(type==M_VNAME)
1247
type = M_SUBNAME;
1248
else if(type==M_SIZE)
1249
goto nosub;
1250
}
1251
else if(d!='.')
1252
sfputc(stkp,RBRACT);
1253
c = fcmbget(&LEN);
1254
if(c==0 && type==M_VNAME)
1255
type = M_SUBNAME;
1256
}
1257
}
1258
}
1259
while(type && c=='.');
1260
if(type!=M_VNAME && c==RBRACE && type && fcpeek(-2)=='.')
1261
{
1262
/* ${x.} or ${x..} */
1263
if(fcpeek(-3) == '.')
1264
{
1265
stkseek(stkp,stktell(stkp)-2);
1266
nv_local = 1;
1267
}
1268
else
1269
{
1270
stkseek(stkp,stktell(stkp)-1);
1271
type = M_TREE;
1272
}
1273
}
1274
sfputc(stkp,0);
1275
id=stkptr(stkp,offset);
1276
if(isastchar(c) && type)
1277
{
1278
if(type==M_VNAME || type==M_SIZE)
1279
{
1280
idbuff[0] = mode = c;
1281
if((d=fcpeek(0))==c)
1282
idbuff[1] = fcget();
1283
if(type==M_VNAME)
1284
type = M_NAMESCAN;
1285
else
1286
type = M_NAMECOUNT;
1287
break;
1288
}
1289
goto nosub;
1290
}
1291
flag |= NV_NOASSIGN|NV_VARNAME|NV_NOADD;
1292
if(c=='=' || c=='?' || (c==':' && ((d=fcpeek(0))=='=' || d=='?')))
1293
{
1294
if(c=='=' || (c==':' && d=='='))
1295
flag |= NV_ASSIGN;
1296
flag &= ~NV_NOADD;
1297
}
1298
#if SHOPT_FILESCAN
1299
if(mp->shp->cur_line && *id=='R' && strcmp(id,"REPLY")==0)
1300
{
1301
mp->shp->argaddr=0;
1302
np = REPLYNOD;
1303
}
1304
else
1305
#endif /* SHOPT_FILESCAN */
1306
{
1307
if(mp->shp->argaddr)
1308
flag &= ~NV_NOADD;
1309
np = nv_open(id,mp->shp->var_tree,flag|NV_NOFAIL);
1310
if(!np)
1311
{
1312
sfprintf(mp->shp->strbuf,"%s%c",id,0);
1313
id = sfstruse(mp->shp->strbuf);
1314
}
1315
}
1316
if(isastchar(mode))
1317
var = 0;
1318
if((!np || nv_isnull(np)) && type==M_BRACE && c==RBRACE && !(flag&NV_ARRAY) && strchr(id,'.'))
1319
{
1320
if(sh_macfun(mp->shp,id,offset))
1321
{
1322
fcmbget(&LEN);
1323
return(1);
1324
}
1325
}
1326
if(np && (flag&NV_NOADD) && nv_isnull(np))
1327
{
1328
if(nv_isattr(np,NV_NOFREE))
1329
nv_offattr(np,NV_NOFREE);
1330
#if SHOPT_FILESCAN
1331
else if(np!=REPLYNOD || !mp->shp->cur_line)
1332
#else
1333
else
1334
#endif /* SHOPT_FILESCAN */
1335
np = 0;
1336
}
1337
ap = np?nv_arrayptr(np):0;
1338
if(type)
1339
{
1340
if(mp->dotdot)
1341
{
1342
Namval_t *nq;
1343
#if SHOPT_FIXEDARRAY
1344
if(ap && !ap->fixed && (nq=nv_opensub(np)))
1345
#else
1346
if(ap && (nq=nv_opensub(np)))
1347
#endif /* SHOPT_FIXEDARRAY */
1348
ap = nv_arrayptr(np=nq);
1349
if(ap)
1350
{
1351
nv_putsub(np,v,ARRAY_SCAN);
1352
v = stkptr(stkp,mp->dotdot);
1353
dolmax =1;
1354
if(array_assoc(ap))
1355
arrmax = strdup(v);
1356
else if((dolmax = (int)sh_arith(mp->shp,v))<0)
1357
dolmax += array_maxindex(np);
1358
if(type==M_SUBNAME)
1359
bysub = 1;
1360
}
1361
else
1362
{
1363
if((int)sh_arith(mp->shp,v))
1364
np = 0;
1365
}
1366
}
1367
else if(ap && (isastchar(mode)||type==M_TREE) && !(ap->nelem&ARRAY_SCAN) && type!=M_SIZE)
1368
nv_putsub(np,NIL(char*),ARRAY_SCAN);
1369
if(!isbracechar(c))
1370
goto nosub;
1371
else
1372
fcseek(-LEN);
1373
}
1374
else
1375
fcseek(-1);
1376
if(type<=1 && np && nv_isvtree(np) && mp->pattern==1 && !mp->split)
1377
{
1378
int cc=fcmbget(&LEN),peek=LEN;
1379
if(type && cc=='}')
1380
{
1381
cc = fcmbget(&LEN);
1382
peek++;
1383
}
1384
if(mp->quote && cc=='"')
1385
{
1386
cc = fcmbget(&LEN);
1387
peek++;
1388
}
1389
fcseek(-peek);
1390
if(cc==0)
1391
mp->assign = 1;
1392
}
1393
if((type==M_VNAME||type==M_SUBNAME) && mp->shp->argaddr && strcmp(nv_name(np),id))
1394
mp->shp->argaddr = 0;
1395
c = (type>M_BRACE && isastchar(mode));
1396
if(np && (type==M_TREE || !c || !ap))
1397
{
1398
char *savptr;
1399
c = *((unsigned char*)stkptr(stkp,offset-1));
1400
savptr = stkfreeze(stkp,0);
1401
if(type==M_VNAME || (type==M_SUBNAME && ap))
1402
{
1403
type = M_BRACE;
1404
v = nv_name(np);
1405
if(ap && !mp->dotdot && !(ap->nelem&ARRAY_UNDEF))
1406
addsub = 1;
1407
}
1408
#ifdef SHOPT_TYPEDEF
1409
else if(type==M_TYPE)
1410
{
1411
Namval_t *nq = nv_type(np);
1412
type = M_BRACE;
1413
if(nq)
1414
nv_typename(nq,mp->shp->strbuf);
1415
else
1416
nv_attribute(np,mp->shp->strbuf,"typeset",1);
1417
v = sfstruse(mp->shp->strbuf);
1418
}
1419
#endif /* SHOPT_TYPEDEF */
1420
#if SHOPT_FILESCAN
1421
else if(mp->shp->cur_line && np==REPLYNOD)
1422
v = mp->shp->cur_line;
1423
#endif /* SHOPT_FILESCAN */
1424
else if(type==M_TREE)
1425
v = nv_getvtree(np,(Namfun_t*)0);
1426
else
1427
{
1428
if(type && fcpeek(0)=='+')
1429
{
1430
if(ap)
1431
v = nv_arrayisset(np,ap)?(char*)"x":0;
1432
else
1433
v = nv_isnull(np)?0:(char*)"x";
1434
}
1435
else
1436
v = nv_getval(np);
1437
mp->atmode = (v && mp->quoted && mode=='@');
1438
/* special case --- ignore leading zeros */
1439
if((mp->let || (mp->arith&&nv_isattr(np,(NV_LJUST|NV_RJUST|NV_ZFILL)))) && !nv_isattr(np,NV_INTEGER) && (offset==0 || isspace(c) || strchr(",.+-*/=%&|^?!<>",c)))
1440
mp->zeros = 1;
1441
}
1442
if(savptr==stakptr(0))
1443
stkseek(stkp,offset);
1444
else
1445
stkset(stkp,savptr,offset);
1446
}
1447
else
1448
{
1449
if(sh_isoption(SH_NOUNSET) && !isastchar(mode) && (type==M_VNAME || type==M_SIZE))
1450
errormsg(SH_DICT,ERROR_exit(1),e_notset,id);
1451
v = 0;
1452
if(type==M_VNAME)
1453
{
1454
v = id;
1455
type = M_BRACE;
1456
}
1457
else if(type==M_TYPE)
1458
type = M_BRACE;
1459
}
1460
stkseek(stkp,offset);
1461
if(ap)
1462
{
1463
#if SHOPT_OPTIMIZE
1464
if(mp->shp->argaddr)
1465
nv_optimize(np);
1466
#endif
1467
if(isastchar(mode) && array_elem(ap)> !c)
1468
dolg = -1;
1469
else
1470
{
1471
ap->nelem &= ~ARRAY_SCAN;
1472
dolg = 0;
1473
1474
}
1475
}
1476
break;
1477
case S_EOF:
1478
fcseek(-1);
1479
default:
1480
goto nosub;
1481
}
1482
c = fcmbget(&LEN);
1483
if(type>M_TREE)
1484
{
1485
if(c!=RBRACE)
1486
mac_error(np);
1487
if(type==M_NAMESCAN || type==M_NAMECOUNT)
1488
{
1489
mp->shp->last_root = mp->shp->var_tree;
1490
id = idx = prefix(mp->shp,id);
1491
stkseek(stkp,offset);
1492
if(type==M_NAMECOUNT)
1493
{
1494
c = namecount(mp,id);
1495
v = ltos(c);
1496
}
1497
else
1498
{
1499
dolmax = strlen(id);
1500
dolg = -1;
1501
nextname(mp,id,0);
1502
v = nextname(mp,id,dolmax);
1503
}
1504
}
1505
else if(type==M_SUBNAME)
1506
{
1507
if(dolg<0)
1508
{
1509
v = nv_getsub(np);
1510
bysub=1;
1511
}
1512
else if(v)
1513
{
1514
if(!ap || isastchar(mode))
1515
v = "0";
1516
else
1517
v = nv_getsub(np);
1518
}
1519
}
1520
else
1521
{
1522
if(!isastchar(mode))
1523
c = charlen(v,vsize);
1524
else if(dolg>0)
1525
{
1526
#if SHOPT_FILESCAN
1527
if(mp->shp->cur_line)
1528
{
1529
getdolarg(mp->shp,MAX_ARGN,(int*)0);
1530
c = mp->shp->offsets[0];
1531
}
1532
else
1533
#endif /* SHOPT_FILESCAN */
1534
c = mp->shp->st.dolc;
1535
}
1536
else if(dolg<0)
1537
c = array_elem(ap);
1538
else
1539
c = (v!=0);
1540
dolg = dolmax = 0;
1541
v = ltos(c);
1542
}
1543
c = RBRACE;
1544
}
1545
nulflg = 0;
1546
if(type && c==':')
1547
{
1548
c = fcmbget(&LEN);
1549
if(isascii(c) &&sh_lexstates[ST_BRACE][c]==S_MOD1 && c!='*' && c!= ':')
1550
nulflg=1;
1551
else if(c!='%' && c!='#')
1552
{
1553
fcseek(-LEN);
1554
c = ':';
1555
}
1556
}
1557
if(type)
1558
{
1559
if(!isbracechar(c))
1560
{
1561
if(!nulflg)
1562
mac_error(np);
1563
fcseek(-LEN);
1564
c = ':';
1565
}
1566
if(c!=RBRACE)
1567
{
1568
int newops = (c=='#' || c == '%' || c=='/');
1569
offset = stktell(stkp);
1570
if(newops && sh_isoption(SH_NOUNSET) && *id && id!=idbuff && (!np || nv_isnull(np)))
1571
errormsg(SH_DICT,ERROR_exit(1),e_notset,id);
1572
if(c=='/' ||c==':' || ((!v || (nulflg && *v==0)) ^ (c=='+'||c=='#'||c=='%')))
1573
{
1574
int newquote = mp->quote;
1575
int split = mp->split;
1576
int quoted = mp->quoted;
1577
int arith = mp->arith;
1578
int zeros = mp->zeros;
1579
int assign = mp->assign;
1580
if(newops)
1581
{
1582
type = fcget();
1583
if(type=='%' || type=='#')
1584
{
1585
int d = fcmbget(&LEN);
1586
fcseek(-LEN);
1587
if(d=='(')
1588
type = 0;
1589
}
1590
fcseek(-1);
1591
mp->pattern = 1+(c=='/');
1592
mp->split = 0;
1593
mp->quoted = 0;
1594
mp->assign &= ~1;
1595
mp->arith = mp->zeros = 0;
1596
newquote = 0;
1597
}
1598
else if(c=='?' || c=='=')
1599
mp->split = mp->pattern = 0;
1600
copyto(mp,RBRACE,newquote);
1601
if(!oldpat)
1602
mp->patfound = 0;
1603
mp->pattern = oldpat;
1604
mp->split = split;
1605
mp->quoted = quoted;
1606
mp->arith = arith;
1607
mp->zeros = zeros;
1608
mp->assign = assign;
1609
/* add null byte */
1610
sfputc(stkp,0);
1611
if(c!='=')
1612
stkseek(stkp,stktell(stkp)-1);
1613
}
1614
else
1615
{
1616
sh_lexskip(lp,RBRACE,0,(!newops&&mp->quote)?ST_QUOTE:ST_NESTED);
1617
stkseek(stkp,offset);
1618
}
1619
argp=stkptr(stkp,offset);
1620
}
1621
}
1622
else
1623
{
1624
fcseek(-1);
1625
c=0;
1626
}
1627
if(c==':') /* ${name:expr1[:expr2]} */
1628
{
1629
char *ptr;
1630
type = (int)sh_strnum(argp,&ptr,1);
1631
if(isastchar(mode))
1632
{
1633
if(id==idbuff) /* ${@} or ${*} */
1634
{
1635
if(type<0 && (type+= dolmax)<0)
1636
type = 0;
1637
if(type==0)
1638
v = special(mp->shp,dolg=0);
1639
#if SHOPT_FILESCAN
1640
else if(mp->shp->cur_line)
1641
{
1642
v = getdolarg(mp->shp,dolg=type,&vsize);
1643
if(!v)
1644
dolmax = type;
1645
}
1646
#endif /* SHOPT_FILESCAN */
1647
else if(type < dolmax)
1648
v = mp->shp->st.dolv[dolg=type];
1649
else
1650
v = 0;
1651
}
1652
else if(ap)
1653
{
1654
if(type<0)
1655
{
1656
if(array_assoc(ap))
1657
type = -type;
1658
else
1659
type += array_maxindex(np);
1660
}
1661
if(array_assoc(ap))
1662
{
1663
while(type-- >0 && (v=0,nv_nextsub(np)))
1664
v = nv_getval(np);
1665
}
1666
else if(type > 0)
1667
{
1668
if(nv_putsub(np,NIL(char*),type|ARRAY_SCAN))
1669
v = nv_getval(np);
1670
else
1671
v = 0;
1672
}
1673
}
1674
else if(type>0)
1675
v = 0;
1676
if(!v)
1677
mp->atmode = 0;
1678
}
1679
else if(v)
1680
{
1681
vsize = charlen(v,vsize);
1682
if(type<0 && (type += vsize)<0)
1683
type = 0;
1684
if(vsize < type)
1685
v = 0;
1686
#if SHOPT_MULTIBYTE
1687
else if(mbwide())
1688
{
1689
mbinit();
1690
for(c=type;c;c--)
1691
mbchar(v);
1692
c = ':';
1693
}
1694
#endif /* SHOPT_MULTIBYTE */
1695
else
1696
v += type;
1697
vsize = v?strlen(v):0;
1698
}
1699
if(*ptr==':')
1700
{
1701
if((type = (int)sh_strnum(ptr+1,&ptr,1)) <=0)
1702
{
1703
v = 0;
1704
mp->atmode = 0;
1705
}
1706
else if(isastchar(mode))
1707
{
1708
if(dolg>=0)
1709
{
1710
if(dolg+type < dolmax)
1711
dolmax = dolg+type;
1712
}
1713
else
1714
dolmax = type;
1715
}
1716
else if(type < vsize)
1717
{
1718
#if SHOPT_MULTIBYTE
1719
if(mbwide())
1720
{
1721
char *vp = v;
1722
mbinit();
1723
while(type-->0)
1724
{
1725
if((c=mbsize(vp))<1)
1726
c = 1;
1727
vp += c;
1728
}
1729
type = vp-v;
1730
c = ':';
1731
}
1732
#endif /* SHOPT_MULTIBYTE */
1733
vsize = type;
1734
}
1735
else
1736
vsize = v?strlen(v):0;
1737
}
1738
if(*ptr)
1739
mac_error(np);
1740
stkseek(stkp,offset);
1741
argp = 0;
1742
}
1743
/* check for substring operations */
1744
else if(c == '#' || c == '%' || c=='/')
1745
{
1746
if(c=='/')
1747
{
1748
if(type=='/' || type=='#' || type=='%')
1749
{
1750
c = type;
1751
type = '/';
1752
argp++;
1753
}
1754
else
1755
type = 0;
1756
}
1757
else
1758
{
1759
if(type==c) /* ## or %% */
1760
argp++;
1761
else
1762
type = 0;
1763
}
1764
pattern = strdup(argp);
1765
if((type=='/' || c=='/') && (repstr = mac_getstring(pattern)))
1766
{
1767
Mac_t savemac;
1768
char *first = fcseek(0);
1769
int n = stktell(stkp);
1770
savemac = *mp;
1771
fcsopen(repstr);
1772
mp->pattern = 3;
1773
mp->split = 0;
1774
copyto(mp,0,0);
1775
sfputc(stkp,0);
1776
repstr = strdup(stkptr(stkp,n));
1777
replen = strlen(repstr);
1778
stkseek(stkp,n);
1779
*mp = savemac;
1780
fcsopen(first);
1781
}
1782
if(v || c=='/' && offset>=0)
1783
stkseek(stkp,offset);
1784
}
1785
/* check for quoted @ */
1786
if(mode=='@' && mp->quote && !v && c!='-')
1787
mp->quoted-=2;
1788
retry2:
1789
if(v && (!nulflg || *v ) && c!='+')
1790
{
1791
register int d = (mode=='@'?' ':mp->ifs);
1792
regoff_t match[2*(MATCH_MAX+1)];
1793
int nmatch, nmatch_prev, vsize_last;
1794
char *vlast;
1795
while(1)
1796
{
1797
if(!v)
1798
v= "";
1799
if(c=='/' || c=='#' || c== '%')
1800
{
1801
int index = 0;
1802
flag = (type || c=='/')?(STR_GROUP|STR_MAXIMAL):STR_GROUP;
1803
if(c!='/')
1804
flag |= STR_LEFT;
1805
nmatch = 0;
1806
while(1)
1807
{
1808
vsize = strlen(v);
1809
nmatch_prev = nmatch;
1810
if(c=='%')
1811
nmatch=substring(v,pattern,match,flag&STR_MAXIMAL);
1812
else
1813
nmatch=strgrpmatch(v,pattern,match,elementsof(match)/2,flag);
1814
if(nmatch && replen>0)
1815
sh_setmatch(mp->shp,v,vsize,nmatch,match,index++);
1816
if(nmatch)
1817
{
1818
vlast = v;
1819
vsize_last = vsize;
1820
vsize = match[0];
1821
}
1822
else if(c=='#')
1823
vsize = 0;
1824
if(vsize)
1825
mac_copy(mp,v,vsize);
1826
if(nmatch && replen>0 && (match[1] || !nmatch_prev))
1827
mac_substitute(mp,repstr,v,match,nmatch);
1828
if(nmatch==0)
1829
v += vsize;
1830
else
1831
v += match[1];
1832
if(*v && c=='/' && type)
1833
{
1834
/* avoid infinite loop */
1835
if(nmatch && match[1]==0)
1836
{
1837
nmatch = 0;
1838
mac_copy(mp,v,1);
1839
v++;
1840
}
1841
continue;
1842
}
1843
vsize = -1;
1844
break;
1845
}
1846
if(replen==0)
1847
sh_setmatch(mp->shp,vlast,vsize_last,nmatch,match,index++);
1848
}
1849
if(vsize)
1850
mac_copy(mp,v,vsize>0?vsize:strlen(v));
1851
if(addsub)
1852
{
1853
mp->shp->instance++;
1854
sfprintf(mp->shp->strbuf,"[%s]",nv_getsub(np));
1855
mp->shp->instance--;
1856
v = sfstruse(mp->shp->strbuf);
1857
mac_copy(mp, v, strlen(v));
1858
}
1859
if(dolg==0 && dolmax==0)
1860
break;
1861
if(mp->dotdot)
1862
{
1863
if(nv_nextsub(np) == 0)
1864
break;
1865
if(bysub)
1866
v = nv_getsub(np);
1867
else
1868
v = nv_getval(np);
1869
if(array_assoc(ap))
1870
{
1871
if(strcmp(bysub?v:nv_getsub(np),arrmax)>0)
1872
break;
1873
}
1874
else
1875
{
1876
if(nv_aindex(np) > dolmax)
1877
break;
1878
}
1879
}
1880
else if(dolg>=0)
1881
{
1882
if(++dolg >= dolmax)
1883
break;
1884
#if SHOPT_FILESCAN
1885
if(mp->shp->cur_line)
1886
{
1887
if(dolmax==MAX_ARGN && isastchar(mode))
1888
break;
1889
if(!(v=getdolarg(mp->shp,dolg,&vsize)))
1890
{
1891
dolmax = dolg;
1892
break;
1893
}
1894
}
1895
else
1896
#endif /* SHOPT_FILESCAN */
1897
v = mp->shp->st.dolv[dolg];
1898
}
1899
else if(!np)
1900
{
1901
if(!(v = nextname(mp,id,dolmax)))
1902
break;
1903
}
1904
else
1905
{
1906
if(dolmax && --dolmax <=0)
1907
{
1908
nv_putsub(np,NIL(char*),ARRAY_UNDEF);
1909
break;
1910
}
1911
if(ap)
1912
ap->nelem |= ARRAY_SCAN;
1913
if(nv_nextsub(np) == 0)
1914
break;
1915
if(bysub)
1916
v = nv_getsub(np);
1917
else
1918
v = nv_getval(np);
1919
}
1920
if(mp->split && (!mp->quote || mode=='@'))
1921
{
1922
if(!np)
1923
mp->pattern = 0;
1924
endfield(mp,mp->quoted);
1925
mp->atmode = mode=='@';
1926
mp->pattern = oldpat;
1927
}
1928
else if(d)
1929
{
1930
if(mp->sp)
1931
sfputc(mp->sp,d);
1932
else
1933
sfputc(stkp,d);
1934
}
1935
}
1936
if(arrmax)
1937
free((void*)arrmax);
1938
}
1939
else if(argp)
1940
{
1941
if(c=='/' && replen>0 && pattern && strmatch("",pattern))
1942
mac_substitute(mp,repstr,v,0,0);
1943
if(c=='?')
1944
{
1945
if(np)
1946
id = nv_name(np);
1947
else if(idnum)
1948
id = ltos(idnum);
1949
if(*argp)
1950
{
1951
sfputc(stkp,0);
1952
errormsg(SH_DICT,ERROR_exit(1),"%s: %s",id,argp);
1953
}
1954
else if(v)
1955
errormsg(SH_DICT,ERROR_exit(1),e_nullset,id);
1956
else
1957
errormsg(SH_DICT,ERROR_exit(1),e_notset,id);
1958
}
1959
else if(c=='=')
1960
{
1961
if(np)
1962
{
1963
if(mp->shp->subshell)
1964
np = sh_assignok(np,1);
1965
nv_putval(np,argp,0);
1966
v = nv_getval(np);
1967
nulflg = 0;
1968
stkseek(stkp,offset);
1969
goto retry2;
1970
}
1971
else
1972
mac_error(np);
1973
}
1974
}
1975
else if(var && sh_isoption(SH_NOUNSET) && type<=M_TREE && (!np || nv_isnull(np) || (nv_isarray(np) && !np->nvalue.cp)))
1976
{
1977
if(np)
1978
{
1979
if(nv_isarray(np))
1980
{
1981
sfprintf(mp->shp->strbuf,"%s[%s]\0",nv_name(np),nv_getsub(np));
1982
id = sfstruse(mp->shp->strbuf);
1983
}
1984
else
1985
id = nv_name(np);
1986
nv_close(np);
1987
}
1988
errormsg(SH_DICT,ERROR_exit(1),e_notset,id);
1989
}
1990
if(np)
1991
nv_close(np);
1992
if(pattern)
1993
free(pattern);
1994
if(repstr)
1995
free(repstr);
1996
if(idx)
1997
free(idx);
1998
return(1);
1999
nosub:
2000
if(type==M_BRACE && sh_lexstates[ST_NORM][c]==S_BREAK)
2001
{
2002
fcseek(-1);
2003
comsubst(mp,(Shnode_t*)0,2);
2004
return(1);
2005
}
2006
if(type)
2007
mac_error(np);
2008
fcseek(-1);
2009
nv_close(np);
2010
return(0);
2011
}
2012
2013
/*
2014
* This routine handles command substitution
2015
* <type> is 0 for older `...` version
2016
*/
2017
static void comsubst(Mac_t *mp,register Shnode_t* t, int type)
2018
{
2019
Sfdouble_t num;
2020
register int c;
2021
register char *str;
2022
Sfio_t *sp;
2023
Stk_t *stkp = mp->shp->stk;
2024
Fcin_t save;
2025
struct slnod *saveslp = mp->shp->st.staklist;
2026
struct _mac_ savemac;
2027
int savtop = stktell(stkp);
2028
char lastc=0, *savptr = stkfreeze(stkp,0);
2029
int was_history = sh_isstate(SH_HISTORY);
2030
int was_verbose = sh_isstate(SH_VERBOSE);
2031
int was_interactive = sh_isstate(SH_INTERACTIVE);
2032
int newlines,bufsize,nextnewlines;
2033
Sfoff_t foff;
2034
Namval_t *np;
2035
mp->shp->argaddr = 0;
2036
savemac = *mp;
2037
mp->shp->st.staklist=0;
2038
#ifdef SHOPT_COSHELL
2039
if(mp->shp->inpool)
2040
return;
2041
#endif /*SHOPT_COSHELL */
2042
if(type)
2043
{
2044
sp = 0;
2045
fcseek(-1);
2046
if(!t)
2047
t = sh_dolparen((Lex_t*)mp->shp->lex_context);
2048
if(t && t->tre.tretyp==TARITH)
2049
{
2050
mp->shp->inarith = 1;
2051
fcsave(&save);
2052
if(t->ar.arcomp)
2053
num = arith_exec(t->ar.arcomp);
2054
else if((t->ar.arexpr->argflag&ARG_RAW))
2055
num = sh_arith(mp->shp,t->ar.arexpr->argval);
2056
else
2057
num = sh_arith(mp->shp,sh_mactrim(mp->shp,t->ar.arexpr->argval,3));
2058
mp->shp->inarith = 0;
2059
out_offset:
2060
stkset(stkp,savptr,savtop);
2061
*mp = savemac;
2062
if((Sflong_t)num!=num)
2063
sfprintf(mp->shp->strbuf,"%.*Lg",LDBL_DIG,num);
2064
else if(num)
2065
sfprintf(mp->shp->strbuf,"%lld",(Sflong_t)num);
2066
else
2067
sfprintf(mp->shp->strbuf,"%Lg",num);
2068
str = sfstruse(mp->shp->strbuf);
2069
mac_copy(mp,str,strlen(str));
2070
mp->shp->st.staklist = saveslp;
2071
fcrestore(&save);
2072
return;
2073
}
2074
}
2075
else
2076
{
2077
while(fcgetc(c)!='`' && c)
2078
{
2079
if(c==ESCAPE)
2080
{
2081
fcgetc(c);
2082
if(!(isescchar(sh_lexstates[ST_QUOTE][c]) ||
2083
(c=='"' && mp->quote)))
2084
sfputc(stkp,ESCAPE);
2085
}
2086
sfputc(stkp,c);
2087
}
2088
c = stktell(stkp);
2089
str=stkfreeze(stkp,1);
2090
/* disable verbose and don't save in history file */
2091
sh_offstate(SH_HISTORY);
2092
sh_offstate(SH_VERBOSE);
2093
if(mp->sp)
2094
sfsync(mp->sp); /* flush before executing command */
2095
sp = sfnew(NIL(Sfio_t*),str,c,-1,SF_STRING|SF_READ);
2096
c = mp->shp->inlineno;
2097
mp->shp->inlineno = error_info.line+mp->shp->st.firstline;
2098
t = (Shnode_t*)sh_parse(mp->shp, sp,SH_EOF|SH_NL);
2099
mp->shp->inlineno = c;
2100
type = 1;
2101
}
2102
#if KSHELL
2103
if(t)
2104
{
2105
fcsave(&save);
2106
sfclose(sp);
2107
if(t->tre.tretyp==0 && !t->com.comarg && !t->com.comset)
2108
{
2109
/* special case $(<file) and $(<#file) */
2110
register int fd;
2111
int r;
2112
struct checkpt buff;
2113
struct ionod *ip=0;
2114
sh_pushcontext(mp->shp,&buff,SH_JMPIO);
2115
if((ip=t->tre.treio) &&
2116
((ip->iofile&IOLSEEK) || !(ip->iofile&IOUFD)) &&
2117
(r=sigsetjmp(buff.buff,0))==0)
2118
fd = sh_redirect(mp->shp,ip,3);
2119
else
2120
fd = sh_chkopen(e_devnull);
2121
sh_popcontext(mp->shp,&buff);
2122
if(r==0 && ip && (ip->iofile&IOLSEEK))
2123
{
2124
if(sp=mp->shp->sftable[fd])
2125
num = sftell(sp);
2126
else
2127
num = lseek(fd, (off_t)0, SEEK_CUR);
2128
goto out_offset;
2129
}
2130
if(!(sp=mp->shp->sftable[fd]))
2131
sp = sfnew(NIL(Sfio_t*),(char*)malloc(IOBSIZE+1),IOBSIZE,fd,SF_READ|SF_MALLOC);
2132
type = 3;
2133
}
2134
else
2135
sp = sh_subshell(mp->shp,t,sh_isstate(SH_ERREXIT),type);
2136
fcrestore(&save);
2137
}
2138
else
2139
sp = sfopen(NIL(Sfio_t*),"","sr");
2140
sh_freeup(mp->shp);
2141
mp->shp->st.staklist = saveslp;
2142
if(was_history)
2143
sh_onstate(SH_HISTORY);
2144
if(was_verbose)
2145
sh_onstate(SH_VERBOSE);
2146
#else
2147
sp = sfpopen(NIL(Sfio_t*),str,"r");
2148
#endif
2149
*mp = savemac;
2150
np = sh_scoped(mp->shp,IFSNOD);
2151
nv_putval(np,mp->ifsp,NV_RDONLY);
2152
mp->ifsp = nv_getval(np);
2153
stkset(stkp,savptr,savtop);
2154
newlines = 0;
2155
sfsetbuf(sp,(void*)sp,0);
2156
bufsize = sfvalue(sp);
2157
/* read command substitution output and put on stack or here-doc */
2158
sfpool(sp, NIL(Sfio_t*), SF_WRITE);
2159
sh_offstate(SH_INTERACTIVE);
2160
if((foff = sfseek(sp,(Sfoff_t)0,SEEK_END)) > 0)
2161
{
2162
size_t soff = stktell(stkp);
2163
sfseek(sp,(Sfoff_t)0,SEEK_SET);
2164
stkseek(stkp,soff+foff+64);
2165
stkseek(stkp,soff);
2166
}
2167
while((str=(char*)sfreserve(sp,SF_UNBOUND,0)) && (c=bufsize=sfvalue(sp))>0)
2168
{
2169
#if SHOPT_CRNL
2170
/* eliminate <cr> */
2171
register char *dp;
2172
char *buff = str;
2173
while(c>1 && (*str !='\r'|| str[1]!='\n'))
2174
{
2175
c--;
2176
str++;
2177
}
2178
dp = str;
2179
while(c>1)
2180
{
2181
str++;
2182
c--;
2183
while(c>1 && (*str!='\r' || str[1]!='\n'))
2184
{
2185
c--;
2186
*dp++ = *str++;
2187
}
2188
}
2189
if(c)
2190
*dp++ = *str++;
2191
str = buff;
2192
c = dp-str;
2193
#endif /* SHOPT_CRNL */
2194
/* delay appending trailing new-lines */
2195
for(nextnewlines=0; c-->0 && str[c]=='\n'; nextnewlines++);
2196
if(c < 0)
2197
{
2198
newlines += nextnewlines;
2199
continue;
2200
}
2201
if(newlines >0)
2202
{
2203
if(mp->sp)
2204
sfnputc(mp->sp,'\n',newlines);
2205
else if(!mp->quote && mp->split && mp->shp->ifstable['\n'])
2206
endfield(mp,0);
2207
else
2208
sfnputc(stkp,'\n',newlines);
2209
}
2210
else if(lastc)
2211
{
2212
mac_copy(mp,&lastc,1);
2213
lastc = 0;
2214
}
2215
newlines = nextnewlines;
2216
if(++c < bufsize)
2217
str[c] = 0;
2218
else
2219
{
2220
ssize_t len = 1;
2221
2222
/* can't write past buffer so save last character */
2223
c -= len;
2224
lastc = str[c];
2225
str[c] = 0;
2226
}
2227
mac_copy(mp,str,c);
2228
}
2229
if(was_interactive)
2230
sh_onstate(SH_INTERACTIVE);
2231
if(--newlines>0 && mp->shp->ifstable['\n']==S_DELIM)
2232
{
2233
if(mp->sp)
2234
sfnputc(mp->sp,'\n',newlines);
2235
else if(!mp->quote && mp->split)
2236
while(newlines--)
2237
endfield(mp,1);
2238
else
2239
sfnputc(stkp,'\n',newlines);
2240
}
2241
if(lastc)
2242
{
2243
mac_copy(mp,&lastc,1);
2244
lastc = 0;
2245
}
2246
sfclose(sp);
2247
return;
2248
}
2249
2250
/*
2251
* copy <str> onto the stack
2252
*/
2253
static void mac_copy(register Mac_t *mp,register const char *str, register int size)
2254
{
2255
register char *state;
2256
register const char *cp=str;
2257
register int c,n,nopat,len;
2258
Stk_t *stkp=mp->shp->stk;
2259
int oldpat = mp->pattern;
2260
nopat = (mp->quote||(mp->assign==1)||mp->arith);
2261
if(mp->zeros)
2262
{
2263
/* prevent leading 0's from becomming octal constants */
2264
while(size>1 && *str=='0')
2265
{
2266
if(str[1]=='x' || str[1]=='X')
2267
break;
2268
str++,size--;
2269
}
2270
mp->zeros = 0;
2271
cp = str;
2272
}
2273
if(mp->sp)
2274
sfwrite(mp->sp,str,size);
2275
else if(mp->pattern>=2 || (mp->pattern && nopat) || mp->assign==3)
2276
{
2277
state = sh_lexstates[ST_MACRO];
2278
/* insert \ before file expansion characters */
2279
while(size-->0)
2280
{
2281
#if SHOPT_MULTIBYTE
2282
if(mbwide() && (len=mbsize(cp))>1)
2283
{
2284
cp += len;
2285
size -= (len-1);
2286
continue;
2287
}
2288
#endif
2289
c = state[n= *(unsigned char*)cp++];
2290
if(mp->assign==3 && mp->pattern!=4)
2291
{
2292
if(c==S_BRACT)
2293
{
2294
nopat = 0;
2295
mp->pattern = 4;
2296
}
2297
continue;
2298
}
2299
if(nopat&&(c==S_PAT||c==S_ESC||c==S_BRACT||c==S_ENDCH) && mp->pattern!=3)
2300
c=1;
2301
else if(mp->pattern==4 && (c==S_ESC||c==S_BRACT||c==S_ENDCH || isastchar(n)))
2302
{
2303
if(c==S_ENDCH && oldpat!=4)
2304
{
2305
if(*cp==0 || *cp=='.' || *cp=='[')
2306
{
2307
mp->pattern = oldpat;
2308
c=0;
2309
}
2310
else
2311
c=1;
2312
}
2313
else
2314
c=1;
2315
}
2316
else if(mp->pattern==2 && c==S_SLASH)
2317
c=1;
2318
else if(mp->pattern==3 && c==S_ESC && (state[*(unsigned char*)cp]==S_DIG||(*cp==ESCAPE)))
2319
{
2320
if(!(c=mp->quote))
2321
cp++;
2322
}
2323
else
2324
c=0;
2325
if(c)
2326
{
2327
if(c = (cp-1) - str)
2328
sfwrite(stkp,str,c);
2329
sfputc(stkp,ESCAPE);
2330
str = cp-1;
2331
}
2332
}
2333
if(c = cp-str)
2334
sfwrite(stkp,str,c);
2335
}
2336
else if(!mp->quote && mp->split && (mp->ifs||mp->pattern))
2337
{
2338
/* split words at ifs characters */
2339
state = mp->shp->ifstable;
2340
if(mp->pattern)
2341
{
2342
char *sp = "&|()";
2343
while(c = *sp++)
2344
{
2345
if(state[c]==0)
2346
state[c] = S_EPAT;
2347
}
2348
sp = "*?[{";
2349
while(c = *sp++)
2350
{
2351
if(state[c]==0)
2352
state[c] = S_PAT;
2353
}
2354
if(state[ESCAPE]==0)
2355
state[ESCAPE] = S_ESC;
2356
}
2357
while(size-->0)
2358
{
2359
n=state[c= *(unsigned char*)cp++];
2360
#if SHOPT_MULTIBYTE
2361
if(mbwide() && n!=S_MBYTE && (len=mbsize(cp-1))>1)
2362
{
2363
sfwrite(stkp,cp-1, len);
2364
cp += --len;
2365
size -= len;
2366
continue;
2367
}
2368
#endif
2369
if(n==S_ESC || n==S_EPAT)
2370
{
2371
/* don't allow extended patterns in this case */
2372
mp->patfound = mp->pattern;
2373
sfputc(stkp,ESCAPE);
2374
}
2375
else if(n==S_PAT)
2376
mp->patfound = mp->pattern;
2377
else if(n && mp->ifs)
2378
{
2379
#if SHOPT_MULTIBYTE
2380
if(n==S_MBYTE)
2381
{
2382
if(sh_strchr(mp->ifsp,cp-1)<0)
2383
continue;
2384
n = mbsize(cp-1) - 1;
2385
if(n==-2)
2386
n = 0;
2387
cp += n;
2388
size -= n;
2389
n= S_DELIM;
2390
}
2391
#endif /* SHOPT_MULTIBYTE */
2392
if(n==S_SPACE || n==S_NL)
2393
{
2394
while(size>0 && ((n=state[c= *(unsigned char*)cp++])==S_SPACE||n==S_NL))
2395
size--;
2396
#if SHOPT_MULTIBYTE
2397
if(n==S_MBYTE && sh_strchr(mp->ifsp,cp-1)>=0)
2398
{
2399
n = mbsize(cp-1) - 1;
2400
if(n==-2)
2401
n = 0;
2402
cp += n;
2403
size -= n;
2404
n=S_DELIM;
2405
}
2406
else
2407
#endif /* SHOPT_MULTIBYTE */
2408
if(n==S_DELIM)
2409
size--;
2410
}
2411
endfield(mp,n==S_DELIM||mp->quoted);
2412
mp->patfound = 0;
2413
if(n==S_DELIM)
2414
while(size>0 && ((n=state[c= *(unsigned char*)cp++])==S_SPACE||n==S_NL))
2415
size--;
2416
if(size<=0)
2417
break;
2418
cp--;
2419
continue;
2420
2421
}
2422
sfputc(stkp,c);
2423
}
2424
if(mp->pattern)
2425
{
2426
cp = "&|()";
2427
while(c = *cp++)
2428
{
2429
if(state[c]==S_EPAT)
2430
state[c] = 0;
2431
}
2432
cp = "*?[{";
2433
while(c = *cp++)
2434
{
2435
if(state[c]==S_PAT)
2436
state[c] = 0;
2437
}
2438
if(mp->shp->ifstable[ESCAPE]==S_ESC)
2439
mp->shp->ifstable[ESCAPE] = 0;
2440
}
2441
}
2442
else
2443
sfwrite(stkp,str,size);
2444
}
2445
2446
/*
2447
* Terminate field.
2448
* If field is null count field if <split> is non-zero
2449
* Do filename expansion of required
2450
*/
2451
static void endfield(register Mac_t *mp,int split)
2452
{
2453
register struct argnod *argp;
2454
register int count=0;
2455
Stk_t *stkp = mp->shp->stk;
2456
if(stktell(stkp) > ARGVAL || split)
2457
{
2458
argp = (struct argnod*)stkfreeze(stkp,1);
2459
argp->argnxt.cp = 0;
2460
argp->argflag = 0;
2461
mp->atmode = 0;
2462
if(mp->patfound)
2463
{
2464
mp->shp->argaddr = 0;
2465
#if SHOPT_BRACEPAT
2466
count = path_generate(mp->shp,argp,mp->arghead);
2467
#else
2468
count = path_expand(mp->shp,argp->argval,mp->arghead);
2469
#endif /* SHOPT_BRACEPAT */
2470
if(count)
2471
mp->fields += count;
2472
else if(split) /* pattern is null string */
2473
*argp->argval = 0;
2474
else /* pattern expands to nothing */
2475
count = -1;
2476
}
2477
if(count==0)
2478
{
2479
argp->argchn.ap = *mp->arghead;
2480
*mp->arghead = argp;
2481
mp->fields++;
2482
}
2483
if(count>=0)
2484
{
2485
(*mp->arghead)->argflag |= ARG_MAKE;
2486
if(mp->assign || sh_isoption(SH_NOGLOB))
2487
argp->argflag |= ARG_RAW|ARG_EXP;
2488
}
2489
stkseek(stkp,ARGVAL);
2490
}
2491
mp->quoted = mp->quote;
2492
}
2493
2494
/*
2495
* Finds the right substring of STRING using the expression PAT
2496
* the longest substring is found when FLAG is set.
2497
*/
2498
static int substring(register const char *string,const char *pat,int match[], int flag)
2499
{
2500
register const char *sp=string;
2501
register int size,len,nmatch,n;
2502
int smatch[2*(MATCH_MAX+1)];
2503
if(flag)
2504
{
2505
if(n=strgrpmatch(sp,pat,smatch,elementsof(smatch)/2,STR_RIGHT|STR_MAXIMAL))
2506
{
2507
memcpy(match,smatch,n*2*sizeof(smatch[0]));
2508
return(n);
2509
}
2510
return(0);
2511
}
2512
size = len = strlen(sp);
2513
sp += size;
2514
while(sp>=string)
2515
{
2516
#if SHOPT_MULTIBYTE
2517
if(mbwide())
2518
sp = lastchar(string,sp);
2519
#endif /* SHOPT_MULTIBYTE */
2520
if(n=strgrpmatch(sp,pat,smatch,elementsof(smatch)/2,STR_RIGHT|STR_LEFT|STR_MAXIMAL))
2521
{
2522
nmatch = n;
2523
memcpy(match,smatch,n*2*sizeof(smatch[0]));
2524
size = sp-string;
2525
break;
2526
}
2527
sp--;
2528
}
2529
if(size==len)
2530
return(0);
2531
if(nmatch)
2532
{
2533
nmatch *=2;
2534
while(--nmatch>=0)
2535
match[nmatch] += size;
2536
}
2537
return(n);
2538
}
2539
2540
#if SHOPT_MULTIBYTE
2541
static char *lastchar(const char *string, const char *endstring)
2542
{
2543
register char *str = (char*)string;
2544
register int c;
2545
mbinit();
2546
while(*str)
2547
{
2548
if((c=mbsize(str))<0)
2549
c = 1;
2550
if(str+c > endstring)
2551
break;
2552
str += c;
2553
}
2554
return(str);
2555
}
2556
#endif /* SHOPT_MULTIBYTE */
2557
static int charlen(const char *string,int len)
2558
{
2559
if(!string)
2560
return(0);
2561
#if SHOPT_MULTIBYTE
2562
if(mbwide())
2563
{
2564
register const char *str = string, *strmax=string+len;
2565
register int n=0;
2566
mbinit();
2567
if(len>0)
2568
{
2569
while(str<strmax && mbchar(str))
2570
n++;
2571
}
2572
else while(mbchar(str))
2573
n++;
2574
return(n);
2575
}
2576
else
2577
#endif /* SHOPT_MULTIBYTE */
2578
{
2579
if(len<0)
2580
return(strlen(string));
2581
return(len);
2582
}
2583
}
2584
2585
/*
2586
* This is the default tilde discipline function
2587
*/
2588
static int sh_btilde(int argc, char *argv[], Shbltin_t *context)
2589
{
2590
Shell_t *shp = context->shp;
2591
char *cp = sh_tilde(shp,argv[1]);
2592
NOT_USED(argc);
2593
if(!cp)
2594
cp = argv[1];
2595
sfputr(sfstdout, cp, '\n');
2596
return(0);
2597
}
2598
2599
/*
2600
* <offset> is byte offset for beginning of tilde string
2601
*/
2602
static void tilde_expand2(Shell_t *shp, register int offset)
2603
{
2604
char shtilde[10], *av[3], *ptr=stkfreeze(shp->stk,1);
2605
Sfio_t *iop, *save=sfstdout;
2606
Namval_t *np;
2607
static int beenhere=0;
2608
strcpy(shtilde,".sh.tilde");
2609
np = nv_open(shtilde,shp->fun_tree, NV_VARNAME|NV_NOARRAY|NV_NOASSIGN|NV_NOFAIL);
2610
if(np && !beenhere)
2611
{
2612
beenhere = 1;
2613
sh_addbuiltin(shtilde,sh_btilde,0);
2614
nv_onattr(np,NV_EXPORT);
2615
}
2616
av[0] = ".sh.tilde";
2617
av[1] = &ptr[offset];
2618
av[2] = 0;
2619
iop = sftmp((IOBSIZE>PATH_MAX?IOBSIZE:PATH_MAX)+1);
2620
sfset(iop,SF_READ,0);
2621
sfstdout = iop;
2622
if(np)
2623
sh_fun(np, (Namval_t*)0, av);
2624
else
2625
sh_btilde(2, av, &shp->bltindata);
2626
sfstdout = save;
2627
stkset(shp->stk,ptr, offset);
2628
sfseek(iop,(Sfoff_t)0,SEEK_SET);
2629
sfset(iop,SF_READ,1);
2630
if(ptr = sfreserve(iop, SF_UNBOUND, -1))
2631
{
2632
Sfoff_t n = sfvalue(iop);
2633
while(ptr[n-1]=='\n')
2634
n--;
2635
if(n==1 && fcpeek(0)=='/' && ptr[n-1])
2636
n--;
2637
if(n)
2638
sfwrite(shp->stk,ptr,n);
2639
}
2640
else
2641
sfputr(shp->stk,av[1],0);
2642
sfclose(iop);
2643
}
2644
2645
/*
2646
* This routine is used to resolve ~ expansion.
2647
* A ~ by itself is replaced with the users login directory.
2648
* A ~- is replaced by the previous working directory in shell.
2649
* A ~+ is replaced by the present working directory in shell.
2650
* If ~name is replaced with login directory of name.
2651
* If string doesn't start with ~ or ~... not found then 0 returned.
2652
*/
2653
2654
static char *sh_tilde(Shell_t *shp,register const char *string)
2655
{
2656
register char *cp;
2657
register int c;
2658
register struct passwd *pw;
2659
register Namval_t *np=0;
2660
static Dt_t *logins_tree;
2661
if(*string++!='~')
2662
return(NIL(char*));
2663
if((c = *string)==0)
2664
{
2665
if(!(cp=nv_getval(sh_scoped(shp,HOME))))
2666
cp = getlogin();
2667
return(cp);
2668
}
2669
if((c=='-' || c=='+') && string[1]==0)
2670
{
2671
if(c=='+')
2672
cp = nv_getval(sh_scoped(shp,PWDNOD));
2673
else
2674
cp = nv_getval(sh_scoped(shp,OLDPWDNOD));
2675
return(cp);
2676
}
2677
#if _WINIX
2678
if(fcgetc(c)=='/')
2679
{
2680
char *str;
2681
int n=0,offset=staktell();
2682
stakputs(string);
2683
do
2684
{
2685
stakputc(c);
2686
n++;
2687
}
2688
while (fcgetc(c) && c!='/');
2689
stakputc(0);
2690
if(c)
2691
fcseek(-1);
2692
str = stakseek(offset);
2693
Skip = n;
2694
if(logins_tree && (np=nv_search(str,logins_tree,0)))
2695
return(nv_getval(np));
2696
if(pw = getpwnam(str))
2697
{
2698
string = str;
2699
goto skip;
2700
}
2701
Skip = 0;
2702
}
2703
#endif /* _WINIX */
2704
if(logins_tree && (np=nv_search(string,logins_tree,0)))
2705
return(nv_getval(np));
2706
if(!(pw = getpwnam(string)))
2707
return(NIL(char*));
2708
#if _WINIX
2709
skip:
2710
#endif /* _WINIX */
2711
if(!logins_tree)
2712
logins_tree = dtopen(&_Nvdisc,Dtbag);
2713
if(np=nv_search(string,logins_tree,NV_ADD))
2714
{
2715
c = shp->subshell;
2716
shp->subshell = 0;
2717
nv_putval(np, pw->pw_dir,0);
2718
shp->subshell = c;
2719
}
2720
return(pw->pw_dir);
2721
}
2722
2723
/*
2724
* return values for special macros
2725
*/
2726
static char *special(Shell_t *shp,register int c)
2727
{
2728
if(c!='$')
2729
shp->argaddr = 0;
2730
switch(c)
2731
{
2732
case '@':
2733
case '*':
2734
return(shp->st.dolc>0?shp->st.dolv[1]:NIL(char*));
2735
case '#':
2736
#if SHOPT_FILESCAN
2737
if(shp->cur_line)
2738
{
2739
getdolarg(shp,MAX_ARGN,(int*)0);
2740
return(ltos(shp->offsets[0]));
2741
}
2742
#endif /* SHOPT_FILESCAN */
2743
return(ltos(shp->st.dolc));
2744
case '!':
2745
if(shp->bckpid)
2746
#if SHOPT_COSHELL
2747
return(sh_pid2str(shp,shp->bckpid));
2748
#else
2749
return(ltos(shp->bckpid));
2750
#endif /* SHOPT_COSHELL */
2751
break;
2752
case '$':
2753
if(nv_isnull(SH_DOLLARNOD))
2754
return(ltos(shp->gd->pid));
2755
return(nv_getval(SH_DOLLARNOD));
2756
case '-':
2757
return(sh_argdolminus(shp->arg_context));
2758
case '?':
2759
return(ltos(shp->savexit));
2760
case 0:
2761
if(sh_isstate(SH_PROFILE) || shp->fn_depth==0 || !shp->st.cmdname)
2762
return(shp->shname);
2763
else
2764
return(shp->st.cmdname);
2765
}
2766
return(NIL(char*));
2767
}
2768
2769
/*
2770
* Handle macro expansion errors
2771
*/
2772
static void mac_error(Namval_t *np)
2773
{
2774
if(np)
2775
nv_close(np);
2776
errormsg(SH_DICT,ERROR_exit(1),e_subst,fcfirst());
2777
}
2778
2779
/*
2780
* Given pattern/string, replace / with 0 and return pointer to string
2781
* \ characters are stripped from string. The \ are stripped in the
2782
* replacement string unless followed by a digit or \.
2783
*/
2784
static char *mac_getstring(char *pattern)
2785
{
2786
register char *cp=pattern, *rep=0, *dp;
2787
register int c;
2788
while(c = *cp++)
2789
{
2790
if(c==ESCAPE && (!rep || (*cp && strchr("&|()[]*?",*cp))))
2791
{
2792
c = *cp++;
2793
}
2794
else if(!rep && c=='/')
2795
{
2796
cp[-1] = 0;
2797
rep = dp = cp;
2798
continue;
2799
}
2800
if(rep)
2801
*dp++ = c;
2802
}
2803
if(rep)
2804
*dp = 0;
2805
return(rep);
2806
}
2807
2808