V9/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 14
#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;
{
int i;
DIR dirbuf, *dirp;
register char *p;
struct stat st;
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, &st)!=0 || (st.st_mode & S_IFMT)!=S_IFDIR){
close(dirbuf.dd_fd);
return(NULL);
}
dirp = (DIR *)shalloc(sizeof(DIR));
*dirp = dirbuf;
dirp->dd_loc = 0;
i = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ);
if(i <= 0) {
close(dirp->dd_fd);
free(dirp);
return(0);
}
lseek(dirp->dd_fd, 0L, 0);
/* the cray and the 68000 are big-endians, vax is not
v9: ??.0000000000000??..000000000000|||||||||
cray: ????????.00000000000000000000000????????..0000000000000000000000|||||||
68k: ????0X01.000????0X02..00|||||||| X=12
vaxn: ????X010.000????X020..00|||||||
/* shortest cray sys v dir is 64 bytes, shortest v8 is 32, and shortest
* sun 4.2(68k) is 24 (except it's supposed to be a whole block long)
*/
if(i < 24) /* mysteriously short directory */
goto old;
p = dirp->dd_buf;
if(p[8] != '.') {
old:
if (fstat(dirp->dd_fd, &st) < 0) {
close(dirp->dd_fd);
free(dirp);
return(0);
}
if (st.st_ino == *(ino_t *)dirp->dd_buf)
dirp->dd_type = TOLD;
else
dirp->dd_type = TOLDSWAP;
return(dirp);
}
if(p[20] == '.' && p[21] == '.') { /* bsd-like or bogus */
if(*(short *)&p[4] == 0x000c) {
dirp->dd_type = TBSD;
return(dirp);
}
if(*(short *)&p[4] == 0x0c00) {
dirp->dd_type = TBSDSWAP;
return(dirp);
}
dirp->dd_type = TUNK;
return(dirp);
}
if(i >= 32 && p[9] == 0 && p[40] == '.' && p[41] == '.' && p[42] == 0) {
dirp->dd_type = TCRAY;
return(dirp);
}
dirp->dd_type = TUNK;
return(dirp);
}
void
closedir(dirp)
DIR *dirp;
{
close(dirp->dd_fd);
shfree((char *)dirp);
}