glob.c revision 22347
122347Spst/* glob.c: The csh et al glob pattern matching routines. 222347Spst 322347Spst%%% copyright-cmetz 422347SpstThis software is Copyright 1996 by Craig Metz, All Rights Reserved. 522347SpstThe Inner Net License Version 2 applies to this software. 622347SpstYou should have received a copy of the license with this software. If 722347Spstyou didn't get a copy, you may request one from <license@inner.net>. 822347Spst 922347SpstPortions of this software are Copyright 1995 by Randall Atkinson and Dan 1022347SpstMcDonald, All Rights Reserved. All Rights under this copyright are assigned 1122347Spstto the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and 1222347SpstLicense Agreement applies to this software. 1322347Spst 1422347Spst History: 1522347Spst 1622347Spst Modified by cmetz for OPIE 2.2. Use FUNCTION declaration et al. 1722347Spst Remove useless strings. Prototype right. 1822347Spst Modified at NRL for OPIE 2.0. 1922347Spst Originally from BSD. 2022347Spst*/ 2122347Spst/* 2222347Spst * Copyright (c) 1980 Regents of the University of California. 2322347Spst * All rights reserved. 2422347Spst * 2522347Spst * Redistribution and use in source and binary forms, with or without 2622347Spst * modification, are permitted provided that the following conditions 2722347Spst * are met: 2822347Spst * 1. Redistributions of source code must retain the above copyright 2922347Spst * notice, this list of conditions and the following disclaimer. 3022347Spst * 2. Redistributions in binary form must reproduce the above copyright 3122347Spst * notice, this list of conditions and the following disclaimer in the 3222347Spst * documentation and/or other materials provided with the distribution. 3322347Spst * 3. All advertising materials mentioning features or use of this software 3422347Spst * must display the following acknowledgement: 3522347Spst * This product includes software developed by the University of 3622347Spst * California, Berkeley and its contributors. 3722347Spst * 4. Neither the name of the University nor the names of its contributors 3822347Spst * may be used to endorse or promote products derived from this software 3922347Spst * without specific prior written permission. 4022347Spst * 4122347Spst * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 4222347Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4322347Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4422347Spst * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 4522347Spst * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4622347Spst * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4722347Spst * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4822347Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4922347Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5022347Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5122347Spst * SUCH DAMAGE. 5222347Spst */ 5322347Spst 5422347Spst/* 5522347Spst * C-shell glob for random programs. 5622347Spst */ 5722347Spst 5822347Spst#include "opie_cfg.h" 5922347Spst 6022347Spst#if HAVE_SYS_PARAM_H 6122347Spst#include <sys/param.h> 6222347Spst#endif /* HAVE_SYS_PARAM_H */ 6322347Spst#include <sys/stat.h> 6422347Spst 6522347Spst#include <dirent.h> 6622347Spst#if HAVE_PWD_H 6722347Spst#include <pwd.h> 6822347Spst#endif /* HAVE_PWD_H */ 6922347Spst#include <errno.h> 7022347Spst#include <stdio.h> 7122347Spst#include <string.h> 7222347Spst#if HAVE_LIMITS_H 7322347Spst#include <limits.h> 7422347Spst#endif /* HAVE_LIMITS_H */ 7522347Spst 7622347Spst#include "opie.h" 7722347Spst 7822347Spst#ifndef NCARGS 7922347Spst#define NCARGS 600 8022347Spst#endif /* NCARGS */ 8122347Spst#define QUOTE 0200 8222347Spst#define TRIM 0177 8322347Spst#define eq(a,b) (strcmp((a),(b)) == (0)) 8422347Spst#define GAVSIZ (NCARGS/6) 8522347Spst#define isdir(d) (((d.st_mode) & S_IFMT) == S_IFDIR) 8622347Spst 8722347Spststatic char **gargv; /* Pointer to the (stack) arglist */ 8822347Spststatic int gargc; /* Number args in gargv */ 8922347Spststatic int gnleft; 9022347Spststatic short gflag; 9122347Spst 9222347Spststatic int letter __P((register char)); 9322347Spststatic int digit __P((register char)); 9422347Spststatic int any __P((int, char *)); 9522347Spststatic int blklen __P((register char **)); 9622347SpstVOIDRET blkfree __P((char **)); 9722347Spststatic char *strspl __P((register char *, register char *)); 9822347Spst 9922347Spststatic int tglob __P((register char c)); 10022347Spst 10122347Spstextern int errno; 10222347Spststatic char *strend __P((char *)); 10322347Spst 10422347Spststatic int globcnt; 10522347Spst 10622347Spststatic char *globchars = "`{[*?"; 10722347Spstchar *globerr = NULL; 10822347Spstchar *home = NULL; 10922347Spst 11022347Spststatic char *gpath, *gpathp, *lastgpathp; 11122347Spststatic int globbed; 11222347Spststatic char *entp; 11322347Spststatic char **sortbas; 11422347Spst 11522347Spststatic int amatch __P((char *p, char *s)); 11622347Spststatic int execbrc __P((register char *p, register char *s)); 11722347SpstVOIDRET opiefatal __P((char *)); 11822347Spstchar **copyblk __P((char **)); 11922347Spst 12022347Spststatic int match FUNCTION((s, p), char *s AND char *p) 12122347Spst{ 12222347Spst register int c; 12322347Spst register char *sentp; 12422347Spst char sglobbed = globbed; 12522347Spst 12622347Spst if (*s == '.' && *p != '.') 12722347Spst return (0); 12822347Spst sentp = entp; 12922347Spst entp = s; 13022347Spst c = amatch(s, p); 13122347Spst entp = sentp; 13222347Spst globbed = sglobbed; 13322347Spst return (c); 13422347Spst} 13522347Spst 13622347Spst 13722347Spststatic int Gmatch FUNCTION((s, p), register char *s AND register char *p) 13822347Spst{ 13922347Spst register int scc; 14022347Spst int ok, lc; 14122347Spst int c, cc; 14222347Spst 14322347Spst for (;;) { 14422347Spst scc = *s++ & TRIM; 14522347Spst switch (c = *p++) { 14622347Spst 14722347Spst case '[': 14822347Spst ok = 0; 14922347Spst lc = 077777; 15022347Spst while (cc = *p++) { 15122347Spst if (cc == ']') { 15222347Spst if (ok) 15322347Spst break; 15422347Spst return (0); 15522347Spst } 15622347Spst if (cc == '-') { 15722347Spst if (lc <= scc && scc <= *p++) 15822347Spst ok++; 15922347Spst } else 16022347Spst if (scc == (lc = cc)) 16122347Spst ok++; 16222347Spst } 16322347Spst if (cc == 0) 16422347Spst if (ok) 16522347Spst p--; 16622347Spst else 16722347Spst return 0; 16822347Spst continue; 16922347Spst 17022347Spst case '*': 17122347Spst if (!*p) 17222347Spst return (1); 17322347Spst for (s--; *s; s++) 17422347Spst if (Gmatch(s, p)) 17522347Spst return (1); 17622347Spst return (0); 17722347Spst 17822347Spst case 0: 17922347Spst return (scc == 0); 18022347Spst 18122347Spst default: 18222347Spst if ((c & TRIM) != scc) 18322347Spst return (0); 18422347Spst continue; 18522347Spst 18622347Spst case '?': 18722347Spst if (scc == 0) 18822347Spst return (0); 18922347Spst continue; 19022347Spst 19122347Spst } 19222347Spst } 19322347Spst} 19422347Spst 19522347Spststatic VOIDRET Gcat FUNCTION((s1, s2), register char *s1 AND register char *s2) 19622347Spst{ 19722347Spst register int len = strlen(s1) + strlen(s2) + 1; 19822347Spst 19922347Spst if (len >= gnleft || gargc >= GAVSIZ - 1) 20022347Spst globerr = "Arguments too long"; 20122347Spst else { 20222347Spst gargc++; 20322347Spst gnleft -= len; 20422347Spst gargv[gargc] = 0; 20522347Spst gargv[gargc - 1] = strspl(s1, s2); 20622347Spst } 20722347Spst} 20822347Spst 20922347Spststatic VOIDRET addpath FUNCTION((c), char c) 21022347Spst{ 21122347Spst 21222347Spst if (gpathp >= lastgpathp) 21322347Spst globerr = "Pathname too long"; 21422347Spst else { 21522347Spst *gpathp++ = c; 21622347Spst *gpathp = 0; 21722347Spst } 21822347Spst} 21922347Spst 22022347Spststatic VOIDRET rscan FUNCTION((t, f), register char **t AND int (*f)__P((char))) 22122347Spst{ 22222347Spst register char *p, c; 22322347Spst 22422347Spst while (p = *t++) { 22522347Spst if (f == tglob) 22622347Spst if (*p == '~') 22722347Spst gflag |= 2; 22822347Spst else 22922347Spst if (eq(p, "{") || eq(p, "{}")) 23022347Spst continue; 23122347Spst while (c = *p++) 23222347Spst (*f) (c); 23322347Spst } 23422347Spst} 23522347Spst 23622347Spststatic int tglob FUNCTION((c), register char c) 23722347Spst{ 23822347Spst if (any(c, globchars)) 23922347Spst gflag |= c == '{' ? 2 : 1; 24022347Spst return (c); 24122347Spst} 24222347Spst 24322347Spststatic int letter FUNCTION((c), register char c) 24422347Spst{ 24522347Spst return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_'); 24622347Spst} 24722347Spst 24822347Spststatic int digit FUNCTION((c), register char c) 24922347Spst{ 25022347Spst return (c >= '0' && c <= '9'); 25122347Spst} 25222347Spst 25322347Spststatic int any FUNCTION((c, s), int c AND char *s) 25422347Spst{ 25522347Spst while (*s) 25622347Spst if (*s++ == c) 25722347Spst return (1); 25822347Spst return (0); 25922347Spst} 26022347Spst 26122347Spststatic int blklen FUNCTION((av), register char **av) 26222347Spst{ 26322347Spst register int i = 0; 26422347Spst 26522347Spst while (*av++) 26622347Spst i++; 26722347Spst return (i); 26822347Spst} 26922347Spst 27022347Spststatic char **blkcpy FUNCTION((oav, bv), char **oav AND register char **bv) 27122347Spst{ 27222347Spst register char **av = oav; 27322347Spst 27422347Spst while (*av++ = *bv++) 27522347Spst continue; 27622347Spst return (oav); 27722347Spst} 27822347Spst 27922347SpstVOIDRET blkfree FUNCTION((av0), char **av0) 28022347Spst{ 28122347Spst register char **av = av0; 28222347Spst 28322347Spst while (*av) 28422347Spst free(*av++); 28522347Spst} 28622347Spst 28722347Spststatic char *strspl FUNCTION((cp, dp), register char *cp AND register char *dp) 28822347Spst{ 28922347Spst register char *ep = (char *) malloc((unsigned) (strlen(cp) + 29022347Spst strlen(dp) + 1)); 29122347Spst 29222347Spst if (ep == (char *) 0) 29322347Spst opiefatal("Out of memory"); 29422347Spst strcpy(ep, cp); 29522347Spst strcat(ep, dp); 29622347Spst return (ep); 29722347Spst} 29822347Spst 29922347Spstchar **copyblk FUNCTION((v), char **v) 30022347Spst{ 30122347Spst register char **nv = (char **) malloc((unsigned) ((blklen(v) + 1) * 30222347Spst sizeof(char **))); 30322347Spst 30422347Spst if (nv == (char **) 0) 30522347Spst opiefatal("Out of memory"); 30622347Spst 30722347Spst return (blkcpy(nv, v)); 30822347Spst} 30922347Spst 31022347Spststatic char *strend FUNCTION((cp), register char *cp) 31122347Spst{ 31222347Spst 31322347Spst while (*cp) 31422347Spst cp++; 31522347Spst return (cp); 31622347Spst} 31722347Spst 31822347Spst/* 31922347Spst * Extract a home directory from the password file 32022347Spst * The argument points to a buffer where the name of the 32122347Spst * user whose home directory is sought is currently. 32222347Spst * We write the home directory of the user back there. 32322347Spst */ 32422347Spststatic int gethdir FUNCTION((home), char *home) 32522347Spst{ 32622347Spst register struct passwd *pp = getpwnam(home); 32722347Spst 32822347Spst if (!pp || home + strlen(pp->pw_dir) >= lastgpathp) 32922347Spst return (1); 33022347Spst strcpy(home, pp->pw_dir); 33122347Spst return (0); 33222347Spst} 33322347Spst 33422347Spststatic VOIDRET ginit FUNCTION((agargv), char **agargv) 33522347Spst{ 33622347Spst agargv[0] = 0; 33722347Spst gargv = agargv; 33822347Spst sortbas = agargv; 33922347Spst gargc = 0; 34022347Spst gnleft = NCARGS - 4; 34122347Spst} 34222347Spst 34322347Spststatic VOIDRET sort FUNCTION_NOARGS 34422347Spst{ 34522347Spst register char **p1, **p2, *c; 34622347Spst char **Gvp = &gargv[gargc]; 34722347Spst 34822347Spst p1 = sortbas; 34922347Spst while (p1 < Gvp - 1) { 35022347Spst p2 = p1; 35122347Spst while (++p2 < Gvp) 35222347Spst if (strcmp(*p1, *p2) > 0) 35322347Spst c = *p1, *p1 = *p2, *p2 = c; 35422347Spst p1++; 35522347Spst } 35622347Spst sortbas = Gvp; 35722347Spst} 35822347Spst 35922347Spststatic VOIDRET matchdir FUNCTION((pattern), char *pattern) 36022347Spst{ 36122347Spst struct stat stb; 36222347Spst 36322347Spst register struct dirent *dp; 36422347Spst 36522347Spst DIR *dirp; 36622347Spst 36722347Spst dirp = opendir(*gpath == '\0' ? "." : gpath); 36822347Spst if (dirp == NULL) { 36922347Spst if (globbed) 37022347Spst return; 37122347Spst goto patherr2; 37222347Spst } 37322347Spst#if !defined(linux) 37422347Spst if (fstat(dirp->dd_fd, &stb) < 0) 37522347Spst goto patherr1; 37622347Spst if (!isdir(stb)) { 37722347Spst errno = ENOTDIR; 37822347Spst goto patherr1; 37922347Spst } 38022347Spst#endif /* !defined(linux) */ 38122347Spst while ((dp = readdir(dirp)) != NULL) { 38222347Spst if (dp->d_ino == 0) 38322347Spst continue; 38422347Spst if (match(dp->d_name, pattern)) { 38522347Spst Gcat(gpath, dp->d_name); 38622347Spst globcnt++; 38722347Spst } 38822347Spst } 38922347Spst closedir(dirp); 39022347Spst return; 39122347Spst 39222347Spstpatherr1: 39322347Spst closedir(dirp); 39422347Spstpatherr2: 39522347Spst globerr = "Bad directory components"; 39622347Spst} 39722347Spst 39822347Spststatic VOIDRET expand FUNCTION((as), char *as) 39922347Spst{ 40022347Spst register char *cs; 40122347Spst register char *sgpathp, *oldcs; 40222347Spst struct stat stb; 40322347Spst 40422347Spst sgpathp = gpathp; 40522347Spst cs = as; 40622347Spst if (*cs == '~' && gpathp == gpath) { 40722347Spst addpath('~'); 40822347Spst for (cs++; letter(*cs) || digit(*cs) || *cs == '-';) 40922347Spst addpath(*cs++); 41022347Spst if (!*cs || *cs == '/') { 41122347Spst if (gpathp != gpath + 1) { 41222347Spst *gpathp = 0; 41322347Spst if (gethdir(gpath + 1)) 41422347Spst globerr = "Unknown user name after ~"; 41522347Spst strcpy(gpath, gpath + 1); 41622347Spst } else 41722347Spst strcpy(gpath, home); 41822347Spst gpathp = strend(gpath); 41922347Spst } 42022347Spst } 42122347Spst while (!any(*cs, globchars)) { 42222347Spst if (*cs == 0) { 42322347Spst if (!globbed) 42422347Spst Gcat(gpath, ""); 42522347Spst else 42622347Spst if (stat(gpath, &stb) >= 0) { 42722347Spst Gcat(gpath, ""); 42822347Spst globcnt++; 42922347Spst } 43022347Spst goto endit; 43122347Spst } 43222347Spst addpath(*cs++); 43322347Spst } 43422347Spst oldcs = cs; 43522347Spst while (cs > as && *cs != '/') 43622347Spst cs--, gpathp--; 43722347Spst if (*cs == '/') 43822347Spst cs++, gpathp++; 43922347Spst *gpathp = 0; 44022347Spst if (*oldcs == '{') { 44122347Spst execbrc(cs, ((char *) 0)); 44222347Spst return; 44322347Spst } 44422347Spst matchdir(cs); 44522347Spstendit: 44622347Spst gpathp = sgpathp; 44722347Spst *gpathp = 0; 44822347Spst} 44922347Spst 45022347Spststatic int execbrc FUNCTION((p, s), char *p AND char *s) 45122347Spst{ 45222347Spst char restbuf[BUFSIZ + 2]; 45322347Spst register char *pe, *pm, *pl; 45422347Spst int brclev = 0; 45522347Spst char *lm, savec, *sgpathp; 45622347Spst 45722347Spst for (lm = restbuf; *p != '{'; *lm++ = *p++) 45822347Spst continue; 45922347Spst for (pe = ++p; *pe; pe++) 46022347Spst switch (*pe) { 46122347Spst 46222347Spst case '{': 46322347Spst brclev++; 46422347Spst continue; 46522347Spst 46622347Spst case '}': 46722347Spst if (brclev == 0) 46822347Spst goto pend; 46922347Spst brclev--; 47022347Spst continue; 47122347Spst 47222347Spst case '[': 47322347Spst for (pe++; *pe && *pe != ']'; pe++) 47422347Spst continue; 47522347Spst continue; 47622347Spst } 47722347Spstpend: 47822347Spst brclev = 0; 47922347Spst for (pl = pm = p; pm <= pe; pm++) 48022347Spst switch (*pm & (QUOTE | TRIM)) { 48122347Spst 48222347Spst case '{': 48322347Spst brclev++; 48422347Spst continue; 48522347Spst 48622347Spst case '}': 48722347Spst if (brclev) { 48822347Spst brclev--; 48922347Spst continue; 49022347Spst } 49122347Spst goto doit; 49222347Spst 49322347Spst case ',' | QUOTE: 49422347Spst case ',': 49522347Spst if (brclev) 49622347Spst continue; 49722347Spst doit: 49822347Spst savec = *pm; 49922347Spst *pm = 0; 50022347Spst strcpy(lm, pl); 50122347Spst strcat(restbuf, pe + 1); 50222347Spst *pm = savec; 50322347Spst if (s == 0) { 50422347Spst sgpathp = gpathp; 50522347Spst expand(restbuf); 50622347Spst gpathp = sgpathp; 50722347Spst *gpathp = 0; 50822347Spst } else 50922347Spst if (amatch(s, restbuf)) 51022347Spst return (1); 51122347Spst sort(); 51222347Spst pl = pm + 1; 51322347Spst if (brclev) 51422347Spst return (0); 51522347Spst continue; 51622347Spst 51722347Spst case '[': 51822347Spst for (pm++; *pm && *pm != ']'; pm++) 51922347Spst continue; 52022347Spst if (!*pm) 52122347Spst pm--; 52222347Spst continue; 52322347Spst } 52422347Spst if (brclev) 52522347Spst goto doit; 52622347Spst return (0); 52722347Spst} 52822347Spst 52922347Spststatic VOIDRET acollect FUNCTION((as), register char *as) 53022347Spst{ 53122347Spst register int ogargc = gargc; 53222347Spst 53322347Spst gpathp = gpath; 53422347Spst *gpathp = 0; 53522347Spst globbed = 0; 53622347Spst expand(as); 53722347Spst if (gargc != ogargc) 53822347Spst sort(); 53922347Spst} 54022347Spst 54122347Spststatic VOIDRET collect FUNCTION((as), register char *as) 54222347Spst{ 54322347Spst if (eq(as, "{") || eq(as, "{}")) { 54422347Spst Gcat(as, ""); 54522347Spst sort(); 54622347Spst } else 54722347Spst acollect(as); 54822347Spst} 54922347Spst 55022347Spststatic int amatch FUNCTION((s, p), register char *s AND register char *p) 55122347Spst{ 55222347Spst register int scc; 55322347Spst int ok, lc; 55422347Spst char *sgpathp; 55522347Spst struct stat stb; 55622347Spst int c, cc; 55722347Spst 55822347Spst globbed = 1; 55922347Spst for (;;) { 56022347Spst scc = *s++ & TRIM; 56122347Spst switch (c = *p++) { 56222347Spst 56322347Spst case '{': 56422347Spst return (execbrc(p - 1, s - 1)); 56522347Spst 56622347Spst case '[': 56722347Spst ok = 0; 56822347Spst lc = 077777; 56922347Spst while (cc = *p++) { 57022347Spst if (cc == ']') { 57122347Spst if (ok) 57222347Spst break; 57322347Spst return (0); 57422347Spst } 57522347Spst if (cc == '-') { 57622347Spst if (lc <= scc && scc <= *p++) 57722347Spst ok++; 57822347Spst } else 57922347Spst if (scc == (lc = cc)) 58022347Spst ok++; 58122347Spst } 58222347Spst if (cc == 0) 58322347Spst if (ok) 58422347Spst p--; 58522347Spst else 58622347Spst return 0; 58722347Spst continue; 58822347Spst 58922347Spst case '*': 59022347Spst if (!*p) 59122347Spst return (1); 59222347Spst if (*p == '/') { 59322347Spst p++; 59422347Spst goto slash; 59522347Spst } 59622347Spst s--; 59722347Spst do { 59822347Spst if (amatch(s, p)) 59922347Spst return (1); 60022347Spst } 60122347Spst while (*s++); 60222347Spst return (0); 60322347Spst 60422347Spst case 0: 60522347Spst return (scc == 0); 60622347Spst 60722347Spst default: 60822347Spst if (c != scc) 60922347Spst return (0); 61022347Spst continue; 61122347Spst 61222347Spst case '?': 61322347Spst if (scc == 0) 61422347Spst return (0); 61522347Spst continue; 61622347Spst 61722347Spst case '/': 61822347Spst if (scc) 61922347Spst return (0); 62022347Spst slash: 62122347Spst s = entp; 62222347Spst sgpathp = gpathp; 62322347Spst while (*s) 62422347Spst addpath(*s++); 62522347Spst addpath('/'); 62622347Spst if (stat(gpath, &stb) == 0 && isdir(stb)) 62722347Spst if (*p == 0) { 62822347Spst Gcat(gpath, ""); 62922347Spst globcnt++; 63022347Spst } else 63122347Spst expand(p); 63222347Spst gpathp = sgpathp; 63322347Spst *gpathp = 0; 63422347Spst return (0); 63522347Spst } 63622347Spst } 63722347Spst} 63822347Spst 63922347Spst 64022347Spstchar **ftpglob FUNCTION((v), register char *v) 64122347Spst{ 64222347Spst char agpath[BUFSIZ]; 64322347Spst char *agargv[GAVSIZ]; 64422347Spst char *vv[2]; 64522347Spst 64622347Spst vv[0] = v; 64722347Spst vv[1] = 0; 64822347Spst gflag = 0; 64922347Spst rscan(vv, tglob); 65022347Spst if (gflag == 0) { 65122347Spst vv[0] = strspl(v, ""); 65222347Spst return (copyblk(vv)); 65322347Spst } 65422347Spst globerr = 0; 65522347Spst gpath = agpath; 65622347Spst gpathp = gpath; 65722347Spst *gpathp = 0; 65822347Spst lastgpathp = &gpath[sizeof agpath - 2]; 65922347Spst ginit(agargv); 66022347Spst globcnt = 0; 66122347Spst collect(v); 66222347Spst if (globcnt == 0 && (gflag & 1)) { 66322347Spst blkfree(gargv), gargv = 0; 66422347Spst return (0); 66522347Spst } else 66622347Spst return (gargv = copyblk(gargv)); 66722347Spst} 668