GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: bin/csh/glob.c Lines: 0 426 0.0 %
Date: 2017-11-07 Branches: 0 331 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: glob.c,v 1.22 2015/12/26 13:48:38 mestre Exp $	*/
2
/*	$NetBSD: glob.c,v 1.10 1995/03/21 09:03:01 cgd Exp $	*/
3
4
/*-
5
 * Copyright (c) 1980, 1991, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
#include <sys/types.h>
34
#include <glob.h>
35
#include <errno.h>
36
#include <stdlib.h>
37
#include <string.h>
38
#include <unistd.h>
39
#include <limits.h>
40
#include <stdarg.h>
41
42
#include "csh.h"
43
#include "extern.h"
44
45
static int noglob;
46
static int pargsiz, gargsiz;
47
48
/*
49
 * Values for gflag
50
 */
51
#define	G_NONE	0		/* No globbing needed			*/
52
#define	G_GLOB	1		/* string contains *?[] characters	*/
53
#define	G_CSH	2		/* string contains ~`{ characters	*/
54
55
#define	GLOBSPACE	100	/* Alloc increment			*/
56
57
#define LBRC '{'
58
#define RBRC '}'
59
#define LBRK '['
60
#define RBRK ']'
61
#define EOS '\0'
62
63
Char  **gargv = NULL;
64
long    gargc = 0;
65
Char  **pargv = NULL;
66
long    pargc = 0;
67
68
/*
69
 * globbing is now done in two stages. In the first pass we expand
70
 * csh globbing idioms ~`{ and then we proceed doing the normal
71
 * globbing if needed ?*[
72
 *
73
 * Csh type globbing is handled in globexpand() and the rest is
74
 * handled in glob() which is part of the 4.4BSD libc.
75
 *
76
 */
77
static Char	*globtilde(Char **, Char *);
78
static Char	**libglob(Char **);
79
static Char	**globexpand(Char **);
80
static int	globbrace(Char *, Char *, Char ***);
81
static void	expbrace(Char ***, Char ***, int);
82
static int	pmatch(Char *, Char *);
83
static void	pword(void);
84
static void	psave(int);
85
static void	backeval(Char *, bool);
86
87
88
static Char *
89
globtilde(Char **nv, Char *s)
90
{
91
    Char    gbuf[PATH_MAX], *gstart, *b, *u, *e;
92
93
    gstart = gbuf;
94
    *gstart++ = *s++;
95
    u = s;
96
    for (b = gstart, e = &gbuf[PATH_MAX - 1];
97
	 *s && *s != '/' && *s != ':' && b < e;
98
	 *b++ = *s++)
99
	 continue;
100
    *b = EOS;
101
    if (gethdir(gstart, &gbuf[sizeof(gbuf)/sizeof(Char)] - gstart)) {
102
	blkfree(nv);
103
	if (*gstart)
104
	    stderror(ERR_UNKUSER, vis_str(gstart));
105
	else
106
	    stderror(ERR_NOHOME);
107
    }
108
    b = &gstart[Strlen(gstart)];
109
    while (*s)
110
	*b++ = *s++;
111
    *b = EOS;
112
    --u;
113
    free(u);
114
    return (Strsave(gstart));
115
}
116
117
static int
118
globbrace(Char *s, Char *p, Char ***bl)
119
{
120
    int     i, len;
121
    Char   *pm, *pe, *lm, *pl;
122
    Char  **nv, **vl;
123
    Char    gbuf[PATH_MAX];
124
    int     size = GLOBSPACE;
125
126
    nv = vl = xreallocarray(NULL, size, sizeof(Char *));
127
    *vl = NULL;
128
129
    len = 0;
130
    /* copy part up to the brace */
131
    for (lm = gbuf, p = s; *p != LBRC; *lm++ = *p++)
132
	continue;
133
134
    /* check for balanced braces */
135
    for (i = 0, pe = ++p; *pe; pe++)
136
	if (*pe == LBRK) {
137
	    /* Ignore everything between [] */
138
	    for (++pe; *pe != RBRK && *pe != EOS; pe++)
139
		continue;
140
	    if (*pe == EOS) {
141
		blkfree(nv);
142
		return (-RBRK);
143
	    }
144
	}
145
	else if (*pe == LBRC)
146
	    i++;
147
	else if (*pe == RBRC) {
148
	    if (i == 0)
149
		break;
150
	    i--;
151
	}
152
153
    if (i != 0 || *pe == '\0') {
154
	blkfree(nv);
155
	return (-RBRC);
156
    }
157
158
    for (i = 0, pl = pm = p; pm <= pe; pm++)
159
	switch (*pm) {
160
	case LBRK:
161
	    for (++pm; *pm != RBRK && *pm != EOS; pm++)
162
		continue;
163
	    if (*pm == EOS) {
164
		*vl = NULL;
165
		blkfree(nv);
166
		return (-RBRK);
167
	    }
168
	    break;
169
	case LBRC:
170
	    i++;
171
	    break;
172
	case RBRC:
173
	    if (i) {
174
		i--;
175
		break;
176
	    }
177
	    /* FALLTHROUGH */
178
	case ',':
179
	    if (i && *pm == ',')
180
		break;
181
	    else {
182
		Char    savec = *pm;
183
184
		*pm = EOS;
185
		(void) Strlcpy(lm, pl, &gbuf[sizeof(gbuf)/sizeof(Char)] - lm);
186
		(void) Strlcat(gbuf, pe + 1, PATH_MAX);
187
		*pm = savec;
188
		*vl++ = Strsave(gbuf);
189
		len++;
190
		pl = pm + 1;
191
		if (vl == &nv[size]) {
192
		    size += GLOBSPACE;
193
		    nv = xreallocarray(nv, size, sizeof(Char *));
194
		    vl = &nv[size - GLOBSPACE];
195
		}
196
	    }
197
	    break;
198
	default:
199
	    break;
200
	}
201
    *vl = NULL;
202
    *bl = nv;
203
    return (len);
204
}
205
206
207
static void
208
expbrace(Char ***nvp, Char ***elp, int size)
209
{
210
    Char **vl, **el, **nv, *s;
211
212
    vl = nv = *nvp;
213
    if (elp != NULL)
214
	el = *elp;
215
    else
216
	for (el = vl; *el; el++)
217
	    continue;
218
219
    for (s = *vl; s; s = *++vl) {
220
	Char   *b;
221
	Char  **vp, **bp;
222
223
	/* leave {} untouched for find */
224
	if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0')))
225
	    continue;
226
	if ((b = Strchr(s, '{')) != NULL) {
227
	    Char  **bl;
228
	    int     len;
229
230
	    if ((len = globbrace(s, b, &bl)) < 0) {
231
		free(nv);
232
		stderror(ERR_MISSING, -len);
233
	    }
234
	    free(s);
235
	    if (len == 1) {
236
		*vl-- = *bl;
237
		free(bl);
238
		continue;
239
	    }
240
	    len = blklen(bl);
241
	    if (&el[len] >= &nv[size]) {
242
		int     l, e;
243
244
		l = &el[len] - &nv[size];
245
		size += GLOBSPACE > l ? GLOBSPACE : l;
246
		l = vl - nv;
247
		e = el - nv;
248
		nv = xreallocarray(nv, size, sizeof(Char *));
249
		vl = nv + l;
250
		el = nv + e;
251
	    }
252
	    vp = vl--;
253
	    *vp = *bl;
254
	    len--;
255
	    for (bp = el; bp != vp; bp--)
256
		bp[len] = *bp;
257
	    el += len;
258
	    vp++;
259
	    for (bp = bl + 1; *bp; *vp++ = *bp++)
260
		continue;
261
	    free(bl);
262
	}
263
264
    }
265
    if (elp != NULL)
266
	*elp = el;
267
    *nvp = nv;
268
}
269
270
static Char **
271
globexpand(Char **v)
272
{
273
    Char   *s;
274
    Char  **nv, **vl, **el;
275
    int     size = GLOBSPACE;
276
277
278
    nv = vl = xreallocarray(NULL, size, sizeof(Char *));
279
    *vl = NULL;
280
281
    /*
282
     * Step 1: expand backquotes.
283
     */
284
    while ((s = *v++) != NULL) {
285
	if (Strchr(s, '`')) {
286
	    int     i;
287
288
	    (void) dobackp(s, 0);
289
	    for (i = 0; i < pargc; i++) {
290
		*vl++ = pargv[i];
291
		if (vl == &nv[size]) {
292
		    size += GLOBSPACE;
293
		    nv = xreallocarray(nv, size, sizeof(Char *));
294
		    vl = &nv[size - GLOBSPACE];
295
		}
296
	    }
297
	    free(pargv);
298
	    pargv = NULL;
299
	}
300
	else {
301
	    *vl++ = Strsave(s);
302
	    if (vl == &nv[size]) {
303
		size += GLOBSPACE;
304
		nv = xreallocarray(nv, size, sizeof(Char *));
305
		vl = &nv[size - GLOBSPACE];
306
	    }
307
	}
308
    }
309
    *vl = NULL;
310
311
    if (noglob)
312
	return (nv);
313
314
    /*
315
     * Step 2: expand braces
316
     */
317
    el = vl;
318
    expbrace(&nv, &el, size);
319
320
    /*
321
     * Step 3: expand ~
322
     */
323
    vl = nv;
324
    for (s = *vl; s; s = *++vl)
325
	if (*s == '~')
326
	    *vl = globtilde(nv, s);
327
    vl = nv;
328
    return (vl);
329
}
330
331
static Char *
332
handleone(Char *str, Char **vl, int action)
333
{
334
335
    Char   *cp, **vlp = vl;
336
337
    switch (action) {
338
    case G_ERROR:
339
	setname(vis_str(str));
340
	blkfree(vl);
341
	stderror(ERR_NAME | ERR_AMBIG);
342
	break;
343
    case G_APPEND:
344
	trim(vlp);
345
	str = Strsave(*vlp++);
346
	do {
347
	    cp = Strspl(str, STRspace);
348
	    free(str);
349
	    str = Strspl(cp, *vlp);
350
	    free(cp);
351
	}
352
	while (*++vlp)
353
	    ;
354
	blkfree(vl);
355
	break;
356
    case G_IGNORE:
357
	str = Strsave(strip(*vlp));
358
	blkfree(vl);
359
	break;
360
    default:
361
	break;
362
    }
363
    return (str);
364
}
365
366
static Char **
367
libglob(Char **vl)
368
{
369
    int     gflgs = GLOB_QUOTE | GLOB_NOMAGIC;
370
    glob_t  globv;
371
    char   *ptr;
372
    int     nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0;
373
374
    if (!vl || !vl[0])
375
	return (vl);
376
377
    globv.gl_offs = 0;
378
    globv.gl_pathv = 0;
379
    globv.gl_pathc = 0;
380
381
    if (nonomatch)
382
	gflgs |= GLOB_NOCHECK;
383
384
    do {
385
	ptr = short2qstr(*vl);
386
	switch (glob(ptr, gflgs, 0, &globv)) {
387
	case GLOB_ABORTED:
388
	    setname(vis_str(*vl));
389
	    stderror(ERR_NAME | ERR_GLOB);
390
	    /* NOTREACHED */
391
	case GLOB_NOSPACE:
392
	    stderror(ERR_NOMEM);
393
	    /* NOTREACHED */
394
	default:
395
	    break;
396
	}
397
	if (globv.gl_flags & GLOB_MAGCHAR) {
398
	    match |= (globv.gl_matchc != 0);
399
	    magic = 1;
400
	}
401
	gflgs |= GLOB_APPEND;
402
    }
403
    while (*++vl)
404
	;
405
    vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ?
406
	NULL : blk2short(globv.gl_pathv);
407
    globfree(&globv);
408
    return (vl);
409
}
410
411
Char   *
412
globone(Char *str, int action)
413
{
414
    Char   *v[2], **vl, **vo;
415
    int    gflg;
416
417
    noglob = adrof(STRnoglob) != 0;
418
    gflag = 0;
419
    v[0] = str;
420
    v[1] = 0;
421
    tglob(v);
422
    gflg = gflag;
423
    if (gflg == G_NONE)
424
	return (strip(Strsave(str)));
425
426
    if (gflg & G_CSH) {
427
	/*
428
	 * Expand back-quote, tilde and brace
429
	 */
430
	vo = globexpand(v);
431
	if (noglob || (gflg & G_GLOB) == 0) {
432
	    if (vo[0] == NULL) {
433
		free(vo);
434
		return (Strsave(STRNULL));
435
	    }
436
	    if (vo[1] != NULL)
437
		return (handleone(str, vo, action));
438
	    else {
439
		str = strip(vo[0]);
440
		free(vo);
441
		return (str);
442
	    }
443
	}
444
    }
445
    else if (noglob || (gflg & G_GLOB) == 0)
446
	return (strip(Strsave(str)));
447
    else
448
	vo = v;
449
450
    vl = libglob(vo);
451
    if ((gflg & G_CSH) && vl != vo)
452
	blkfree(vo);
453
    if (vl == NULL) {
454
	setname(vis_str(str));
455
	stderror(ERR_NAME | ERR_NOMATCH);
456
    }
457
    if (vl[0] == NULL) {
458
	free(vl);
459
	return (Strsave(STRNULL));
460
    }
461
    if (vl[1] != NULL)
462
	return (handleone(str, vl, action));
463
    else {
464
	str = strip(*vl);
465
	free(vl);
466
	return (str);
467
    }
468
}
469
470
Char  **
471
globall(Char **v)
472
{
473
    Char  **vl, **vo;
474
    int   gflg = gflag;
475
476
    if (!v || !v[0]) {
477
	gargv = saveblk(v);
478
	gargc = blklen(gargv);
479
	return (gargv);
480
    }
481
482
    noglob = adrof(STRnoglob) != 0;
483
484
    if (gflg & G_CSH)
485
	/*
486
	 * Expand back-quote, tilde and brace
487
	 */
488
	vl = vo = globexpand(v);
489
    else
490
	vl = vo = saveblk(v);
491
492
    if (!noglob && (gflg & G_GLOB)) {
493
	vl = libglob(vo);
494
	if ((gflg & G_CSH) && vl != vo)
495
	    blkfree(vo);
496
    }
497
    else
498
	trim(vl);
499
500
    gargc = vl ? blklen(vl) : 0;
501
    return (gargv = vl);
502
}
503
504
void
505
ginit(void)
506
{
507
    gargsiz = GLOBSPACE;
508
    gargv = xreallocarray(NULL, gargsiz, sizeof(Char *));
509
    gargv[0] = 0;
510
    gargc = 0;
511
}
512
513
void
514
rscan(Char **t, void (*f)(int))
515
{
516
    Char *p;
517
518
    while ((p = *t++) != NULL)
519
	while (*p)
520
	    (*f) (*p++);
521
}
522
523
void
524
trim(Char **t)
525
{
526
    Char *p;
527
528
    while ((p = *t++) != NULL)
529
	while (*p)
530
	    *p++ &= TRIM;
531
}
532
533
void
534
tglob(Char **t)
535
{
536
    Char *p, c;
537
538
    while ((p = *t++) != NULL) {
539
	if (*p == '~' || *p == '=')
540
	    gflag |= G_CSH;
541
	else if (*p == '{' &&
542
		 (p[1] == '\0' || (p[1] == '}' && p[2] == '\0')))
543
	    continue;
544
	while ((c = *p++) != '\0') {
545
	    /*
546
	     * eat everything inside the matching backquotes
547
	     */
548
	    if (c == '`') {
549
		gflag |= G_CSH;
550
		while (*p && *p != '`')
551
		    if (*p++ == '\\') {
552
			if (*p)		/* Quoted chars */
553
			    p++;
554
			else
555
			    break;
556
		    }
557
		if (*p)			/* The matching ` */
558
		    p++;
559
		else
560
		    break;
561
	    }
562
	    else if (c == '{')
563
		gflag |= G_CSH;
564
	    else if (isglob(c))
565
		gflag |= G_GLOB;
566
	}
567
    }
568
}
569
570
/*
571
 * Command substitute cp.  If literal, then this is a substitution from a
572
 * << redirection, and so we should not crunch blanks and tabs, separating
573
 * words only at newlines.
574
 */
575
Char  **
576
dobackp(Char *cp, bool literal)
577
{
578
    Char *lp, *rp;
579
    Char   *ep, word[PATH_MAX];
580
581
    if (pargv) {
582
	blkfree(pargv);
583
    }
584
    pargsiz = GLOBSPACE;
585
    pargv = xreallocarray(NULL, pargsiz, sizeof(Char *));
586
    pargv[0] = NULL;
587
    pargcp = pargs = word;
588
    pargc = 0;
589
    pnleft = PATH_MAX - 4;
590
    for (;;) {
591
	for (lp = cp; *lp != '`'; lp++) {
592
	    if (*lp == 0) {
593
		if (pargcp != pargs)
594
		    pword();
595
		return (pargv);
596
	    }
597
	    psave(*lp);
598
	}
599
	lp++;
600
	for (rp = lp; *rp && *rp != '`'; rp++)
601
	    if (*rp == '\\') {
602
		rp++;
603
		if (!*rp)
604
		    goto oops;
605
	    }
606
	if (!*rp)
607
    oops:  stderror(ERR_UNMATCHED, '`');
608
	ep = Strsave(lp);
609
	ep[rp - lp] = 0;
610
	backeval(ep, literal);
611
	cp = rp + 1;
612
    }
613
}
614
615
static void
616
backeval(Char *cp, bool literal)
617
{
618
    int icnt, c;
619
    Char *ip;
620
    struct command faket;
621
    bool    hadnl;
622
    int     pvec[2], quoted;
623
    Char   *fakecom[2], ibuf[BUFSIZ];
624
    char    tibuf[BUFSIZ];
625
626
    hadnl = 0;
627
    icnt = 0;
628
    quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
629
    faket.t_dtyp = NODE_COMMAND;
630
    faket.t_dflg = 0;
631
    faket.t_dlef = 0;
632
    faket.t_drit = 0;
633
    faket.t_dspr = 0;
634
    faket.t_dcom = fakecom;
635
    fakecom[0] = STRfakecom1;
636
    fakecom[1] = 0;
637
638
    /*
639
     * We do the psave job to temporarily change the current job so that the
640
     * following fork is considered a separate job.  This is so that when
641
     * backquotes are used in a builtin function that calls glob the "current
642
     * job" is not corrupted.  We only need one level of pushed jobs as long as
643
     * we are sure to fork here.
644
     */
645
    psavejob();
646
647
    /*
648
     * It would be nicer if we could integrate this redirection more with the
649
     * routines in sh.sem.c by doing a fake execute on a builtin function that
650
     * was piped out.
651
     */
652
    mypipe(pvec);
653
    if (pfork(&faket, -1) == 0) {
654
	struct wordent paraml;
655
	struct command *t;
656
657
	(void) close(pvec[0]);
658
	(void) dmove(pvec[1], 1);
659
	(void) dmove(SHERR, 2);
660
	initdesc();
661
	/*
662
	 * Bugfix for nested backquotes by Michael Greim <greim@sbsvax.UUCP>,
663
	 * posted to comp.bugs.4bsd 12 Sep. 1989.
664
	 */
665
	if (pargv)		/* mg, 21.dec.88 */
666
	    blkfree(pargv), pargv = 0, pargsiz = 0;
667
	/* mg, 21.dec.88 */
668
	arginp = cp;
669
	while (*cp)
670
	    *cp++ &= TRIM;
671
672
	/*
673
	 * In the child ``forget'' everything about current aliases or
674
	 * eval vectors.
675
	 */
676
	alvec = NULL;
677
	evalvec = NULL;
678
	alvecp = NULL;
679
	evalp = NULL;
680
	(void) lex(&paraml);
681
	if (seterr)
682
	    stderror(ERR_OLD);
683
	alias(&paraml);
684
	t = syntax(paraml.next, &paraml, 0);
685
	if (seterr)
686
	    stderror(ERR_OLD);
687
	if (t)
688
	    t->t_dflg |= F_NOFORK;
689
	(void) signal(SIGTSTP, SIG_IGN);
690
	(void) signal(SIGTTIN, SIG_IGN);
691
	(void) signal(SIGTTOU, SIG_IGN);
692
	execute(t, -1, NULL, NULL);
693
	exitstat();
694
    }
695
    free(cp);
696
    (void) close(pvec[1]);
697
    c = 0;
698
    ip = NULL;
699
    do {
700
	int     cnt = 0;
701
702
	for (;;) {
703
	    if (icnt == 0) {
704
		int     i;
705
706
		ip = ibuf;
707
		do
708
		    icnt = read(pvec[0], tibuf, BUFSIZ);
709
		while (icnt == -1 && errno == EINTR);
710
		if (icnt <= 0) {
711
		    c = -1;
712
		    break;
713
		}
714
		for (i = 0; i < icnt; i++)
715
		    ip[i] = (unsigned char) tibuf[i];
716
	    }
717
	    if (hadnl)
718
		break;
719
	    --icnt;
720
	    c = (*ip++ & TRIM);
721
	    if (c == 0)
722
		break;
723
	    if (c == '\n') {
724
		/*
725
		 * Continue around the loop one more time, so that we can eat
726
		 * the last newline without terminating this word.
727
		 */
728
		hadnl = 1;
729
		continue;
730
	    }
731
	    if (!quoted && (c == ' ' || c == '\t'))
732
		break;
733
	    cnt++;
734
	    psave(c | quoted);
735
	}
736
	/*
737
	 * Unless at end-of-file, we will form a new word here if there were
738
	 * characters in the word, or in any case when we take text literally.
739
	 * If we didn't make empty words here when literal was set then we
740
	 * would lose blank lines.
741
	 */
742
	if (c != -1 && (cnt || literal))
743
	    pword();
744
	hadnl = 0;
745
    } while (c >= 0);
746
    (void) close(pvec[0]);
747
    pwait();
748
    prestjob();
749
}
750
751
static void
752
psave(int c)
753
{
754
    if (--pnleft <= 0)
755
	stderror(ERR_WTOOLONG);
756
    *pargcp++ = c;
757
}
758
759
static void
760
pword(void)
761
{
762
    psave(0);
763
    if (pargc == pargsiz - 1) {
764
	pargsiz += GLOBSPACE;
765
	pargv = xreallocarray(pargv, pargsiz, sizeof(Char *));
766
    }
767
    pargv[pargc++] = Strsave(pargs);
768
    pargv[pargc] = NULL;
769
    pargcp = pargs;
770
    pnleft = PATH_MAX - 4;
771
}
772
773
int
774
Gmatch(Char *string, Char *pattern)
775
{
776
    Char **blk, **p;
777
    int	   gpol = 1, gres = 0;
778
779
    if (*pattern == '^') {
780
	gpol = 0;
781
	pattern++;
782
    }
783
784
    blk = xreallocarray(NULL, GLOBSPACE, sizeof(Char *));
785
    blk[0] = Strsave(pattern);
786
    blk[1] = NULL;
787
788
    expbrace(&blk, NULL, GLOBSPACE);
789
790
    for (p = blk; *p; p++)
791
	gres |= pmatch(string, *p);
792
793
    blkfree(blk);
794
    return(gres == gpol);
795
}
796
797
static int
798
pmatch(Char *string, Char *pattern)
799
{
800
    Char stringc, patternc;
801
    int     match, negate_range;
802
    Char    rangec;
803
804
    for (;; ++string) {
805
	stringc = *string & TRIM;
806
	patternc = *pattern++;
807
	switch (patternc) {
808
	case 0:
809
	    return (stringc == 0);
810
	case '?':
811
	    if (stringc == 0)
812
		return (0);
813
	    break;
814
	case '*':
815
	    if (!*pattern)
816
		return (1);
817
	    while (*string)
818
		if (Gmatch(string++, pattern))
819
		    return (1);
820
	    return (0);
821
	case '[':
822
	    match = 0;
823
	    if ((negate_range = (*pattern == '^')) != 0)
824
		pattern++;
825
	    while ((rangec = *pattern++) != '\0') {
826
		if (rangec == ']')
827
		    break;
828
		if (match)
829
		    continue;
830
		if (rangec == '-' && *(pattern-2) != '[' && *pattern  != ']') {
831
		    match = (stringc <= (*pattern & TRIM) &&
832
			      (*(pattern-2) & TRIM) <= stringc);
833
		    pattern++;
834
		}
835
		else
836
		    match = (stringc == (rangec & TRIM));
837
	    }
838
	    if (rangec == 0)
839
		stderror(ERR_NAME | ERR_MISSING, ']');
840
	    if (match == negate_range)
841
		return (0);
842
	    break;
843
	default:
844
	    if ((patternc & TRIM) != stringc)
845
		return (0);
846
	    break;
847
848
	}
849
    }
850
}
851
852
void
853
Gcat(Char *s1, Char *s2)
854
{
855
    Char *p, *q;
856
    int     n;
857
858
    for (p = s1; *p++;)
859
	continue;
860
    for (q = s2; *q++;)
861
	continue;
862
    n = (p - s1) + (q - s2) - 1;
863
    if (++gargc >= gargsiz) {
864
	gargsiz += GLOBSPACE;
865
	gargv = xreallocarray(gargv, gargsiz, sizeof(Char *));
866
    }
867
    gargv[gargc] = 0;
868
    p = gargv[gargc - 1] = xreallocarray(NULL, n, sizeof(Char));
869
    for (q = s1; (*p++ = *q++) != '\0';)
870
	continue;
871
    for (p--, q = s2; (*p++ = *q++) != '\0';)
872
	continue;
873
}
874
875
int
876
sortscmp(const void *a, const void *b)
877
{
878
    char    buf[2048];
879
880
    if (!a)			/* check for NULL */
881
	return (b ? 1 : 0);
882
    if (!b)
883
	return (-1);
884
885
    if (!*(Char **)a)			/* check for NULL */
886
	return (*(Char **)b ? 1 : 0);
887
    if (!*(Char **)b)
888
	return (-1);
889
890
    (void) strlcpy(buf, short2str(*(Char **)a), sizeof buf);
891
    return ((int) strcoll(buf, short2str(*(Char **)b)));
892
}