V10/cmd/sh/expand.c
/* @(#)expand.c 1.4 */
/*
* UNIX shell
*
* Bell Telephone Laboratories
*
*/
#include "defs.h"
#include <sys/types.h>
#include <sys/stat.h>
#ifndef BSD4_2
#include <ndir.h>
#else
#include <sys/dir.h>
#endif
#ifdef BSD4_2
#define DIRSIZE MAXNAMELEN
#else
#define DIRSIZE 255
#endif
#ifndef MAXNAMELEN
#define MAXNAMELEN 255
#endif
static char entry[DIRSIZE+1];
/*
* globals (file name generation)
*
* "*" in params matches r.e ".*"
* "?" in params matches r.e. "."
* "[...]" in params matches character class
* "[...a-z...]" in params matches a through z.
*
*/
static addg();
expand(as, rcnt)
char *as;
{
int count;
DIR *dirf;
BOOL dir = 0;
char *rescan = 0;
register char *s, *cs;
struct argnod *schain = gchain;
BOOL slash;
if (trapnote & SIGSET)
return(0);
s = cs = as;
/*
* check for meta chars
*/
{
register BOOL open;
slash = 0;
open = 0;
do
{
switch (*cs++)
{
case 0:
if (rcnt && slash)
break;
else
return(0);
case '/':
slash++;
open = 0;
continue;
case '[':
open++;
continue;
case ']':
if (open == 0)
continue;
case '?':
case '*':
if (rcnt > slash)
continue;
else
cs--;
break;
default:
continue;
}
break;
} while (TRUE);
}
for (;;)
{
if (cs == s)
{
s = nullstr;
break;
}
else if (*--cs == '/')
{
*cs = 0;
if (s == cs)
s = "/";
break;
}
}
if ((dirf = opendir(*s ? s : ".")) != 0)
dir = TRUE;
count = 0;
if (*cs == 0)
*cs++ = 0200;
if(dir)
{
register char *rs;
struct direct *e;
rs = cs;
do
{
if (*rs == '/')
{
rescan = rs;
*rs = 0;
gchain = 0;
}
} while (*rs++);
while ((e = readdir(dirf)) && (trapnote & SIGSET) == 0)
{
*(movstrn(e->d_name, entry, DIRSIZE)) = 0;
if (entry[0] == '.' && *cs != '.')
{
if (entry[1] == 0)
continue;
if (entry[1] == '.' && entry[2] == 0)
continue;
}
if (gmatch(entry, cs))
{
addg(s, entry, rescan);
count++;
}
}
closedir(dirf);
if (rescan)
{
register struct argnod *rchain;
rchain = gchain;
gchain = schain;
if (count)
{
count = 0;
while (rchain)
{
count += expand(rchain->argval, slash + 1);
rchain = rchain->argnxt;
}
}
*rescan = '/';
}
}
{
register char c;
s = as;
while (c = *s)
*s++ = (c & STRIP ? c : '/');
}
return(count);
}
gmatch(s, p)
register char *s, *p;
{
register int scc;
char c;
if (scc = *s++)
{
if ((scc &= STRIP) == 0)
scc=0200;
}
switch (c = *p++)
{
case '[':
{
BOOL ok;
int lc;
int notflag = 0;
ok = 0;
lc = 077777;
if (*p == '^')
{
notflag = 1;
p++;
}
while (c = *p++)
{
if (c == ']')
return(ok ? gmatch(s, p) : 0);
else if (c == MINUS)
{
if (notflag)
{
if (scc < lc || scc > *(p++))
ok++;
else
return(0);
}
else
{
if (lc <= scc && scc <= (*p++))
ok++;
}
}
else
{
lc = c & STRIP;
if (notflag)
{
if (scc && scc != lc)
ok++;
else
return(0);
}
else
{
if (scc == lc)
ok++;
}
}
}
return(0);
}
default:
if ((c & STRIP) != scc)
return(0);
case '?':
return(scc ? gmatch(s, p) : 0);
case '*':
while (*p == '*')
p++;
if (*p == 0)
return(1);
--s;
while (*s)
{
if (gmatch(s++, p))
return(1);
}
return(0);
case 0:
return(scc == 0);
}
}
static
addg(as1, as2, as3)
char *as1, *as2, *as3;
{
register char *s1;
register int c;
staktop = locstak() + BYTESPERWORD;
s1 = as1;
while (c = *s1++)
{
if ((c &= STRIP) == 0)
{
pushstak('/');
break;
}
pushstak(c);
}
s1 = as2;
while (c = *s1++)
pushstak(c);
if (s1 = as3)
{
pushstak('/');
do
pushstak(*++s1);
while(*s1);
}
makearg(fixstak());
}
makearg(args)
register struct argnod *args;
{
args->argnxt = gchain;
gchain = args;
}
DIR *
opendir(name)
register char *name;
{
DIR dirbuf, *dirp;
struct stat statb;
char buf[MAXNAMELEN+1];
register char *s;
*(movstrn(name, buf, MAXNAMELEN)) = 0;
for (s=buf; *s; s++)
*s &= STRIP;
if ((dirbuf.dd_fd = open(buf, 0)) < 0)
return(NULL);
if (fstat(dirbuf.dd_fd, &statb)!=0 || (statb.st_mode & S_IFMT)!=S_IFDIR){
close(dirbuf.dd_fd);
return(NULL);
}
dirbuf.dd_size = dirbuf.dd_loc = 0;
dirp = (DIR *)shalloc(sizeof(DIR));
*dirp = dirbuf;
return(dirp);
}
void
closedir(dirp)
DIR *dirp;
{
close(dirp->dd_fd);
shfree((char *)dirp);
}