openenvutils/commandshell/shell/src/glob.c
changeset 0 2e3d3ce01487
child 4 0fdb7f6b0309
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 //glob.c - filename generation
       
     2 //
       
     3 // © Portions Copyright (c) Symbian Software Ltd 2007. All rights reserved.
       
     4 //
       
     5 /*
       
     6  * This file is part of zsh, the Z shell.
       
     7  *
       
     8  * Copyright (c) 1992-1997 Paul Falstad
       
     9  * All rights reserved.
       
    10  *
       
    11  * Permission is hereby granted, without written agreement and without
       
    12  * license or royalty fees, to use, copy, modify, and distribute this
       
    13  * software and to distribute modified versions of this software for any
       
    14  * purpose, provided that the above copyright notice and the following
       
    15  * two paragraphs appear in all copies of this software.
       
    16  *
       
    17  * In no event shall Paul Falstad or the Zsh Development Group be liable
       
    18  * to any party for direct, indirect, special, incidental, or consequential
       
    19  * damages arising out of the use of this software and its documentation,
       
    20  * even if Paul Falstad and the Zsh Development Group have been advised of
       
    21  * the possibility of such damage.
       
    22  *
       
    23  * Paul Falstad and the Zsh Development Group specifically disclaim any
       
    24  * warranties, including, but not limited to, the implied warranties of
       
    25  * merchantability and fitness for a particular purpose.  The software
       
    26  * provided hereunder is on an "as is" basis, and Paul Falstad and the
       
    27  * Zsh Development Group have no obligation to provide maintenance,
       
    28  * support, updates, enhancements, or modifications.
       
    29  *
       
    30  */
       
    31 
       
    32 #include "zsh.mdh"
       
    33 #include "glob.pro"
       
    34 
       
    35 #ifdef __SYMBIAN32__
       
    36 #ifdef __WINSCW__
       
    37 #pragma warn_unusedarg off
       
    38 #pragma warn_possunwant off
       
    39 #endif//__WINSCW__
       
    40 #endif//__SYMBIAN32__
       
    41 
       
    42 
       
    43 #if defined(OFF_T_IS_64_BIT) && defined(__GNUC__)
       
    44 # define ALIGN64 __attribute__((aligned(8)))
       
    45 #else
       
    46 # define ALIGN64
       
    47 #endif
       
    48 
       
    49 /* flag for CSHNULLGLOB */
       
    50 
       
    51 typedef struct gmatch *Gmatch;
       
    52 
       
    53 struct gmatch {
       
    54     char *name;
       
    55     off_t size ALIGN64;
       
    56     long atime;
       
    57     long mtime;
       
    58     long ctime;
       
    59     long links;
       
    60     off_t _size ALIGN64;
       
    61     long _atime;
       
    62     long _mtime;
       
    63     long _ctime;
       
    64     long _links;
       
    65 };
       
    66 
       
    67 #define GS_NAME   1
       
    68 #define GS_DEPTH  2
       
    69 #define GS_SIZE   4
       
    70 #define GS_ATIME  8
       
    71 #define GS_MTIME 16
       
    72 #define GS_CTIME 32
       
    73 #define GS_LINKS 64
       
    74 
       
    75 #define GS_SHIFT  5
       
    76 #define GS__SIZE  (GS_SIZE << GS_SHIFT)
       
    77 #define GS__ATIME (GS_ATIME << GS_SHIFT)
       
    78 #define GS__MTIME (GS_MTIME << GS_SHIFT)
       
    79 #define GS__CTIME (GS_CTIME << GS_SHIFT)
       
    80 #define GS__LINKS (GS_LINKS << GS_SHIFT)
       
    81 
       
    82 #define GS_DESC  4096
       
    83 
       
    84 #define GS_NORMAL (GS_SIZE | GS_ATIME | GS_MTIME | GS_CTIME | GS_LINKS)
       
    85 #define GS_LINKED (GS_NORMAL << GS_SHIFT)
       
    86 
       
    87 /**/
       
    88 int badcshglob;
       
    89 
       
    90 /**/
       
    91 int pathpos;		/* position in pathbuf (needed by pattern code) */
       
    92 
       
    93 /**/
       
    94 char *pathbuf;		/* pathname buffer (needed by pattern code) */
       
    95 
       
    96 typedef struct stat *Statptr;	 /* This makes the Ultrix compiler happy.  Go figure. */
       
    97 
       
    98 /* modifier for unit conversions */
       
    99 
       
   100 #define TT_DAYS 0
       
   101 #define TT_HOURS 1
       
   102 #define TT_MINS 2
       
   103 #define TT_WEEKS 3
       
   104 #define TT_MONTHS 4
       
   105 #define TT_SECONDS 5
       
   106 
       
   107 #define TT_BYTES 0
       
   108 #define TT_POSIX_BLOCKS 1
       
   109 #define TT_KILOBYTES 2
       
   110 #define TT_MEGABYTES 3
       
   111 
       
   112 
       
   113 typedef int (*TestMatchFunc) _((char *, struct stat *, off_t, char *));
       
   114 
       
   115 struct qual {
       
   116     struct qual *next;		/* Next qualifier, must match                */
       
   117     struct qual *or;		/* Alternative set of qualifiers to match    */
       
   118     TestMatchFunc func;		/* Function to call to test match            */
       
   119     off_t data ALIGN64;		/* Argument passed to function               */
       
   120     int sense;			/* Whether asserting or negating             */
       
   121     int amc;			/* Flag for which time to test (a, m, c)     */
       
   122     int range;			/* Whether to test <, > or = (as per signum) */
       
   123     int units;			/* Multiplier for time or size, respectively */
       
   124     char *sdata;		/* currently only: expression to eval        */
       
   125 };
       
   126 
       
   127 /* Prefix, suffix for doing zle trickery */
       
   128 
       
   129 /**/
       
   130 mod_export char *glob_pre, *glob_suf;
       
   131 
       
   132 /* struct to easily save/restore current state */
       
   133 
       
   134 struct globdata {
       
   135     int gd_pathpos;
       
   136     char *gd_pathbuf;
       
   137 
       
   138     int gd_matchsz;		/* size of matchbuf                     */
       
   139     int gd_matchct;		/* number of matches found              */
       
   140     int gd_pathbufsz;		/* size of pathbuf			*/
       
   141     int gd_pathbufcwd;		/* where did we chdir()'ed		*/
       
   142     Gmatch gd_matchbuf;		/* array of matches                     */
       
   143     Gmatch gd_matchptr;		/* &matchbuf[matchct]                   */
       
   144     char *gd_colonmod;		/* colon modifiers in qualifier list    */
       
   145 
       
   146     /* Qualifiers pertaining to current pattern */
       
   147     struct qual *gd_quals;
       
   148 
       
   149     /* Other state values for current pattern */
       
   150     int gd_qualct, gd_qualorct;
       
   151     int gd_range, gd_amc, gd_units;
       
   152     int gd_gf_nullglob, gd_gf_markdirs, gd_gf_noglobdots, gd_gf_listtypes;
       
   153     int gd_gf_numsort;
       
   154     int gd_gf_follow, gd_gf_sorts, gd_gf_nsorts, gd_gf_sortlist[11];
       
   155 
       
   156     char *gd_glob_pre, *gd_glob_suf;
       
   157 };
       
   158 
       
   159 /* The variable with the current globbing state and convenience macros */
       
   160 
       
   161 static struct globdata curglobdata;
       
   162 
       
   163 #define matchsz       (curglobdata.gd_matchsz)
       
   164 #define matchct       (curglobdata.gd_matchct)
       
   165 #define pathbufsz     (curglobdata.gd_pathbufsz)
       
   166 #define pathbufcwd    (curglobdata.gd_pathbufcwd)
       
   167 #define matchbuf      (curglobdata.gd_matchbuf)
       
   168 #define matchptr      (curglobdata.gd_matchptr)
       
   169 #define colonmod      (curglobdata.gd_colonmod)
       
   170 #define quals         (curglobdata.gd_quals)
       
   171 #define qualct        (curglobdata.gd_qualct)
       
   172 #define qualorct      (curglobdata.gd_qualorct)
       
   173 #define g_range       (curglobdata.gd_range)
       
   174 #define g_amc         (curglobdata.gd_amc)
       
   175 #define g_units       (curglobdata.gd_units)
       
   176 #define gf_nullglob   (curglobdata.gd_gf_nullglob)
       
   177 #define gf_markdirs   (curglobdata.gd_gf_markdirs)
       
   178 #define gf_noglobdots (curglobdata.gd_gf_noglobdots)
       
   179 #define gf_listtypes  (curglobdata.gd_gf_listtypes)
       
   180 #define gf_numsort    (curglobdata.gd_gf_numsort)
       
   181 #define gf_follow     (curglobdata.gd_gf_follow)
       
   182 #define gf_sorts      (curglobdata.gd_gf_sorts)
       
   183 #define gf_nsorts     (curglobdata.gd_gf_nsorts)
       
   184 #define gf_sortlist   (curglobdata.gd_gf_sortlist)
       
   185 
       
   186 /* and macros for save/restore */
       
   187 
       
   188 #define save_globstate(N) \
       
   189   do { \
       
   190     memcpy(&(N), &curglobdata, sizeof(struct globdata)); \
       
   191     (N).gd_pathpos = pathpos; \
       
   192     (N).gd_pathbuf = pathbuf; \
       
   193     (N).gd_pathbufsz = 0; \
       
   194     (N).gd_glob_pre = glob_pre; \
       
   195     (N).gd_glob_suf = glob_suf; \
       
   196     pathbuf = NULL; \
       
   197   } while (0)
       
   198 
       
   199 #define restore_globstate(N) \
       
   200   do { \
       
   201     zfree(pathbuf, pathbufsz); \
       
   202     memcpy(&curglobdata, &(N), sizeof(struct globdata)); \
       
   203     pathpos = (N).gd_pathpos; \
       
   204     pathbuf = (N).gd_pathbuf; \
       
   205     glob_pre = (N).gd_glob_pre; \
       
   206     glob_suf = (N).gd_glob_suf; \
       
   207   } while (0)
       
   208 
       
   209 /* pathname component in filename patterns */
       
   210 
       
   211 struct complist {
       
   212     Complist next;
       
   213     Patprog pat;
       
   214     int closure;		/* 1 if this is a (foo/)# */
       
   215     int follow; 		/* 1 to go thru symlinks */
       
   216 };
       
   217 
       
   218 /* Next character after one which may be a Meta (x is any char *) */
       
   219 #define METANEXT(x)	(*(x) == Meta ? (x)+2 : (x)+1)
       
   220 /*
       
   221  * Increment pointer which may be on a Meta (x is a pointer variable),
       
   222  * returning the incremented value (i.e. like pre-increment).
       
   223  */
       
   224 #define METAINC(x)	((x) += (*(x) == Meta) ? 2 : 1)
       
   225 /*
       
   226  * Return unmetafied char from string (x is any char *)
       
   227  */
       
   228 #define UNMETA(x)	(*(x) == Meta ? (x)[1] ^ 32 : *(x))
       
   229 
       
   230 /* Add a component to pathbuf: This keeps track of how    *
       
   231  * far we are into a file name, since each path component *
       
   232  * must be matched separately.                            */
       
   233 
       
   234 /**/
       
   235 static void
       
   236 addpath(char *s, int l)
       
   237 {
       
   238     DPUTS(!pathbuf, "BUG: pathbuf not initialised");
       
   239     while (pathpos + l + 1 >= pathbufsz)
       
   240 	pathbuf = realloc(pathbuf, pathbufsz *= 2);
       
   241     while (l--)
       
   242 	pathbuf[pathpos++] = *s++;
       
   243     pathbuf[pathpos++] = '/';
       
   244     pathbuf[pathpos] = '\0';
       
   245 }
       
   246 
       
   247 /* stat the filename s appended to pathbuf.  l should be true for lstat,    *
       
   248  * false for stat.  If st is NULL, the file is only checked for existance.  *
       
   249  * s == "" is treated as s == ".".  This is necessary since on most systems *
       
   250  * foo/ can be used to reference a non-directory foo.  Returns nonzero if   *
       
   251  * the file does not exists.                                                */
       
   252 
       
   253 /**/
       
   254 static int
       
   255 statfullpath(const char *s, struct stat *st, int l)
       
   256 {
       
   257     char buf[PATH_MAX];
       
   258 
       
   259     DPUTS(strlen(s) + !*s + pathpos - pathbufcwd >= PATH_MAX,
       
   260 	  "BUG: statfullpath(): pathname too long");
       
   261     strcpy(buf, pathbuf + pathbufcwd);
       
   262     strcpy(buf + pathpos - pathbufcwd, s);
       
   263     if (!*s && *buf) {
       
   264 	/*
       
   265 	 * Don't add the '.' if the path so far is empty, since
       
   266 	 * then we get bogus empty strings inserted as files.
       
   267 	 */
       
   268 	buf[pathpos - pathbufcwd] = '.';
       
   269 	buf[pathpos - pathbufcwd + 1] = '\0';
       
   270 	l = 0;
       
   271     }
       
   272     unmetafy(buf, NULL);
       
   273     if (!st)
       
   274 	return access(buf, F_OK) && (!l || readlink(buf, NULL, 0));
       
   275     return l ? lstat(buf, st) : stat(buf, st);
       
   276 }
       
   277 
       
   278 /* This may be set by qualifier functions to an array of strings to insert
       
   279  * into the list instead of the original string. */
       
   280 
       
   281 char **inserts;
       
   282 
       
   283 /* add a match to the list */
       
   284 
       
   285 /**/
       
   286 static void
       
   287 insert(char *s, int checked)
       
   288 {
       
   289     struct stat buf, buf2, *bp;
       
   290     char *news = s;
       
   291     int statted = 0;
       
   292 
       
   293     queue_signals();
       
   294     inserts = NULL;
       
   295 
       
   296     if (gf_listtypes || gf_markdirs) {
       
   297 	/* Add the type marker to the end of the filename */
       
   298 	mode_t mode;
       
   299 	checked = statted = 1;
       
   300 	if (statfullpath(s, &buf, 1)) {
       
   301 	    unqueue_signals();
       
   302 	    return;
       
   303 	}
       
   304 	mode = buf.st_mode;
       
   305 	if (gf_follow) {
       
   306 	    if (!S_ISLNK(mode) || statfullpath(s, &buf2, 0))
       
   307 		memcpy(&buf2, &buf, sizeof(buf));
       
   308 	    statted |= 2;
       
   309 	    mode = buf2.st_mode;
       
   310 	}
       
   311 	if (gf_listtypes || S_ISDIR(mode)) {
       
   312 	    int ll = strlen(s);
       
   313 
       
   314 	    news = (char *) hcalloc(ll + 2);
       
   315 	    strcpy(news, s);
       
   316 	    news[ll] = file_type(mode);
       
   317 	    news[ll + 1] = '\0';
       
   318 	}
       
   319     }
       
   320     if (qualct || qualorct) {
       
   321 	/* Go through the qualifiers, rejecting the file if appropriate */
       
   322 	struct qual *qo, *qn;
       
   323 
       
   324 	if (!statted && statfullpath(s, &buf, 1)) {
       
   325 	    unqueue_signals();
       
   326 	    return;
       
   327 	}
       
   328 	news = dyncat(pathbuf, news);
       
   329 
       
   330 	statted = 1;
       
   331 	qo = quals;
       
   332 	for (qn = qo; qn && qn->func;) {
       
   333 	    g_range = qn->range;
       
   334 	    g_amc = qn->amc;
       
   335 	    g_units = qn->units;
       
   336 	    if ((qn->sense & 2) && !(statted & 2)) {
       
   337 		/* If (sense & 2), we're following links */
       
   338 		if (!S_ISLNK(buf.st_mode) || statfullpath(s, &buf2, 0))
       
   339 		    memcpy(&buf2, &buf, sizeof(buf));
       
   340 		statted |= 2;
       
   341 	    }
       
   342 	    bp = (qn->sense & 2) ? &buf2 : &buf;
       
   343 	    /* Reject the file if the function returned zero *
       
   344 	     * and the sense was positive (sense&1 == 0), or *
       
   345 	     * vice versa.                                   */
       
   346 	    if ((!((qn->func) (news, bp, qn->data, qn->sdata)) ^ qn->sense) & 1) {
       
   347 		/* Try next alternative, or return if there are no more */
       
   348 		if (!(qo = qo->or)) {
       
   349 		    unqueue_signals();
       
   350 		    return;
       
   351 		}
       
   352 		qn = qo;
       
   353 		continue;
       
   354 	    }
       
   355 	    qn = qn->next;
       
   356 	}
       
   357     } else if (!checked) {
       
   358 	if (statfullpath(s, NULL, 1)) {
       
   359 	    unqueue_signals();
       
   360 	    return;
       
   361 	}
       
   362 	statted = 1;
       
   363 	news = dyncat(pathbuf, news);
       
   364     } else
       
   365 	news = dyncat(pathbuf, news);
       
   366 
       
   367     while (!inserts || (news = dupstring(*inserts++))) {
       
   368 	if (colonmod) {
       
   369 	    /* Handle the remainder of the qualifier:  e.g. (:r:s/foo/bar/). */
       
   370 	    s = colonmod;
       
   371 	    modify(&news, &s);
       
   372 	}
       
   373 	if (!statted && (gf_sorts & GS_NORMAL)) {
       
   374 	    statfullpath(s, &buf, 1);
       
   375 	    statted = 1;
       
   376 	}
       
   377 	if (!(statted & 2) && (gf_sorts & GS_LINKED)) {
       
   378 	    if (statted) {
       
   379 		if (!S_ISLNK(buf.st_mode) || statfullpath(s, &buf2, 0))
       
   380 		    memcpy(&buf2, &buf, sizeof(buf));
       
   381 	    } else if (statfullpath(s, &buf2, 0))
       
   382 		statfullpath(s, &buf2, 1);
       
   383 	    statted |= 2;
       
   384 	}
       
   385 	matchptr->name = news;
       
   386 	if (statted & 1) {
       
   387 	    matchptr->size = buf.st_size;
       
   388 	    matchptr->atime = buf.st_atime;
       
   389 	    matchptr->mtime = buf.st_mtime;
       
   390 	    matchptr->ctime = buf.st_ctime;
       
   391 	    matchptr->links = buf.st_nlink;
       
   392 	}
       
   393 	if (statted & 2) {
       
   394 	    matchptr->_size = buf2.st_size;
       
   395 	    matchptr->_atime = buf2.st_atime;
       
   396 	    matchptr->_mtime = buf2.st_mtime;
       
   397 	    matchptr->_ctime = buf2.st_ctime;
       
   398 	    matchptr->_links = buf2.st_nlink;
       
   399 	}
       
   400 	matchptr++;
       
   401 
       
   402 	if (++matchct == matchsz) {
       
   403 	    matchbuf = (Gmatch )realloc((char *)matchbuf,
       
   404 					sizeof(struct gmatch) * (matchsz *= 2));
       
   405 
       
   406 	    matchptr = matchbuf + matchct;
       
   407 	}
       
   408 	if (!inserts)
       
   409 	    break;
       
   410     }
       
   411     unqueue_signals();
       
   412 }
       
   413 
       
   414 /* Check to see if str is eligible for filename generation. */
       
   415 
       
   416 /**/
       
   417 mod_export int
       
   418 haswilds(char *str)
       
   419 {
       
   420     /* `[' and `]' are legal even if bad patterns are usually not. */
       
   421     if ((*str == Inbrack || *str == Outbrack) && !str[1])
       
   422 	return 0;
       
   423 
       
   424     /* If % is immediately followed by ?, then that ? is     *
       
   425      * not treated as a wildcard.  This is so you don't have *
       
   426      * to escape job references such as %?foo.               */
       
   427     if (str[0] == '%' && str[1] == Quest)
       
   428 	str[1] = '?';
       
   429 
       
   430     for (; *str; str++) {
       
   431 	switch (*str) {
       
   432 	    case Inpar:
       
   433 	    case Bar:
       
   434 	    case Star:
       
   435 	    case Inbrack:
       
   436 	    case Inang:
       
   437 	    case Quest:
       
   438 		return 1;
       
   439 	    case Pound:
       
   440 	    case Hat:
       
   441 		if (isset(EXTENDEDGLOB))
       
   442 		    return 1;
       
   443 		break;
       
   444 	}
       
   445     }
       
   446     return 0;
       
   447 }
       
   448 
       
   449 /* Do the globbing:  scanner is called recursively *
       
   450  * with successive bits of the path until we've    *
       
   451  * tried all of it.                                */
       
   452 
       
   453 /**/
       
   454 static void
       
   455 scanner(Complist q)
       
   456 {
       
   457     Patprog p;
       
   458     int closure;
       
   459     int pbcwdsav = pathbufcwd;
       
   460     int errssofar = errsfound;
       
   461     struct dirsav ds;
       
   462 
       
   463     ds.ino = ds.dev = 0;
       
   464     ds.dirname = NULL;
       
   465     ds.dirfd = ds.level = -1;
       
   466     if (!q)
       
   467 	return;
       
   468 
       
   469     if ((closure = q->closure)) {
       
   470 	/* (foo/)# - match zero or more dirs */
       
   471 	if (q->closure == 2)	/* (foo/)## - match one or more dirs */
       
   472 	    q->closure = 1;
       
   473 	else
       
   474 	    scanner(q->next);
       
   475     }
       
   476     p = q->pat;
       
   477     /* Now the actual matching for the current path section. */
       
   478     if (p->flags & PAT_PURES) {
       
   479 	/*
       
   480 	 * It's a straight string to the end of the path section.
       
   481 	 */
       
   482 	char *str = (char *)p + p->startoff;
       
   483 	int l = p->patmlen;
       
   484 
       
   485 	if (l + !l + pathpos - pathbufcwd >= PATH_MAX) {
       
   486 	    int err;
       
   487 
       
   488 	    if (l >= PATH_MAX)
       
   489 		return;
       
   490 	    err = lchdir(pathbuf + pathbufcwd, &ds, 0);
       
   491 	    if (err == -1)
       
   492 		return;
       
   493 	    if (err) {
       
   494 		zerr("current directory lost during glob", NULL, 0);
       
   495 		return;
       
   496 	    }
       
   497 	    pathbufcwd = pathpos;
       
   498 	}
       
   499 	if (q->next) {
       
   500 	    /* Not the last path section. Just add it to the path. */
       
   501 	    int oppos = pathpos;
       
   502 
       
   503 	    if (!errflag) {
       
   504 		int add = 1;
       
   505 
       
   506 		if (q->closure && *pathbuf) {
       
   507 		    if (!strcmp(str, "."))
       
   508 			add = 0;
       
   509 		    else if (!strcmp(str, "..")) {
       
   510 			struct stat sc, sr;
       
   511 
       
   512 			add = (stat("/", &sr) || stat(pathbuf, &sc) ||
       
   513 			       sr.st_ino != sc.st_ino ||
       
   514 			       sr.st_dev != sc.st_dev);
       
   515 		    }
       
   516 		}
       
   517 		if (add) {
       
   518 		    addpath(str, l);
       
   519 		    if (!closure || !statfullpath("", NULL, 1))
       
   520 			scanner((q->closure) ? q : q->next);
       
   521 		    pathbuf[pathpos = oppos] = '\0';
       
   522 		}
       
   523 	    }
       
   524 	} else {
       
   525 	    if (str[l])
       
   526 		str = dupstrpfx(str, l);
       
   527 	    insert(str, 0);
       
   528 	}
       
   529     } else {
       
   530 	/* Do pattern matching on current path section. */
       
   531 	char *fn = pathbuf[pathbufcwd] ? unmeta(pathbuf + pathbufcwd) : ".";
       
   532 	int dirs = !!q->next;
       
   533 	DIR *lock = opendir(fn);
       
   534 	char *subdirs = NULL;
       
   535 	int subdirlen = 0;
       
   536 
       
   537 	if (lock == NULL)
       
   538 	    return;
       
   539 	while ((fn = zreaddir(lock, 1)) && !errflag) {
       
   540 	    /* prefix and suffix are zle trickery */
       
   541 	    if (!dirs && !colonmod &&
       
   542 		((glob_pre && !strpfx(glob_pre, fn))
       
   543 		 || (glob_suf && !strsfx(glob_suf, fn))))
       
   544 		continue;
       
   545 	    errsfound = errssofar;
       
   546 	    if (pattry(p, fn)) {
       
   547 		/* if this name matchs the pattern... */
       
   548 		if (pbcwdsav == pathbufcwd &&
       
   549 		    strlen(fn) + pathpos - pathbufcwd >= PATH_MAX) {
       
   550 		    int err;
       
   551 
       
   552 		    DPUTS(pathpos == pathbufcwd,
       
   553 			  "BUG: filename longer than PATH_MAX");
       
   554 		    err = lchdir(pathbuf + pathbufcwd, &ds, 0);
       
   555 		    if (err == -1)
       
   556 			break;
       
   557 		    if (err) {
       
   558 			zerr("current directory lost during glob", NULL, 0);
       
   559 			break;
       
   560 		    }
       
   561 		    pathbufcwd = pathpos;
       
   562 		}
       
   563 		if (dirs) {
       
   564 		    int l;
       
   565 
       
   566 		    /*
       
   567 		     * If not the last component in the path:
       
   568 		     *
       
   569 		     * If we made an approximation in the new path segment,
       
   570 		     * then it is possible we made too many errors.  For
       
   571 		     * example, (ab)#(cb)# will match the directory abcb
       
   572 		     * with one error if allowed to, even though it can
       
   573 		     * match with none.  This will stop later parts of the
       
   574 		     * path matching, so we need to check by reducing the
       
   575 		     * maximum number of errors and seeing if the directory
       
   576 		     * still matches.  Luckily, this is not a terribly
       
   577 		     * common case, since complex patterns typically occur
       
   578 		     * in the last part of the path which is not affected
       
   579 		     * by this problem.
       
   580 		     */
       
   581 		    if (errsfound > errssofar) {
       
   582 			forceerrs = errsfound - 1;
       
   583 			while (forceerrs >= errssofar) {
       
   584 			    errsfound = errssofar;
       
   585 			    if (!pattry(p, fn))
       
   586 				break;
       
   587 			    forceerrs = errsfound - 1;
       
   588 			}
       
   589 			errsfound = forceerrs + 1;
       
   590 			forceerrs = -1;
       
   591 		    }
       
   592 		    if (closure) {
       
   593 			/* if matching multiple directories */
       
   594 			struct stat buf;
       
   595 
       
   596 			if (statfullpath(fn, &buf, !q->follow)) {
       
   597 			    if (errno != ENOENT && errno != EINTR &&
       
   598 				errno != ENOTDIR && !errflag) {
       
   599 				zwarn("%e: %s", fn, errno);
       
   600 			    }
       
   601 			    continue;
       
   602 			}
       
   603 			if (!S_ISDIR(buf.st_mode))
       
   604 			    continue;
       
   605 		    }
       
   606 		    l = strlen(fn) + 1;
       
   607 		    subdirs = hrealloc(subdirs, subdirlen, subdirlen + l
       
   608 				       + sizeof(int));
       
   609 		    strcpy(subdirs + subdirlen, fn);
       
   610 		    subdirlen += l;
       
   611 		    /* store the count of errors made so far, too */
       
   612 		    memcpy(subdirs + subdirlen, (char *)&errsfound,
       
   613 			   sizeof(int));
       
   614 		    subdirlen += sizeof(int);
       
   615 		} else
       
   616 		    /* if the last filename component, just add it */
       
   617 		    insert(fn, 1);
       
   618 	    }
       
   619 	}
       
   620 	closedir(lock);
       
   621 	if (subdirs) {
       
   622 	    int oppos = pathpos;
       
   623 
       
   624 	    for (fn = subdirs; fn < subdirs+subdirlen; ) {
       
   625 		int l = strlen(fn);
       
   626 		addpath(fn, l);
       
   627 		fn += l + 1;
       
   628 		memcpy((char *)&errsfound, fn, sizeof(int));
       
   629 		fn += sizeof(int);
       
   630 		scanner((q->closure) ? q : q->next);  /* scan next level */
       
   631 		pathbuf[pathpos = oppos] = '\0';
       
   632 	    }
       
   633 	    hrealloc(subdirs, subdirlen, 0);
       
   634 	}
       
   635     }
       
   636     if (pbcwdsav < pathbufcwd) {
       
   637 	if (restoredir(&ds))
       
   638 	    zerr("current directory lost during glob", NULL, 0);
       
   639 	zsfree(ds.dirname);
       
   640 	if (ds.dirfd >= 0)
       
   641 	    close(ds.dirfd);
       
   642 	pathbufcwd = pbcwdsav;
       
   643     }
       
   644 }
       
   645 
       
   646 /* This function tokenizes a zsh glob pattern */
       
   647 
       
   648 /**/
       
   649 static Complist
       
   650 parsecomplist(char *instr)
       
   651 {
       
   652     Patprog p1;
       
   653     Complist l1;
       
   654     char *str;
       
   655     int compflags = gf_noglobdots ? (PAT_FILE|PAT_NOGLD) : PAT_FILE;
       
   656 
       
   657     if (instr[0] == Star && instr[1] == Star &&
       
   658         (instr[2] == '/' || (instr[2] == Star && instr[3] == '/'))) {
       
   659 	/* Match any number of directories. */
       
   660 	int follow;
       
   661 
       
   662 	/* with three stars, follow symbolic links */
       
   663 	follow = (instr[2] == Star);
       
   664 	instr += (3 + follow);
       
   665 
       
   666 	/* Now get the next path component if there is one. */
       
   667 	l1 = (Complist) zhalloc(sizeof *l1);
       
   668 	if ((l1->next = parsecomplist(instr)) == NULL) {
       
   669 	    errflag = 1;
       
   670 	    return NULL;
       
   671 	}
       
   672 	l1->pat = patcompile(NULL, compflags | PAT_ANY, NULL);
       
   673 	l1->closure = 1;		/* ...zero or more times. */
       
   674 	l1->follow = follow;
       
   675 	return l1;
       
   676     }
       
   677 
       
   678     /* Parse repeated directories such as (dir/)# and (dir/)## */
       
   679     if (*(str = instr) == Inpar && !skipparens(Inpar, Outpar, (char **)&str) &&
       
   680         *str == Pound && isset(EXTENDEDGLOB) && str[-2] == '/') {
       
   681 	instr++;
       
   682 	if (!(p1 = patcompile(instr, compflags, &instr)))
       
   683 	    return NULL;
       
   684 	if (instr[0] == '/' && instr[1] == Outpar && instr[2] == Pound) {
       
   685 	    int pdflag = 0;
       
   686 
       
   687 	    instr += 3;
       
   688 	    if (*instr == Pound) {
       
   689 		pdflag = 1;
       
   690 		instr++;
       
   691 	    }
       
   692 	    l1 = (Complist) zhalloc(sizeof *l1);
       
   693 	    l1->pat = p1;
       
   694 	    l1->closure = 1 + pdflag;
       
   695 	    l1->follow = 0;
       
   696 	    l1->next = parsecomplist(instr);
       
   697 	    return (l1->pat) ? l1 : NULL;
       
   698 	}
       
   699     } else {
       
   700 	/* parse single path component */
       
   701 	if (!(p1 = patcompile(instr, compflags|PAT_FILET, &instr)))
       
   702 	    return NULL;
       
   703 	/* then do the remaining path components */
       
   704 	if (*instr == '/' || !*instr) {
       
   705 	    int ef = *instr == '/';
       
   706 
       
   707 	    l1 = (Complist) zhalloc(sizeof *l1);
       
   708 	    l1->pat = p1;
       
   709 	    l1->closure = 0;
       
   710 	    l1->next = ef ? parsecomplist(instr+1) : NULL;
       
   711 	    return (ef && !l1->next) ? NULL : l1;
       
   712 	}
       
   713     }
       
   714     errflag = 1;
       
   715     return NULL;
       
   716 }
       
   717 
       
   718 /* turn a string into a Complist struct:  this has path components */
       
   719 
       
   720 /**/
       
   721 static Complist
       
   722 parsepat(char *str)
       
   723 {
       
   724     long assert;
       
   725     int ignore;
       
   726 
       
   727     patcompstart();
       
   728     /*
       
   729      * Check for initial globbing flags, so that they don't form
       
   730      * a bogus path component.
       
   731      */
       
   732     if ((*str == Inpar && str[1] == Pound && isset(EXTENDEDGLOB)) ||
       
   733 	(isset(KSHGLOB) && *str == '@' && str[1] == Inpar &&
       
   734 	 str[2] == Pound)) {
       
   735 	str += (*str == Inpar) ? 2 : 3;
       
   736 	if (!patgetglobflags(&str, &assert, &ignore))
       
   737 	    return NULL;
       
   738     }
       
   739 
       
   740     /* Now there is no (#X) in front, we can check the path. */
       
   741     if (!pathbuf)
       
   742 	pathbuf = zalloc(pathbufsz = PATH_MAX);
       
   743     DPUTS(pathbufcwd, "BUG: glob changed directory");
       
   744     if (*str == '/') {		/* pattern has absolute path */
       
   745 	str++;
       
   746 	pathbuf[0] = '/';
       
   747 	pathbuf[pathpos = 1] = '\0';
       
   748     } else			/* pattern is relative to pwd */
       
   749 	pathbuf[pathpos = 0] = '\0';
       
   750 
       
   751     return parsecomplist(str);
       
   752 }
       
   753 
       
   754 /* get number after qualifier */
       
   755 
       
   756 /**/
       
   757 static off_t
       
   758 qgetnum(char **s)
       
   759 {
       
   760     off_t v = 0;
       
   761 
       
   762     if (!idigit(**s)) {
       
   763 	zerr("number expected", NULL, 0);
       
   764 	return 0;
       
   765     }
       
   766     while (idigit(**s))
       
   767 	v = v * 10 + *(*s)++ - '0';
       
   768     return v;
       
   769 }
       
   770 
       
   771 /* get mode spec after qualifier */
       
   772 
       
   773 /**/
       
   774 static zlong
       
   775 qgetmodespec(char **s)
       
   776 {
       
   777     zlong yes = 0, no = 0, val, mask, t;
       
   778     char *p = *s, c, how, end;
       
   779 
       
   780     if ((c = *p) == '=' || c == Equals || c == '+' || c == '-' ||
       
   781 	c == '?' || c == Quest || (c >= '0' && c <= '7')) {
       
   782 	end = 0;
       
   783 	c = 0;
       
   784     } else {
       
   785 	end = (c == '<' ? '>' :
       
   786 	       (c == '[' ? ']' :
       
   787 		(c == '{' ? '}' :
       
   788 		 (c == Inang ? Outang :
       
   789 		  (c == Inbrack ? Outbrack :
       
   790 		   (c == Inbrace ? Outbrace : c))))));
       
   791 	p++;
       
   792     }
       
   793     do {
       
   794 	mask = 0;
       
   795 	while (((c = *p) == 'u' || c == 'g' || c == 'o' || c == 'a') && end) {
       
   796 	    switch (c) {
       
   797 	    case 'o': mask |= 01007; break;
       
   798 	    case 'g': mask |= 02070; break;
       
   799 	    case 'u': mask |= 04700; break;
       
   800 	    case 'a': mask |= 07777; break;
       
   801 	    }
       
   802 	    p++;
       
   803 	}
       
   804 	how = ((c == '+' || c == '-') ? c : '=');
       
   805 	if (c == '+' || c == '-' || c == '=' || c == Equals)
       
   806 	    p++;
       
   807 	val = 0;
       
   808 	if (mask) {
       
   809 	    while ((c = *p++) != ',' && c != end) {
       
   810 		switch (c) {
       
   811 		case 'x': val |= 00111; break;
       
   812 		case 'w': val |= 00222; break;
       
   813 		case 'r': val |= 00444; break;
       
   814 		case 's': val |= 06000; break;
       
   815 		case 't': val |= 01000; break;
       
   816 		case '0': case '1': case '2': case '3':
       
   817 		case '4': case '5': case '6': case '7':
       
   818 		    t = ((zlong) c - '0');
       
   819 		    val |= t | (t << 3) | (t << 6);
       
   820 		    break;
       
   821 		default:
       
   822 		    zerr("invalid mode specification", NULL, 0);
       
   823 		    return 0;
       
   824 		}
       
   825 	    }
       
   826 	    if (how == '=' || how == '+') {
       
   827 		yes |= val & mask;
       
   828 		val = ~val;
       
   829 	    }
       
   830 	    if (how == '=' || how == '-')
       
   831 		no |= val & mask;
       
   832 	} else if (!(end && c == end) && c != ',' && c) {
       
   833 	    t = 07777;
       
   834 	    while ((c = *p) == '?' || c == Quest ||
       
   835 		   (c >= '0' && c <= '7')) {
       
   836 		if (c == '?' || c == Quest) {
       
   837 		    t = (t << 3) | 7;
       
   838 		    val <<= 3;
       
   839 		} else {
       
   840 		    t <<= 3;
       
   841 		    val = (val << 3) | ((zlong) c - '0');
       
   842 		}
       
   843 		p++;
       
   844 	    }
       
   845 	    if (end && c != end && c != ',') {
       
   846 		zerr("invalid mode specification", NULL, 0);
       
   847 		return 0;
       
   848 	    }
       
   849 	    if (how == '=') {
       
   850 		yes = (yes & ~t) | val;
       
   851 		no = (no & ~t) | (~val & ~t);
       
   852 	    } else if (how == '+')
       
   853 		yes |= val;
       
   854 	    else
       
   855 		no |= val;
       
   856 	} else {
       
   857 	    zerr("invalid mode specification", NULL, 0);
       
   858 	    return 0;
       
   859         }
       
   860     } while (end && c != end);
       
   861 
       
   862     *s = p;
       
   863     return ((yes & 07777) | ((no & 07777) << 12));
       
   864 }
       
   865 
       
   866 static int
       
   867 gmatchcmp(Gmatch a, Gmatch b)
       
   868 {
       
   869     int i, *s;
       
   870     off_t r = 0L;
       
   871 
       
   872     for (i = gf_nsorts, s = gf_sortlist; i; i--, s++) {
       
   873 	switch (*s & ~GS_DESC) {
       
   874 	case GS_NAME:
       
   875 	    if (gf_numsort)
       
   876 	    	r = nstrpcmp(&b->name, &a->name);
       
   877 	    else
       
   878 	    	r = strpcmp(&b->name, &a->name);
       
   879 	    break;
       
   880 	case GS_DEPTH:
       
   881 	    {
       
   882 		char *aptr = a->name, *bptr = b->name;
       
   883 		int slasha = 0, slashb = 0;
       
   884 		/* Count slashes.  Trailing slashes don't count. */
       
   885 		while (*aptr && *aptr == *bptr)
       
   886 		    aptr++, bptr++;
       
   887 		if (*aptr)
       
   888 		    for (; aptr[1]; aptr++)
       
   889 			if (*aptr == '/') {
       
   890 			    slasha = 1;
       
   891 			    break;
       
   892 			}
       
   893 		if (*bptr)
       
   894 		    for (; bptr[1]; bptr++)
       
   895 			if (*bptr == '/') {
       
   896 			    slashb = 1;
       
   897 			    break;
       
   898 			}
       
   899 		r = slasha - slashb;
       
   900 	    }
       
   901 	    break;
       
   902 	case GS_SIZE:
       
   903 	    r = b->size - a->size;
       
   904 	    break;
       
   905 	case GS_ATIME:
       
   906 	    r = a->atime - b->atime;
       
   907 	    break;
       
   908 	case GS_MTIME:
       
   909 	    r = a->mtime - b->mtime;
       
   910 	    break;
       
   911 	case GS_CTIME:
       
   912 	    r = a->ctime - b->ctime;
       
   913 	    break;
       
   914 	case GS_LINKS:
       
   915 	    r = b->links - a->links;
       
   916 	    break;
       
   917 	case GS__SIZE:
       
   918 	    r = b->_size - a->_size;
       
   919 	    break;
       
   920 	case GS__ATIME:
       
   921 	    r = a->_atime - b->_atime;
       
   922 	    break;
       
   923 	case GS__MTIME:
       
   924 	    r = a->_mtime - b->_mtime;
       
   925 	    break;
       
   926 	case GS__CTIME:
       
   927 	    r = a->_ctime - b->_ctime;
       
   928 	    break;
       
   929 	case GS__LINKS:
       
   930 	    r = b->_links - a->_links;
       
   931 	    break;
       
   932 	}
       
   933 	if (r)
       
   934 	    return (int) ((*s & GS_DESC) ? -r : r);
       
   935     }
       
   936     return 0;
       
   937 }
       
   938 
       
   939 /*
       
   940  * Duplicate a list of qualifiers using the `next' linkage (not the
       
   941  * `or' linkage).  Return the head element and set *last (if last non-NULL)
       
   942  * to point to the last element of the new list.  All allocation is on the
       
   943  * heap (or off the heap?)
       
   944  */
       
   945 static struct qual *dup_qual_list(struct qual *orig, struct qual **lastp)
       
   946 {
       
   947     struct qual *qfirst = NULL, *qlast = NULL;
       
   948 
       
   949     while (orig) {
       
   950 	struct qual *qnew = (struct qual *)zhalloc(sizeof(struct qual));
       
   951 	*qnew = *orig;
       
   952 	qnew->next = qnew->or = NULL;
       
   953 
       
   954 	if (!qfirst)
       
   955 	    qfirst = qnew;
       
   956 	if (qlast)
       
   957 	    qlast->next = qnew;
       
   958 	qlast = qnew;
       
   959 
       
   960 	orig = orig->next;
       
   961     }
       
   962 
       
   963     if (lastp)
       
   964 	*lastp = qlast;
       
   965     return qfirst;
       
   966 }
       
   967 
       
   968 /* Main entry point to the globbing code for filename globbing. *
       
   969  * np points to a node in the list list which will be expanded  *
       
   970  * into a series of nodes.                                      */
       
   971 
       
   972 /**/
       
   973 void
       
   974 zglob(LinkList list, LinkNode np, int nountok)
       
   975 {
       
   976     struct qual *qo, *qn, *ql;
       
   977     LinkNode node = prevnode(np);
       
   978     char *str;				/* the pattern                   */
       
   979     int sl;				/* length of the pattern         */
       
   980     Complist q;				/* pattern after parsing         */
       
   981     char *ostr = (char *)getdata(np);	/* the pattern before the parser */
       
   982 					/* chops it up                   */
       
   983     int first = 0, end = -1;		/* index of first match to return */
       
   984 					/* and index+1 of the last match */
       
   985     struct globdata saved;		/* saved glob state              */
       
   986     int nobareglob = !isset(BAREGLOBQUAL);
       
   987 
       
   988     if (unset(GLOBOPT) || !haswilds(ostr)) {
       
   989 	if (!nountok)
       
   990 	    untokenize(ostr);
       
   991 	return;
       
   992     }
       
   993     save_globstate(saved);
       
   994 
       
   995     str = dupstring(ostr);
       
   996     uremnode(list, np);
       
   997 
       
   998     /* quals will hold the complete list of qualifiers (file static). */
       
   999     quals = NULL;
       
  1000     /*
       
  1001      * qualct and qualorct indicate we have qualifiers in the last
       
  1002      * alternative, or a set of alternatives, respectively.  They
       
  1003      * are not necessarily an accurate count, however.
       
  1004      */
       
  1005     qualct = qualorct = 0;
       
  1006     /*
       
  1007      * colonmod is a concatenated list of all colon modifiers found in
       
  1008      * all sets of qualifiers.
       
  1009      */
       
  1010     colonmod = NULL;
       
  1011     /* The gf_* flags are qualifiers which are applied globally. */
       
  1012     gf_nullglob = isset(NULLGLOB);
       
  1013     gf_markdirs = isset(MARKDIRS);
       
  1014     gf_listtypes = gf_follow = 0;
       
  1015     gf_noglobdots = unset(GLOBDOTS);
       
  1016     gf_numsort = isset(NUMERICGLOBSORT);
       
  1017     gf_sorts = gf_nsorts = 0;
       
  1018 
       
  1019     /* Check for qualifiers */
       
  1020     while (!nobareglob || isset(EXTENDEDGLOB)) {
       
  1021 	struct qual *newquals;
       
  1022 	char *s;
       
  1023 	int sense, paren;
       
  1024 	off_t data;
       
  1025 	char *sdata, *newcolonmod;
       
  1026 	int (*func) _((char *, Statptr, off_t, char *));
       
  1027 
       
  1028 	/*
       
  1029 	 * Initialise state variables for current file pattern.
       
  1030 	 * newquals is the root for the linked list of all qualifiers.
       
  1031 	 * qo is the root of the current list of alternatives.
       
  1032 	 * ql is the end of the current alternative where the `next' will go.
       
  1033 	 * qn is the current qualifier node to be added.
       
  1034 	 *
       
  1035 	 * Here is an attempt at a diagram.  An `or' is added horizontally
       
  1036 	 * to the top line, a `next' at the bottom of the right hand line.
       
  1037 	 * `qn' is usually NULL unless a new `or' has just been added.
       
  1038 	 *
       
  1039 	 * quals -> x  -> x -> qo
       
  1040 	 *          |     |    |
       
  1041 	 *          x     x    x
       
  1042 	 *          |          |
       
  1043 	 *          x          ql
       
  1044 	 *
       
  1045 	 * In fact, after each loop the complete set is in the file static
       
  1046 	 * `quals'.  Then, if we have a second set of qualifiers, we merge
       
  1047 	 * the lists together.  This is only tricky if one or both have an
       
  1048 	 * `or' in them; then we need to distribute over all alternatives.
       
  1049 	 */
       
  1050 	newquals = qo = qn = ql = NULL;
       
  1051 
       
  1052 	sl = strlen(str);
       
  1053 	if (str[sl - 1] != Outpar)
       
  1054 	    break;
       
  1055 
       
  1056 	/* Check these are really qualifiers, not a set of *
       
  1057 	 * alternatives or exclusions.  We can be more     *
       
  1058 	 * lenient with an explicit (#q) than with a bare  *
       
  1059 	 * set of qualifiers.                              */
       
  1060 	paren = 0;
       
  1061 	for (s = str + sl - 2; *s && (*s != Inpar || paren); s--) {
       
  1062 	    switch (*s) {
       
  1063 	    case Outpar:
       
  1064 		paren++; /*FALLTHROUGH*/
       
  1065 	    case Bar:
       
  1066 		nobareglob = 1;
       
  1067 		break;
       
  1068 	    case Tilde:
       
  1069 		if (isset(EXTENDEDGLOB))
       
  1070 		    nobareglob = 1;
       
  1071 		break;
       
  1072 	    case Inpar:
       
  1073 		paren--;
       
  1074 		break;
       
  1075 	    }
       
  1076 	}
       
  1077 	if (*s != Inpar)
       
  1078 	    break;
       
  1079 	if (isset(EXTENDEDGLOB) && s[1] == Pound) {
       
  1080 	    if (s[2] == 'q') {
       
  1081 		*s = 0;
       
  1082 		s += 2;
       
  1083 	    } else
       
  1084 		break;
       
  1085 	} else if (nobareglob)
       
  1086 	    break;
       
  1087 
       
  1088 	/* Real qualifiers found. */
       
  1089 	nobareglob = 1;
       
  1090 	sense = 0;	   /* bit 0 for match (0)/don't match (1)   */
       
  1091 			   /* bit 1 for follow links (2), don't (0) */
       
  1092 	data = 0;	   /* Any numerical argument required       */
       
  1093 	sdata = NULL;	   /* Any list argument required            */
       
  1094 	newcolonmod = NULL; /* Contains trailing colon modifiers    */
       
  1095 
       
  1096 	str[sl-1] = 0;
       
  1097 	*s++ = 0;
       
  1098 	while (*s && !newcolonmod) {
       
  1099 	    func = (int (*) _((char *, Statptr, off_t, char *)))0;
       
  1100 	    if (idigit(*s)) {
       
  1101 		/* Store numeric argument for qualifier */
       
  1102 		func = qualflags;
       
  1103 		data = 0;
       
  1104 		sdata = NULL;
       
  1105 		while (idigit(*s))
       
  1106 		    data = data * 010 + (*s++ - '0');
       
  1107 	    } else if (*s == ',') {
       
  1108 		/* A comma separates alternative sets of qualifiers */
       
  1109 		s++;
       
  1110 		sense = 0;
       
  1111 		if (qualct) {
       
  1112 		    qn = (struct qual *)hcalloc(sizeof *qn);
       
  1113 		    qo->or = qn;
       
  1114 		    qo = qn;
       
  1115 		    qualorct++;
       
  1116 		    qualct = 0;
       
  1117 		    ql = NULL;
       
  1118 		}
       
  1119 	    } else {
       
  1120 		switch (*s++) {
       
  1121 		case ':':
       
  1122 		    /* Remaining arguments are history-type     *
       
  1123 		     * colon substitutions, handled separately. */
       
  1124 		    newcolonmod = s - 1;
       
  1125 		    untokenize(newcolonmod);
       
  1126 		    if (colonmod) {
       
  1127 			/* remember we're searching backwards */
       
  1128 			colonmod = dyncat(newcolonmod, colonmod);
       
  1129 		    } else
       
  1130 			colonmod = newcolonmod;
       
  1131 		    break;
       
  1132 		case Hat:
       
  1133 		case '^':
       
  1134 		    /* Toggle sense:  go from positive to *
       
  1135 		     * negative match and vice versa.     */
       
  1136 		    sense ^= 1;
       
  1137 		    break;
       
  1138 		case '-':
       
  1139 		    /* Toggle matching of symbolic links */
       
  1140 		    sense ^= 2;
       
  1141 		    break;
       
  1142 		case '@':
       
  1143 		    /* Match symbolic links */
       
  1144 		    func = qualislnk;
       
  1145 		    break;
       
  1146 		case Equals:
       
  1147 		case '=':
       
  1148 		    /* Match sockets */
       
  1149 		    func = qualissock;
       
  1150 		    break;
       
  1151 		case 'p':
       
  1152 		    /* Match named pipes */
       
  1153 		    func = qualisfifo;
       
  1154 		    break;
       
  1155 		case '/':
       
  1156 		    /* Match directories */
       
  1157 		    func = qualisdir;
       
  1158 		    break;
       
  1159 		case '.':
       
  1160 		    /* Match regular files */
       
  1161 		    func = qualisreg;
       
  1162 		    break;
       
  1163 		case '%':
       
  1164 		    /* Match special files: block, *
       
  1165 		     * character or any device     */
       
  1166 		    if (*s == 'b')
       
  1167 			s++, func = qualisblk;
       
  1168 		    else if (*s == 'c')
       
  1169 			s++, func = qualischr;
       
  1170 		    else
       
  1171 			func = qualisdev;
       
  1172 		    break;
       
  1173 		case Star:
       
  1174 		    /* Match executable plain files */
       
  1175 		    func = qualiscom;
       
  1176 		    break;
       
  1177 		case 'R':
       
  1178 		    /* Match world-readable files */
       
  1179 		    func = qualflags;
       
  1180 		    data = 0004;
       
  1181 		    break;
       
  1182 		case 'W':
       
  1183 		    /* Match world-writeable files */
       
  1184 		    func = qualflags;
       
  1185 		    data = 0002;
       
  1186 		    break;
       
  1187 		case 'X':
       
  1188 		    /* Match world-executable files */
       
  1189 		    func = qualflags;
       
  1190 		    data = 0001;
       
  1191 		    break;
       
  1192 		case 'A':
       
  1193 		    func = qualflags;
       
  1194 		    data = 0040;
       
  1195 		    break;
       
  1196 		case 'I':
       
  1197 		    func = qualflags;
       
  1198 		    data = 0020;
       
  1199 		    break;
       
  1200 		case 'E':
       
  1201 		    func = qualflags;
       
  1202 		    data = 0010;
       
  1203 		    break;
       
  1204 		case 'r':
       
  1205 		    /* Match files readable by current process */
       
  1206 		    func = qualflags;
       
  1207 		    data = 0400;
       
  1208 		    break;
       
  1209 		case 'w':
       
  1210 		    /* Match files writeable by current process */
       
  1211 		    func = qualflags;
       
  1212 		    data = 0200;
       
  1213 		    break;
       
  1214 		case 'x':
       
  1215 		    /* Match files executable by current process */
       
  1216 		    func = qualflags;
       
  1217 		    data = 0100;
       
  1218 		    break;
       
  1219 		case 's':
       
  1220 		    /* Match setuid files */
       
  1221 		    func = qualflags;
       
  1222 		    data = 04000;
       
  1223 		    break;
       
  1224 		case 'S':
       
  1225 		    /* Match setgid files */
       
  1226 		    func = qualflags;
       
  1227 		    data = 02000;
       
  1228 		    break;
       
  1229 		case 't':
       
  1230 		    func = qualflags;
       
  1231 		    data = 01000;
       
  1232 		    break;
       
  1233 		case 'd':
       
  1234 		    /* Match device files by device number  *
       
  1235 		     * (as given by stat's st_dev element). */
       
  1236 		    func = qualdev;
       
  1237 		    data = qgetnum(&s);
       
  1238 		    break;
       
  1239 		case 'l':
       
  1240 		    /* Match files with the given no. of hard links */
       
  1241 		    func = qualnlink;
       
  1242 		    g_amc = -1;
       
  1243 		    goto getrange;
       
  1244 		case 'U':
       
  1245 		    /* Match files owned by effective user ID */
       
  1246 		    func = qualuid;
       
  1247 		    data = geteuid();
       
  1248 		    break;
       
  1249 		case 'G':
       
  1250 		    /* Match files owned by effective group ID */
       
  1251 		    func = qualgid;
       
  1252 		    data = getegid();
       
  1253 		    break;
       
  1254 		case 'u':
       
  1255 		    /* Match files owned by given user id */
       
  1256 		    func = qualuid;
       
  1257 		    /* either the actual uid... */
       
  1258 		    if (idigit(*s))
       
  1259 			data = qgetnum(&s);
       
  1260 		    else {
       
  1261 			/* ... or a user name */
       
  1262 			char sav, *tt;
       
  1263 
       
  1264 			/* Find matching delimiters */
       
  1265 			tt = get_strarg(s);
       
  1266 			if (!*tt) {
       
  1267 			    zerr("missing end of name",
       
  1268 				 NULL, 0);
       
  1269 			    data = 0;
       
  1270 			} else {
       
  1271 #ifdef HAVE_GETPWNAM
       
  1272 			    struct passwd *pw;
       
  1273 			    sav = *tt;
       
  1274 			    *tt = '\0';
       
  1275 
       
  1276 			    if ((pw = getpwnam(s + 1)))
       
  1277 				data = pw->pw_uid;
       
  1278 			    else {
       
  1279 				zerr("unknown user", NULL, 0);
       
  1280 				data = 0;
       
  1281 			    }
       
  1282 			    *tt = sav;
       
  1283 #else /* !HAVE_GETPWNAM */
       
  1284 			    sav = *tt;
       
  1285 			    zerr("unknown user", NULL, 0);
       
  1286 			    data = 0;
       
  1287 #endif /* !HAVE_GETPWNAM */
       
  1288 			    if (sav)
       
  1289 				s = tt + 1;
       
  1290 			    else
       
  1291 				s = tt;
       
  1292 			}
       
  1293 		    }
       
  1294 		    break;
       
  1295 		case 'g':
       
  1296 		    /* Given gid or group id... works like `u' */
       
  1297 		    func = qualgid;
       
  1298 		    /* either the actual gid... */
       
  1299 		    if (idigit(*s))
       
  1300 			data = qgetnum(&s);
       
  1301 		    else {
       
  1302 			/* ...or a delimited group name. */
       
  1303 			char sav, *tt;
       
  1304 
       
  1305 			tt = get_strarg(s);
       
  1306 			if (!*tt) {
       
  1307 			    zerr("missing end of name",
       
  1308 				 NULL, 0);
       
  1309 			    data = 0;
       
  1310 			} else {
       
  1311 #ifdef HAVE_GETGRNAM
       
  1312 			    struct group *gr;
       
  1313 			    sav = *tt;
       
  1314 			    *tt = '\0';
       
  1315 
       
  1316 			    if ((gr = getgrnam(s + 1)))
       
  1317 				data = gr->gr_gid;
       
  1318 			    else {
       
  1319 				zerr("unknown group", NULL, 0);
       
  1320 				data = 0;
       
  1321 			    }
       
  1322 			    *tt = sav;
       
  1323 #else /* !HAVE_GETGRNAM */
       
  1324 			    sav = *tt;
       
  1325 			    zerr("unknown group", NULL, 0);
       
  1326 			    data = 0;
       
  1327 #endif /* !HAVE_GETGRNAM */
       
  1328 			    if (sav)
       
  1329 				s = tt + 1;
       
  1330 			    else
       
  1331 				s = tt;
       
  1332 			}
       
  1333 		    }
       
  1334 		    break;
       
  1335 		case 'f':
       
  1336 		    /* Match modes with chmod-spec. */
       
  1337 		    func = qualmodeflags;
       
  1338 		    data = qgetmodespec(&s);
       
  1339 		    break;
       
  1340 		case 'F':
       
  1341 		    func = qualnonemptydir;
       
  1342 		    break;
       
  1343 		case 'M':
       
  1344 		    /* Mark directories with a / */
       
  1345 		    if ((gf_markdirs = !(sense & 1)))
       
  1346 			gf_follow = sense & 2;
       
  1347 		    break;
       
  1348 		case 'T':
       
  1349 		    /* Mark types in a `ls -F' type fashion */
       
  1350 		    if ((gf_listtypes = !(sense & 1)))
       
  1351 			gf_follow = sense & 2;
       
  1352 		    break;
       
  1353 		case 'N':
       
  1354 		    /* Nullglob:  remove unmatched patterns. */
       
  1355 		    gf_nullglob = !(sense & 1);
       
  1356 		    break;
       
  1357 		case 'D':
       
  1358 		    /* Glob dots: match leading dots implicitly */
       
  1359 		    gf_noglobdots = sense & 1;
       
  1360 		    break;
       
  1361 		case 'n':
       
  1362 		    /* Numeric glob sort */
       
  1363 		    gf_numsort = !(sense & 1);
       
  1364 		    break;
       
  1365 		case 'a':
       
  1366 		    /* Access time in given range */
       
  1367 		    g_amc = 0;
       
  1368 		    func = qualtime;
       
  1369 		    goto getrange;
       
  1370 		case 'm':
       
  1371 		    /* Modification time in given range */
       
  1372 		    g_amc = 1;
       
  1373 		    func = qualtime;
       
  1374 		    goto getrange;
       
  1375 		case 'c':
       
  1376 		    /* Inode creation time in given range */
       
  1377 		    g_amc = 2;
       
  1378 		    func = qualtime;
       
  1379 		    goto getrange;
       
  1380 		case 'L':
       
  1381 		    /* File size (Length) in given range */
       
  1382 		    func = qualsize;
       
  1383 		    g_amc = -1;
       
  1384 		    /* Get size multiplier */
       
  1385 		    g_units = TT_BYTES;
       
  1386 		    if (*s == 'p' || *s == 'P')
       
  1387 			g_units = TT_POSIX_BLOCKS, ++s;
       
  1388 		    else if (*s == 'k' || *s == 'K')
       
  1389 			g_units = TT_KILOBYTES, ++s;
       
  1390 		    else if (*s == 'm' || *s == 'M')
       
  1391 			g_units = TT_MEGABYTES, ++s;
       
  1392 		  getrange:
       
  1393 		    /* Get time multiplier */
       
  1394 		    if (g_amc >= 0) {
       
  1395 			g_units = TT_DAYS;
       
  1396 			if (*s == 'h')
       
  1397 			    g_units = TT_HOURS, ++s;
       
  1398 			else if (*s == 'm')
       
  1399 			    g_units = TT_MINS, ++s;
       
  1400 			else if (*s == 'w')
       
  1401 			    g_units = TT_WEEKS, ++s;
       
  1402 			else if (*s == 'M')
       
  1403 			    g_units = TT_MONTHS, ++s;
       
  1404 			else if (*s == 's')
       
  1405 			    g_units = TT_SECONDS, ++s;
       
  1406 		    }
       
  1407 		    /* See if it's greater than, equal to, or less than */
       
  1408 		    if ((g_range = *s == '+' ? 1 : *s == '-' ? -1 : 0))
       
  1409 			++s;
       
  1410 		    data = qgetnum(&s);
       
  1411 		    break;
       
  1412 
       
  1413 		case 'o':
       
  1414 		case 'O':
       
  1415 		{
       
  1416 		    int t;
       
  1417 
       
  1418 		    switch (*s) {
       
  1419 		    case 'n': t = GS_NAME; break;
       
  1420 		    case 'L': t = GS_SIZE; break;
       
  1421 		    case 'l': t = GS_LINKS; break;
       
  1422 		    case 'a': t = GS_ATIME; break;
       
  1423 		    case 'm': t = GS_MTIME; break;
       
  1424 		    case 'c': t = GS_CTIME; break;
       
  1425 		    case 'd': t = GS_DEPTH; break;
       
  1426 		    default:
       
  1427 			zerr("unknown sort specifier", NULL, 0);
       
  1428 			restore_globstate(saved);
       
  1429 			return;
       
  1430 		    }
       
  1431 		    if ((sense & 2) && !(t & (GS_NAME|GS_DEPTH)))
       
  1432 			t <<= GS_SHIFT;
       
  1433 		    if (gf_sorts & t) {
       
  1434 			zerr("doubled sort specifier", NULL, 0);
       
  1435 			restore_globstate(saved);
       
  1436 			return;
       
  1437 		    }
       
  1438 		    gf_sorts |= t;
       
  1439 		    gf_sortlist[gf_nsorts++] = t |
       
  1440 			(((sense & 1) ^ (s[-1] == 'O')) ? GS_DESC : 0);
       
  1441 		    s++;
       
  1442 		    break;
       
  1443 		}
       
  1444 		case '+':
       
  1445 		case 'e':
       
  1446 		{
       
  1447 		    char sav, *tt;
       
  1448 		    int plus;
       
  1449 
       
  1450 		    if (s[-1] == '+') {
       
  1451 			plus = 0;
       
  1452 			tt = s;
       
  1453 			while (iident(*tt))
       
  1454 			    tt++;
       
  1455 			if (tt == s)
       
  1456 			{
       
  1457 			    zerr("missing identifier after `+'", NULL, 0);
       
  1458 			    tt = NULL;
       
  1459 			}
       
  1460 		    } else {
       
  1461 			plus = 1;
       
  1462 			tt = get_strarg(s);
       
  1463 			if (!*tt)
       
  1464 			{
       
  1465 			    zerr("missing end of string", NULL, 0);
       
  1466 			    tt = NULL;
       
  1467 			}
       
  1468 		    }
       
  1469 
       
  1470 		    if (tt == NULL) {
       
  1471 			data = 0;
       
  1472 		    } else {
       
  1473 			sav = *tt;
       
  1474 			*tt = '\0';
       
  1475 			func = qualsheval;
       
  1476 			sdata = dupstring(s + plus);
       
  1477 			untokenize(sdata);
       
  1478 			*tt = sav;
       
  1479 			if (sav)
       
  1480 			    s = tt + plus;
       
  1481 			else
       
  1482 			    s = tt;
       
  1483 		    }
       
  1484 		    break;
       
  1485 		}
       
  1486 		case '[':
       
  1487 		case Inbrack:
       
  1488 		{
       
  1489 		    char *os = --s;
       
  1490 		    struct value v;
       
  1491 
       
  1492 		    v.isarr = SCANPM_WANTVALS;
       
  1493 		    v.pm = NULL;
       
  1494 		    v.end = -1;
       
  1495 		    v.inv = 0;
       
  1496 		    if (getindex(&s, &v, 0) || s == os) {
       
  1497 			zerr("invalid subscript", NULL, 0);
       
  1498 			restore_globstate(saved);
       
  1499 			return;
       
  1500 		    }
       
  1501 		    first = v.start;
       
  1502 		    end = v.end;
       
  1503 		    break;
       
  1504 		}
       
  1505 		default:
       
  1506 		    zerr("unknown file attribute", NULL, 0);
       
  1507 		    restore_globstate(saved);
       
  1508 		    return;
       
  1509 		}
       
  1510 	    }
       
  1511 	    if (func) {
       
  1512 		/* Requested test is performed by function func */
       
  1513 		if (!qn)
       
  1514 		    qn = (struct qual *)hcalloc(sizeof *qn);
       
  1515 		if (ql)
       
  1516 		    ql->next = qn;
       
  1517 		ql = qn;
       
  1518 		if (!newquals)
       
  1519 		    newquals = qo = qn;
       
  1520 		qn->func = func;
       
  1521 		qn->sense = sense;
       
  1522 		qn->data = data;
       
  1523 		qn->sdata = sdata;
       
  1524 		qn->range = g_range;
       
  1525 		qn->units = g_units;
       
  1526 		qn->amc = g_amc;
       
  1527 
       
  1528 		qn = NULL;
       
  1529 		qualct++;
       
  1530 	    }
       
  1531 	    if (errflag) {
       
  1532 		restore_globstate(saved);
       
  1533 		return;
       
  1534 	    }
       
  1535 	}
       
  1536 
       
  1537 	if (quals && newquals) {
       
  1538 	    /* Merge previous group of qualifiers with new set. */
       
  1539 	    if (quals->or || newquals->or) {
       
  1540 		/* The hard case. */
       
  1541 		struct qual *qorhead = NULL, *qortail = NULL;
       
  1542 		/*
       
  1543 		 * Distribute in the most trivial way, by creating
       
  1544 		 * all possible combinations of the two sets and chaining
       
  1545 		 * these into one long set of alternatives given
       
  1546 		 * by qorhead and qortail.
       
  1547 		 */
       
  1548 		for (qn = newquals; qn; qn = qn->or) {
       
  1549 		    for (qo = quals; qo; qo = qo->or) {
       
  1550 			struct qual *qfirst, *qlast;
       
  1551 			int islast = !qn->or && !qo->or;
       
  1552 			/* Generate first set of qualifiers... */
       
  1553 			if (islast) {
       
  1554 			    /* Last time round:  don't bother copying. */
       
  1555 			    qfirst = qn;
       
  1556 			    for (qlast = qfirst; qlast->next;
       
  1557 				 qlast = qlast->next)
       
  1558 				;			    
       
  1559 			} else
       
  1560 			    qfirst = dup_qual_list(qn, &qlast);
       
  1561 			/* ... link into new `or' chain ... */
       
  1562 			if (!qorhead)
       
  1563 			    qorhead = qfirst;
       
  1564 			if (qortail)
       
  1565 			    qortail->or = qfirst;
       
  1566 			qortail = qfirst;
       
  1567 			/* ... and concatenate second set. */
       
  1568 			qlast->next = islast ? qo : dup_qual_list(qo, NULL);
       
  1569 		    }
       
  1570 		}
       
  1571 		quals = qorhead;
       
  1572 	    } else {
       
  1573 		/*
       
  1574 		 * Easy: we can just chain the qualifiers together.
       
  1575 		 * This is an optimisation; the code above will work, too.
       
  1576 		 * We retain the original left to right ordering --- remember
       
  1577 		 * we are searching for sets of qualifiers from the right.
       
  1578 		 */
       
  1579 		qn = newquals;
       
  1580 		for ( ; newquals->next; newquals = newquals->next)
       
  1581 		    ;
       
  1582 		newquals->next = quals;
       
  1583 		quals = qn;
       
  1584 	    }
       
  1585 	} else if (newquals)
       
  1586 	    quals = newquals;
       
  1587     }
       
  1588     q = parsepat(str);
       
  1589     if (!q || errflag) {	/* if parsing failed */
       
  1590 	restore_globstate(saved);
       
  1591 	if (unset(BADPATTERN)) {
       
  1592 	    if (!nountok)
       
  1593 		untokenize(ostr);
       
  1594 	    insertlinknode(list, node, ostr);
       
  1595 	    return;
       
  1596 	}
       
  1597 	errflag = 0;
       
  1598 	zerr("bad pattern: %s", ostr, 0);
       
  1599 	return;
       
  1600     }
       
  1601     if (!gf_nsorts) {
       
  1602 	gf_sortlist[0] = gf_sorts = GS_NAME;
       
  1603 	gf_nsorts = 1;
       
  1604     }
       
  1605     /* Initialise receptacle for matched files, *
       
  1606      * expanded by insert() where necessary.    */
       
  1607     matchptr = matchbuf = (Gmatch)zalloc((matchsz = 16) *
       
  1608 					 sizeof(struct gmatch));
       
  1609     matchct = 0;
       
  1610     pattrystart();
       
  1611 
       
  1612     /* The actual processing takes place here: matches go into  *
       
  1613      * matchbuf.  This is the only top-level call to scanner(). */
       
  1614     scanner(q);
       
  1615 
       
  1616     /* Deal with failures to match depending on options */
       
  1617     if (matchct)
       
  1618 	badcshglob |= 2;	/* at least one cmd. line expansion O.K. */
       
  1619     else if (!gf_nullglob) {
       
  1620 	if (isset(CSHNULLGLOB)) {
       
  1621 	    badcshglob |= 1;	/* at least one cmd. line expansion failed */
       
  1622 	} else if (isset(NOMATCH)) {
       
  1623 	    zerr("no matches found: %s", ostr, 0);
       
  1624 	    free(matchbuf);
       
  1625 	    restore_globstate(saved);
       
  1626 	    return;
       
  1627 	} else {
       
  1628 	    /* treat as an ordinary string */
       
  1629 	    untokenize(matchptr->name = dupstring(ostr));
       
  1630 	    matchptr++;
       
  1631 	    matchct = 1;
       
  1632 	}
       
  1633     }
       
  1634     /* Sort arguments in to lexical (and possibly numeric) order. *
       
  1635      * This is reversed to facilitate insertion into the list.    */
       
  1636     qsort((void *) & matchbuf[0], matchct, sizeof(struct gmatch),
       
  1637 	       (int (*) _((const void *, const void *)))gmatchcmp);
       
  1638 
       
  1639     if (first < 0) {
       
  1640 	first += matchct;
       
  1641 	if (first < 0)
       
  1642 	    first = 0;
       
  1643     }
       
  1644     if (end < 0)
       
  1645 	end += matchct + 1;
       
  1646     else if (end > matchct)
       
  1647 	end = matchct;
       
  1648     if ((end -= first) > 0) {
       
  1649 	matchptr = matchbuf + matchct - first - end;
       
  1650 	while (end-- > 0) {		/* insert matches in the arg list */
       
  1651 	    insertlinknode(list, node, matchptr->name);
       
  1652 	    matchptr++;
       
  1653 	}
       
  1654     }
       
  1655     free(matchbuf);
       
  1656 
       
  1657     restore_globstate(saved);
       
  1658 }
       
  1659 
       
  1660 /* Return the trailing character for marking file types */
       
  1661 
       
  1662 /**/
       
  1663 mod_export char
       
  1664 file_type(mode_t filemode)
       
  1665 {
       
  1666     if(S_ISBLK(filemode))
       
  1667 	return '#';
       
  1668     else if(S_ISCHR(filemode))
       
  1669 	return '%';
       
  1670     else if(S_ISDIR(filemode))
       
  1671 	return '/';
       
  1672     else if(S_ISFIFO(filemode))
       
  1673 	return '|';
       
  1674     else if(S_ISLNK(filemode))
       
  1675 	return '@';
       
  1676     else if(S_ISREG(filemode))
       
  1677 	return (filemode & S_IXUGO) ? '*' : ' ';
       
  1678     else if(S_ISSOCK(filemode))
       
  1679 	return '=';
       
  1680     else
       
  1681 	return '?';
       
  1682 }
       
  1683 
       
  1684 /* check to see if str is eligible for brace expansion */
       
  1685 
       
  1686 /**/
       
  1687 mod_export int
       
  1688 hasbraces(char *str)
       
  1689 {
       
  1690     char *lbr, *mbr, *comma;
       
  1691 
       
  1692     if (isset(BRACECCL)) {
       
  1693 	/* In this case, any properly formed brace expression  *
       
  1694 	 * will match and expand to the characters in between. */
       
  1695 	int bc, c;
       
  1696 
       
  1697 	for (bc = 0; (c = *str); ++str)
       
  1698 	    if (c == Inbrace) {
       
  1699 		if (!bc && str[1] == Outbrace)
       
  1700 		    *str++ = '{', *str = '}';
       
  1701 		else
       
  1702 		    bc++;
       
  1703 	    } else if (c == Outbrace) {
       
  1704 		if (!bc)
       
  1705 		    *str = '}';
       
  1706 		else if (!--bc)
       
  1707 		    return 1;
       
  1708 	    }
       
  1709 	return 0;
       
  1710     }
       
  1711     /* Otherwise we need to look for... */
       
  1712     lbr = mbr = comma = NULL;
       
  1713     for (;;) {
       
  1714 	switch (*str++) {
       
  1715 	case Inbrace:
       
  1716 	    if (!lbr) {
       
  1717 		lbr = str - 1;
       
  1718 		while (idigit(*str))
       
  1719 		    str++;
       
  1720 		if (*str == '.' && str[1] == '.') {
       
  1721 		    str++;
       
  1722 		    while (idigit(*++str));
       
  1723 		    if (*str == Outbrace &&
       
  1724 			(idigit(lbr[1]) || idigit(str[-1])))
       
  1725 			return 1;
       
  1726 		}
       
  1727 	    } else {
       
  1728 		char *s = --str;
       
  1729 
       
  1730 		if (skipparens(Inbrace, Outbrace, &str)) {
       
  1731 		    *lbr = *s = '{';
       
  1732 		    if (comma)
       
  1733 			str = comma;
       
  1734 		    if (mbr && mbr < str)
       
  1735 			str = mbr;
       
  1736 		    lbr = mbr = comma = NULL;
       
  1737 		} else if (!mbr)
       
  1738 		    mbr = s;
       
  1739 	    }
       
  1740 	    break;
       
  1741 	case Outbrace:
       
  1742 	    if (!lbr)
       
  1743 		str[-1] = '}';
       
  1744 	    else if (comma)
       
  1745 		return 1;
       
  1746 	    else {
       
  1747 		*lbr = '{';
       
  1748 		str[-1] = '}';
       
  1749 		if (mbr)
       
  1750 		    str = mbr;
       
  1751 		mbr = lbr = NULL;
       
  1752 	    }
       
  1753 	    break;
       
  1754 	case Comma:
       
  1755 	    if (!lbr)
       
  1756 		str[-1] = ',';
       
  1757 	    else if (!comma)
       
  1758 		comma = str - 1;
       
  1759 	    break;
       
  1760 	case '\0':
       
  1761 	    if (lbr)
       
  1762 		*lbr = '{';
       
  1763 	    if (!mbr && !comma)
       
  1764 		return 0;
       
  1765 	    if (comma)
       
  1766 		str = comma;
       
  1767 	    if (mbr && mbr < str)
       
  1768 		str = mbr;
       
  1769 	    lbr = mbr = comma = NULL;
       
  1770 	    break;
       
  1771 	}
       
  1772     }
       
  1773 }
       
  1774 
       
  1775 /* expand stuff like >>*.c */
       
  1776 
       
  1777 /**/
       
  1778 int
       
  1779 xpandredir(struct redir *fn, LinkList tab)
       
  1780 {
       
  1781     char *nam;
       
  1782     struct redir *ff;
       
  1783     int ret = 0;
       
  1784     local_list1(fake);
       
  1785 
       
  1786     /* Stick the name in a list... */
       
  1787     init_list1(fake, fn->name);
       
  1788     /* ...which undergoes all the usual shell expansions */
       
  1789     prefork(&fake, isset(MULTIOS) ? 0 : PF_SINGLE);
       
  1790     /* Globbing is only done for multios. */
       
  1791     if (!errflag && isset(MULTIOS))
       
  1792 	globlist(&fake, 0);
       
  1793     if (errflag)
       
  1794 	return 0;
       
  1795     if (nonempty(&fake) && !nextnode(firstnode(&fake))) {
       
  1796 	/* Just one match, the usual case. */
       
  1797 	char *s = peekfirst(&fake);
       
  1798 	fn->name = s;
       
  1799 	untokenize(s);
       
  1800 	if (fn->type == REDIR_MERGEIN || fn->type == REDIR_MERGEOUT) {
       
  1801 	    if (s[0] == '-' && !s[1])
       
  1802 		fn->type = REDIR_CLOSE;
       
  1803 	    else if (s[0] == 'p' && !s[1])
       
  1804 		fn->fd2 = -2;
       
  1805 	    else {
       
  1806 		while (idigit(*s))
       
  1807 		    s++;
       
  1808 		if (!*s && s > fn->name)
       
  1809 		    fn->fd2 = zstrtol(fn->name, NULL, 10);
       
  1810 		else if (fn->type == REDIR_MERGEIN)
       
  1811 		    zerr("file number expected", NULL, 0);
       
  1812 		else
       
  1813 		    fn->type = REDIR_ERRWRITE;
       
  1814 	    }
       
  1815 	}
       
  1816     } else if (fn->type == REDIR_MERGEIN)
       
  1817 	zerr("file number expected", NULL, 0);
       
  1818     else {
       
  1819 	if (fn->type == REDIR_MERGEOUT)
       
  1820 	    fn->type = REDIR_ERRWRITE;
       
  1821 	while ((nam = (char *)ugetnode(&fake))) {
       
  1822 	    /* Loop over matches, duplicating the *
       
  1823 	     * redirection for each file found.   */
       
  1824 	    ff = (struct redir *) zhalloc(sizeof *ff);
       
  1825 	    *ff = *fn;
       
  1826 	    ff->name = nam;
       
  1827 	    addlinknode(tab, ff);
       
  1828 	    ret = 1;
       
  1829 	}
       
  1830     }
       
  1831     return ret;
       
  1832 }
       
  1833 
       
  1834 /* brace expansion */
       
  1835 
       
  1836 /**/
       
  1837 mod_export void
       
  1838 xpandbraces(LinkList list, LinkNode *np)
       
  1839 {
       
  1840     LinkNode node = (*np), last = prevnode(node);
       
  1841     char *str = (char *)getdata(node), *str3 = str, *str2;
       
  1842     int prev, bc, comma, dotdot;
       
  1843 
       
  1844     for (; *str != Inbrace; str++);
       
  1845     /* First, match up braces and see what we have. */
       
  1846     for (str2 = str, bc = comma = dotdot = 0; *str2; ++str2)
       
  1847 	if (*str2 == Inbrace)
       
  1848 	    ++bc;
       
  1849 	else if (*str2 == Outbrace) {
       
  1850 	    if (--bc == 0)
       
  1851 		break;
       
  1852 	} else if (bc == 1) {
       
  1853 	    if (*str2 == Comma)
       
  1854 		++comma;	/* we have {foo,bar} */
       
  1855 	    else if (*str2 == '.' && str2[1] == '.')
       
  1856 		dotdot++;	/* we have {num1..num2} */
       
  1857 	}
       
  1858     DPUTS(bc, "BUG: unmatched brace in xpandbraces()");
       
  1859     if (!comma && dotdot) {
       
  1860 	/* Expand range like 0..10 numerically: comma or recursive
       
  1861 	   brace expansion take precedence. */
       
  1862 	char *dots, *p;
       
  1863 	LinkNode olast = last;
       
  1864 	/* Get the first number of the range */
       
  1865 	int rstart = zstrtol(str+1,&dots,10), rend = 0, err = 0, rev = 0;
       
  1866 	int wid1 = (dots - str) - 1, wid2 = (str2 - dots) - 2;
       
  1867 	int strp = str - str3;
       
  1868 
       
  1869 	if (dots == str + 1 || *dots != '.' || dots[1] != '.')
       
  1870 	    err++;
       
  1871 	else {
       
  1872 	    /* Get the last number of the range */
       
  1873 	    rend = zstrtol(dots+2,&p,10);
       
  1874 	    if (p == dots+2 || p != str2)
       
  1875 		err++;
       
  1876 	}
       
  1877 	if (!err) {
       
  1878 	    /* If either no. begins with a zero, pad the output with   *
       
  1879 	     * zeroes. Otherwise, choose a min width to suppress them. */
       
  1880 	    int minw = (str[1] == '0') ? wid1 : (dots[2] == '0' ) ? wid2 :
       
  1881 		(wid2 > wid1) ? wid1 : wid2;
       
  1882 	    if (rstart > rend) {
       
  1883 		/* Handle decreasing ranges correctly. */
       
  1884 		int rt = rend;
       
  1885 		rend = rstart;
       
  1886 		rstart = rt;
       
  1887 		rev = 1;
       
  1888 	    }
       
  1889 	    uremnode(list, node);
       
  1890 	    for (; rend >= rstart; rend--) {
       
  1891 		/* Node added in at end, so do highest first */
       
  1892 		p = dupstring(str3);
       
  1893 		sprintf(p + strp, "%0*d", minw, rend);
       
  1894 		strcat(p + strp, str2 + 1);
       
  1895 		insertlinknode(list, last, p);
       
  1896 		if (rev)	/* decreasing:  add in reverse order. */
       
  1897 		    last = nextnode(last);
       
  1898 	    }
       
  1899 	    *np = nextnode(olast);
       
  1900 	    return;
       
  1901 	}
       
  1902     }
       
  1903     if (!comma && isset(BRACECCL)) {	/* {a-mnop} */
       
  1904 	/* Here we expand each character to a separate node,      *
       
  1905 	 * but also ranges of characters like a-m.  ccl is a      *
       
  1906 	 * set of flags saying whether each character is present; *
       
  1907 	 * the final list is in lexical order.                    */
       
  1908 	char ccl[256], *p;
       
  1909 	unsigned char c1, c2;
       
  1910 	unsigned int len, pl;
       
  1911 	int lastch = -1;
       
  1912 
       
  1913 	uremnode(list, node);
       
  1914 	memset(ccl, 0, sizeof(ccl) / sizeof(ccl[0]));
       
  1915 	for (p = str + 1; p < str2;) {
       
  1916 	    if (itok(c1 = *p++))
       
  1917 		c1 = ztokens[c1 - STOUC(Pound)];
       
  1918 	    if ((char) c1 == Meta)
       
  1919 		c1 = 32 ^ *p++;
       
  1920 	    if (itok(c2 = *p))
       
  1921 		c2 = ztokens[c2 - STOUC(Pound)];
       
  1922 	    if ((char) c2 == Meta)
       
  1923 		c2 = 32 ^ p[1];
       
  1924 	    if (c1 == '-' && lastch >= 0 && p < str2 && lastch <= (int)c2) {
       
  1925 		while (lastch < (int)c2)
       
  1926 		    ccl[lastch++] = 1;
       
  1927 		lastch = -1;
       
  1928 	    } else
       
  1929 		ccl[lastch = c1] = 1;
       
  1930 	}
       
  1931 	pl = str - str3;
       
  1932 	len = pl + strlen(++str2) + 2;
       
  1933 	for (p = ccl + 255; p-- > ccl;)
       
  1934 	    if (*p) {
       
  1935 		c1 = p - ccl;
       
  1936 		if (imeta(c1)) {
       
  1937 		    str = hcalloc(len + 1);
       
  1938 		    str[pl] = Meta;
       
  1939 		    str[pl+1] = c1 ^ 32;
       
  1940 		    strcpy(str + pl + 2, str2);
       
  1941 		} else {
       
  1942 		    str = hcalloc(len);
       
  1943 		    str[pl] = c1;
       
  1944 		    strcpy(str + pl + 1, str2);
       
  1945 		}
       
  1946 		memcpy(str, str3, pl);
       
  1947 		insertlinknode(list, last, str);
       
  1948 	    }
       
  1949 	*np = nextnode(last);
       
  1950 	return;
       
  1951     }
       
  1952     prev = str++ - str3;
       
  1953     str2++;
       
  1954     uremnode(list, node);
       
  1955     node = last;
       
  1956     /* Finally, normal comma expansion               *
       
  1957      * str1{foo,bar}str2 -> str1foostr2 str1barstr2. *
       
  1958      * Any number of intervening commas is allowed.  */
       
  1959     for (;;) {
       
  1960 	char *zz, *str4;
       
  1961 	int cnt;
       
  1962 
       
  1963 	for (str4 = str, cnt = 0; cnt || (*str != Comma && *str !=
       
  1964 					  Outbrace); str++) {
       
  1965 	    if (*str == Inbrace)
       
  1966 		cnt++;
       
  1967 	    else if (*str == Outbrace)
       
  1968 		cnt--;
       
  1969 	    DPUTS(!*str, "BUG: illegal brace expansion");
       
  1970 	}
       
  1971 	/* Concatenate the string before the braces (str3), the section *
       
  1972 	 * just found (str4) and the text after the braces (str2)       */
       
  1973 	zz = (char *) hcalloc(prev + (str - str4) + strlen(str2) + 1);
       
  1974 	ztrncpy(zz, str3, prev);
       
  1975 	strncat(zz, str4, str - str4);
       
  1976 	strcat(zz, str2);
       
  1977 	/* and add this text to the argument list. */
       
  1978 	insertlinknode(list, node, zz);
       
  1979 	incnode(node);
       
  1980 	if (*str != Outbrace)
       
  1981 	    str++;
       
  1982 	else
       
  1983 	    break;
       
  1984     }
       
  1985     *np = nextnode(last);
       
  1986 }
       
  1987 
       
  1988 /* check to see if a matches b (b is not a filename pattern) */
       
  1989 
       
  1990 /**/
       
  1991 int
       
  1992 matchpat(char *a, char *b)
       
  1993 {
       
  1994     Patprog p = patcompile(b, PAT_STATIC, NULL);
       
  1995 
       
  1996     if (!p) {
       
  1997 	zerr("bad pattern: %s", b, 0);
       
  1998 	return 0;
       
  1999     }
       
  2000     return pattry(p, a);
       
  2001 }
       
  2002 
       
  2003 /* do the ${foo%%bar}, ${foo#bar} stuff */
       
  2004 /* please do not laugh at this code. */
       
  2005 
       
  2006 struct repldata {
       
  2007     int b, e;			/* beginning and end of chunk to replace */
       
  2008     char *replstr;		/* replacement string to use */
       
  2009 };
       
  2010 typedef struct repldata *Repldata;
       
  2011 
       
  2012 /*
       
  2013  * List of bits of matches to concatenate with replacement string.
       
  2014  * The data is a struct repldata.  It is not used in cases like
       
  2015  * ${...//#foo/bar} even though SUB_GLOBAL is set, since the match
       
  2016  * is anchored.  It goes on the heap.
       
  2017  */
       
  2018 
       
  2019 static LinkList repllist;
       
  2020 
       
  2021 /* Having found a match in getmatch, decide what part of string
       
  2022  * to return.  The matched part starts b characters into string s
       
  2023  * and finishes e characters in: 0 <= b <= e <= strlen(s)
       
  2024  * (yes, empty matches should work).
       
  2025  * fl is a set of the SUB_* matches defined in zsh.h from SUB_MATCH onwards;
       
  2026  * the lower parts are ignored.
       
  2027  * replstr is the replacement string for a substitution
       
  2028  */
       
  2029 
       
  2030 /**/
       
  2031 static char *
       
  2032 get_match_ret(char *s, int b, int e, int fl, char *replstr)
       
  2033 {
       
  2034     char buf[80], *r, *p, *rr;
       
  2035     int ll = 0, l = strlen(s), bl = 0, t = 0, i;
       
  2036 
       
  2037     if (replstr) {
       
  2038 	if (fl & SUB_DOSUBST) {
       
  2039 	    replstr = dupstring(replstr);
       
  2040 	    singsub(&replstr);
       
  2041 	    untokenize(replstr);
       
  2042 	}
       
  2043 	if ((fl & SUB_GLOBAL) && repllist) {
       
  2044 	    /* We are replacing the chunk, just add this to the list */
       
  2045 	    Repldata rd = (Repldata) zhalloc(sizeof(*rd));
       
  2046 	    rd->b = b;
       
  2047 	    rd->e = e;
       
  2048 	    rd->replstr = replstr;
       
  2049 	    addlinknode(repllist, rd);
       
  2050 	    return s;
       
  2051 	}
       
  2052 	ll += strlen(replstr);
       
  2053     }
       
  2054     if (fl & SUB_MATCH)			/* matched portion */
       
  2055 	ll += 1 + (e - b);
       
  2056     if (fl & SUB_REST)		/* unmatched portion */
       
  2057 	ll += 1 + (l - (e - b));
       
  2058     if (fl & SUB_BIND) {
       
  2059 	/* position of start of matched portion */
       
  2060 	sprintf(buf, "%d ", b + 1);
       
  2061 	ll += (bl = strlen(buf));
       
  2062     }
       
  2063     if (fl & SUB_EIND) {
       
  2064 	/* position of end of matched portion */
       
  2065 	sprintf(buf + bl, "%d ", e + 1);
       
  2066 	ll += (bl = strlen(buf));
       
  2067     }
       
  2068     if (fl & SUB_LEN) {
       
  2069 	/* length of matched portion */
       
  2070 	sprintf(buf + bl, "%d ", e - b);
       
  2071 	ll += (bl = strlen(buf));
       
  2072     }
       
  2073     if (bl)
       
  2074 	buf[bl - 1] = '\0';
       
  2075 
       
  2076     rr = r = (char *) hcalloc(ll);
       
  2077 
       
  2078     if (fl & SUB_MATCH) {
       
  2079 	/* copy matched portion to new buffer */
       
  2080 	for (i = b, p = s + b; i < e; i++)
       
  2081 	    *rr++ = *p++;
       
  2082 	t = 1;
       
  2083     }
       
  2084     if (fl & SUB_REST) {
       
  2085 	/* Copy unmatched portion to buffer.  If both portions *
       
  2086 	 * requested, put a space in between (why?)            */
       
  2087 	if (t)
       
  2088 	    *rr++ = ' ';
       
  2089 	/* there may be unmatched bits at both beginning and end of string */
       
  2090 	for (i = 0, p = s; i < b; i++)
       
  2091 	    *rr++ = *p++;
       
  2092 	if (replstr)
       
  2093 	    for (p = replstr; *p; )
       
  2094 		*rr++ = *p++;
       
  2095 	for (i = e, p = s + e; i < l; i++)
       
  2096 	    *rr++ = *p++;
       
  2097 	t = 1;
       
  2098     }
       
  2099     *rr = '\0';
       
  2100     if (bl) {
       
  2101 	/* if there was a buffer (with a numeric result), add it; *
       
  2102 	 * if there was other stuff too, stick in a space first.  */
       
  2103 	if (t)
       
  2104 	    *rr++ = ' ';
       
  2105 	strcpy(rr, buf);
       
  2106     }
       
  2107     return r;
       
  2108 }
       
  2109 
       
  2110 static Patprog
       
  2111 compgetmatch(char *pat, int *flp, char **replstrp)
       
  2112 {
       
  2113     Patprog p;
       
  2114     /*
       
  2115      * Flags to pattern compiler:  use static buffer since we only
       
  2116      * have one pattern at a time; we will try the must-match test ourselves,
       
  2117      * so tell the pattern compiler we are scanning.
       
  2118      */
       
  2119 
       
  2120     /* int patflags = PAT_STATIC|PAT_SCAN|PAT_NOANCH;*/
       
  2121 
       
  2122     /* Unfortunately, PAT_STATIC doesn't work if we have a replstr with
       
  2123      * something like ${x#...} in it which will be singsub()ed below because
       
  2124      * that would overwrite the pattern buffer. */
       
  2125 
       
  2126     int patflags = PAT_SCAN|PAT_NOANCH | (*replstrp ? 0 : PAT_STATIC);
       
  2127 
       
  2128     /*
       
  2129      * Search is anchored to the end of the string if we want to match
       
  2130      * it all, or if we are matching at the end of the string and not
       
  2131      * using substrings.
       
  2132      */
       
  2133     if ((*flp & SUB_ALL) || ((*flp & SUB_END) && !(*flp & SUB_SUBSTR)))
       
  2134 	patflags &= ~PAT_NOANCH;
       
  2135     p = patcompile(pat, patflags, NULL);
       
  2136     if (!p) {
       
  2137 	zerr("bad pattern: %s", pat, 0);
       
  2138 	return NULL;
       
  2139     }
       
  2140     if (*replstrp) {
       
  2141 	if (p->patnpar || (p->globend & GF_MATCHREF)) {
       
  2142 	    /*
       
  2143 	     * Either backreferences or match references, so we
       
  2144 	     * need to re-substitute replstr each time round.
       
  2145 	     */
       
  2146 	    *flp |= SUB_DOSUBST;
       
  2147 	} else {
       
  2148 	    singsub(replstrp);
       
  2149 	    untokenize(*replstrp);
       
  2150 	}
       
  2151     }
       
  2152 
       
  2153     return p;
       
  2154 }
       
  2155 
       
  2156 /*
       
  2157  * This is called from paramsubst to get the match for ${foo#bar} etc.
       
  2158  * fl is a set of the SUB_* flags defined in zsh.h
       
  2159  * *sp points to the string we have to modify. The n'th match will be
       
  2160  * returned in *sp. The heap is used to get memory for the result string.
       
  2161  * replstr is the replacement string from a ${.../orig/repl}, in
       
  2162  * which case pat is the original.
       
  2163  *
       
  2164  * n is now ignored unless we are looking for a substring, in
       
  2165  * which case the n'th match from the start is counted such that
       
  2166  * there is no more than one match from each position.
       
  2167  */
       
  2168 
       
  2169 /**/
       
  2170 int
       
  2171 getmatch(char **sp, char *pat, int fl, int n, char *replstr)
       
  2172 {
       
  2173     Patprog p;
       
  2174 
       
  2175     if (!(p = compgetmatch(pat, &fl, &replstr)))
       
  2176 	return 1;
       
  2177 
       
  2178     return igetmatch(sp, p, fl, n, replstr);
       
  2179 }
       
  2180 
       
  2181 /**/
       
  2182 void
       
  2183 getmatcharr(char ***ap, char *pat, int fl, int n, char *replstr)
       
  2184 {
       
  2185     char **arr = *ap, **pp;
       
  2186     Patprog p;
       
  2187 
       
  2188     if (!(p = compgetmatch(pat, &fl, &replstr)))
       
  2189 	return;
       
  2190 
       
  2191     *ap = pp = hcalloc(sizeof(char *) * (arrlen(arr) + 1));
       
  2192     while ((*pp = *arr++))
       
  2193 	if (igetmatch(pp, p, fl, n, replstr))
       
  2194 	    pp++;
       
  2195 }
       
  2196 
       
  2197 /**/
       
  2198 static void
       
  2199 set_pat_start(Patprog p, int offs)
       
  2200 {
       
  2201     /*
       
  2202      * If we are messing around with the test string by advancing up
       
  2203      * it from the start, we need to tell the pattern matcher that
       
  2204      * a start-of-string assertion, i.e. (#s), should fail.  Hence
       
  2205      * we test whether the offset of the real start of string from
       
  2206      * the actual start, passed as offs, is zero.
       
  2207      */
       
  2208     if (offs)
       
  2209 	p->flags |= PAT_NOTSTART;
       
  2210     else
       
  2211 	p->flags &= ~PAT_NOTSTART;
       
  2212 }
       
  2213 
       
  2214 /**/
       
  2215 static void
       
  2216 set_pat_end(Patprog p, char null_me)
       
  2217 {
       
  2218     /*
       
  2219      * If we are messing around with the string by shortening it at the
       
  2220      * tail, we need to tell the pattern matcher that an end-of-string
       
  2221      * assertion, i.e. (#e), should fail.  Hence we test whether
       
  2222      * the character null_me about to be zapped is or is not already a null.
       
  2223      */
       
  2224     if (null_me)
       
  2225 	p->flags |= PAT_NOTEND;
       
  2226     else
       
  2227 	p->flags &= ~PAT_NOTEND;
       
  2228 }
       
  2229 
       
  2230 /**/
       
  2231 static int
       
  2232 igetmatch(char **sp, Patprog p, int fl, int n, char *replstr)
       
  2233 {
       
  2234     char *s = *sp, *t;
       
  2235     /*
       
  2236      * Note that ioff and uml count characters in the character
       
  2237      * set (Meta's are not included), while l counts characters in the
       
  2238      * metafied string.  umlen is a counter for (unmetafied) character
       
  2239      * lengths.
       
  2240      */
       
  2241     int ioff, l = strlen(*sp), uml = ztrlen(*sp), matched = 1, umlen;
       
  2242 
       
  2243     repllist = NULL;
       
  2244 
       
  2245     /* perform must-match test for complex closures */
       
  2246     if (p->mustoff)
       
  2247     {
       
  2248 	/*
       
  2249 	 * Yuk.  Probably we should rewrite this whole function to
       
  2250 	 * use an unmetafied test string.
       
  2251 	 *
       
  2252 	 * Use META_HEAPDUP because we need a terminating NULL.
       
  2253 	 */
       
  2254 	char *muststr = metafy((char *)p + p->mustoff,
       
  2255 			       p->patmlen, META_HEAPDUP);
       
  2256 
       
  2257 	if (!strstr(s, muststr))
       
  2258 	    matched = 0;
       
  2259     }
       
  2260 
       
  2261     /* in case we used the prog before... */
       
  2262     p->flags &= ~(PAT_NOTSTART|PAT_NOTEND);
       
  2263 
       
  2264     if (fl & SUB_ALL) {
       
  2265 	int i = matched && pattry(p, s);
       
  2266 	*sp = get_match_ret(*sp, 0, i ? l : 0, fl, i ? replstr : 0);
       
  2267 	if (! **sp && (((fl & SUB_MATCH) && !i) || ((fl & SUB_REST) && i)))
       
  2268 	    return 0;
       
  2269 	return 1;
       
  2270     }
       
  2271     if (matched) {
       
  2272 	switch (fl & (SUB_END|SUB_LONG|SUB_SUBSTR)) {
       
  2273 	case 0:
       
  2274 	case SUB_LONG:
       
  2275 	    /*
       
  2276 	     * Largest/smallest possible match at head of string.
       
  2277 	     * First get the longest match...
       
  2278 	     */
       
  2279 	    if (pattry(p, s)) {
       
  2280 		/* patmatchlen returns metafied length, as we need */
       
  2281 	        int mlen = patmatchlen();
       
  2282 		if (!(fl & SUB_LONG) && !(p->flags & PAT_PURES)) {
       
  2283 		    /*
       
  2284 		     * ... now we know whether it's worth looking for the
       
  2285 		     * shortest, which we do by brute force.
       
  2286 		     */
       
  2287 		    for (t = s, umlen = 0; t < s + mlen; METAINC(t), umlen++) {
       
  2288 			set_pat_end(p, *t);
       
  2289 			if (pattrylen(p, s, t - s, umlen, 0)) {
       
  2290 			    mlen = patmatchlen();
       
  2291 			    break;
       
  2292 			}
       
  2293 		    }
       
  2294 		}
       
  2295 		*sp = get_match_ret(*sp, 0, mlen, fl, replstr);
       
  2296 		return 1;
       
  2297 	    }
       
  2298 	    break;
       
  2299 
       
  2300 	case SUB_END:
       
  2301 	    /* Smallest possible match at tail of string:  *
       
  2302 	     * move back down string until we get a match. *
       
  2303 	     * There's no optimization here.               */
       
  2304 	    for (ioff = uml, t = s + l, umlen = 0; t >= s;
       
  2305 		 t--, ioff--, umlen++) {
       
  2306 		if (t > s && t[-1] == Meta)
       
  2307 		    t--;
       
  2308 		set_pat_start(p, t-s);
       
  2309 		if (pattrylen(p, t, s + l - t, umlen, ioff)) {
       
  2310 		    *sp = get_match_ret(*sp, t - s, l, fl, replstr);
       
  2311 		    return 1;
       
  2312 		}
       
  2313 		if (t > s+1 && t[-2] == Meta)
       
  2314 		    t--;
       
  2315 	    }
       
  2316 	    break;
       
  2317 
       
  2318 	case (SUB_END|SUB_LONG):
       
  2319 	    /* Largest possible match at tail of string:       *
       
  2320 	     * move forward along string until we get a match. *
       
  2321 	     * Again there's no optimisation.                  */
       
  2322 	    for (ioff = 0, t = s, umlen = uml; t < s + l;
       
  2323 		 ioff++, METAINC(t), umlen--) {
       
  2324 		set_pat_start(p, t-s);
       
  2325 		if (pattrylen(p, t, s + l - t, umlen, ioff)) {
       
  2326 		    *sp = get_match_ret(*sp, t-s, l, fl, replstr);
       
  2327 		    return 1;
       
  2328 		}
       
  2329 		if (*t == Meta)
       
  2330 		    t++;
       
  2331 	    }
       
  2332 	    break;
       
  2333 
       
  2334 	case SUB_SUBSTR:
       
  2335 	    /* Smallest at start, but matching substrings. */
       
  2336 	    set_pat_start(p, l);
       
  2337 	    if (!(fl & SUB_GLOBAL) && pattry(p, s + l) && !--n) {
       
  2338 		*sp = get_match_ret(*sp, 0, 0, fl, replstr);
       
  2339 		return 1;
       
  2340 	    } /* fall through */
       
  2341 	case (SUB_SUBSTR|SUB_LONG):
       
  2342 	    /* longest or smallest at start with substrings */
       
  2343 	    t = s;
       
  2344 	    if (fl & SUB_GLOBAL)
       
  2345 		repllist = newlinklist();
       
  2346 	    ioff = 0;		/* offset into string */
       
  2347 	    umlen = uml;
       
  2348 	    do {
       
  2349 		/* loop over all matches for global substitution */
       
  2350 		matched = 0;
       
  2351 		for (; t < s + l; METAINC(t), ioff++, umlen--) {
       
  2352 		    /* Find the longest match from this position. */
       
  2353 		    set_pat_start(p, t-s);
       
  2354 		    if (pattrylen(p, t, s + l - t, umlen, ioff)) {
       
  2355 			char *mpos = t + patmatchlen();
       
  2356 			if (!(fl & SUB_LONG) && !(p->flags & PAT_PURES)) {
       
  2357 			    char *ptr;
       
  2358 			    int umlen2;
       
  2359 			    for (ptr = t, umlen2 = 0; ptr < mpos;
       
  2360 				 METAINC(ptr), umlen2++) {
       
  2361 				set_pat_end(p, *ptr);
       
  2362 				if (pattrylen(p, t, ptr - t, umlen2, ioff)) {
       
  2363 				    mpos = t + patmatchlen();
       
  2364 				    break;
       
  2365 				}
       
  2366 			    }
       
  2367 			}
       
  2368 			if (!--n || (n <= 0 && (fl & SUB_GLOBAL))) {
       
  2369 			    *sp = get_match_ret(*sp, t-s, mpos-s, fl, replstr);
       
  2370 			    if (mpos == t)
       
  2371 				METAINC(mpos);
       
  2372 			}
       
  2373 			if (!(fl & SUB_GLOBAL)) {
       
  2374 			    if (n) {
       
  2375 				/*
       
  2376 				 * Looking for a later match: in this case,
       
  2377 				 * we can continue looking for matches from
       
  2378 				 * the next character, even if it overlaps
       
  2379 				 * with what we just found.
       
  2380 				 */
       
  2381 				continue;
       
  2382 			    } else {
       
  2383 				return 1;
       
  2384 			    }
       
  2385 			}
       
  2386 			/*
       
  2387 			 * For a global match, we need to skip the stuff
       
  2388 			 * which is already marked for replacement.
       
  2389 			 */
       
  2390 			matched = 1;
       
  2391 			for ( ; t < mpos; t++, ioff++, umlen--)
       
  2392 			    if (*t == Meta)
       
  2393 				t++;
       
  2394 			break;
       
  2395 		    }
       
  2396 		    if (*t == Meta)
       
  2397 			t++;
       
  2398 		}
       
  2399 	    } while (matched);
       
  2400 	    /*
       
  2401 	     * check if we can match a blank string, if so do it
       
  2402 	     * at the start.  Goodness knows if this is a good idea
       
  2403 	     * with global substitution, so it doesn't happen.
       
  2404 	     */
       
  2405 	    set_pat_start(p, l);
       
  2406 	    if ((fl & (SUB_LONG|SUB_GLOBAL)) == SUB_LONG &&
       
  2407 		pattry(p, s + l) && !--n) {
       
  2408 		*sp = get_match_ret(*sp, 0, 0, fl, replstr);
       
  2409 		return 1;
       
  2410 	    }
       
  2411 	    break;
       
  2412 
       
  2413 	case (SUB_END|SUB_SUBSTR):
       
  2414 	case (SUB_END|SUB_LONG|SUB_SUBSTR):
       
  2415 	    /* Longest/shortest at end, matching substrings.       */
       
  2416 	    if (!(fl & SUB_LONG)) {
       
  2417 		set_pat_start(p, l);
       
  2418 		if (pattrylen(p, s + l, 0, 0, uml) && !--n) {
       
  2419 		    *sp = get_match_ret(*sp, l, l, fl, replstr);
       
  2420 		    return 1;
       
  2421 		}
       
  2422 	    }
       
  2423 	    for (ioff = uml - 1, t = s + l - 1, umlen = 1; t >= s;
       
  2424 		 t--, ioff--, umlen++) {
       
  2425 		if (t > s && t[-1] == Meta)
       
  2426 		    t--;
       
  2427 		set_pat_start(p, t-s);
       
  2428 		if (pattrylen(p, t, s + l - t, umlen, ioff) && !--n) {
       
  2429 		    /* Found the longest match */
       
  2430 		    char *mpos = t + patmatchlen();
       
  2431 		    if (!(fl & SUB_LONG) && !(p->flags & PAT_PURES)) {
       
  2432 			char *ptr;
       
  2433 			int umlen2;
       
  2434 			for (ptr = t, umlen2 = 0; ptr < mpos;
       
  2435 			     METAINC(ptr), umlen2++) {
       
  2436 			    set_pat_end(p, *ptr);
       
  2437 			    if (pattrylen(p, t, ptr - t, umlen2, ioff)) {
       
  2438 				mpos = t + patmatchlen();
       
  2439 				break;
       
  2440 			    }
       
  2441 			}
       
  2442 		    }
       
  2443 		    *sp = get_match_ret(*sp, t-s, mpos-s, fl, replstr);
       
  2444 		    return 1;
       
  2445 		}
       
  2446 	    }
       
  2447 	    set_pat_start(p, l);
       
  2448 	    if ((fl & SUB_LONG) && pattrylen(p, s + l, 0, 0, uml) && !--n) {
       
  2449 		*sp = get_match_ret(*sp, l, l, fl, replstr);
       
  2450 		return 1;
       
  2451 	    }
       
  2452 	    break;
       
  2453 	}
       
  2454     }
       
  2455 
       
  2456     if (repllist && nonempty(repllist)) {
       
  2457 	/* Put all the bits of a global search and replace together. */
       
  2458 	LinkNode nd;
       
  2459 	Repldata rd;
       
  2460 	int lleft = 0;		/* size of returned string */
       
  2461 	char *ptr, *start;
       
  2462 	int i;
       
  2463 
       
  2464 	i = 0;			/* start of last chunk we got from *sp */
       
  2465 	for (nd = firstnode(repllist); nd; incnode(nd)) {
       
  2466 	    rd = (Repldata) getdata(nd);
       
  2467 	    lleft += rd->b - i; /* previous chunk of *sp */
       
  2468 	    lleft += strlen(rd->replstr);	/* the replaced bit */
       
  2469 	    i = rd->e;		/* start of next chunk of *sp */
       
  2470 	}
       
  2471 	lleft += l - i;	/* final chunk from *sp */
       
  2472 	start = t = zhalloc(lleft+1);
       
  2473 	i = 0;
       
  2474 	for (nd = firstnode(repllist); nd; incnode(nd)) {
       
  2475 	    rd = (Repldata) getdata(nd);
       
  2476 	    memcpy(t, s + i, rd->b - i);
       
  2477 	    t += rd->b - i;
       
  2478 	    ptr = rd->replstr;
       
  2479 	    while (*ptr)
       
  2480 		*t++ = *ptr++;
       
  2481 	    i = rd->e;
       
  2482 	}
       
  2483 	memcpy(t, s + i, l - i);
       
  2484 	start[lleft] = '\0';
       
  2485 	*sp = (char *)start;
       
  2486 	return 1;
       
  2487     }
       
  2488 
       
  2489     /* munge the whole string: no match, so no replstr */
       
  2490     *sp = get_match_ret(*sp, 0, 0, fl, 0);
       
  2491     return 1;
       
  2492 }
       
  2493 
       
  2494 /* blindly turn a string into a tokenised expression without lexing */
       
  2495 
       
  2496 /**/
       
  2497 mod_export void
       
  2498 tokenize(char *s)
       
  2499 {
       
  2500     zshtokenize(s, 0);
       
  2501 }
       
  2502 
       
  2503 /**/
       
  2504 mod_export void
       
  2505 shtokenize(char *s)
       
  2506 {
       
  2507     zshtokenize(s, isset(SHGLOB));
       
  2508 }
       
  2509 
       
  2510 /**/
       
  2511 static void
       
  2512 zshtokenize(char *s, int shglob)
       
  2513 {
       
  2514     char *t;
       
  2515     int bslash = 0;
       
  2516 
       
  2517     for (; *s; s++) {
       
  2518       cont:
       
  2519 	switch (*s) {
       
  2520 	case Bnull:
       
  2521 	case '\\':
       
  2522 	    if (bslash) {
       
  2523 		s[-1] = Bnull;
       
  2524 		break;
       
  2525 	    }
       
  2526 	    bslash = 1;
       
  2527 	    continue;
       
  2528 	case '<':
       
  2529 	    if (shglob)
       
  2530 		break;
       
  2531 	    if (bslash) {
       
  2532 		s[-1] = Bnull;
       
  2533 		break;
       
  2534 	    }
       
  2535 	    t = s;
       
  2536 	    while (idigit(*++s));
       
  2537 	    if (*s != '-')
       
  2538 		goto cont;
       
  2539 	    while (idigit(*++s));
       
  2540 	    if (*s != '>')
       
  2541 		goto cont;
       
  2542 	    *t = Inang;
       
  2543 	    *s = Outang;
       
  2544 	    break;
       
  2545 	case '(':
       
  2546 	case '|':
       
  2547 	case ')':
       
  2548 	    if (shglob)
       
  2549 		break;
       
  2550 	case '>':
       
  2551 	case '^':
       
  2552 	case '#':
       
  2553 	case '~':
       
  2554 	case '[':
       
  2555 	case ']':
       
  2556 	case '*':
       
  2557 	case '?':
       
  2558 	case '=':
       
  2559 	    for (t = ztokens; *t; t++)
       
  2560 		if (*t == *s) {
       
  2561 		    if (bslash)
       
  2562 			s[-1] = Bnull;
       
  2563 		    else
       
  2564 			*s = (t - ztokens) + Pound;
       
  2565 		    break;
       
  2566 		}
       
  2567 	}
       
  2568 	bslash = 0;
       
  2569     }
       
  2570 }
       
  2571 
       
  2572 /* remove unnecessary Nulargs */
       
  2573 
       
  2574 /**/
       
  2575 mod_export void
       
  2576 remnulargs(char *s)
       
  2577 {
       
  2578     if (*s) {
       
  2579 	char *o = s, c;
       
  2580 
       
  2581 	while ((c = *s++))
       
  2582 	    if (INULL(c)) {
       
  2583 		char *t = s - 1;
       
  2584 
       
  2585 		while ((c = *s++))
       
  2586 		    if (!INULL(c))
       
  2587 			*t++ = c;
       
  2588 		*t = '\0';
       
  2589 		if (!*o) {
       
  2590 		    o[0] = Nularg;
       
  2591 		    o[1] = '\0';
       
  2592 		}
       
  2593 		break;
       
  2594 	    }
       
  2595     }
       
  2596 }
       
  2597 
       
  2598 /* qualifier functions:  mostly self-explanatory, see glob(). */
       
  2599 
       
  2600 /* device number */
       
  2601 
       
  2602 /**/
       
  2603 static int
       
  2604 qualdev(UNUSED(char *name), struct stat *buf, off_t dv, UNUSED(char *dummy))
       
  2605 {
       
  2606     return (off_t)buf->st_dev == dv;
       
  2607 }
       
  2608 
       
  2609 /* number of hard links to file */
       
  2610 
       
  2611 /**/
       
  2612 static int
       
  2613 qualnlink(UNUSED(char *name), struct stat *buf, off_t ct, UNUSED(char *dummy))
       
  2614 {
       
  2615     return (g_range < 0 ? buf->st_nlink < ct :
       
  2616 	    g_range > 0 ? buf->st_nlink > ct :
       
  2617 	    buf->st_nlink == ct);
       
  2618 }
       
  2619 
       
  2620 /* user ID */
       
  2621 
       
  2622 /**/
       
  2623 static int
       
  2624 qualuid(UNUSED(char *name), struct stat *buf, off_t uid, UNUSED(char *dummy))
       
  2625 {
       
  2626     return buf->st_uid == uid;
       
  2627 }
       
  2628 
       
  2629 /* group ID */
       
  2630 
       
  2631 /**/
       
  2632 static int
       
  2633 qualgid(UNUSED(char *name), struct stat *buf, off_t gid, UNUSED(char *dummy))
       
  2634 {
       
  2635     return buf->st_gid == gid;
       
  2636 }
       
  2637 
       
  2638 /* device special file? */
       
  2639 
       
  2640 /**/
       
  2641 static int
       
  2642 qualisdev(UNUSED(char *name), struct stat *buf, UNUSED(off_t junk), UNUSED(char *dummy))
       
  2643 {
       
  2644     return S_ISBLK(buf->st_mode) || S_ISCHR(buf->st_mode);
       
  2645 }
       
  2646 
       
  2647 /* block special file? */
       
  2648 
       
  2649 /**/
       
  2650 static int
       
  2651 qualisblk(UNUSED(char *name), struct stat *buf, UNUSED(off_t junk), UNUSED(char *dummy))
       
  2652 {
       
  2653     return S_ISBLK(buf->st_mode);
       
  2654 }
       
  2655 
       
  2656 /* character special file? */
       
  2657 
       
  2658 /**/
       
  2659 static int
       
  2660 qualischr(UNUSED(char *name), struct stat *buf, UNUSED(off_t junk), UNUSED(char *dummy))
       
  2661 {
       
  2662     return S_ISCHR(buf->st_mode);
       
  2663 }
       
  2664 
       
  2665 /* directory? */
       
  2666 
       
  2667 /**/
       
  2668 static int
       
  2669 qualisdir(UNUSED(char *name), struct stat *buf, UNUSED(off_t junk), UNUSED(char *dummy))
       
  2670 {
       
  2671     return S_ISDIR(buf->st_mode);
       
  2672 }
       
  2673 
       
  2674 /* FIFO? */
       
  2675 
       
  2676 /**/
       
  2677 static int
       
  2678 qualisfifo(UNUSED(char *name), struct stat *buf, UNUSED(off_t junk), UNUSED(char *dummy))
       
  2679 {
       
  2680     return S_ISFIFO(buf->st_mode);
       
  2681 }
       
  2682 
       
  2683 /* symbolic link? */
       
  2684 
       
  2685 /**/
       
  2686 static int
       
  2687 qualislnk(UNUSED(char *name), struct stat *buf, UNUSED(off_t junk), UNUSED(char *dummy))
       
  2688 {
       
  2689     return S_ISLNK(buf->st_mode);
       
  2690 }
       
  2691 
       
  2692 /* regular file? */
       
  2693 
       
  2694 /**/
       
  2695 static int
       
  2696 qualisreg(UNUSED(char *name), struct stat *buf, UNUSED(off_t junk), UNUSED(char *dummy))
       
  2697 {
       
  2698     return S_ISREG(buf->st_mode);
       
  2699 }
       
  2700 
       
  2701 /* socket? */
       
  2702 
       
  2703 /**/
       
  2704 static int
       
  2705 qualissock(UNUSED(char *name), struct stat *buf, UNUSED(off_t junk), UNUSED(char *dummy))
       
  2706 {
       
  2707     return S_ISSOCK(buf->st_mode);
       
  2708 }
       
  2709 
       
  2710 /* given flag is set in mode */
       
  2711 
       
  2712 /**/
       
  2713 static int
       
  2714 qualflags(UNUSED(char *name), struct stat *buf, off_t mod, UNUSED(char *dummy))
       
  2715 {
       
  2716     return mode_to_octal(buf->st_mode) & mod;
       
  2717 }
       
  2718 
       
  2719 /* mode matches specification */
       
  2720 
       
  2721 /**/
       
  2722 static int
       
  2723 qualmodeflags(UNUSED(char *name), struct stat *buf, off_t mod, UNUSED(char *dummy))
       
  2724 {
       
  2725     long v = mode_to_octal(buf->st_mode), y = mod & 07777, n = mod >> 12;
       
  2726 
       
  2727     return ((v & y) == y && !(v & n));
       
  2728 }
       
  2729 
       
  2730 /* regular executable file? */
       
  2731 
       
  2732 /**/
       
  2733 static int
       
  2734 qualiscom(UNUSED(char *name), struct stat *buf, UNUSED(off_t mod), UNUSED(char *dummy))
       
  2735 {
       
  2736     return S_ISREG(buf->st_mode) && (buf->st_mode & S_IXUGO);
       
  2737 }
       
  2738 
       
  2739 /* size in required range? */
       
  2740 
       
  2741 /**/
       
  2742 static int
       
  2743 qualsize(UNUSED(char *name), struct stat *buf, off_t size, UNUSED(char *dummy))
       
  2744 {
       
  2745 #if defined(LONG_IS_64_BIT) || defined(OFF_T_IS_64_BIT)
       
  2746 # define QS_CAST_SIZE()
       
  2747     off_t scaled = buf->st_size;
       
  2748 #else
       
  2749 # define QS_CAST_SIZE() (unsigned long)
       
  2750     unsigned long scaled = (unsigned long)buf->st_size;
       
  2751 #endif
       
  2752 
       
  2753     switch (g_units) {
       
  2754     case TT_POSIX_BLOCKS:
       
  2755 	scaled += 511l;
       
  2756 	scaled /= 512l;
       
  2757 	break;
       
  2758     case TT_KILOBYTES:
       
  2759 	scaled += 1023l;
       
  2760 	scaled /= 1024l;
       
  2761 	break;
       
  2762     case TT_MEGABYTES:
       
  2763 	scaled += 1048575l;
       
  2764 	scaled /= 1048576l;
       
  2765 	break;
       
  2766     }
       
  2767 
       
  2768     return (g_range < 0 ? scaled < QS_CAST_SIZE() size :
       
  2769 	    g_range > 0 ? scaled > QS_CAST_SIZE() size :
       
  2770 	    scaled == QS_CAST_SIZE() size);
       
  2771 #undef QS_CAST_SIZE
       
  2772 }
       
  2773 
       
  2774 /* time in required range? */
       
  2775 
       
  2776 /**/
       
  2777 static int
       
  2778 qualtime(UNUSED(char *name), struct stat *buf, off_t days, UNUSED(char *dummy))
       
  2779 {
       
  2780     time_t now, diff;
       
  2781 
       
  2782     time(&now);
       
  2783     diff = now - (g_amc == 0 ? buf->st_atime : g_amc == 1 ? buf->st_mtime :
       
  2784 		  buf->st_ctime);
       
  2785     /* handle multipliers indicating units */
       
  2786     switch (g_units) {
       
  2787     case TT_DAYS:
       
  2788 	diff /= 86400l;
       
  2789 	break;
       
  2790     case TT_HOURS:
       
  2791 	diff /= 3600l;
       
  2792 	break;
       
  2793     case TT_MINS:
       
  2794 	diff /= 60l;
       
  2795 	break;
       
  2796     case TT_WEEKS:
       
  2797 	diff /= 604800l;
       
  2798 	break;
       
  2799     case TT_MONTHS:
       
  2800 	diff /= 2592000l;
       
  2801 	break;
       
  2802     }
       
  2803 
       
  2804     return (g_range < 0 ? diff < days :
       
  2805 	    g_range > 0 ? diff > days :
       
  2806 	    diff == days);
       
  2807 }
       
  2808 
       
  2809 /* evaluate a string */
       
  2810 
       
  2811 /**/
       
  2812 static int
       
  2813 qualsheval(char *name, UNUSED(struct stat *buf), UNUSED(off_t days), char *str)
       
  2814 {
       
  2815     Eprog prog;
       
  2816 
       
  2817     if ((prog = parse_string(str))) {
       
  2818 	int ef = errflag, lv = lastval, ret;
       
  2819 
       
  2820 	unsetparam("reply");
       
  2821 	setsparam("REPLY", ztrdup(name));
       
  2822 
       
  2823 	execode(prog, 1, 0);
       
  2824 
       
  2825 	ret = lastval;
       
  2826 	errflag = ef;
       
  2827 	lastval = lv;
       
  2828 
       
  2829 	if (!(inserts = getaparam("reply")) &&
       
  2830 	    !(inserts = gethparam("reply"))) {
       
  2831 	    char *tmp;
       
  2832 
       
  2833 	    if ((tmp = getsparam("reply")) || (tmp = getsparam("REPLY"))) {
       
  2834 		static char *tmparr[2];
       
  2835 
       
  2836 		tmparr[0] = tmp;
       
  2837 		tmparr[1] = NULL;
       
  2838 
       
  2839 		inserts = tmparr;
       
  2840 	    }
       
  2841 	}
       
  2842 	return !ret;
       
  2843     }
       
  2844     return 0;
       
  2845 }
       
  2846 
       
  2847 /**/
       
  2848 static int
       
  2849 qualnonemptydir(char *name, struct stat *buf, UNUSED(off_t days), UNUSED(char *str))
       
  2850 {
       
  2851     DIR *dirh;
       
  2852     struct dirent *de;
       
  2853 
       
  2854     if (!S_ISDIR(buf->st_mode))
       
  2855 	return 0;
       
  2856 
       
  2857     if (buf->st_nlink > 2)
       
  2858 	return 1;
       
  2859 
       
  2860     if (!(dirh = opendir(name)))
       
  2861 	return 0;
       
  2862 
       
  2863     while ((de = readdir(dirh))) {
       
  2864 	if (strcmp(de->d_name, ".") && strcmp(de->d_name, "..")) {
       
  2865 	    closedir(dirh);
       
  2866 	    return 1;
       
  2867 	}
       
  2868     }
       
  2869 
       
  2870     closedir(dirh);
       
  2871     return 0;
       
  2872 }