1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * David Korn <dgk@research.att.com> *
19 ***********************************************************************/
22 * Shell macro expander
38 #include "variables.h"
53 #define mbchar(p) (*(unsigned char*)p++)
59 Shell_t
*shp
; /* pointer to shell interpreter */
60 Sfio_t
*sp
; /* stream pointer for here-document */
61 struct argnod
**arghead
; /* address of head of argument list */
62 char *ifsp
; /* pointer to IFS value */
63 int fields
; /* number of fields */
64 short quoted
; /* set when word has quotes */
65 unsigned char ifs
; /* first char of IFS */
66 char quote
; /* set within double quoted contexts */
67 char lit
; /* set within single quotes */
68 char split
; /* set when word splittin is possible */
69 char pattern
; /* set when file expansion follows */
70 char patfound
; /* set if pattern character found */
71 char assign
; /* set for assignments */
72 char arith
; /* set for ((...)) */
73 char let
; /* set when expanding let arguments */
74 char zeros
; /* strip leading zeros when set */
75 char arrayok
; /* $x[] ok for arrays */
76 char subcopy
; /* set when copying subscript */
77 int dotdot
; /* set for .. in subscript */
78 void *nvwalk
; /* for name space walking*/
83 #define isescchar(s) ((s)>S_QUOTE)
84 #define isqescchar(s) ((s)>=S_QUOTE)
85 #define isbracechar(c) ((c)==RBRACE || (_c_=sh_lexstates[ST_BRACE][c])==S_MOD1 ||_c_==S_MOD2)
86 #define ltos(x) fmtbase((long)(x),0,0)
88 /* type of macro expansions */
89 #define M_BRACE 1 /* ${var} */
90 #define M_TREE 2 /* ${var.} */
91 #define M_SIZE 3 /* ${#var} */
92 #define M_VNAME 4 /* ${!var} */
93 #define M_SUBNAME 5 /* ${!var[sub]} */
94 #define M_NAMESCAN 6 /* ${!var*} */
95 #define M_NAMECOUNT 7 /* ${#var*} */
96 #define M_TYPE 8 /* ${@var} */
98 static int substring(const char*, const char*, int[], int);
99 static void copyto(Mac_t
*, int, int);
100 static void comsubst(Mac_t
*, Shnode_t
*, int);
101 static int varsub(Mac_t
*);
102 static void mac_copy(Mac_t
*,const char*, int);
103 static void tilde_expand2(Shell_t
*,int);
104 static char *sh_tilde(Shell_t
*,const char*);
105 static char *special(Shell_t
*,int);
106 static void endfield(Mac_t
*,int);
107 static void mac_error(Namval_t
*);
108 static char *mac_getstring(char*);
109 static int charlen(const char*,int);
111 static char *lastchar(const char*,const char*);
112 #endif /* SHOPT_MULTIBYTE */
114 void *sh_macopen(Shell_t
*shp
)
116 void *addr
= newof(0,Mac_t
,1,0);
117 Mac_t
*mp
= (Mac_t
*)addr
;
123 * perform only parameter substitution and catch failures
125 char *sh_mactry(Shell_t
*shp
,register char *string
)
130 int savexit
= shp
->savexit
;
132 sh_pushcontext(&buff
,SH_JMPSUB
);
133 jmp_val
= sigsetjmp(buff
.buff
,0);
135 string
= sh_mactrim(shp
,string
,0);
136 sh_popcontext(&buff
);
137 shp
->savexit
= savexit
;
144 * Perform parameter expansion, command substitution, and arithmetic
145 * expansion on <str>.
146 * If <mode> greater than 1 file expansion is performed if the result
147 * yields a single pathname.
148 * If <mode> negative, than expansion rules for assignment are applied.
150 char *sh_mactrim(Shell_t
*shp
, char *str
, register int mode
)
152 register Mac_t
*mp
= (Mac_t
*)shp
->mac_context
;
153 Stk_t
*stkp
= shp
->stk
;
157 mp
->arith
= (mode
==3);
160 mp
->pattern
= (mode
==1||mode
==2);
165 mp
->quoted
= mp
->lit
= mp
->split
= mp
->quote
= 0;
167 if(mp
->ifsp
=nv_getval(sh_scoped(shp
,IFSNOD
)))
173 copyto(mp
,0,mp
->arith
);
174 str
= stkfreeze(stkp
,1);
177 /* expand only if unique */
178 struct argnod
*arglist
=0;
179 if((mode
=path_expand(str
,&arglist
))==1)
180 str
= arglist
->argval
;
182 errormsg(SH_DICT
,ERROR_exit(1),e_ambiguous
,str
);
190 * Perform all the expansions on the argument <argp>
192 int sh_macexpand(Shell_t
* shp
, register struct argnod
*argp
, struct argnod
**arghead
,int flag
)
194 register int flags
= argp
->argflag
;
195 register char *str
= argp
->argval
;
196 register Mac_t
*mp
= (Mac_t
*)shp
->mac_context
;
197 char **saveargaddr
= shp
->argaddr
;
199 Stk_t
*stkp
= shp
->stk
;
202 if(mp
->ifsp
=nv_getval(sh_scoped(shp
,IFSNOD
)))
206 if((flag
&ARG_OPTIMIZE
) && !shp
->indebug
)
207 shp
->argaddr
= (char**)&argp
->argchn
.ap
;
210 mp
->arghead
= arghead
;
211 mp
->quoted
= mp
->lit
= mp
->quote
= 0;
212 mp
->arith
= ((flag
&ARG_ARITH
)!=0);
213 mp
->let
= ((flag
&ARG_LET
)!=0);
214 mp
->split
= !(flag
&ARG_ASSIGN
);
215 mp
->assign
= !mp
->split
;
216 mp
->pattern
= mp
->split
&& !(flag
&ARG_NOGLOB
) && !sh_isoption(SH_NOGLOB
);
217 mp
->arrayok
= mp
->arith
|| (flag
&ARG_ARRAYOK
);
224 mp
->pattern
= ((flag
&ARG_EXP
)!=0);
229 stkseek(stkp
,ARGVAL
);
230 *stkptr(stkp
,ARGVAL
-1) = 0;
235 copyto(mp
,0,mp
->arith
);
238 argp
->argchn
.cp
= stkfreeze(stkp
,1);
240 argp
->argflag
|= ARG_MAKE
;
244 endfield(mp
,mp
->quoted
);
246 if(flags
==1 && shp
->argaddr
)
247 argp
->argchn
.ap
= *arghead
;
249 shp
->argaddr
= saveargaddr
;
255 * Expand here document which is stored in <infile> or <string>
256 * The result is written to <outfile>
258 void sh_machere(Shell_t
*shp
,Sfio_t
*infile
, Sfio_t
*outfile
, char *string
)
261 register const char *state
= sh_lexstates
[ST_QUOTE
];
263 register Mac_t
*mp
= (Mac_t
*)shp
->mac_context
;
264 Lex_t
*lp
= (Lex_t
*)mp
->shp
->lex_context
;
267 Stk_t
*stkp
= shp
->stk
;
272 mp
->split
= mp
->assign
= mp
->pattern
= mp
->patfound
= mp
->lit
= mp
->arith
= mp
->let
= 0;
274 mp
->ifsp
= nv_getval(sh_scoped(shp
,IFSNOD
));
291 switch(len
= mbsize(cp
))
293 case -1: /* illegal multi-byte char */
296 n
=state
[*(unsigned char*)cp
++];
299 /* use state of alpha character */
307 #endif /* SHOPT_MULTIBYTE */
308 while((n
=state
[*(unsigned char*)cp
++])==0);
309 if(n
==S_NL
|| n
==S_QUOTE
|| n
==S_RBRA
)
311 if(c
=(cp
-1)-fcseek(0))
312 sfwrite(outfile
,fcseek(0),c
);
319 /* ignore 0 byte when reading from file */
333 if(!isescchar(state
[c
]))
334 sfputc(outfile
,ESCAPE
);
337 comsubst(mp
,(Shnode_t
*)0,0);
344 switch(n
=sh_lexstates
[ST_DOL
][c
])
346 case S_ALP
: case S_SPC1
: case S_SPC2
:
347 case S_DIG
: case S_LBRA
:
350 int offset
= stktell(stkp
);
357 if(sh_lexstates
[ST_NORM
][c
]==S_BREAK
)
359 comsubst(mp
,(Shnode_t
*)0,2);
362 sh_lexskip(lp
,RBRACE
,1,ST_BRACE
);
366 while(fcgetc(c
),isaname(c
))
371 offset2
= stktell(stkp
);
373 fcsopen(stkptr(stkp
,offset
));
375 if(c
=stktell(stkp
)-offset2
)
376 sfwrite(outfile
,(char*)stkptr(stkp
,offset2
),c
);
378 stkseek(stkp
,offset
);
382 comsubst(mp
,(Shnode_t
*)0,1);
400 * expand argument but do not trim pattern characters
402 char *sh_macpat(Shell_t
*shp
,register struct argnod
*arg
, int flags
)
404 register char *sp
= arg
->argval
;
405 if((arg
->argflag
&ARG_RAW
))
407 sh_stats(STAT_ARGEXPAND
);
408 if(flags
&ARG_OPTIMIZE
)
410 if(!(sp
=arg
->argchn
.cp
))
412 sh_macexpand(shp
,arg
,NIL(struct argnod
**),flags
|ARG_ARRAYOK
);
414 if(!(flags
&ARG_OPTIMIZE
) || !(arg
->argflag
&ARG_MAKE
))
416 arg
->argflag
&= ~ARG_MAKE
;
419 sh_stats(STAT_ARGHITS
);
424 * Process the characters up to <endch> or end of input string
426 static void copyto(register Mac_t
*mp
,int endch
, int newquote
)
429 register const char *state
= sh_lexstates
[ST_MACRO
];
430 register char *cp
,*first
;
431 Lex_t
*lp
= (Lex_t
*)mp
->shp
->lex_context
;
433 int oldquote
= mp
->quote
;
439 Stk_t
*stkp
= mp
->shp
->stk
;
440 mp
->sp
= NIL(Sfio_t
*);
441 mp
->quote
= newquote
;
442 first
= cp
= fcseek(0);
443 if(!mp
->quote
&& *cp
=='~' && cp
[1]!=LPAREN
)
444 tilde
= stktell(stkp
);
445 /* handle // operator specially */
446 if(mp
->pattern
==2 && *cp
=='/')
456 switch(len
= mbsize(cp
))
458 case -1: /* illegal multi-byte char */
462 n
= state
[*(unsigned char*)cp
++];
465 /* treat as if alpha */
471 c
= (cp
-len
) - first
;
474 #endif /* SHOPT_MULTIBYTE */
476 while((n
=state
[*(unsigned char*)cp
++])==0);
484 /* process ANSI-C escape character */
487 sfwrite(stkp
,first
,c
);
488 c
= chresc(cp
,&addr
);
490 first
= fcseek(cp
-first
);
492 if(c
> UCHAR_MAX
&& mbwide())
497 n
= wctomb((char*)mb
, c
);
502 #endif /* SHOPT_MULTIBYTE */
504 if(c
==ESCAPE
&& mp
->pattern
)
508 else if(sh_isoption(SH_BRACEEXPAND
) && mp
->pattern
==4 && (*cp
==',' || *cp
==LBRACE
|| *cp
==RBRACE
|| *cp
=='.'))
510 else if(mp
->split
&& endch
&& !mp
->quote
&& !mp
->lit
)
513 mac_copy(mp
,first
,c
);
526 n
= state
[*(unsigned char*)cp
];
527 if(n
==S_ENDCH
&& *cp
!=endch
)
531 /* preserve \digit for pattern matching */
532 /* also \alpha for extended patterns */
533 if(!mp
->lit
&& !mp
->quote
)
535 if((n
==S_DIG
|| ((paren
+ere
) && sh_lexstates
[ST_DOL
][*(unsigned char*)cp
]==S_ALP
)))
537 if(ere
&& mp
->pattern
==1 && strchr(".[()*+?{|^$&!",*cp
))
540 /* followed by file expansion */
541 if(!mp
->lit
&& (n
==S_ESC
|| (!mp
->quote
&&
542 (n
==S_PAT
||n
==S_ENDCH
||n
==S_SLASH
||n
==S_BRACT
||*cp
=='-'))))
545 if(ere
&& n
==S_ESC
&& *cp
=='\\' && cp
[1]=='$')
547 /* convert \\\$ into \$' */
548 sfwrite(stkp
,first
,c
+1);
549 cp
= first
= fcseek(c
+3);
553 if(!(ere
&& *cp
=='$') && (mp
->lit
|| (mp
->quote
&& !isqescchar(n
) && n
!=S_ENDCH
)))
555 /* add \ for file expansion */
556 sfwrite(stkp
,first
,c
+1);
563 if(!mp
->quote
|| isqescchar(n
) || n
==S_ENDCH
)
567 sfwrite(stkp
,first
,c
);
568 /* check new-line joining */
573 case S_GRAVE
: case S_DOL
:
578 if(mp
->split
&& !mp
->quote
&& endch
)
579 mac_copy(mp
,first
,c
);
581 sfwrite(stkp
,first
,c
);
586 comsubst(mp
,(Shnode_t
*)0,0);
587 else if((n
= *cp
)==0 || !varsub(mp
))
589 if(n
=='\'' && !mp
->quote
)
591 else if(mp
->quote
|| n
!='"')
594 cp
= first
= fcseek(0);
599 if((mp
->lit
|| cp
[-1]!=endch
|| mp
->quote
!=newquote
))
601 if(endch
==RBRACE
&& *cp
==LPAREN
&& mp
->pattern
&& brace
)
606 if(mp
->split
&& !mp
->quote
&& !mp
->lit
&& endch
)
607 mac_copy(mp
,first
,c
);
609 sfwrite(stkp
,first
,c
);
614 tilde_expand2(mp
->shp
,tilde
);
617 if(mp
->lit
|| mp
->arith
)
622 if((*cp
=='`' || *cp
=='[') && cp
[1]=='\'')
626 if(n
==S_LIT
&& mp
->quote
)
630 if(mp
->split
&& endch
&& !mp
->quote
&& !mp
->lit
)
631 mac_copy(mp
,first
,c
);
633 sfwrite(stkp
,first
,c
);
641 mp
->lit
= ansi_c
= 0;
646 mp
->quote
= !mp
->quote
;
650 if(mp
->arith
|| (((mp
->assign
&1) || endch
==RBRACT
) &&
651 !(mp
->quote
|| mp
->lit
)))
653 int offset
=0,oldpat
= mp
->pattern
;
654 int oldarith
= mp
->arith
, oldsub
=mp
->subcopy
;
655 sfwrite(stkp
,first
,++c
);
659 offset
= stktell(stkp
);
660 if(isastchar(*cp
) && cp
[1]==']')
661 errormsg(SH_DICT
,ERROR_exit(1),
669 mp
->subcopy
= oldsub
;
670 mp
->arith
= oldarith
;
671 mp
->pattern
= oldpat
;
675 cp
= stkptr(stkp
,stktell(stkp
));
676 if(sh_checkid(stkptr(stkp
,offset
),cp
)!=cp
)
677 stkseek(stkp
,stktell(stkp
)-2);
679 cp
= first
= fcseek(0);
683 if(mp
->pattern
&& !(mp
->quote
|| mp
->lit
))
685 mp
->patfound
= mp
->pattern
;
686 if((n
=cp
[-1])==LPAREN
)
689 if((cp
-first
)>1 && cp
[-2]=='~')
692 while((c
=mbchar(p
)) && c
!=RPAREN
&& c
!='E');
693 ere
= (c
=='E'||c
=='A');
701 if(mp
->pattern
==4 && (mp
->quote
|| mp
->lit
))
705 sfwrite(stkp
,first
,c
);
712 if(!(mp
->quote
|| mp
->lit
))
714 mp
->patfound
= mp
->split
&& sh_isoption(SH_BRACEEXPAND
);
718 if(!mp
->pattern
|| !(mp
->quote
|| mp
->lit
))
720 /* mark beginning of {a,b} */
721 if(n
==S_BRACE
&& endch
==0 && mp
->pattern
)
723 if(n
==S_SLASH
&& mp
->pattern
==2)
730 sfwrite(stkp
,first
,c
);
737 if(*cp
=='~' && !endch
&& !mp
->quote
&& !mp
->lit
)
738 tilde
= stktell(stkp
)+(c
+1);
747 sfwrite(stkp
,first
,c
);
749 tilde_expand2(mp
->shp
,tilde
);
753 if(n
==S_COLON
&& mp
->assign
==2 && *cp
=='~' && endch
==0 && !mp
->quote
&&!mp
->lit
)
754 tilde
= stktell(stkp
)+(c
+1);
755 else if(n
==S_SLASH
&& mp
->pattern
==2)
760 if(mp
->quote
|| mp
->lit
)
762 sfwrite(stkp
,first
,c
+1);
765 sh_lexskip(lp
,RBRACE
,0,ST_NESTED
);
768 sfwrite(stkp
,first
,cp
-first
);
774 if(*cp
=='.' && mp
->subcopy
==1)
776 sfwrite(stkp
,first
,c
);
778 mp
->dotdot
= stktell(stkp
);
779 cp
= first
= fcseek(c
+2);
786 mp
->quote
= oldquote
;
790 * copy <str> to stack performing sub-expression substitutions
792 static void mac_substitute(Mac_t
*mp
, register char *cp
,char *str
,register int subexp
[],int subsize
)
795 register char *first
=fcseek(0);
798 Stk_t
*stkp
= mp
->shp
->stk
;
806 ptr
= cp
= strdup(stkptr(stkp
,n
));
813 while((c
= *cp
++) && c
!=ESCAPE
);
816 if((n
= *cp
++)=='\\' || n
==RBRACE
|| (n
>='0' && n
<='9' && (n
-='0')<subsize
))
820 mac_copy(mp
,first
,c
);
822 if(n
=='\\' || n
==RBRACE
)
827 if((c
=subexp
[2*n
])>=0)
829 if((n
=subexp
[2*n
+1]-c
)>0)
830 mac_copy(mp
,str
+c
,n
);
837 mac_copy(mp
,first
,n
);
842 #define MAX_OFFSETS (sizeof(shp->offsets)/sizeof(shp->offsets[0]))
843 #define MAX_ARGN (32*1024)
846 * compute the arguments $1 ... $n and $# from the current line as needed
847 * save line offsets in the offsets array.
849 static char *getdolarg(Shell_t
*shp
, int n
, int *size
)
851 register int c
=S_DELIM
, d
=shp
->ifstable
['\\'];
852 register unsigned char *first
,*last
,*cp
= (unsigned char*)shp
->cur_line
;
853 register int m
=shp
->offsets
[0],delim
=0;
862 if(m
>= MAX_OFFSETS
-1)
864 cp
+= shp
->offsets
[m
+1];
866 shp
->ifstable
['\\'] = 0;
867 shp
->ifstable
[0] = S_EOF
;
871 while(shp
->ifstable
[*cp
++]==S_SPACE
);
873 if(++m
< MAX_OFFSETS
)
874 shp
->offsets
[m
] = (first
-(unsigned char*)shp
->cur_line
);
875 while((c
=shp
->ifstable
[*cp
++])==0);
878 while((c
=shp
->ifstable
[*cp
++])==S_SPACE
);
879 if(--n
==0 || c
==S_EOF
)
881 if(last
==first
&& c
==S_EOF
&& (!delim
|| (m
>1)))
888 delim
= (c
==S_DELIM
);
890 shp
->ifstable
['\\'] = d
;
891 if(m
> shp
->offsets
[0])
897 return((char*)first
);
899 #endif /* SHOPT_FILESCAN */
902 * get the prefix after name reference resolution
904 static char *prefix(Shell_t
*shp
, char *id
)
907 register char *sub
=0, *cp
= strchr(id
,'.');
911 np
= nv_search(id
, shp
->var_tree
,0);
915 if(np
&& nv_isref(np
))
920 while(nv_isref(np
) && np
->nvalue
.cp
)
925 nv_putsub(np
,sub
,0L);
927 id
= (char*)malloc(strlen(cp
)+1+(n
=strlen(sp
=nv_name(np
)))+ (sub
?strlen(sub
)+3:1));
944 * copy to ']' onto the stack and return offset to it
946 static int subcopy(Mac_t
*mp
, int flag
)
948 int split
= mp
->split
;
949 int xpattern
= mp
->pattern
;
950 int loc
= stktell(mp
->shp
->stk
);
951 int xarith
= mp
->arith
;
952 int arrayok
= mp
->arrayok
;
955 mp
->pattern
= flag
?4:0;
961 mp
->pattern
= xpattern
;
964 mp
->arrayok
= arrayok
;
969 * if name is a discipline function, run the function and put the results
970 * on the stack so that ${x.foo} behaves like ${ x.foo;}
972 int sh_macfun(Shell_t
*shp
, const char *name
, int offset
)
975 np
= nv_bfsearch(name
,shp
->fun_tree
,&nq
,(char**)0);
978 /* treat ${x.foo} as ${x.foo;} */
980 char buff
[sizeof(struct dolnod
)+sizeof(char*)];
982 struct dolnod
*dp
= (struct dolnod
*)buff
;
983 memset(&node
,0,sizeof(node
));
984 memset(&buff
,0,sizeof(buff
));
985 tp
= (Shnode_t
*)&node
;
986 tp
->com
.comarg
= (struct argnod
*)dp
;
987 tp
->com
.comline
= shp
->inlineno
;
989 dp
->dolval
[0] = strdup(name
);
990 stkseek(shp
->stk
,offset
);
991 comsubst((Mac_t
*)shp
->mac_context
,tp
,2);
998 static int namecount(Mac_t
*mp
,const char *prefix
)
1001 mp
->nvwalk
= nv_diropen((Namval_t
*)0,prefix
);
1002 while(nv_dirnext(mp
->nvwalk
))
1004 nv_dirclose(mp
->nvwalk
);
1008 static char *nextname(Mac_t
*mp
,const char *prefix
, int len
)
1013 mp
->nvwalk
= nv_diropen((Namval_t
*)0,prefix
);
1014 return((char*)mp
->nvwalk
);
1016 if(!(cp
=nv_dirnext(mp
->nvwalk
)))
1017 nv_dirclose(mp
->nvwalk
);
1022 * This routine handles $param, ${parm}, and ${param op word}
1023 * The input stream is assumed to be a string
1025 static int varsub(Mac_t
*mp
)
1028 register int type
=0; /* M_xxx */
1029 register char *v
,*argp
=0;
1030 register Namval_t
*np
= NIL(Namval_t
*);
1031 register int dolg
=0, mode
=0;
1032 Lex_t
*lp
= (Lex_t
*)mp
->shp
->lex_context
;
1034 int dolmax
=0, vsize
= -1, offset
= -1, nulflg
, replen
=0, bysub
=0;
1035 char idbuff
[3], *id
= idbuff
, *pattern
=0, *repstr
, *arrmax
=0;
1036 int var
=1,addsub
=0,oldpat
=mp
->pattern
,idnum
=0,flag
=0,d
;
1037 Stk_t
*stkp
= mp
->shp
->stk
;
1043 switch(isascii(c
)?sh_lexstates
[ST_DOL
][c
]:S_ALP
)
1048 /* This code handles ${#} */
1055 if(isaletter(mode
=fcpeek(0)) || mode
=='.')
1059 #ifdef SHOPT_TYPEDEF
1065 #endif /* SHOPT_TYPEDEF */
1071 else if(c
=='#' && (isadigit(mode
)||fcpeek(1)==RBRACE
))
1082 v
= special(mp
->shp
,c
);
1087 if(mp
->shp
->cur_line
)
1089 v
= getdolarg(&sh
,1,(int*)0);
1093 #endif /* SHOPT_FILESCAN */
1094 dolmax
= mp
->shp
->st
.dolc
+1;
1106 comsubst(mp
,(Shnode_t
*)0,1);
1111 mp
->shp
->argaddr
= 0;
1115 while((d
=fcget()),isadigit(d
))
1121 v
= special(mp
->shp
,c
);
1123 else if(mp
->shp
->cur_line
)
1125 mp
->shp
->used_pos
= 1;
1126 v
= getdolarg(&sh
,c
,&vsize
);
1128 #endif /* SHOPT_FILESCAN */
1129 else if(c
<= mp
->shp
->st
.dolc
)
1131 mp
->shp
->used_pos
= 1;
1132 v
= mp
->shp
->st
.dolv
[c
];
1138 if(c
=='.' && type
==0)
1140 offset
= stktell(stkp
);
1146 while(((c
=fcget()),(!isascii(c
)||isaname(c
)))||type
&& c
=='.');
1147 while(c
==LBRACT
&& (type
||mp
->arrayok
))
1150 if((c
=fcget(),isastchar(c
)) && fcpeek(0)==RBRACT
)
1154 idbuff
[0] = mode
= c
;
1157 if(c
=='.' || c
==LBRACT
)
1159 sfputc(stkp
,LBRACT
);
1161 sfputc(stkp
,RBRACT
);
1171 sfputc(stkp
,LBRACT
);
1172 v
= stkptr(stkp
,subcopy(mp
,1));
1173 if(type
&& mp
->dotdot
)
1179 else if(type
==M_SIZE
)
1183 sfputc(stkp
,RBRACT
);
1185 if(c
==0 && type
==M_VNAME
)
1190 while(type
&& c
=='.');
1191 if(c
==RBRACE
&& type
&& fcpeek(-2)=='.')
1193 /* ${x.} or ${x..} */
1194 if(fcpeek(-3) == '.')
1196 stkseek(stkp
,stktell(stkp
)-2);
1201 stkseek(stkp
,stktell(stkp
)-1);
1206 id
=stkptr(stkp
,offset
);
1207 if(isastchar(c
) && type
)
1209 if(type
==M_VNAME
|| type
==M_SIZE
)
1211 idbuff
[0] = mode
= c
;
1212 if((d
=fcpeek(0))==c
)
1213 idbuff
[1] = fcget();
1222 flag
|= NV_NOASSIGN
|NV_VARNAME
|NV_NOADD
;
1223 if(c
=='=' || c
=='?' || (c
==':' && ((d
=fcpeek(0))=='=' || d
=='?')))
1226 if(mp
->shp
->cur_line
&& *id
=='R' && strcmp(id
,"REPLY")==0)
1232 #endif /* SHOPT_FILESCAN */
1234 if(mp
->shp
->argaddr
)
1236 np
= nv_open(id
,mp
->shp
->var_tree
,flag
|NV_NOFAIL
);
1240 if((!np
|| nv_isnull(np
)) && type
==M_BRACE
&& c
==RBRACE
&& !(flag
&NV_ARRAY
) && strchr(id
,'.'))
1242 if(sh_macfun(mp
->shp
,id
,offset
))
1248 if(np
&& (flag
&NV_NOADD
) && nv_isnull(np
))
1250 if(nv_isattr(np
,NV_NOFREE
))
1251 nv_offattr(np
,NV_NOFREE
);
1255 ap
= np
?nv_arrayptr(np
):0;
1262 nv_putsub(np
,v
,ARRAY_SCAN
);
1263 v
= stkptr(stkp
,mp
->dotdot
);
1267 else if((dolmax
= (int)sh_arith(v
))<0)
1268 dolmax
+= array_maxindex(np
);
1274 if((int)sh_arith(v
))
1278 else if(ap
&& (isastchar(mode
)||type
==M_TREE
) && !(ap
->nelem
&ARRAY_SCAN
) && type
!=M_SIZE
)
1279 nv_putsub(np
,NIL(char*),ARRAY_SCAN
);
1287 if(type
<=1 && np
&& nv_isvtree(np
) && mp
->pattern
==1 && !mp
->split
)
1289 int peek
=1,cc
=fcget();
1295 if(mp
->quote
&& cc
=='"')
1304 if((type
==M_VNAME
||type
==M_SUBNAME
) && mp
->shp
->argaddr
&& strcmp(nv_name(np
),id
))
1305 mp
->shp
->argaddr
= 0;
1306 c
= (type
>M_BRACE
&& isastchar(mode
));
1307 if(np
&& (type
==M_TREE
|| !c
|| !ap
))
1310 c
= *((unsigned char*)stkptr(stkp
,offset
-1));
1311 savptr
= stkfreeze(stkp
,0);
1312 if(type
==M_VNAME
|| (type
==M_SUBNAME
&& ap
))
1316 if(ap
&& !mp
->dotdot
&& !(ap
->nelem
&ARRAY_UNDEF
))
1319 #ifdef SHOPT_TYPEDEF
1320 else if(type
==M_TYPE
)
1322 Namval_t
*nq
= nv_type(np
);
1325 nv_typename(nq
,mp
->shp
->strbuf
);
1327 nv_attribute(np
,mp
->shp
->strbuf
,"typeset",1);
1328 v
= sfstruse(mp
->shp
->strbuf
);
1330 #endif /* SHOPT_TYPEDEF */
1332 else if(mp
->shp
->cur_line
&& np
==REPLYNOD
)
1333 v
= mp
->shp
->cur_line
;
1334 #endif /* SHOPT_FILESCAN */
1335 else if(type
==M_TREE
)
1336 v
= nv_getvtree(np
,(Namfun_t
*)0);
1339 if(type
&& fcpeek(0)=='+')
1342 v
= nv_arrayisset(np
,ap
)?(char*)"x":0;
1344 v
= nv_isnull(np
)?0:(char*)"x";
1348 /* special case --- ignore leading zeros */
1349 if( (mp
->arith
||mp
->let
) && (np
->nvfun
|| nv_isattr(np
,(NV_LJUST
|NV_RJUST
|NV_ZFILL
))) && (offset
==0 || !isalnum(c
)))
1352 if(savptr
==stakptr(0))
1353 stkseek(stkp
,offset
);
1355 stkset(stkp
,savptr
,offset
);
1365 else if(type
==M_TYPE
)
1368 stkseek(stkp
,offset
);
1372 if(mp
->shp
->argaddr
)
1375 if(isastchar(mode
) && array_elem(ap
)> !c
)
1391 if(type
==M_NAMESCAN
|| type
==M_NAMECOUNT
)
1393 mp
->shp
->last_root
= mp
->shp
->var_tree
;
1394 id
= prefix(mp
->shp
,id
);
1395 stkseek(stkp
,offset
);
1396 if(type
==M_NAMECOUNT
)
1398 c
= namecount(mp
,id
);
1403 dolmax
= strlen(id
);
1406 v
= nextname(mp
,id
,dolmax
);
1409 else if(type
==M_SUBNAME
)
1418 if(!ap
|| isastchar(mode
))
1426 if(!isastchar(mode
))
1427 c
= charlen(v
,vsize
);
1431 if(mp
->shp
->cur_line
)
1433 getdolarg(&sh
,MAX_ARGN
,(int*)0);
1434 c
= mp
->shp
->offsets
[0];
1437 #endif /* SHOPT_FILESCAN */
1438 c
= mp
->shp
->st
.dolc
;
1453 if(sh_lexstates
[ST_BRACE
][c
]==S_MOD1
&& c
!='*' && c
!= ':')
1455 else if(c
!='%' && c
!='#')
1472 int newops
= (c
=='#' || c
== '%' || c
=='/');
1473 offset
= stktell(stkp
);
1474 if(c
=='/' ||c
==':' || ((!v
|| (nulflg
&& *v
==0)) ^ (c
=='+'||c
=='#'||c
=='%')))
1476 int newquote
= mp
->quote
;
1477 int split
= mp
->split
;
1478 int quoted
= mp
->quoted
;
1479 int arith
= mp
->arith
;
1480 int zeros
= mp
->zeros
;
1481 int assign
= mp
->assign
;
1485 if(type
=='%' || type
=='#')
1493 mp
->pattern
= 1+(c
=='/');
1497 mp
->arith
= mp
->zeros
= 0;
1500 else if(c
=='?' || c
=='=')
1501 mp
->split
= mp
->pattern
= 0;
1502 copyto(mp
,RBRACE
,newquote
);
1505 mp
->pattern
= oldpat
;
1507 mp
->quoted
= quoted
;
1510 mp
->assign
= assign
;
1513 stkseek(stkp
,stktell(stkp
)-1);
1517 sh_lexskip(lp
,RBRACE
,0,(!newops
&&mp
->quote
)?ST_QUOTE
:ST_NESTED
);
1518 stkseek(stkp
,offset
);
1520 argp
=stkptr(stkp
,offset
);
1528 if(c
==':') /* ${name:expr1[:expr2]} */
1531 type
= (int)sh_strnum(argp
,&ptr
,1);
1534 if(id
==idbuff
) /* ${@} or ${*} */
1536 if(type
<0 && (type
+= dolmax
)<0)
1539 v
= special(mp
->shp
,dolg
=0);
1541 else if(mp
->shp
->cur_line
)
1543 v
= getdolarg(&sh
,dolg
=type
,&vsize
);
1547 #endif /* SHOPT_FILESCAN */
1548 else if(type
< dolmax
)
1549 v
= mp
->shp
->st
.dolv
[dolg
=type
];
1560 type
+= array_maxindex(np
);
1564 while(type
-- >0 && (v
=0,nv_nextsub(np
)))
1569 if(nv_putsub(np
,NIL(char*),type
|ARRAY_SCAN
))
1580 vsize
= charlen(v
,vsize
);
1581 if(type
<0 && (type
+= vsize
)<0)
1597 #endif /* SHOPT_MULTIBYTE */
1604 if((type
= (int)sh_strnum(ptr
+1,&ptr
,1)) <=0)
1606 else if(isastchar(mode
))
1610 if(dolg
+type
< dolmax
)
1616 else if(type
< vsize
)
1625 if((c
=mbsize(vp
))<1)
1632 #endif /* SHOPT_MULTIBYTE */
1638 stkseek(stkp
,offset
);
1641 /* check for substring operations */
1642 else if(c
== '#' || c
== '%' || c
=='/')
1646 if(type
=='/' || type
=='#' || type
=='%')
1657 if(type
==c
) /* ## or %% */
1662 pattern
= strdup(argp
);
1663 if((type
=='/' || c
=='/') && (repstr
= mac_getstring(pattern
)))
1664 replen
= strlen(repstr
);
1665 if(v
|| c
=='/' && offset
>=0)
1666 stkseek(stkp
,offset
);
1668 /* check for quoted @ */
1669 if(mode
=='@' && mp
->quote
&& !v
&& c
!='-')
1672 if(v
&& (!nulflg
|| *v
) && c
!='+')
1674 register int d
= (mode
=='@'?' ':mp
->ifs
);
1675 int match
[2*(MATCH_MAX
+1)], nmatch
, nmatch_prev
, vsize_last
;
1681 if(c
=='/' || c
=='#' || c
== '%')
1683 flag
= (type
|| c
=='/')?(STR_GROUP
|STR_MAXIMAL
):STR_GROUP
;
1690 nmatch_prev
= nmatch
;
1692 nmatch
=substring(v
,pattern
,match
,flag
&STR_MAXIMAL
);
1694 nmatch
=strgrpmatch(v
,pattern
,match
,elementsof(match
)/2,flag
);
1696 sh_setmatch(v
,vsize
,nmatch
,match
);
1706 mac_copy(mp
,v
,vsize
);
1707 if(nmatch
&& replen
>0 && (match
[1] || !nmatch_prev
))
1708 mac_substitute(mp
,repstr
,v
,match
,nmatch
);
1713 if(*v
&& c
=='/' && type
)
1715 /* avoid infinite loop */
1716 if(nmatch
&& match
[1]==0)
1728 sh_setmatch(vlast
,vsize_last
,nmatch
,match
);
1731 mac_copy(mp
,v
,vsize
>0?vsize
:strlen(v
));
1734 sfprintf(mp
->shp
->strbuf
,"[%s]",nv_getsub(np
));
1735 v
= sfstruse(mp
->shp
->strbuf
);
1736 mac_copy(mp
, v
, strlen(v
));
1738 if(dolg
==0 && dolmax
==0)
1742 if(nv_nextsub(np
) == 0)
1750 if(strcmp(bysub
?v
:nv_getsub(np
),arrmax
)>0)
1755 if(nv_aindex(np
) > dolmax
)
1761 if(++dolg
>= dolmax
)
1764 if(mp
->shp
->cur_line
)
1766 if(dolmax
==MAX_ARGN
&& isastchar(mode
))
1768 if(!(v
=getdolarg(&sh
,dolg
,&vsize
)))
1775 #endif /* SHOPT_FILESCAN */
1776 v
= mp
->shp
->st
.dolv
[dolg
];
1780 if(!(v
= nextname(mp
,id
,dolmax
)))
1785 if(dolmax
&& --dolmax
<=0)
1787 nv_putsub(np
,NIL(char*),ARRAY_UNDEF
);
1791 ap
->nelem
|= ARRAY_SCAN
;
1792 if(nv_nextsub(np
) == 0)
1799 if(mp
->split
&& (!mp
->quote
|| mode
=='@'))
1803 endfield(mp
,mp
->quoted
);
1804 mp
->pattern
= oldpat
;
1815 free((void*)arrmax
);
1817 free((void*)pattern
);
1821 if(c
=='/' && replen
>0 && pattern
&& strmatch("",pattern
))
1822 mac_substitute(mp
,repstr
,v
,0,0);
1832 errormsg(SH_DICT
,ERROR_exit(1),"%s: %s",id
,argp
);
1835 errormsg(SH_DICT
,ERROR_exit(1),e_nullset
,id
);
1837 errormsg(SH_DICT
,ERROR_exit(1),e_notset
,id
);
1843 if(mp
->shp
->subshell
)
1844 np
= sh_assignok(np
,1);
1845 nv_putval(np
,argp
,0);
1848 stkseek(stkp
,offset
);
1855 else if(var
&& sh_isoption(SH_NOUNSET
) && type
<=M_TREE
&& (!np
|| nv_isnull(np
) || (nv_isarray(np
) && !np
->nvalue
.cp
)))
1861 sfprintf(mp
->shp
->strbuf
,"%s[%s]\0",nv_name(np
),nv_getsub(np
));
1862 id
= sfstruse(mp
->shp
->strbuf
);
1868 errormsg(SH_DICT
,ERROR_exit(1),e_notset
,id
);
1874 if(type
==M_BRACE
&& sh_lexstates
[ST_NORM
][c
]==S_BREAK
)
1877 comsubst(mp
,(Shnode_t
*)0,2);
1888 * This routine handles command substitution
1889 * <type> is 0 for older `...` version
1891 static void comsubst(Mac_t
*mp
,register Shnode_t
* t
, int type
)
1897 Stk_t
*stkp
= mp
->shp
->stk
;
1899 struct slnod
*saveslp
= mp
->shp
->st
.staklist
;
1900 struct _mac_ savemac
;
1901 int savtop
= stktell(stkp
);
1902 char lastc
, *savptr
= stkfreeze(stkp
,0);
1903 int was_history
= sh_isstate(SH_HISTORY
);
1904 int was_verbose
= sh_isstate(SH_VERBOSE
);
1905 int was_interactive
= sh_isstate(SH_INTERACTIVE
);
1906 int newlines
,bufsize
,nextnewlines
;
1908 mp
->shp
->argaddr
= 0;
1910 mp
->shp
->st
.staklist
=0;
1916 t
= sh_dolparen((Lex_t
*)mp
->shp
->lex_context
);
1917 if(t
&& t
->tre
.tretyp
==TARITH
)
1920 if((t
->ar
.arexpr
->argflag
&ARG_RAW
))
1921 num
= arith_exec(t
->ar
.arcomp
);
1923 num
= sh_arith(sh_mactrim(mp
->shp
,t
->ar
.arexpr
->argval
,3));
1925 stkset(stkp
,savptr
,savtop
);
1927 if((Sflong_t
)num
!=num
)
1928 sfprintf(mp
->shp
->strbuf
,"%.*Lg",LDBL_DIG
,num
);
1930 sfprintf(mp
->shp
->strbuf
,"%lld",(Sflong_t
)num
);
1932 sfprintf(mp
->shp
->strbuf
,"%Lg",num
);
1933 str
= sfstruse(mp
->shp
->strbuf
);
1934 mac_copy(mp
,str
,strlen(str
));
1935 mp
->shp
->st
.staklist
= saveslp
;
1942 while(fcgetc(c
)!='`' && c
)
1947 if(!(isescchar(sh_lexstates
[ST_QUOTE
][c
]) ||
1948 (c
=='"' && mp
->quote
)))
1949 sfputc(stkp
,ESCAPE
);
1954 str
=stkfreeze(stkp
,1);
1955 /* disable verbose and don't save in history file */
1956 sh_offstate(SH_HISTORY
);
1957 sh_offstate(SH_VERBOSE
);
1959 sfsync(mp
->sp
); /* flush before executing command */
1960 sp
= sfnew(NIL(Sfio_t
*),str
,c
,-1,SF_STRING
|SF_READ
);
1961 c
= mp
->shp
->inlineno
;
1962 mp
->shp
->inlineno
= error_info
.line
+mp
->shp
->st
.firstline
;
1963 t
= (Shnode_t
*)sh_parse(mp
->shp
, sp
,SH_EOF
|SH_NL
);
1964 mp
->shp
->inlineno
= c
;
1972 if(t
->tre
.tretyp
==0 && !t
->com
.comarg
&& !t
->com
.comset
)
1974 /* special case $(<file) and $(<#file) */
1977 struct checkpt buff
;
1979 sh_pushcontext(&buff
,SH_JMPIO
);
1980 if((ip
=t
->tre
.treio
) &&
1981 ((ip
->iofile
&IOLSEEK
) || !(ip
->iofile
&IOUFD
)) &&
1982 (r
=sigsetjmp(buff
.buff
,0))==0)
1983 fd
= sh_redirect(mp
->shp
,ip
,3);
1985 fd
= sh_chkopen(e_devnull
);
1986 sh_popcontext(&buff
);
1987 if(r
==0 && ip
&& (ip
->iofile
&IOLSEEK
))
1989 if(sp
=mp
->shp
->sftable
[fd
])
1992 num
= lseek(fd
, (off_t
)0, SEEK_CUR
);
1995 sp
= sfnew(NIL(Sfio_t
*),(char*)malloc(IOBSIZE
+1),IOBSIZE
,fd
,SF_READ
|SF_MALLOC
);
1999 sp
= sh_subshell(t
,sh_isstate(SH_ERREXIT
),type
);
2003 sp
= sfopen(NIL(Sfio_t
*),"","sr");
2005 mp
->shp
->st
.staklist
= saveslp
;
2007 sh_onstate(SH_HISTORY
);
2009 sh_onstate(SH_VERBOSE
);
2011 sp
= sfpopen(NIL(Sfio_t
*),str
,"r");
2014 np
= sh_scoped(mp
->shp
,IFSNOD
);
2015 nv_putval(np
,mp
->ifsp
,NV_RDONLY
);
2016 mp
->ifsp
= nv_getval(np
);
2017 stkset(stkp
,savptr
,savtop
);
2020 sfsetbuf(sp
,(void*)sp
,0);
2021 bufsize
= sfvalue(sp
);
2022 /* read command substitution output and put on stack or here-doc */
2023 sfpool(sp
, NIL(Sfio_t
*), SF_WRITE
);
2024 sh_offstate(SH_INTERACTIVE
);
2025 while((str
=(char*)sfreserve(sp
,SF_UNBOUND
,0)) && (c
= sfvalue(sp
))>0)
2028 /* eliminate <cr> */
2031 while(c
>1 && (*str
!='\r'|| str
[1]!='\n'))
2041 while(c
>1 && (*str
!='\r' || str
[1]!='\n'))
2051 #endif /* SHOPT_CRNL */
2052 /* delay appending trailing new-lines */
2053 for(nextnewlines
=0; c
-->0 && str
[c
]=='\n'; nextnewlines
++);
2056 newlines
+= nextnewlines
;
2062 sfnputc(mp
->sp
,'\n',newlines
);
2063 else if(!mp
->quote
&& mp
->split
&& mp
->shp
->ifstable
['\n'])
2066 sfnputc(stkp
,'\n',newlines
);
2070 mac_copy(mp
,&lastc
,1);
2073 newlines
= nextnewlines
;
2078 /* can't write past buffer so save last character */
2085 sh_onstate(SH_INTERACTIVE
);
2087 job_wait(mp
->shp
->spid
);
2088 if(--newlines
>0 && mp
->shp
->ifstable
['\n']==S_DELIM
)
2091 sfnputc(mp
->sp
,'\n',newlines
);
2092 else if(!mp
->quote
&& mp
->split
)
2096 sfnputc(stkp
,'\n',newlines
);
2099 mac_copy(mp
,&lastc
,1);
2105 * copy <str> onto the stack
2107 static void mac_copy(register Mac_t
*mp
,register const char *str
, register int size
)
2109 register char *state
;
2110 register const char *cp
=str
;
2111 register int c
,n
,nopat
,len
;
2112 Stk_t
*stkp
=mp
->shp
->stk
;
2113 nopat
= (mp
->quote
||mp
->assign
==1||mp
->arith
);
2116 /* prevent leading 0's from becomming octal constants */
2117 while(size
>1 && *str
=='0')
2123 sfwrite(mp
->sp
,str
,size
);
2124 else if(mp
->pattern
>=2 || (mp
->pattern
&& nopat
))
2126 state
= sh_lexstates
[ST_MACRO
];
2127 /* insert \ before file expansion characters */
2131 if(mbwide() && (len
=mbsize(cp
))>1)
2138 c
= state
[n
= *(unsigned char*)cp
++];
2139 if(nopat
&&(c
==S_PAT
||c
==S_ESC
||c
==S_BRACT
||c
==S_ENDCH
) && mp
->pattern
!=3)
2141 else if(mp
->pattern
==4 && (c
==S_ESC
||c
==S_BRACT
||c
==S_ENDCH
|| isastchar(n
)))
2143 else if(mp
->pattern
==2 && c
==S_SLASH
)
2145 else if(mp
->pattern
==3 && c
==S_ESC
&& (state
[*(unsigned char*)cp
]==S_DIG
||(*cp
==ESCAPE
)))
2154 if(c
= (cp
-1) - str
)
2155 sfwrite(stkp
,str
,c
);
2156 sfputc(stkp
,ESCAPE
);
2161 sfwrite(stkp
,str
,c
);
2163 else if(!mp
->quote
&& mp
->split
&& (mp
->ifs
||mp
->pattern
))
2165 /* split words at ifs characters */
2166 state
= mp
->shp
->ifstable
;
2181 if(state
[ESCAPE
]==0)
2182 state
[ESCAPE
] = S_ESC
;
2186 n
=state
[c
= *(unsigned char*)cp
++];
2188 if(mbwide() && n
!=S_MBYTE
&& (len
=mbsize(cp
-1))>1)
2190 sfwrite(stkp
,cp
-1, len
);
2196 if(n
==S_ESC
|| n
==S_EPAT
)
2198 /* don't allow extended patterns in this case */
2199 mp
->patfound
= mp
->pattern
;
2200 sfputc(stkp
,ESCAPE
);
2203 mp
->patfound
= mp
->pattern
;
2204 else if(n
&& mp
->ifs
)
2209 if(sh_strchr(mp
->ifsp
,cp
-1)<0)
2211 n
= mbsize(cp
-1) - 1;
2218 #endif /* SHOPT_MULTIBYTE */
2219 if(n
==S_SPACE
|| n
==S_NL
)
2221 while(size
>0 && ((n
=state
[c
= *(unsigned char*)cp
++])==S_SPACE
||n
==S_NL
))
2224 if(n
==S_MBYTE
&& sh_strchr(mp
->ifsp
,cp
-1)>=0)
2226 n
= mbsize(cp
-1) - 1;
2234 #endif /* SHOPT_MULTIBYTE */
2238 endfield(mp
,n
==S_DELIM
||mp
->quoted
);
2241 while(size
>0 && ((n
=state
[c
= *(unsigned char*)cp
++])==S_SPACE
||n
==S_NL
))
2256 if(state
[c
]==S_EPAT
)
2265 if(mp
->shp
->ifstable
[ESCAPE
]==S_ESC
)
2266 mp
->shp
->ifstable
[ESCAPE
] = 0;
2270 sfwrite(stkp
,str
,size
);
2275 * If field is null count field if <split> is non-zero
2276 * Do filename expansion of required
2278 static void endfield(register Mac_t
*mp
,int split
)
2280 register struct argnod
*argp
;
2281 register int count
=0;
2282 Stk_t
*stkp
= mp
->shp
->stk
;
2283 if(stktell(stkp
) > ARGVAL
|| split
)
2285 argp
= (struct argnod
*)stkfreeze(stkp
,1);
2286 argp
->argnxt
.cp
= 0;
2290 mp
->shp
->argaddr
= 0;
2292 count
= path_generate(argp
,mp
->arghead
);
2294 count
= path_expand(argp
->argval
,mp
->arghead
);
2295 #endif /* SHOPT_BRACEPAT */
2297 mp
->fields
+= count
;
2298 else if(split
) /* pattern is null string */
2300 else /* pattern expands to nothing */
2305 argp
->argchn
.ap
= *mp
->arghead
;
2306 *mp
->arghead
= argp
;
2311 (*mp
->arghead
)->argflag
|= ARG_MAKE
;
2312 if(mp
->assign
|| sh_isoption(SH_NOGLOB
))
2313 argp
->argflag
|= ARG_RAW
|ARG_EXP
;
2315 stkseek(stkp
,ARGVAL
);
2317 mp
->quoted
= mp
->quote
;
2321 * Finds the right substring of STRING using the expression PAT
2322 * the longest substring is found when FLAG is set.
2324 static int substring(register const char *string
,const char *pat
,int match
[], int flag
)
2326 register const char *sp
=string
;
2327 register int size
,len
,nmatch
,n
;
2328 int smatch
[2*(MATCH_MAX
+1)];
2331 if(n
=strgrpmatch(sp
,pat
,smatch
,elementsof(smatch
)/2,STR_RIGHT
|STR_MAXIMAL
))
2333 memcpy(match
,smatch
,n
*2*sizeof(smatch
[0]));
2338 size
= len
= strlen(sp
);
2344 sp
= lastchar(string
,sp
);
2345 #endif /* SHOPT_MULTIBYTE */
2346 if(n
=strgrpmatch(sp
,pat
,smatch
,elementsof(smatch
)/2,STR_RIGHT
|STR_LEFT
|STR_MAXIMAL
))
2349 memcpy(match
,smatch
,n
*2*sizeof(smatch
[0]));
2361 match
[nmatch
] += size
;
2367 static char *lastchar(const char *string
, const char *endstring
)
2369 register char *str
= (char*)string
;
2374 if((c
=mbsize(str
))<0)
2376 if(str
+c
> endstring
)
2382 #endif /* SHOPT_MULTIBYTE */
2383 static int charlen(const char *string
,int len
)
2390 register const char *str
= string
, *strmax
=string
+len
;
2395 while(str
<strmax
&& mbchar(str
))
2398 else while(mbchar(str
))
2403 #endif /* SHOPT_MULTIBYTE */
2406 return(strlen(string
));
2412 * This is the default tilde discipline function
2414 static int sh_btilde(int argc
, char *argv
[], void *context
)
2416 Shell_t
*shp
= ((Shbltin_t
*)context
)->shp
;
2417 char *cp
= sh_tilde(shp
,argv
[1]);
2421 sfputr(sfstdout
, cp
, '\n');
2426 * <offset> is byte offset for beginning of tilde string
2428 static void tilde_expand2(Shell_t
*shp
, register int offset
)
2430 char shtilde
[10], *av
[3], *ptr
=stkfreeze(shp
->stk
,1);
2431 Sfio_t
*iop
, *save
=sfstdout
;
2433 static int beenhere
=0;
2434 strcpy(shtilde
,".sh.tilde");
2435 np
= nv_open(shtilde
,shp
->fun_tree
, NV_VARNAME
|NV_NOARRAY
|NV_NOASSIGN
|NV_NOFAIL
);
2439 sh_addbuiltin(shtilde
,sh_btilde
,0);
2440 nv_onattr(np
,NV_EXPORT
);
2442 av
[0] = ".sh.tilde";
2443 av
[1] = &ptr
[offset
];
2445 iop
= sftmp(IOBSIZE
+1);;
2446 sfset(iop
,SF_READ
,0);
2449 sh_fun(np
, (Namval_t
*)0, av
);
2451 sh_btilde(2, av
, &sh
);
2453 stkset(shp
->stk
,ptr
, offset
);
2454 sfseek(iop
,(Sfoff_t
)0,SEEK_SET
);
2455 sfset(iop
,SF_READ
,1);
2456 if(ptr
= sfreserve(iop
, SF_UNBOUND
, -1))
2458 Sfoff_t n
= sfvalue(iop
);
2459 while(ptr
[n
-1]=='\n')
2461 if(n
==1 && fcpeek(0)=='/' && ptr
[n
-1])
2464 sfwrite(shp
->stk
,ptr
,n
);
2467 sfputr(shp
->stk
,av
[1],0);
2472 * This routine is used to resolve ~ expansion.
2473 * A ~ by itself is replaced with the users login directory.
2474 * A ~- is replaced by the previous working directory in shell.
2475 * A ~+ is replaced by the present working directory in shell.
2476 * If ~name is replaced with login directory of name.
2477 * If string doesn't start with ~ or ~... not found then 0 returned.
2480 static char *sh_tilde(Shell_t
*shp
,register const char *string
)
2484 register struct passwd
*pw
;
2485 register Namval_t
*np
=0;
2486 static Dt_t
*logins_tree
;
2489 if((c
= *string
)==0)
2491 if(!(cp
=nv_getval(sh_scoped(shp
,HOME
))))
2495 if((c
=='-' || c
=='+') && string
[1]==0)
2498 cp
= nv_getval(sh_scoped(shp
,PWDNOD
));
2500 cp
= nv_getval(sh_scoped(shp
,OLDPWDNOD
));
2503 if(logins_tree
&& (np
=nv_search(string
,logins_tree
,0)))
2504 return(nv_getval(np
));
2505 if(!(pw
= getpwnam(string
)))
2508 logins_tree
= dtopen(&_Nvdisc
,Dtbag
);
2509 if(np
=nv_search(string
,logins_tree
,NV_ADD
))
2510 nv_putval(np
, pw
->pw_dir
,0);
2515 * return values for special macros
2517 static char *special(Shell_t
*shp
,register int c
)
2525 return(shp
->st
.dolc
>0?shp
->st
.dolv
[1]:NIL(char*));
2530 getdolarg(shp
,MAX_ARGN
,(int*)0);
2531 return(ltos(shp
->offsets
[0]));
2533 #endif /* SHOPT_FILESCAN */
2534 return(ltos(shp
->st
.dolc
));
2537 return(ltos(shp
->bckpid
));
2540 if(nv_isnull(SH_DOLLARNOD
))
2541 return(ltos(shp
->pid
));
2542 return(nv_getval(SH_DOLLARNOD
));
2544 return(sh_argdolminus(shp
->arg_context
));
2546 return(ltos(shp
->savexit
));
2548 if(sh_isstate(SH_PROFILE
) || shp
->fn_depth
==0 || !shp
->st
.cmdname
)
2549 return(shp
->shname
);
2551 return(shp
->st
.cmdname
);
2557 * Handle macro expansion errors
2559 static void mac_error(Namval_t
*np
)
2563 errormsg(SH_DICT
,ERROR_exit(1),e_subst
,fcfirst());
2567 * Given pattern/string, replace / with 0 and return pointer to string
2568 * \ characters are stripped from string. The \ are stripped in the
2569 * replacement string unless followed by a digit or \.
2571 static char *mac_getstring(char *pattern
)
2573 register char *cp
=pattern
, *rep
=0, *dp
;
2577 if(c
==ESCAPE
&& (!rep
|| (*cp
&& strchr("&|()[]*?",*cp
))))
2581 else if(!rep
&& c
=='/')