diff options
Diffstat (limited to 'usr/src/cmd/sh/expand.c')
| -rw-r--r-- | usr/src/cmd/sh/expand.c | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/usr/src/cmd/sh/expand.c b/usr/src/cmd/sh/expand.c new file mode 100644 index 0000000000..f5bfea5bd1 --- /dev/null +++ b/usr/src/cmd/sh/expand.c @@ -0,0 +1,292 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1995 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +#pragma ident "%Z%%M% %I% %E% SMI" +/* + * 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. + * + */ +static int addg(); + +expand(as, rcnt) + unsigned char *as; +{ + int count; + DIR *dirf; + BOOL dir = 0; + unsigned char *rescan = 0; + unsigned char *slashsav = 0; + register unsigned char *s, *cs; + unsigned char *s2 = 0; + struct argnod *schain = gchain; + BOOL slash; + int len; + wchar_t wc; + + if (trapnote & SIGSET) + return (0); + s = cs = as; + /* + * check for meta chars + */ + { + register BOOL open; + + slash = 0; + open = 0; + do + { + if ((len = mbtowc(&wc, (char *)cs, MB_LEN_MAX)) <= 0) { + len = 1; + wc = (unsigned char)*cs; + } + + cs += len; + switch (wc) { + 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 = (unsigned char *)nullstr; + break; + } else if (*--cs == '/') + { + *cs = 0; + if (s == cs) + s = (unsigned char *)"/"; + else { + /* + * push trimmed copy of directory prefix + * onto stack + */ + s2 = cpystak(s); + trim(s2); + s = s2; + } + break; + } + } + + if ((dirf = opendir(*s ? (char *)s : (char *)".")) != 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 */ + + /* check for rescan */ + if (dir) + { + register unsigned char *rs; + struct dirent *e; + + rs = cs; + do /* find next / in as */ + { + if (*rs == '/') + { + rescan = rs; + *rs = 0; + gchain = 0; + } + } while (*rs++); + + 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); + + 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 = '/'; + } + } + + if (slashsav) + *slashsav = '/'; + return (count); +} + +static int +addg(as1, as2, as3, as4) +unsigned char *as1, *as2, *as3, *as4; +{ + register unsigned char *s1, *s2; + register int c; + int len; + wchar_t wc; + + 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 ((len = mbtowc(&wc, (char *)s1, MB_LEN_MAX)) <= 0) { + len = 1; + wc = (unsigned char)*s1; + } + if (s2 >= brkend) + growstak(s2); + + if (wc == 0) { + *s2 = *s1++; + break; + } + + if (wc == '\\') { + *s2++ = '\\'; + if (s2 >= brkend) + growstak(s2); + *s2++ = '\\'; + s1++; + continue; + } + if ((s2 + len) >= brkend) + growstak(s2 + len); + memcpy(s2, s1, len); + s2 += len; + s1 += len; + } + 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; +} |
