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