BSD 4_1c_2 development
[unix-history] / usr / src / bin / sh / expand.c
/* expand.c 4.1 82/05/07 */
#
/*
* UNIX shell
*
* S. R. Bourne
* Bell Telephone Laboratories
*
*/
#include "defs.h"
#include <sys/param.h>
#include <sys/stat.h>
#include <dir.h>
/* 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.
*
*/
PROC VOID addg();
INT expand(as,rflg)
STRING as;
{
INT count;
DIR *dirf;
BOOL dir=0;
STRING rescan = 0;
REG STRING s, cs;
ARGPTR schain = gchain;
struct direct *dp;
STATBUF statb;
IF trapnote&SIGSET THEN return(0); FI
s=cs=as;
/* check for meta chars */
BEGIN
REG BOOL slash; slash=0;
WHILE !fngchar(*cs)
DO IF *cs++==0
THEN IF rflg ANDF slash THEN break; ELSE return(0) FI
ELIF *cs=='/'
THEN slash++;
FI
OD
END
LOOP IF cs==s
THEN s=nullstr;
break;
ELIF *--cs == '/'
THEN *cs=0;
IF s==cs THEN s="/" FI
break;
FI
POOL
IF stat(s,&statb)>=0
ANDF (statb.st_mode&S_IFMT)==S_IFDIR
ANDF (dirf=opendir(s))>0
THEN dir++;
FI
count=0;
IF *cs==0 THEN *cs++=0200 FI
IF dir
THEN /* check for rescan */
REG STRING rs; rs=cs;
REP IF *rs=='/' THEN rescan=rs; *rs=0; gchain=0 FI
PER *rs++ DONE
WHILE (dp = readdir(dirf)) != NULL ANDF (trapnote&SIGSET) == 0
DO IF (*dp->d_name=='.' ANDF *cs!='.')
THEN continue;
FI
IF gmatch(dp->d_name, cs)
THEN addg(s,dp->d_name,rescan); count++;
FI
OD
closedir(dirf);
IF rescan
THEN REG ARGPTR rchain;
rchain=gchain; gchain=schain;
IF count
THEN count=0;
WHILE rchain
DO count += expand(rchain->argval,1);
rchain=rchain->argnxt;
OD
FI
*rescan='/';
FI
FI
BEGIN
REG CHAR c;
s=as;
WHILE c = *s
DO *s++=(c&STRIP?c:'/') OD
END
return(count);
}
gmatch(s, p)
REG STRING s, p;
{
REG INT scc;
CHAR c;
IF scc = *s++
THEN IF (scc &= STRIP)==0
THEN scc=0200;
FI
FI
SWITCH c = *p++ IN
case '[':
{BOOL ok; INT lc;
ok=0; lc=077777;
WHILE c = *p++
DO IF c==']'
THEN return(ok?gmatch(s,p):0);
ELIF c==MINUS
THEN IF lc<=scc ANDF scc<=(*p++) THEN ok++ FI
ELSE IF scc==(lc=(c&STRIP)) THEN ok++ FI
FI
OD
return(0);
}
default:
IF (c&STRIP)!=scc THEN return(0) FI
case '?':
return(scc?gmatch(s,p):0);
case '*':
IF *p==0 THEN return(1) FI
--s;
WHILE *s
DO IF gmatch(s++,p) THEN return(1) FI OD
return(0);
case 0:
return(scc==0);
ENDSW
}
LOCAL VOID addg(as1,as2,as3)
STRING as1, as2, as3;
{
REG STRING s1, s2;
REG INT c;
s2 = locstak()+BYTESPERWORD;
s1=as1;
WHILE c = *s1++
DO IF (c &= STRIP)==0
THEN *s2++='/';
break;
FI
*s2++=c;
OD
s1=as2;
WHILE *s2 = *s1++ DO s2++ OD
IF s1=as3
THEN *s2++='/';
WHILE *s2++ = *++s1 DONE
FI
makearg(endstak(s2));
}
makearg(args)
REG STRING args;
{
args->argnxt=gchain;
gchain=args;
}