2021-10-11 18:37:13 -03:00

365 lines
5.3 KiB
C

/* Copyright (c) 1984 AT&T */
/* All Rights Reserved */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
/* The copyright notice above does not evidence any */
/* actual or intended publication of such source code. */
#ifndef lint
static char sccsid[] = "@(#)expand.c 1.1 94/10/31 SMI"; /* from S5R3 1.15 */
#endif
/*
* UNIX shell
*
*/
#include "defs.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.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.
*
*/
extern int addg();
expand(as, rcnt)
char *as;
{
int count;
DIR *dirf;
BOOL dir = 0;
char *rescan = 0;
char *slashsav = 0;
register char *s, *cs;
int quotflag = 0;
int quotflag2 = 0;
char *s2 = 0;
struct argnod *schain = gchain;
struct stat statb;
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;
case '\\':
cs++;
default:
continue;
}
break;
} while (TRUE);
}
for (;;)
{
if (cs == s)
{
s = nullstr;
break;
}
else if (*--cs == '/')
{
cs--;
if(cs >= s && *cs == '\\') {
*cs = 0; /* null out backslash before / */
slash++; /* increment slash count because
slash will be unquoted in expansion
string */
quotflag = 1;
} else
*++cs = 0;
if (s == cs)
s = "/";
else {
s2 = cpystak(s);
trim(s2);
s = s2;
}
break;
}
}
if ((dirf = opendir(*s ? s : ".")) != 0)
dir++;
/* Let s point to original string because it will be trimmed later */
if(s2)
s = as;
count = 0;
if (*cs == 0) {
slashsav = cs++; /* remember where first slash in as is */
if(quotflag)
cs++; /* advance past / */
}
if (dir) /* check for rescan */
{
register char *rs;
struct dirent *e;
rs = cs;
do /* find next / in as */
{
if (*rs == '/')
{
if(*--rs != '\\') {
rescan = ++rs;
*rs = 0;
} else {
quotflag2 = 1;
*rs = 0;
rescan = rs + 1; /* advance past / */
}
gchain = 0;
}
} while (*rs++);
if (setjmp(INTbuf) == 0)
trapjmp = 1;
while ((e = readdir(dirf)) && (trapnote & SIGSET) == 0)
{
if (e->d_name[0] == '.' && *cs != '.')
continue;
if (gmatch(e->d_name, cs))
{
addg(s, e->d_name, rescan, slashsav);
count++;
}
}
(void)closedir(dirf);
trapjmp = 0;
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;
}
}
if(quotflag2)
*--rescan = '\\';
else
*rescan = '/';
}
}
if(slashsav) {
if(quotflag)
*slashsav = '\\';
else
*slashsav = '/';
}
return(count);
}
gmatch(s, p)
register unsigned char *s, *p;
{
register unsigned char scc;
unsigned char c;
scc = *s++;
switch (c = *p++)
{
case '[':
{
BOOL ok;
int lc = -1;
int notflag = 0;
ok = 0;
if (*p == '!')
{
notflag = 1;
p++;
}
while (c = *p++)
{
if (c == ']')
return(ok ? gmatch(s, p) : 0);
else if (c == MINUS && lc > 0 && *p!= ']')
{
if (notflag)
{
if (scc < lc || scc > *(p++))
ok++;
else
return(0);
}
else
{
if (lc <= scc && scc <= (*p++))
ok++;
}
}
else
{
if(c == '\\') /* skip to quoted character */
c = *p++;
lc = c;
if (notflag)
{
if (scc && scc != lc)
ok++;
else
return(0);
}
else
{
if (scc == lc)
ok++;
}
}
}
return(0);
}
case '\\':
c = *p++; /* skip to quoted character and see if it matches */
default:
if (c != 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 int
addg(as1, as2, as3, as4)
char *as1, *as2, *as3, *as4;
{
register char *s1, *s2;
register int c;
s2 = locstak() + BYTESPERWORD;
s1 = as1;
if(as4) {
while (c = *s1++)
{
if (s2 >= brkend)
growstak(s2);
*s2++ = c;
}
/* Restore first slash before the first metacharacter if as1 is not "/" */
if(as4 + 1 == s1) {
if (s2 >= brkend)
growstak(s2);
*s2++ = '/';
}
}
/* add matched entries, plus extra \\ to escape \\'s */
s1 = as2;
for (;;)
{
if (s2 >= brkend)
growstak(s2);
if ((*s2 = *s1++) == 0)
break;
if(*s2 == '\\') {
s2++;
if (s2 >= brkend)
growstak(s2);
*s2 = '\\';
}
s2++;
}
if (s1 = as3)
{
if (s2 >= brkend)
growstak(s2);
*s2++ = '/';
do
{
if (s2 >= brkend)
growstak(s2);
}
while (*s2++ = *++s1);
}
makearg(endstak(s2));
}
makearg(args)
register struct argnod *args;
{
args->argnxt = gchain;
gchain = args;
}