sh.glob.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright 2001 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley Software License Agreement
* specifies the terms and conditions for redistribution.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "sh.h"
#include "sh.tconst.h"
#include <dirent.h>
#ifdef MBCHAR
#include <widec.h> /* wcsetno() */
#include <fnmatch.h> /* fnmatch() */
#endif /* MBCHAR */
/*
* C Shell
*/
int globcnt;
int globbed;
bool noglob;
bool nonomatch;
int sortscmp();
sizeof (*sortbas), (int (*)(const void *, \
tchar **
glob(v)
register tchar **v;
{
#ifdef TRACE
tprintf("TRACE- glob()\n");
#endif
#ifdef GDEBUG
#endif
while (*v)
collect(*v++);
#ifdef GDEBUG
#endif
return (0);
} else
}
{
}
{
register int i;
#ifdef TRACE
tprintf("TRACE- collect()\n");
#endif
#ifdef GDEBUG
#endif
#ifdef GDEBUG
printf("backp done, acollect'ing\n");
#endif
/*
* dobackp has the side effect of messing with
* gflag, since it does more globbing, so check
* if the results is still globbable
*/
for (i = 0; i < pargc; i++)
if (noglob) {
} else
if (pargv)
#ifdef GDEBUG
printf("acollect done\n");
#endif
sort();
} else
}
{
#ifdef TRACE
tprintf("TRACE- acollect()\n");
#endif
if (nonomatch) {
sort();
}
} else
sort();
}
/*
* String compare for qsort. Also used by filec code in sh.file.c.
*/
{
}
{
#ifdef TRACE
tprintf("TRACE- expand()\n");
#endif
addpath('~');
*gpathp = 0;
/*
* modified from %s to %t
*/
} else
}
}
if (*cs == 0) {
if (!globbed)
globcnt++;
}
goto endit;
}
}
if (*cs == '/')
*gpathp = 0;
if (*oldcs == '{') {
return;
}
*gpathp = 0;
}
{
int slproc = 0;
#ifdef TRACE
tprintf("TRACE- matchdir()\n");
#endif
/*
* BSD's opendir would open "." if argument is NULL, but not S5
*/
else
if (globbed)
return;
goto patherr2;
}
goto patherr1;
goto patherr1;
}
continue;
slproc = 0;
globcnt++;
}
}
return;
}
execbrc(p, s)
tchar *p, *s;
{
int brclev = 0;
int slproc = 0;
#ifdef TRACE
tprintf("TRACE- execbrc()\n");
#endif
continue;
switch (*pe) {
case '{':
brclev++;
continue;
case '}':
if (brclev == 0)
goto pend;
brclev--;
continue;
case '[':
continue;
if (!*pe)
error("Missing ]");
continue;
}
pend:
error("Missing }");
case '{':
brclev++;
continue;
case '}':
if (brclev) {
brclev--;
continue;
}
goto doit;
case ',':
if (brclev)
continue;
doit:
*pm = 0;
if (s == 0) {
*gpathp = 0;
return (1);
sort();
continue;
case '[':
continue;
if (!*pm)
error("Missing ]");
continue;
}
return (0);
}
tchar *s, *p;
int *slproc;
{
register int c;
#ifdef TRACE
tprintf("TRACE- match()\n");
#endif
if (*s == '.' && *p != '.')
return (0);
entp = s;
return (c);
}
register tchar *s, *p;
int *slproc;
{
register int scc;
int c, cc;
#ifdef TRACE
tprintf("TRACE- amatch()\n");
#endif
globbed = 1;
for (;;) {
switch (c = *p++) {
case '{':
case '[':
ok = 0;
while (cc = *p++) {
if (cc == ']') {
if (ok)
break;
return (0);
}
if (cc == '-') {
#ifdef MBCHAR
if (rc == ']') {
p--;
continue;
}
/*
* Both ends of the char range
* must belong to the same codeset.
*/
ok++;
#else /* !MBCHAR */
ok++;
#endif /* !MBCHAR */
} else
ok++;
}
if (cc == 0)
error("Missing ]");
continue;
case '*':
if (!*p)
return (1);
if (*p == '/') {
p++;
goto slash;
} else if (*p == '*') {
s--;
continue;
}
for (s--; *s; s++)
return (1);
return (0);
case 0:
return (scc == 0);
default:
return (0);
continue;
case '?':
if (scc == 0)
return (0);
continue;
case '/':
if (scc)
return (0);
if (*slproc) /* Need to expand "/" only once */
return (0);
else
*slproc = 1;
s = entp;
while (*s)
addpath(*s++);
addpath('/');
if (*p == 0) {
globcnt++;
} else
expand(p);
*gpathp = 0;
return (0);
}
}
}
Gmatch(s, p)
register tchar *s, *p;
{
register int scc;
int c, cc;
#ifdef TRACE
tprintf("TRACE- Gmatch()\n");
#endif
for (;;) {
switch (c = *p++) {
case '[':
ok = 0;
while (cc = *p++) {
if (cc == ']') {
if (ok)
break;
return (0);
}
if (cc == '-') {
#ifdef MBCHAR
/*
* Both ends of the char range
* must belong to the same codeset...
*/
ok++;
#else /* !MBCHAR */
ok++;
#endif /* !MBCHAR */
} else
ok++;
}
if (cc == 0)
bferr("Missing ]");
continue;
case '*':
if (!*p)
return (1);
for (s--; *s; s++)
if (Gmatch(s, p))
return (1);
return (0);
case 0:
return (scc == 0);
default:
return (0);
continue;
case '?':
if (scc == 0)
return (0);
continue;
}
}
}
{
register tchar *p, *q;
int n;
#ifdef TRACE
tprintf("TRACE- Gcat()\n");
#endif
for (p = s1; *p++; )
;
for (q = s2; *q++; )
;
error("Arguments too long");
for (q = s1; *p++ = *q++; )
;
for (p--, q = s2; *p++ = *q++; )
;
}
addpath(c)
tchar c;
{
#ifdef TRACE
tprintf("TRACE- addpath()\n");
#endif
if (gpathp >= lastgpathp)
error("Pathname too long");
*gpathp = 0;
}
rscan(t, f)
register tchar **t;
int (*f)();
{
register tchar *p;
#ifdef TRACE
tprintf("TRACE- rscan()\n");
#endif
while (p = *t++)
while (*p)
(*f)(*p++);
}
trim(t)
register tchar **t;
{
register tchar *p;
#ifdef TRACE
tprintf("TRACE- trim()\n");
#endif
while (p = *t++)
while (*p)
*p++ &= TRIM;
}
tglob(t)
register tchar **t;
{
register tchar *p, c;
#ifdef TRACE
tprintf("TRACE- tglob()\n");
#endif
while (p = *t++) {
if (*p == '~')
gflag |= 2;
else if (*p == '{' && (p[1] == '\0' ||
p[1] == '}' && p[2] == '\0'))
continue;
while (c = *p++)
if (isglob(c))
}
}
tchar *
{
#ifdef TRACE
tprintf("TRACE- globone()\n");
#endif
gv[1] = 0;
gflag = 0;
if (gflag) {
if (gvp == 0) {
bferr("No match");
}
if (cp == 0)
else if (*gvp) {
bferr("Ambiguous");
} else
/*
if (cp == 0 || *gvp) {
setname(str);
bferr(cp ? "Ambiguous" : "No output");
}
*/
} else {
}
return (cp);
}
/*
* Command substitute cp. If literal, then this is
* a substitution from a << redirection, and so we should
* not crunch blanks and tabs, separating words only at newlines.
*/
tchar **
bool literal;
{
#ifdef TRACE
tprintf("TRACE- dobackp()\n");
#endif
if (pargv) {
}
pargc = 0;
for (;;) {
if (*lp == 0) {
pword();
#ifdef GDEBUG
printf("leaving dobackp\n");
#endif
}
}
lp++;
if (*rp == '\\') {
rp++;
if (!*rp)
goto oops;
}
if (!*rp)
oops:
error("Unmatched `");
#ifdef GDEBUG
printf("back from backeval\n");
#endif
}
}
bool literal;
{
int pvec[2];
register int icnt = 0, c;
bool hadnl = 0;
#ifdef TRACE
tprintf("TRACE- backeval()\n");
#endif
fakecom[1] = 0;
/*
* We do the psave job to temporarily change the current job
* so that the following fork is considered a separate job.
* This is so that when backquotes are used in a
* builtin function that calls glob the "current job" is not corrupted.
* We only need one level of pushed jobs as long as we are sure to
* fork here.
*/
psavejob();
/*
* It would be nicer if we could integrate this redirection more
* with the routines in sh.sem.c by doing a fake execute on a builtin
* function that was piped out.
*/
struct command *t;
new_process();
reinitdesc(0, NULL);
while (*cp)
/*
* disable history subsitution in sub-shell
* of `` evaluation prevents possible
* infinite recursion of `` evaluation
*/
HIST = 0;
if (err)
if (err)
if (t)
execute(t, -1);
exitstat();
}
do {
int cnt = 0;
for (;;) {
if (icnt == 0) {
if (icnt <= 0) {
c = -1;
break;
}
}
if (hadnl)
break;
--icnt;
if (c == 0)
break;
if (c == '\n') {
/*
* Continue around the loop one
* more time, so that we can eat
* the last newline without terminating
* this word.
*/
hadnl = 1;
continue;
}
break;
cnt++;
}
/*
* Unless at end-of-file, we will form a new word
* here if there were characters in the word, or in
* any case when we take text literally. If
* we didn't make empty words here when literal was
* set then we would lose blank lines.
*/
break;
pword();
}
hadnl = 0;
} while (c >= 0);
#ifdef GDEBUG
#endif
pwait();
prestjob();
}
psave(c)
tchar c;
{
#ifdef TRACE
tprintf("TRACE- psave()\n");
#endif
if (--pnleft <= 0)
error("Word too long");
*pargcp++ = c;
}
pword()
{
#ifdef TRACE
tprintf("TRACE- pword()\n");
#endif
psave(0);
error("Too many words from ``");
#ifdef GDEBUG
#endif
}
/*
* dir is a null-terminated string;
*/
char *
char *dir;
char *file;
{
/*
* Maximum length of a
* dfile is static as this is returned
* by makename();
*/
while (*fp)
*dp++ = '/';
while (*fp)
*dp = '\0';
/*
* dfile points to the absolute pathname. We are
* only interested in the last component.
*/
}
{
char *p;
int i;
return(1);
p = t_patan;
return(0);
t_char[i] = 0;
*p++ = '[';
return(0);
p += i;
*p++ = '-';
return(0);
p += i;
*p++ = ']';
*p = 0;
return(0);
return(1);
}