2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
10 * Copyright (c) 1980 Regents of the University of California.
11 * All rights reserved. The Berkeley Software License Agreement
12 * specifies the terms and conditions for redistribution.
15 #pragma ident "%Z%%M% %I% %E% SMI"
18 #include "sh.tconst.h"
22 #include <widec.h> /* wcsetno() */
23 #include <fnmatch.h> /* fnmatch() */
32 tchar
*gpath
, *gpathp
, *lastgpathp
;
38 int sortscmp(tchar
**, tchar
**);
40 void collect(tchar
*);
41 void acollect(tchar
*);
43 void matchdir_(tchar
*);
44 void Gcat(tchar
*, tchar
*);
47 tchar
**dobackp(tchar
*, bool);
48 void backeval(tchar
*, bool);
52 extern DIR *opendir_(tchar
*);
54 #define sort() qsort((char *)sortbas, &gargv[gargc] - sortbas, \
55 sizeof (*sortbas), (int (*)(const void *, \
56 const void *)) sortscmp), sortbas = &gargv[gargc]
63 tchar
*agargv
[GAVSIZ
];
65 gpath
= agpath
; gpathp
= gpath
; *gpathp
= 0;
66 lastgpathp
= &gpath
[BUFSIZ
- 2];
67 ginit(agargv
); globcnt
= 0;
69 tprintf("TRACE- glob()\n");
72 printf("glob entered: "); blkpr(v
); printf("\n");
74 noglob
= adrof(S_noglob
/* "noglob" */) != 0;
75 nonomatch
= adrof(S_nonomatch
/* "nonomatch" */) != 0;
76 globcnt
= noglob
| nonomatch
;
80 printf("glob done, globcnt=%d, gflag=%d: ", globcnt
, gflag
);
81 blkpr(gargv
); printf("\n");
83 if (globcnt
== 0 && (gflag
&1)) {
84 blkfree(gargv
), gargv
= 0;
87 return (gargv
= copyblk(gargv
));
94 agargv
[0] = 0; gargv
= agargv
; sortbas
= agargv
; gargc
= 0;
104 tprintf("TRACE- collect()\n");
108 printf("doing backp of %t\n", as
);
110 (void) dobackp(as
, 0);
112 printf("backp done, acollect'ing\n");
115 * dobackp has the side effect of messing with
116 * gflag, since it does more globbing, so check
117 * if the results is still globbable
121 for (i
= 0; i
< pargc
; i
++)
123 Gcat(pargv
[i
], S_
/* "" */);
124 sortbas
= &gargv
[gargc
];
128 blkfree(pargv
), pargv
= 0;
130 printf("acollect done\n");
132 } else if (noglob
|| eq(as
, S_LBRA
/* "{" */) ||
133 eq(as
, S_BRABRA
/* "{}" */)) {
134 Gcat(as
, S_
/* "" */);
146 tprintf("TRACE- acollect()\n");
148 gpathp
= gpath
; *gpathp
= 0; globbed
= 0;
150 if (gargc
== ogargc
) {
152 Gcat(as
, S_
/* "" */);
160 * String compare for qsort. Also used by filec code in sh.file.c.
163 sortscmp(tchar
**a1
, tchar
**a2
)
166 return (strcoll_(*a1
, *a2
));
173 tchar
*sgpathp
, *oldcs
;
177 tprintf("TRACE- expand()\n");
181 if (*cs
== '~' && gpathp
== gpath
) {
183 for (cs
++; alnum(*cs
) || *cs
== '-'; )
185 if (!*cs
|| *cs
== '/') {
186 if (gpathp
!= gpath
+ 1) {
188 if (gethdir(gpath
+ 1))
190 * modified from %s to %t
192 error("Unknown user: %t", gpath
+ 1);
193 (void) strcpy_(gpath
, gpath
+ 1);
195 (void) strcpy_(gpath
,
196 value(S_home
/* "home" */));
197 gpathp
= strend(gpath
);
200 while (!isglob(*cs
)) {
203 Gcat(gpath
, S_
/* "" */);
204 else if (lstat_(gpath
, &stb
) >= 0) {
205 Gcat(gpath
, S_
/* "" */);
213 while (cs
> as
&& *cs
!= '/')
219 (void) execbrc(cs
, NOSTR
);
229 matchdir_(tchar
*pattern
)
234 tchar curdir_
[MAXNAMLEN
+1];
238 tprintf("TRACE- matchdir()\n");
241 * BSD's opendir would open "." if argument is NULL, but not S5
245 dirp
= opendir_(S_DOT
/* "." */);
247 dirp
= opendir_(gpath
);
253 if (fstat(dirp
->dd_fd
, &stb
) < 0)
259 while ((dp
= readdir(dirp
)) != NULL
) {
263 strtots(curdir_
, dp
->d_name
);
265 if (match(curdir_
, pattern
, &slproc
)) {
266 Gcat(gpath
, curdir_
);
270 unsetfd(dirp
->dd_fd
);
275 unsetfd(dirp
->dd_fd
);
282 execbrc(tchar
*p
, tchar
*s
)
284 tchar restbuf
[BUFSIZ
+ 2];
287 tchar
*lm
, savec
, *sgpathp
;
291 tprintf("TRACE- execbrc()\n");
293 for (lm
= restbuf
; *p
!= '{'; *lm
++ = *p
++)
295 for (pe
= ++p
; *pe
; pe
++)
309 for (pe
++; *pe
&& *pe
!= ']'; pe
++)
318 for (pl
= pm
= p
; pm
<= pe
; pm
++)
319 switch (*pm
& (QUOTE
|TRIM
)) {
338 (void) strcpy_(lm
, pl
);
339 (void) strcat_(restbuf
, pe
+ 1);
346 } else if (amatch(s
, restbuf
, &slproc
))
353 for (pm
++; *pm
&& *pm
!= ']'; pm
++)
363 match(tchar
*s
, tchar
*p
, int *slproc
)
367 tchar sglobbed
= globbed
;
370 tprintf("TRACE- match()\n");
372 if (*s
== '.' && *p
!= '.')
376 c
= amatch(s
, p
, slproc
);
383 amatch(tchar
*s
, tchar
*p
, int *slproc
)
392 tprintf("TRACE- amatch()\n");
400 return (execbrc(p
- 1, s
- 1));
419 * Both ends of the char range
420 * must belong to the same codeset.
422 if (sh_bracket_exp(scc
, lc
, rc
))
425 if (lc
<= scc
&& scc
<= (int)*p
++)
429 if (scc
== (lc
= cc
))
442 } else if (*p
== '*') {
448 if (amatch(s
, p
, slproc
))
457 if ((c
& TRIM
) != scc
)
470 if (*slproc
) /* Need to expand "/" only once */
480 if (stat_(gpath
, &stb
) == 0 && isdir(stb
))
482 Gcat(gpath
, S_
/* "" */);
494 Gmatch(tchar
*s
, tchar
*p
)
501 tprintf("TRACE- Gmatch()\n");
520 * Both ends of the char range
521 * must belong to the same codeset...
523 if (sh_bracket_exp(scc
, lc
, rc
))
526 if (lc
<= scc
&& scc
<= (int)*p
++)
530 if (scc
== (lc
= cc
))
549 if ((c
& TRIM
) != scc
)
563 Gcat(tchar
*s1
, tchar
*s2
)
569 tprintf("TRACE- Gcat()\n");
575 gnleft
-= (n
= (p
- s1
) + (q
- s2
) - 1);
576 if (gnleft
<= 0 || ++gargc
>= GAVSIZ
)
577 error("Arguments too long");
579 p
= gargv
[gargc
- 1] = (tchar
*) xalloc((unsigned)n
*sizeof (tchar
));
581 for (q
= s1
; *p
++ = *q
++; )
583 for (p
--, q
= s2
; *p
++ = *q
++; )
592 tprintf("TRACE- addpath()\n");
594 if (gpathp
>= lastgpathp
)
595 error("Pathname too long");
596 *gpathp
++ = c
& TRIM
;
601 rscan(tchar
**t
, int (*f
)(int))
606 tprintf("TRACE- rscan()\n");
619 tprintf("TRACE- trim()\n");
632 tprintf("TRACE- tglob()\n");
637 else if (*p
== '{' && (p
[1] == '\0' ||
638 p
[1] == '}' && p
[2] == '\0'))
642 gflag
|= c
== '{' ? 2 : 1;
654 tprintf("TRACE- globone()\n");
675 if (cp
== 0 || *gvp
) {
677 bferr(cp
? "Ambiguous" : "No output");
680 xfree((char *)gargv
); gargv
= 0;
689 * Command substitute cp. If literal, then this is
690 * a substitution from a << redirection, and so we should
691 * not crunch blanks and tabs, separating words only at newlines.
694 dobackp(tchar
*cp
, bool literal
)
699 tchar
*apargv
[GAVSIZ
+ 2];
702 tprintf("TRACE- dobackp()\n");
709 pargcp
= pargs
= word
;
713 for (lp
= cp
; *lp
!= '`'; lp
++) {
718 printf("leaving dobackp\n");
720 return (pargv
= copyblk(pargv
));
725 for (rp
= lp
; *rp
&& *rp
!= '`'; rp
++)
733 error("Unmatched `");
736 backeval(ep
, literal
);
738 printf("back from backeval\n");
745 backeval(tchar
*cp
, bool literal
)
748 int quoted
= (literal
|| (cp
[0] & QUOTE
)) ? QUOTE
: 0;
749 tchar ibuf
[BUFSIZ
+ MB_LEN_MAX
]; /* read_ can return extra bytes */
754 struct command faket
;
757 tprintf("TRACE- backeval()\n");
764 faket
.t_dcom
= fakecom
;
765 fakecom
[0] = S_QPPPQ
; /* "` ... `" */;
768 * We do the psave job to temporarily change the current job
769 * so that the following fork is considered a separate job.
770 * This is so that when backquotes are used in a
771 * builtin function that calls glob the "current job" is not corrupted.
772 * We only need one level of pushed jobs as long as we are sure to
777 * It would be nicer if we could integrate this redirection more
778 * with the routines in sh.sem.c by doing a fake execute on a builtin
779 * function that was piped out.
782 if (pfork(&faket
, -1) == 0) {
783 struct wordent paraml
;
788 (void) close(pvec
[0]);
790 (void) dmove(pvec
[1], 1);
791 (void) dmove(SHDIAG
, 2);
797 * disable history subsitution in sub-shell
798 * of `` evaluation prevents possible
799 * infinite recursion of `` evaluation
806 error("%s", gettext(err
));
808 t
= syntax(paraml
.next
, ¶ml
, 0);
810 error("%s", gettext(err
));
813 (void) signal(SIGTSTP
, SIG_IGN
);
814 (void) signal(SIGTTIN
, SIG_IGN
);
815 (void) signal(SIGTTOU
, SIG_IGN
);
820 (void) close(pvec
[1]);
827 icnt
= read_(pvec
[0], ip
, BUFSIZ
);
841 * Continue around the loop one
842 * more time, so that we can eat
843 * the last newline without terminating
849 if (!quoted
&& issp(c
))
855 * Unless at end-of-file, we will form a new word
856 * here if there were characters in the word, or in
857 * any case when we take text literally. If
858 * we didn't make empty words here when literal was
859 * set then we would lose blank lines.
861 if (c
!= -1 && (cnt
|| literal
)) {
869 printf("done in backeval, pvec: %d %d\n", pvec
[0], pvec
[1]);
870 printf("also c = %c <%o>\n", (tchar
) c
, (tchar
) c
);
872 (void) close(pvec
[0]);
882 tprintf("TRACE- psave()\n");
886 error("Word too long");
894 tprintf("TRACE- pword()\n");
899 error("Too many words from ``");
900 pargv
[pargc
++] = savestr(pargs
);
901 pargv
[pargc
] = NOSTR
;
903 printf("got word %t\n", pargv
[pargc
-1]);
912 * returns pathname of the form dir/file;
913 * dir is a null-terminated string;
916 makename(char *dir
, char *file
)
919 * Maximum length of a
920 * file/dir name in ls-command;
921 * dfile is static as this is returned
924 static char dfile
[MAXNAMLEN
];
932 if (dp
> dfile
&& *(dp
- 1) != '/')
939 * dfile points to the absolute pathname. We are
940 * only interested in the last component.
942 return (rindex(dfile
, '/') + 1);
946 sh_bracket_exp(tchar t_ch
, tchar t_fch
, tchar t_lch
)
948 char t_char
[MB_LEN_MAX
+ 1];
949 char t_patan
[MB_LEN_MAX
* 2 + 8];
953 if ((t_ch
== t_fch
) || (t_ch
== t_lch
))
957 if ((i
= wctomb(t_char
, (wchar_t)t_ch
)) <= 0)
962 if ((i
= wctomb(p
, (wchar_t)t_fch
)) <= 0)
966 if ((i
= wctomb(p
, (wchar_t)t_lch
)) <= 0)
972 if (fnmatch(t_patan
, t_char
, FNM_NOESCAPE
))