Initial revision
This commit is contained in:
parent
9e906af316
commit
1c94496bd8
462
bsd_src/glob.c
Normal file
462
bsd_src/glob.c
Normal file
|
|
@ -0,0 +1,462 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1980 Regents of the University of California.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms are permitted
|
||||||
|
* provided that the above copyright notice and this paragraph are
|
||||||
|
* duplicated in all such forms and that any documentation,
|
||||||
|
* advertising materials, and other materials related to such
|
||||||
|
* distribution and use acknowledge that the software was developed
|
||||||
|
* by the University of California, Berkeley. The name of the
|
||||||
|
* University may not be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* C-shell glob for random programs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tweak.h"
|
||||||
|
#include "client_def.h"
|
||||||
|
#include "c_extern.h"
|
||||||
|
#include "bsd_extern.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_LIMITS_H
|
||||||
|
#include <limits.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_SYSLIMITS_H
|
||||||
|
#include <sys/syslimits.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef STDC_HEADERS
|
||||||
|
#include <stdlib.h>
|
||||||
|
#endif
|
||||||
|
#include "my-string.h"
|
||||||
|
|
||||||
|
#ifndef NCARGS
|
||||||
|
#define NCARGS ARG_MAX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define QUOTE 0200
|
||||||
|
#define TRIM 0177
|
||||||
|
#define eq(a,b) (strcmp(a, b)==0)
|
||||||
|
#define GAVSIZ (NCARGS/6)
|
||||||
|
#define isdir(d) ((d.st_mode & S_IFMT) == S_IFDIR)
|
||||||
|
|
||||||
|
static char **gargv; /* Pointer to the (stack) arglist */
|
||||||
|
static int gargc; /* Number args in gargv */
|
||||||
|
static int gnleft;
|
||||||
|
static int gflag;
|
||||||
|
const char *globerr;
|
||||||
|
|
||||||
|
static int globcnt;
|
||||||
|
|
||||||
|
const char *globchars = "`{[*?";
|
||||||
|
|
||||||
|
static char *gpath, *gpathp, *lastgpathp;
|
||||||
|
static int globbed;
|
||||||
|
static char *entp;
|
||||||
|
static char **sortbas;
|
||||||
|
|
||||||
|
static int any PROTO2(register int, c, register const char *, s)
|
||||||
|
{
|
||||||
|
while (*s)
|
||||||
|
if (*s++ == c) return(1);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tglob PROTO1(char, c)
|
||||||
|
{
|
||||||
|
if (any(c, globchars))
|
||||||
|
gflag |= c == '{' ? 2 : 1;
|
||||||
|
return (c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int addpath PROTO1(char, c)
|
||||||
|
{
|
||||||
|
if (gpathp >= lastgpathp) globerr = "Pathname too long";
|
||||||
|
else {
|
||||||
|
*gpathp++ = c;
|
||||||
|
*gpathp = 0;
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ginit PROTO1(char **, agargv)
|
||||||
|
{
|
||||||
|
agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0;
|
||||||
|
gnleft = NCARGS - 4;
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sort PROTO0((void))
|
||||||
|
{
|
||||||
|
register char **p1, **p2, *c;
|
||||||
|
char **Gvp = &gargv[gargc];
|
||||||
|
|
||||||
|
p1 = sortbas;
|
||||||
|
while (p1 < Gvp-1) {
|
||||||
|
p2 = p1;
|
||||||
|
while (++p2 < Gvp)
|
||||||
|
if (strcmp(*p1, *p2) > 0) {
|
||||||
|
c = *p1;
|
||||||
|
*p1 = *p2;
|
||||||
|
*p2 = c;
|
||||||
|
}
|
||||||
|
p1++;
|
||||||
|
}
|
||||||
|
sortbas = Gvp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *strspl PROTO2(register char *, cp, register const char *, dp)
|
||||||
|
{
|
||||||
|
register char *ep = (char *)malloc((unsigned)(strlen(cp) + strlen(dp) + 1));
|
||||||
|
|
||||||
|
if (ep == (char *)0) {
|
||||||
|
perror("Out of memory 1");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
(void) strcpy(ep, cp);
|
||||||
|
(void) strcat(ep, dp);
|
||||||
|
return (ep);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int Gcat PROTO2(char *, s1, const char *, s2)
|
||||||
|
{
|
||||||
|
register int len = strlen(s1) + strlen(s2) + 1;
|
||||||
|
|
||||||
|
if (len >= gnleft || gargc >= GAVSIZ - 1) globerr = "Arguments too long";
|
||||||
|
else {
|
||||||
|
gargc++;
|
||||||
|
gnleft -= len;
|
||||||
|
gargv[gargc] = 0;
|
||||||
|
gargv[gargc - 1] = strspl(s1, s2);
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int execbrc PROTO0((char *, char *));
|
||||||
|
void matchdir PROTO0((char *));
|
||||||
|
|
||||||
|
static void expand PROTO1(char *, as)
|
||||||
|
{
|
||||||
|
register char *cs;
|
||||||
|
register char *sgpathp, *oldcs;
|
||||||
|
struct stat stb;
|
||||||
|
|
||||||
|
sgpathp = gpathp;
|
||||||
|
cs = as;
|
||||||
|
while (!any(*cs, globchars)) {
|
||||||
|
if (*cs == 0) {
|
||||||
|
if (!globbed) Gcat(gpath, "");
|
||||||
|
else if (util_stat(gpath, &stb) >= 0) {
|
||||||
|
Gcat(gpath, "");
|
||||||
|
globcnt++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
addpath(*cs++);
|
||||||
|
}
|
||||||
|
if(*cs) {
|
||||||
|
oldcs = cs;
|
||||||
|
while (cs > as && *cs != '/') {
|
||||||
|
cs--; gpathp--;
|
||||||
|
}
|
||||||
|
if (*cs == '/') {
|
||||||
|
cs++; gpathp++;
|
||||||
|
}
|
||||||
|
*gpathp = 0;
|
||||||
|
if (*oldcs == '{') {
|
||||||
|
(void) execbrc(cs, ((char *)0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
matchdir(cs);
|
||||||
|
}
|
||||||
|
gpathp = sgpathp;
|
||||||
|
*gpathp = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int amatch PROTO2(char *, s, char *, p)
|
||||||
|
{
|
||||||
|
register int scc;
|
||||||
|
int ok, lc;
|
||||||
|
char *sgpathp;
|
||||||
|
struct stat stb;
|
||||||
|
int c, cc;
|
||||||
|
|
||||||
|
globbed = 1;
|
||||||
|
for (;;) {
|
||||||
|
scc = *s++ & TRIM;
|
||||||
|
switch (c = *p++) {
|
||||||
|
case '{':
|
||||||
|
return (execbrc(p - 1, s - 1));
|
||||||
|
case '[':
|
||||||
|
ok = 0;
|
||||||
|
lc = 077777;
|
||||||
|
while ( (cc = *p++) ) {
|
||||||
|
if (cc == ']') {
|
||||||
|
if (ok) break;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
if (cc == '-') {
|
||||||
|
if (lc <= scc && scc <= *p++) ok++;
|
||||||
|
} else if (scc == (lc = cc)) ok++;
|
||||||
|
}
|
||||||
|
if (cc == 0) {
|
||||||
|
if (ok) p--;
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
case '*':
|
||||||
|
if (!*p) return (1);
|
||||||
|
if (*p == '/') {
|
||||||
|
p++;
|
||||||
|
goto slash;
|
||||||
|
}
|
||||||
|
s--;
|
||||||
|
do {
|
||||||
|
if (amatch(s, p)) return (1);
|
||||||
|
} while (*s++);
|
||||||
|
return (0);
|
||||||
|
case 0:
|
||||||
|
return (scc == 0);
|
||||||
|
default:
|
||||||
|
if (c != scc) return (0);
|
||||||
|
continue;
|
||||||
|
case '?':
|
||||||
|
if (scc == 0) return (0);
|
||||||
|
continue;
|
||||||
|
case '/':
|
||||||
|
if (scc) return (0);
|
||||||
|
slash:
|
||||||
|
s = entp;
|
||||||
|
sgpathp = gpathp;
|
||||||
|
while (*s) addpath(*s++);
|
||||||
|
addpath('/');
|
||||||
|
if (util_stat(gpath, &stb) == 0 && isdir(stb))
|
||||||
|
{
|
||||||
|
if (*p == 0) {
|
||||||
|
Gcat(gpath, "");
|
||||||
|
globcnt++;
|
||||||
|
} else expand(p);
|
||||||
|
}
|
||||||
|
gpathp = sgpathp;
|
||||||
|
*gpathp = 0;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int match PROTO2(char *, s, char *, p)
|
||||||
|
{
|
||||||
|
register int c;
|
||||||
|
register char *sentp;
|
||||||
|
char sglobbed = globbed;
|
||||||
|
|
||||||
|
if (*s == '.' && *p != '.') return (0);
|
||||||
|
sentp = entp;
|
||||||
|
entp = s;
|
||||||
|
c = amatch(s, p);
|
||||||
|
entp = sentp;
|
||||||
|
globbed = sglobbed;
|
||||||
|
return (c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void matchdir PROTO1(char *, pattern)
|
||||||
|
{
|
||||||
|
struct stat stb;
|
||||||
|
register struct rdirent *dp;
|
||||||
|
RDIR *dirp;
|
||||||
|
|
||||||
|
dirp = util_opendir(gpath);
|
||||||
|
if (dirp == NULL) {
|
||||||
|
if (globbed) return;
|
||||||
|
globerr = "Bad directory components";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (util_stat(gpath, &stb) < 0) {
|
||||||
|
util_closedir(dirp);
|
||||||
|
globerr = "Bad directory components";
|
||||||
|
}
|
||||||
|
if (!isdir(stb)) {
|
||||||
|
errno = ENOTDIR;
|
||||||
|
util_closedir(dirp);
|
||||||
|
globerr = "Bad directory components";
|
||||||
|
}
|
||||||
|
while ((dp = util_readdir(dirp)) != NULL) {
|
||||||
|
if (dp->d_fileno == 0) continue;
|
||||||
|
if (match(dp->d_name, pattern)) {
|
||||||
|
Gcat(gpath, dp->d_name);
|
||||||
|
globcnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
util_closedir(dirp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int execbrc PROTO2(char *, p, char *, s)
|
||||||
|
{
|
||||||
|
char restbuf[BUFSIZ + 2];
|
||||||
|
register char *pe, *pm, *pl;
|
||||||
|
int brclev = 0;
|
||||||
|
char *lm, savec, *sgpathp;
|
||||||
|
|
||||||
|
for (lm = restbuf; *p != '{'; *lm++ = *p++);
|
||||||
|
for (pe = ++p; *pe; pe++)
|
||||||
|
switch (*pe) {
|
||||||
|
case '{':
|
||||||
|
brclev++;
|
||||||
|
continue;
|
||||||
|
case '}':
|
||||||
|
if (brclev == 0) goto pend;
|
||||||
|
brclev--;
|
||||||
|
continue;
|
||||||
|
case '[':
|
||||||
|
for (pe++; *pe && *pe != ']'; pe++);
|
||||||
|
}
|
||||||
|
pend:
|
||||||
|
brclev = 0;
|
||||||
|
for (pl = pm = p; pm <= pe; pm++)
|
||||||
|
switch (*pm & (QUOTE|TRIM)) {
|
||||||
|
case '{':
|
||||||
|
brclev++;
|
||||||
|
continue;
|
||||||
|
case '}':
|
||||||
|
if (brclev) {
|
||||||
|
brclev--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
goto doit;
|
||||||
|
case ','|QUOTE:
|
||||||
|
case ',':
|
||||||
|
if (brclev) continue;
|
||||||
|
doit:
|
||||||
|
savec = *pm;
|
||||||
|
*pm = 0;
|
||||||
|
(void) strcpy(lm, pl);
|
||||||
|
(void) strcat(restbuf, pe + 1);
|
||||||
|
*pm = savec;
|
||||||
|
if (s == 0) {
|
||||||
|
sgpathp = gpathp;
|
||||||
|
expand(restbuf);
|
||||||
|
gpathp = sgpathp;
|
||||||
|
*gpathp = 0;
|
||||||
|
} else if (amatch(s, restbuf)) return (1);
|
||||||
|
sort();
|
||||||
|
pl = pm + 1;
|
||||||
|
if (brclev) return (0);
|
||||||
|
continue;
|
||||||
|
case '[':
|
||||||
|
for (pm++; *pm && *pm != ']'; pm++);
|
||||||
|
if (!*pm) pm--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (brclev) goto doit;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void acollect PROTO1(register char *, as)
|
||||||
|
{
|
||||||
|
register int ogargc = gargc;
|
||||||
|
|
||||||
|
gpathp = gpath; *gpathp = 0; globbed = 0;
|
||||||
|
expand(as);
|
||||||
|
if (gargc != ogargc) sort();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void collect PROTO1(register char *, as)
|
||||||
|
{
|
||||||
|
if (eq(as, "{") || eq(as, "{}")) {
|
||||||
|
Gcat(as, "");
|
||||||
|
sort();
|
||||||
|
} else acollect(as);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void blkfree PROTO1(char **, av0)
|
||||||
|
{
|
||||||
|
register char **av = av0;
|
||||||
|
|
||||||
|
while (*av) free(*av++);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int blklen PROTO1(register char **, av)
|
||||||
|
{
|
||||||
|
register int i = 0;
|
||||||
|
|
||||||
|
while (*av++) i++;
|
||||||
|
return (i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char **blkcpy PROTO2(char **, oav, register char **, bv)
|
||||||
|
{
|
||||||
|
register char **av = oav;
|
||||||
|
|
||||||
|
while ( (*av++ = *bv++) ) continue;
|
||||||
|
return (oav);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char **copyblk PROTO1(register char **, v)
|
||||||
|
{
|
||||||
|
register char **nv;
|
||||||
|
|
||||||
|
nv = (char **)malloc((unsigned)((blklen(v) + 1) * sizeof(char **)));
|
||||||
|
if (nv == (char **)0) {
|
||||||
|
perror("Out of memory 2");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
return (blkcpy(nv, v));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PROTOTYPES
|
||||||
|
typedef int (*charfunc) (char) ;
|
||||||
|
static void rscan (register char **t, charfunc f)
|
||||||
|
#else
|
||||||
|
static void rscan(t, f)
|
||||||
|
register char **t;
|
||||||
|
int (*f)();
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
register char *p, c;
|
||||||
|
|
||||||
|
while ((p = *t++)) {
|
||||||
|
#ifdef PROTOTYPES
|
||||||
|
if (f == (charfunc) tglob)
|
||||||
|
#else
|
||||||
|
if (f == tglob)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (*p == '~') gflag |= 2;
|
||||||
|
else if (eq(p, "{") || eq(p, "{}")) continue;
|
||||||
|
}
|
||||||
|
while ( (c = *p++) ) (*f)(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char **glob PROTO1(register char *, v)
|
||||||
|
{
|
||||||
|
char agpath[BUFSIZ];
|
||||||
|
char *agargv[GAVSIZ];
|
||||||
|
char *vv[2];
|
||||||
|
vv[0] = v;
|
||||||
|
vv[1] = 0;
|
||||||
|
gflag = 0;
|
||||||
|
#ifdef PROTOTYPES
|
||||||
|
rscan(vv, (charfunc) tglob);
|
||||||
|
#else
|
||||||
|
rscan(vv, tglob);
|
||||||
|
#endif
|
||||||
|
if (gflag == 0) return (copyblk(vv));
|
||||||
|
|
||||||
|
globerr = 0;
|
||||||
|
gpath = agpath; gpathp = gpath; *gpathp = 0;
|
||||||
|
lastgpathp = &gpath[sizeof agpath - 2];
|
||||||
|
ginit(agargv); globcnt = 0;
|
||||||
|
collect(v);
|
||||||
|
if (globcnt == 0 && (gflag&1)) {
|
||||||
|
blkfree(gargv), gargv = 0;
|
||||||
|
return (0);
|
||||||
|
} else return (gargv = copyblk(gargv));
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user