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