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