Sync usage with man page.
[netbsd-mini2440.git] / bin / csh / glob.c
blob1aa8c8b7f066c6ea5b11071aae18049ecac9bee5
1 /* $NetBSD: glob.c,v 1.24 2007/07/16 14:07:01 christos Exp $ */
3 /*-
4 * Copyright (c) 1980, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)glob.c 8.1 (Berkeley) 5/31/93";
36 #else
37 __RCSID("$NetBSD: glob.c,v 1.24 2007/07/16 14:07:01 christos Exp $");
38 #endif
39 #endif /* not lint */
41 #include <sys/param.h>
43 #include <errno.h>
44 #include <glob.h>
45 #include <stdarg.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
50 #include "csh.h"
51 #include "extern.h"
53 static int noglob;
54 static int gargsiz, pargsiz;
57 * Values for gflag
59 #define G_NONE 0 /* No globbing needed */
60 #define G_GLOB 1 /* string contains *?[] characters */
61 #define G_CSH 2 /* string contains ~`{ characters */
63 #define GLOBSPACE 100 /* Alloc increment */
65 #define LBRC '{'
66 #define RBRC '}'
67 #define LBRK '['
68 #define RBRK ']'
69 #define EOS '\0'
71 Char **gargv = NULL;
72 Char **pargv = NULL;
73 long gargc = 0;
74 long pargc = 0;
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 ?*[
81 * Csh type globbing is handled in globexpand() and the rest is
82 * handled in glob() which is part of the 4.4BSD libc.
85 static Char *globtilde(Char **, Char *);
86 static Char *handleone(Char *, Char **, int);
87 static Char **libglob(Char **);
88 static Char **globexpand(Char **);
89 static int globbrace(Char *, Char *, Char ***);
90 static void expbrace(Char ***, Char ***, int);
91 static int pmatch(Char *, Char *);
92 static void pword(void);
93 static void psave(int);
94 static void backeval(Char *, int);
96 static Char *
97 globtilde(Char **nv, Char *s)
99 Char gbuf[MAXPATHLEN], *b, *e, *gstart, *u;
101 gstart = gbuf;
102 *gstart++ = *s++;
103 u = s;
104 for (b = gstart, e = &gbuf[MAXPATHLEN - 1];
105 *s && *s != '/' && *s != ':' && b < e;
106 *b++ = *s++)
107 continue;
108 *b = EOS;
109 if (gethdir(gstart)) {
110 blkfree(nv);
111 if (*gstart)
112 stderror(ERR_UNKUSER, vis_str(gstart));
113 else
114 stderror(ERR_NOHOME);
116 b = &gstart[Strlen(gstart)];
117 while (*s)
118 *b++ = *s++;
119 *b = EOS;
120 --u;
121 xfree((ptr_t) u);
122 return (Strsave(gstart));
125 static int
126 globbrace(Char *s, Char *p, Char ***bl)
128 Char gbuf[MAXPATHLEN];
129 Char *lm, *pe, *pl, *pm, **nv, **vl;
130 int i, len, size;
132 size = GLOBSPACE;
133 nv = vl = (Char **)xmalloc((size_t) sizeof(Char *) * size);
134 *vl = NULL;
135 len = 0;
136 /* copy part up to the brace */
137 for (lm = gbuf, p = s; *p != LBRC; *lm++ = *p++)
138 continue;
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 (-RBRK);
151 else if (*pe == LBRC)
152 i++;
153 else if (*pe == RBRC) {
154 if (i == 0)
155 break;
156 i--;
159 if (i != 0 || *pe == '\0') {
160 blkfree(nv);
161 return (-RBRC);
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);
174 break;
175 case LBRC:
176 i++;
177 break;
178 case RBRC:
179 if (i) {
180 i--;
181 break;
183 /* FALLTHROUGH */
184 case ',':
185 if (i && *pm == ',')
186 break;
187 else {
188 Char savec = *pm;
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,
200 (size_t)size * sizeof(Char *));
201 vl = &nv[size - GLOBSPACE];
204 break;
205 default:
206 break;
208 *vl = NULL;
209 *bl = nv;
210 return (len);
213 static void
214 expbrace(Char ***nvp, Char ***elp, int size)
216 Char **el, **nv, *s, **vl;
218 vl = nv = *nvp;
219 if (elp != NULL)
220 el = *elp;
221 else
222 for (el = vl; *el; el++)
223 continue;
225 for (s = *vl; s; s = *++vl) {
226 Char *b, **bp, **vp;
228 /* leave {} untouched for find */
229 if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0')))
230 continue;
231 if ((b = Strchr(s, '{')) != NULL) {
232 Char **bl;
233 int len;
235 if ((len = globbrace(s, b, &bl)) < 0) {
236 xfree((ptr_t)nv);
237 stderror(ERR_MISSING, -len);
239 xfree((ptr_t) s);
240 if (len == 1) {
241 *vl-- = *bl;
242 xfree((ptr_t) bl);
243 continue;
245 len = blklen(bl);
246 if (&el[len] >= &nv[size]) {
247 int e, l;
249 l = &el[len] - &nv[size];
250 size += GLOBSPACE > l ? GLOBSPACE : l;
251 l = vl - nv;
252 e = el - nv;
253 nv = (Char **)xrealloc((ptr_t)nv,
254 (size_t)size * sizeof(Char *));
255 vl = nv + l;
256 el = nv + e;
258 vp = vl--;
259 *vp = *bl;
260 len--;
261 for (bp = el; bp != vp; bp--)
262 bp[len] = *bp;
263 el += len;
264 vp++;
265 for (bp = bl + 1; *bp; *vp++ = *bp++)
266 continue;
267 xfree((ptr_t)bl);
271 if (elp != NULL)
272 *elp = el;
273 *nvp = nv;
276 static Char **
277 globexpand(Char **v)
279 Char **el, **nv, *s, **vl;
280 int size;
282 size = GLOBSPACE;
283 nv = vl = (Char **)xmalloc((size_t)sizeof(Char *) * size);
284 *vl = NULL;
287 * Step 1: expand backquotes.
289 while ((s = *v++) != NULL) {
290 if (Strchr(s, '`')) {
291 int i;
293 (void) dobackp(s, 0);
294 for (i = 0; i < pargc; i++) {
295 *vl++ = pargv[i];
296 if (vl == &nv[size]) {
297 size += GLOBSPACE;
298 nv = (Char **)xrealloc((ptr_t) nv,
299 (size_t)size * sizeof(Char *));
300 vl = &nv[size - GLOBSPACE];
303 xfree((ptr_t)pargv);
304 pargv = NULL;
306 else {
307 *vl++ = Strsave(s);
308 if (vl == &nv[size]) {
309 size += GLOBSPACE;
310 nv = (Char **)xrealloc((ptr_t)nv,
311 (size_t)size * sizeof(Char *));
312 vl = &nv[size - GLOBSPACE];
316 *vl = NULL;
318 if (noglob)
319 return (nv);
322 * Step 2: expand braces
324 el = vl;
325 expbrace(&nv, &el, size);
328 * Step 3: expand ~
330 vl = nv;
331 for (s = *vl; s; s = *++vl)
332 if (*s == '~')
333 *vl = globtilde(nv, s);
334 vl = nv;
335 return (vl);
338 static Char *
339 handleone(Char *str, Char **vl, int action)
341 Char *cp, **vlp;
343 vlp = vl;
344 switch (action) {
345 case G_ERROR:
346 setname(vis_str(str));
347 blkfree(vl);
348 stderror(ERR_NAME | ERR_AMBIG);
349 /* NOTREACHED */
350 case G_APPEND:
351 trim(vlp);
352 str = Strsave(*vlp++);
353 do {
354 cp = Strspl(str, STRspace);
355 xfree((ptr_t)str);
356 str = Strspl(cp, *vlp);
357 xfree((ptr_t)cp);
359 while (*++vlp);
360 blkfree(vl);
361 break;
362 case G_IGNORE:
363 str = Strsave(strip(*vlp));
364 blkfree(vl);
365 break;
366 default:
367 break;
369 return (str);
372 static Char **
373 libglob(Char **vl)
375 glob_t globv;
376 char *ptr;
377 int gflgs, magic, match, nonomatch;
379 gflgs = GLOB_NOMAGIC;
380 magic = 0;
381 match = 0;
382 nonomatch = adrof(STRnonomatch) != 0;
384 if (!vl || !vl[0])
385 return (vl);
387 globv.gl_offs = 0;
388 globv.gl_pathv = 0;
389 globv.gl_pathc = 0;
391 if (nonomatch)
392 gflgs |= GLOB_NOCHECK;
394 do {
395 ptr = short2qstr(*vl);
396 switch (glob(ptr, gflgs, 0, &globv)) {
397 case GLOB_ABORTED:
398 setname(vis_str(*vl));
399 stderror(ERR_NAME | ERR_GLOB);
400 /* NOTREACHED */
401 case GLOB_NOSPACE:
402 stderror(ERR_NOMEM);
403 /* NOTREACHED */
404 default:
405 break;
407 if (globv.gl_flags & GLOB_MAGCHAR) {
408 match |= (globv.gl_matchc != 0);
409 magic = 1;
411 gflgs |= GLOB_APPEND;
413 while (*++vl);
414 vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ?
415 NULL : blk2short(globv.gl_pathv);
416 globfree(&globv);
417 return (vl);
420 Char *
421 globone(Char *str, int action)
423 Char *v[2], **vl, **vo;
424 int gflg;
426 noglob = adrof(STRnoglob) != 0;
427 gflag = 0;
428 v[0] = str;
429 v[1] = 0;
430 tglob(v);
431 gflg = gflag;
432 if (gflg == G_NONE)
433 return (strip(Strsave(str)));
435 if (gflg & G_CSH) {
437 * Expand back-quote, tilde and brace
439 vo = globexpand(v);
440 if (noglob || (gflg & G_GLOB) == 0) {
441 if (vo[0] == NULL) {
442 xfree((ptr_t)vo);
443 return (Strsave(STRNULL));
445 if (vo[1] != NULL)
446 return (handleone(str, vo, action));
447 else {
448 str = strip(vo[0]);
449 xfree((ptr_t) vo);
450 return (str);
454 else if (noglob || (gflg & G_GLOB) == 0)
455 return (strip(Strsave(str)));
456 else
457 vo = v;
459 vl = libglob(vo);
460 if ((gflg & G_CSH) && vl != vo)
461 blkfree(vo);
462 if (vl == NULL) {
463 setname(vis_str(str));
464 stderror(ERR_NAME | ERR_NOMATCH);
466 if (vl[0] == NULL) {
467 xfree((ptr_t)vl);
468 return (Strsave(STRNULL));
470 if (vl[1] != NULL)
471 return (handleone(str, vl, action));
472 else {
473 str = strip(*vl);
474 xfree((ptr_t)vl);
475 return (str);
479 Char **
480 globall(Char **v)
482 Char **vl, **vo;
483 int gflg;
485 gflg = gflag;
486 if (!v || !v[0]) {
487 gargv = saveblk(v);
488 gargc = blklen(gargv);
489 return (gargv);
492 noglob = adrof(STRnoglob) != 0;
494 if (gflg & G_CSH)
496 * Expand back-quote, tilde and brace
498 vl = vo = globexpand(v);
499 else
500 vl = vo = saveblk(v);
502 if (!noglob && (gflg & G_GLOB)) {
503 vl = libglob(vo);
504 if ((gflg & G_CSH) && vl != vo)
505 blkfree(vo);
507 else
508 trim(vl);
510 gargc = vl ? blklen(vl) : 0;
511 return (gargv = vl);
514 void
515 ginit(void)
517 gargsiz = GLOBSPACE;
518 gargv = (Char **)xmalloc((size_t)sizeof(Char *) * gargsiz);
519 gargv[0] = 0;
520 gargc = 0;
523 void
524 rscan(Char **t, void (*f)(int))
526 Char *p;
528 while ((p = *t++) != NULL)
529 while (*p)
530 (*f) (*p++);
533 void
534 trim(Char **t)
536 Char *p;
538 while ((p = *t++) != NULL)
539 while (*p)
540 *p++ &= TRIM;
543 void
544 tglob(Char **t)
546 Char *p, c;
548 while ((p = *t++) != NULL) {
549 if (*p == '~' || *p == '=')
550 gflag |= G_CSH;
551 else if (*p == '{' &&
552 (p[1] == '\0' || (p[1] == '}' && p[2] == '\0')))
553 continue;
554 while ((c = *p++) != '\0') {
556 * eat everything inside the matching backquotes
558 if (c == '`') {
559 gflag |= G_CSH;
560 while (*p && *p != '`')
561 if (*p++ == '\\') {
562 if (*p) /* Quoted chars */
563 p++;
564 else
565 break;
567 if (*p) /* The matching ` */
568 p++;
569 else
570 break;
572 else if (c == '{')
573 gflag |= G_CSH;
574 else if (isglob(c))
575 gflag |= G_GLOB;
581 * Command substitute cp. If literal, then this is a substitution from a
582 * << redirection, and so we should not crunch blanks and tabs, separating
583 * words only at newlines.
585 Char **
586 dobackp(Char *cp, int literal)
588 Char word[MAXPATHLEN], *ep, *lp, *rp;
590 if (pargv) {
591 #ifdef notdef
592 abort();
593 #endif
594 blkfree(pargv);
596 pargsiz = GLOBSPACE;
597 pargv = (Char **)xmalloc((size_t)sizeof(Char *) * pargsiz);
598 pargv[0] = NULL;
599 pargcp = pargs = word;
600 pargc = 0;
601 pnleft = MAXPATHLEN - 4;
602 for (;;) {
603 for (lp = cp; *lp != '`'; lp++) {
604 if (*lp == 0) {
605 if (pargcp != pargs)
606 pword();
607 return (pargv);
609 psave(*lp);
611 lp++;
612 for (rp = lp; *rp && *rp != '`'; rp++)
613 if (*rp == '\\') {
614 rp++;
615 if (!*rp)
616 goto oops;
618 if (!*rp) {
619 oops:
620 stderror(ERR_UNMATCHED, '`');
622 ep = Strsave(lp);
623 ep[rp - lp] = 0;
624 backeval(ep, literal);
625 cp = rp + 1;
629 static void
630 backeval(Char *cp, int literal)
632 struct command faket;
633 char tibuf[BUFSIZE];
634 Char ibuf[BUFSIZE], *fakecom[2], *ip;
635 int pvec[2], c, icnt, quoted;
636 int hadnl;
638 hadnl = 0;
639 icnt = 0;
640 quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
641 faket.t_dtyp = NODE_COMMAND;
642 faket.t_dflg = 0;
643 faket.t_dlef = 0;
644 faket.t_drit = 0;
645 faket.t_dspr = 0;
646 faket.t_dcom = fakecom;
647 fakecom[0] = STRfakecom1;
648 fakecom[1] = 0;
651 * We do the psave job to temporarily change the current job so that the
652 * following fork is considered a separate job. This is so that when
653 * backquotes are used in a builtin function that calls glob the "current
654 * job" is not corrupted. We only need one level of pushed jobs as long as
655 * we are sure to fork here.
657 psavejob();
660 * It would be nicer if we could integrate this redirection more with the
661 * routines in sh.sem.c by doing a fake execute on a builtin function that
662 * was piped out.
664 mypipe(pvec);
665 if (pfork(&faket, -1) == 0) {
666 struct wordent fparaml;
667 struct command *t;
669 (void)close(pvec[0]);
670 (void)dmove(pvec[1], 1);
671 (void)dmove(SHERR, 2);
672 initdesc();
674 * Bugfix for nested backquotes by Michael Greim <greim@sbsvax.UUCP>,
675 * posted to comp.bugs.4bsd 12 Sep. 1989.
677 if (pargv) /* mg, 21.dec.88 */
678 blkfree(pargv), pargv = 0, pargsiz = 0;
679 /* mg, 21.dec.88 */
680 arginp = cp;
681 for (arginp = cp; *cp; cp++) {
682 *cp &= TRIM;
683 if (*cp == '\n' || *cp == '\r')
684 *cp = ';';
688 * In the child ``forget'' everything about current aliases or
689 * eval vectors.
691 alvec = NULL;
692 evalvec = NULL;
693 alvecp = NULL;
694 evalp = NULL;
695 (void) lex(&fparaml);
696 if (seterr)
697 stderror(ERR_OLD);
698 alias(&fparaml);
699 t = syntax(fparaml.next, &fparaml, 0);
700 if (seterr)
701 stderror(ERR_OLD);
702 if (t)
703 t->t_dflg |= F_NOFORK;
704 (void)signal(SIGTSTP, SIG_IGN);
705 (void)signal(SIGTTIN, SIG_IGN);
706 (void)signal(SIGTTOU, SIG_IGN);
707 execute(t, -1, NULL, NULL);
708 exitstat();
710 xfree((ptr_t)cp);
711 (void)close(pvec[1]);
712 c = 0;
713 ip = NULL;
714 do {
715 int cnt;
717 cnt = 0;
719 for (;;) {
720 if (icnt == 0) {
721 int i;
723 ip = ibuf;
725 icnt = read(pvec[0], tibuf, BUFSIZE);
726 while (icnt == -1 && errno == EINTR);
727 if (icnt <= 0) {
728 c = -1;
729 break;
731 for (i = 0; i < icnt; i++)
732 ip[i] = (unsigned char) tibuf[i];
734 if (hadnl)
735 break;
736 --icnt;
737 c = (*ip++ & TRIM);
738 if (c == 0)
739 break;
740 if (c == '\n') {
742 * Continue around the loop one more time, so that we can eat
743 * the last newline without terminating this word.
745 hadnl = 1;
746 continue;
748 if (!quoted && (c == ' ' || c == '\t'))
749 break;
750 cnt++;
751 psave(c | quoted);
754 * Unless at end-of-file, we will form a new word here if there were
755 * characters in the word, or in any case when we take text literally.
756 * If we didn't make empty words here when literal was set then we
757 * would lose blank lines.
759 if (c != -1 && (cnt || literal))
760 pword();
761 hadnl = 0;
762 } while (c >= 0);
763 (void)close(pvec[0]);
764 pwait();
765 prestjob();
768 static void
769 psave(int c)
771 if (--pnleft <= 0)
772 stderror(ERR_WTOOLONG);
773 *pargcp++ = c;
776 static void
777 pword(void)
779 psave(0);
780 if (pargc == pargsiz - 1) {
781 pargsiz += GLOBSPACE;
782 pargv = (Char **)xrealloc((ptr_t)pargv,
783 (size_t)pargsiz * sizeof(Char *));
785 pargv[pargc++] = Strsave(pargs);
786 pargv[pargc] = NULL;
787 pargcp = pargs;
788 pnleft = MAXPATHLEN - 4;
791 int
792 Gmatch(Char *string, Char *pattern)
794 Char **blk, **p;
795 int gpol, gres;
797 gpol = 1;
798 gres = 0;
800 if (*pattern == '^') {
801 gpol = 0;
802 pattern++;
805 blk = (Char **)xmalloc(GLOBSPACE * sizeof(Char *));
806 blk[0] = Strsave(pattern);
807 blk[1] = NULL;
809 expbrace(&blk, NULL, GLOBSPACE);
811 for (p = blk; *p; p++)
812 gres |= pmatch(string, *p);
814 blkfree(blk);
815 return(gres == gpol);
818 static int
819 pmatch(Char *string, Char *pattern)
821 int match, negate_range;
822 Char patternc, rangec, stringc;
824 for (;; ++string) {
825 stringc = *string & TRIM;
826 patternc = *pattern++;
827 switch (patternc) {
828 case 0:
829 return (stringc == 0);
830 case '?':
831 if (stringc == 0)
832 return (0);
833 break;
834 case '*':
835 if (!*pattern)
836 return (1);
837 while (*string)
838 if (Gmatch(string++, pattern))
839 return (1);
840 return (0);
841 case '[':
842 match = 0;
843 if ((negate_range = (*pattern == '^')) != 0)
844 pattern++;
845 while ((rangec = *pattern++) != '\0') {
846 if (rangec == ']')
847 break;
848 if (match)
849 continue;
850 if (rangec == '-' && *(pattern-2) != '[' && *pattern != ']') {
851 match = (stringc <= (*pattern & TRIM) &&
852 (*(pattern-2) & TRIM) <= stringc);
853 pattern++;
855 else
856 match = (stringc == (rangec & TRIM));
858 if (rangec == 0)
859 stderror(ERR_NAME | ERR_MISSING, ']');
860 if (match == negate_range)
861 return (0);
862 break;
863 default:
864 if ((patternc & TRIM) != stringc)
865 return (0);
866 break;
872 void
873 Gcat(Char *s1, Char *s2)
875 Char *p, *q;
876 int n;
878 for (p = s1; *p++;)
879 continue;
880 for (q = s2; *q++;)
881 continue;
882 n = (p - s1) + (q - s2) - 1;
883 if (++gargc >= gargsiz) {
884 gargsiz += GLOBSPACE;
885 gargv = (Char **)xrealloc((ptr_t)gargv,
886 (size_t)gargsiz * sizeof(Char *));
888 gargv[gargc] = 0;
889 p = gargv[gargc - 1] = (Char *)xmalloc((size_t)n * sizeof(Char));
890 for (q = s1; (*p++ = *q++) != '\0';)
891 continue;
892 for (p--, q = s2; (*p++ = *q++) != '\0';)
893 continue;
896 #ifdef FILEC
898 sortscmp(const ptr_t a, const ptr_t b)
900 #if defined(NLS) && !defined(NOSTRCOLL)
901 char buf[2048];
902 #endif
904 if (!a) /* check for NULL */
905 return (b ? 1 : 0);
906 if (!b)
907 return (-1);
909 if (!*(Char **)a) /* check for NULL */
910 return (*(Char **)b ? 1 : 0);
911 if (!*(Char **)b)
912 return (-1);
914 #if defined(NLS) && !defined(NOSTRCOLL)
915 (void)strcpy(buf, short2str(*(Char **)a));
916 return ((int)strcoll(buf, short2str(*(Char **)b)));
917 #else
918 return ((int)Strcmp(*(Char **)a, *(Char **)b));
919 #endif
921 #endif /* FILEC */