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