Subversion Repositories DevTools

Rev

Rev 313 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
313 dpurdie 1
/* -*- mode: c; tabs: 4; -*- ************************************************
2
* Module name   : vpath.c
3
* Module type   : CMDFILE source file
4
* Environment(s): n/a
5
*
6
* Description:
7
*
8
    vpath --- dependencies search path support
9
*
10
* Version   Who      Date       Description
11
            APY      12/99      Created
12
            APY      14/03/00   fixpath's,vpath2
13
                                Check for abs path prior to scanning vpath.
14
            APY      30/11/00   - VPATH, wild arguments
15
                                -vlib()
16
                     11/10/04   vlint
17
                                vlib, host specification
18
*
19
* $Source: /cvsroot/device/DEVL/UTILS/CMDFILE/vpath.c,v $
20
* $Revision: 1.7 $ $Date: 2004/10/11 08:59:27 $ $State: Exp $
21
* $Author: ayoung $ $Locker:  $
22
*.........................................................................*/
23
 
24
#if defined(HAVE_DIRECT_H)
25
#include <direct.h>
26
#define  NAMLEN(dirent)     strlen((dirent)->d_name)
27
#elif defined(HAVE_DIRENT_H) || \
28
                defined(sun) || defined(linux) || defined(WIN32)
29
#include <dirent.h>
30
#define  NAMLEN(dirent)     strlen((dirent)->d_name)
31
#else
32
# define dirent             direct
33
# define NAMLEN(dirent)     (dirent)->d_namlen
34
# if defined(HAVE_SYS_NDIR_H)
35
#  include <sys/ndir.h>
36
# endif
37
# if defined(HAVE_SYS_DIR_H)
38
#  include <sys/dir.h>
39
# endif
40
# if defined(HAVE_NDIR_H)
41
#  include <ndir.h>
42
# endif
43
#endif
44
 
45
#include <unistd.h>
46
#include <ctype.h>
47
#include "cmdfile.h"
48
 
49
#ifdef MSDOS
50
#include <dos.h>            /* For intdos() */
51
#endif
52
 
53
typedef struct {
54
#define FICASE       0x0001
55
    int              gl_argc;
56
    char           **gl_argv;
57
} Glob_t;
58
 
59
#define HWIN32      0x01
60
#define HUNIX       0x02
61
 
62
static const char   *find_on_vpath(int flags, const char *name,
63
                        const char *vpath, char *buf);
64
static const char   *find_on_vpath2(int flags, const char *name,
65
                        const char *vpath, char *buf);
66
static const char   *next_path(const char *path, char sep,
67
                        const char *name, char *dir, char *buf);
68
 
69
static void          fixpath(const char *in, char *out, char sep);
70
static int           is_term(int c);
71
static int           is_slash(int c);
72
#if defined(MSDOS) || defined(WIN32)
73
static int           GetDisk(void);
74
#endif
75
static char         *GetCwd(char *out, int drive, char sep);
76
 
77
static int           Glob(int flags, const char *pPath,
78
                        Glob_t *pGlob, const char *pPattern);
79
static void          GlobFree(Glob_t *pGlob);
80
static void          GlobPrint(Glob_t *pGlob);
81
 
82
const char *         vpath_lib_default = NULL;
83
char                 vpath_sep = ';';           /*default*/
84
 
85
#if defined(unix)
86
int                  vpath_host = HUNIX;
87
 
88
#elif defined(WIN32) || defined(MSDOS)
89
int                  vpath_host = HWIN32;
90
 
91
#else
92
#error vpath: Unknown host ...
93
#endif
94
 
95
int do_clean_sep ( String_t *str, const char *s )
96
{
97
    char  gsep[2];
98
    char  name[ MACRO_MAX ];
99
    int   len = 0, len2;
100
    char  *i;
101
 
102
    if (expected(s++, ',') > 0 &&
103
            (len2 = pathargument(s, gsep, 2)) > 0)
104
    {
105
        len += 1+len2, s += len2;
106
        if (expected(s++, ',') > 0 &&
107
                (len2 = pathargument(s, name, MACRO_MAX)) > 0)
108
        {
109
            len += 1+len2, s += len2;
110
 
111
            /* Step through the input path */
112
            for (i = name; *i; i++)
113
            {
114
                if (is_slash(*i))
115
                    *i = gsep[0];
116
            }
117
 
118
            StringCat( str, name );
119
            return (len);
120
        }
121
    }
122
    return (-1);
123
}
124
 
125
 
126
int
127
vpath( String_t *str, const char *s, int flags )
128
{
129
    char    name[ PATH_MAX ], vpath[ MACRO_MAX ], result[ PATH_MAX ];
130
    char    gsep[2];
131
    int     len = 0, len2;
132
    const   char *p;
133
 
134
    if (expected(s++, ',') > 0 &&
135
            (len2 = pathargument(s, name, PATH_MAX)) > 0)
136
    {
137
        len = 1+len2, s += len2;
138
        if (expected(s++, ',') > 0 &&
139
                (len2 = pathargument(s, vpath, MACRO_MAX)) > 0)
140
        {
141
            len += 1+len2, s += len2;
142
            gsep[0] = 0;
143
            if ( *s++ == ','  && (len2 = pathargument(s, gsep, 2)) > 0)
144
            {
145
                len += 1+len2, s += len2;
146
            }
147
 
148
            if (vflg)
149
            {
150
                const char *type = 
151
                        (flags & VFLAG_LINT     ? "vlint" :
152
                        (flags & VFLAG_LIBRARY  ? "vlib"  :
153
                        (flags & VFLAG_GLOB     ? "vglob" : "vpath" )));
154
 
155
                verbose( " %s%s(%s,%s)", type,
156
                    (flags & VFLAG_OPTIONAL ? "3":
157
                        (flags & VFLAG_MUSTRESOLVE ? "2": "")),
158
                    name, vpath );
159
            }
160
 
161
            if ((p = find_on_vpath(flags, name, vpath, result)) == NULL)
162
            {
163
                if (flags & VFLAG_MUSTRESOLVE)
164
                {
165
                    if (strchr(vpath, '/') || strchr(vpath,'\\') ||
166
                              strchr(vpath, '.'))
167
                        p = NULL;
168
                    else
169
                    {
170
                        p = getenv(vpath);
171
                    }
172
 
173
                    /*
174
                    **  Generate a readable error message
175
                    **  Display each element of the path on a new line
176
                    */
177
                    {
178
                        int len;
179
                        const char *ptr;
180
 
181
                        message ( "ERROR: Unable to locate the file '%s' " \
182
                                  "using the path:\n", name);
183
 
184
                        p = (p ? p : vpath);
185
                        for ( ptr = p; *p ; p++  )
186
                        {
187
                            if ( *p == vpath_sep )
188
                            {
189
                                len = p - ptr;
190
                                if ( len )
191
                                {
192
                                    message ( "    %-*.*s\n", len, len, ptr  );
193
                                    len = 0;
194
                                }
195
                                ptr = p+1;
196
                            }
197
                        }
198
 
199
                        len = p - ptr;
200
                        if ( len )
201
                        {
202
                            message ( "    %-*.*s\n", len, len, ptr  );
203
                        }
204
 
205
                        fatalerr( "Unable to resolve '%s'\n", name );
206
                    }
207
                }
208
 
209
                else if ((flags & VFLAG_OPTIONAL) == 0)
210
                {
211
                    p = name;                   /* quote path */
212
                }
213
            }
214
            else
215
            {
216
                verbose( " path = %s", p );
217
            }
218
            if ( gsep[0] )
219
                fixpath( p, (char *)p, gsep[0]);
220
            StringPath( str, p );
221
            return (len);
222
        }
223
    }
224
    return (-1);
225
}
226
 
227
 
228
int
229
do_vhost( const char *s )
230
{
231
    char host[ 32 ];
232
    int len = 0, len2;
233
 
234
    if (expected(s++, ',') > 0 &&
235
            (len2 = argument(s, host, sizeof(host))) > 0)
236
    {
237
        len = 1+len2, s += len2;
238
        if (strcasecmp(host, "unix") == 0)
239
            vpath_host = HUNIX;
240
        else if (strcasecmp(host, "win32") == 0)
241
            vpath_host = HWIN32;
242
        else
243
        {
244
            fatalerr( "Unknown host '%s'\n", host );
245
        }
246
    }
247
    return (len);
248
}
249
 
250
 
251
int
252
do_vsep( const char *s )
253
{
254
    char sep[ 32 ];
255
    int len = 0, len2;
256
 
257
    if (expected(s++, ',') > 0 &&
258
            (len2 = argument(s, sep, sizeof(sep))) > 0)
259
    {
260
        len = 1+len2, s += len2;
261
        if (!strcasecmp(sep, ":") || !strcasecmp(sep, "colon"))
262
            vpath_sep = ':';
263
        else if (!strcasecmp(sep, ";") || !strcasecmp(sep, "semicolon"))
264
            vpath_sep = ';';
265
        else
266
        {
267
            fatalerr( "Unknown seperator '%s'\n", sep );
268
        }
269
    }
270
    return (len);
271
}
272
 
273
 
274
static char *
275
fcat(char *buf, const char *dir, char sep, const char *name)
276
{
277
    char  tbuf[ PATH_MAX ];
278
    char  *s = tbuf;
279
    int   fsize;
280
 
281
    (void) strncpy(tbuf, dir, PATH_MAX);
282
    s += (fsize = strlen(dir));
283
    if (fsize + strlen(name) + 1 >= PATH_MAX)
284
         fatalerr( "PATH_MAX(%d) exceeded on dir '%s'\n", PATH_MAX, buf );
285
 
286
    if ((tbuf != s) && !is_slash(s[-1]) && (fsize++ < PATH_MAX))
287
         *s++ = sep;
288
    *s = '\0';
289
    (void) strncpy(s, name, PATH_MAX-fsize);
290
    tbuf[ PATH_MAX-1 ] = '\0';
291
    (void) fixpath((const char *)tbuf, buf, sep);
292
    return (buf);
293
}
294
 
295
 
296
static int
297
x_exists( const char *buf )
298
{
299
    int     ret;
300
 
301
    ret = access( buf, F_OK );
302
    verbose( "   access(%s) : %d", buf, ret );
303
    return (ret);;
304
}
305
 
306
 
307
static int
308
file_access( char sep, const char *name, char *buf )
309
{
310
    (void) fixpath( name, buf, sep );
311
    return x_exists( buf );
312
}
313
 
314
 
315
static int
316
lib_access( const char *dir, char sep, const char *name, char *buf )
317
{
318
    char    *s;
319
    int     fsize;
320
 
321
    (void) fcat(buf, dir, sep, name);
322
    verbose( "  libsearch(%s%c%s=%s)", dir, sep, name, buf );
323
    s = buf + (fsize = strlen(buf));
324
 
325
    if (vpath_host == HUNIX)
326
    {                                           /* shared library */
327
        (void) strncpy(s, ".so", PATH_MAX-fsize);   
328
        buf[ PATH_MAX-1 ] = '\0';
329
        if (x_exists( buf ) == 0)
330
            return (0);
331
 
332
                                                /* static library */
333
        (void) strncpy(s, ".a", PATH_MAX-fsize);    
334
        buf[ PATH_MAX-1 ] = '\0';
335
        if (x_exists( buf ) == 0)
336
            return (0);
337
 
338
    } 
339
    else if (vpath_host == HWIN32) 
340
    {                                           /* static/implib */
341
        (void) strncpy(s, ".lib", PATH_MAX-fsize);  
342
        buf[ PATH_MAX-1 ] = '\0';
343
        if (x_exists( buf ) == 0)
344
            return (0);
345
    }    
346
    return (ENOENT);
347
}
348
 
349
 
350
static int
351
lint_access( const char *dir, char sep, const char *name, char *buf )
352
{
353
    char    *s;
354
    int     fsize;
355
 
356
    (void) fcat(buf, dir, sep, name);
357
    verbose( "  lintsearch(%s%c%s=%s)", dir, sep, name, buf );
358
    s = buf + (fsize = strlen(buf));
359
 
360
    (void) strncpy(s, ".lob", PATH_MAX-fsize);  /* lint object */
361
    buf[ PATH_MAX-1 ] = '\0';
362
    if (x_exists( buf ) == 0)
363
        return (0);
364
 
365
    (void) strncpy(s, ".lnt", PATH_MAX-fsize);  /* lint specification */
366
    buf[ PATH_MAX-1 ] = '\0';
367
    if (x_exists( buf ) == 0)
368
        return (0);
369
 
370
    return (ENOENT);
371
}
372
 
373
 
374
static int
375
glob_access(const char *dir, char sep, const char *name, char *buf)
376
{
377
    Glob_t  glob;
378
 
379
    verbose( "  globbing(%s, %s)", dir, name );
380
    if (Glob(0, dir, &glob, name) == 0)
381
    {
382
        int i;
383
 
384
        for (i=0; i<glob.gl_argc; i++)
385
        {
386
            fcat(buf, dir, sep, glob.gl_argv[i]);
387
            verbose( "  testing access(%s)", buf );
388
            if (access(buf, F_OK) == 0)
389
            {
390
                (void) GlobFree(&glob);
391
                return (0);
392
            }
393
        }
394
        (void) GlobFree(&glob);
395
     }
396
     return (ENOENT);
397
}
398
 
399
 
400
static const char *
401
find_on_vpath(
402
    int flags, const char *name, const char *vpath, char *buf )
403
{
404
    const char *ret;
405
                                                /* specified path */
406
    if ((ret = find_on_vpath2( flags, name, vpath, buf )) == NULL)
407
    {
408
        if (flags & VFLAG_LIBRARY)              /* default LIB path, if any */
409
            if (vpath_lib_default != NULL)
410
            {
411
                ret = find_on_vpath2( flags, name, vpath_lib_default, buf );
412
            }
413
    }
414
    return (ret);
415
}
416
 
417
 
418
static const char *
419
find_on_vpath2(
420
    int flags, const char *name, const char *vpath, char *buf )
421
{
422
    char  dir[ PATH_MAX ];
423
    const char *sp;
424
    char  sep;
425
 
426
    if (strchr(vpath, '/') || strchr(vpath, '\\') || strchr(vpath, '.'))
427
        sp = vpath;
428
    else if ((sp = getenv(vpath)) == NULL)
429
        sp = "";
430
 
431
    sep = (strchr(sp, '/') ? '/' : '\\');
432
 
433
    verbose( "  vpath(%s), sep=%c", sp, sep );
434
 
435
    if (file_access( sep, name, buf ) == 0 )    /* is path already absolute */
436
        return name;
437
 
438
    do {                                        /* scan vpath */
439
        sp = next_path( sp, sep, name, dir, buf );
440
 
441
        if (dir[0] == '\0')
442
            continue;                           /* empty specification */
443
 
444
        if (x_exists( buf ) == 0)               /* abs match ? */
445
            return buf;
446
 
447
        if ((flags & VFLAG_LINT) &&             /* lint search */
448
                lint_access(dir, sep, name, buf) == 0)
449
            return (buf);
450
 
451
        if ((flags & VFLAG_LIBRARY) &&          /* library search */
452
                lib_access(dir, sep, name, buf) == 0)
453
            return (buf);
454
 
455
        if ((flags & VFLAG_GLOB) &&             /* globbing */
456
                glob_access(dir, sep, name, buf) == 0)
457
            return buf;
458
 
459
    } while (sp != (char *)NULL);
460
    errno = ENOENT;
461
    return (NULL);                              /* no match */
462
}
463
 
464
 
465
/*
466
 *  Build next path
467
 */
468
static const char *
469
next_path(
470
    const char *path, char sep, const char *name, char *dir, char *buf)
471
{
472
    char  *d = dir;
473
    int   fsize = 0;
474
 
475
/* retrieve path */
476
    while (*path && *path != vpath_sep) {
477
        if (*path != ' ' || d != dir)           /* trim leading spaces */
478
            if (fsize < PATH_MAX) {
479
                *d++ = *path, fsize++;
480
            }
481
        path++;
482
    }
483
 
484
    while (fsize && d[-1] == ' ')               /* trim trailing spaces */
485
       d--, fsize--;
486
 
487
    if (fsize > 2 && dir[0] == '"' && d[-1] == '"') {
488
        fsize -= 2;                             /* strip quoted path */
489
        memmove( dir, dir+1, fsize );
490
        d = dir + fsize;
491
    }
492
 
493
                                                /* add seperator */
494
    if (fsize && !is_slash(d[-1]) && (++fsize < PATH_MAX))
495
        *d++ = sep;
496
 
497
    *d = '\0';                                  /* terminator */
498
 
499
/* build fullname */
500
    (void) fcat( buf, dir, sep, name );
501
    verbose( "  search(%s,%s=%s)", dir, name, buf );
502
    return (*path ? ++path : (char *)NULL);
503
}
504
 
505
 
506
/* fixpath ---
507
 *
508
 *  Takes as input an arbitrary path.  Fixes up the path by:
509
 *      1.  Convert relative path to absolute
510
 *      2.  Removing consecutive slashes
511
 *      3.  Removing trailing slashes
512
 *      4.  Making the path absolute if it wasn't already
513
 *      5.  Removing "." in the path
514
 *      6.  Removing ".." entries in the path (and the directory above them)
515
 */
516
static void
517
fixpath( const char *in, char *out, char sep )
518
{
519
    register const char *i = in;
520
    register char *o = out;
521
 
522
/* Convert relative path to absolute */
523
#if defined(MSDOS) || defined(WIN32)
524
    {
525
        int drive;
526
 
527
        if (*(i+1) == ':' &&
528
                ((*i >= 'a' && *i <= 'z') || (*i >= 'A' && *i <= 'Z'))) {
529
            if (*i >= 'a' && *i <= 'z')
530
                drive = *i - 'a';
531
            else drive = *i - 'A';
532
            *o++ = *i++;
533
            *o++ = *i++;
534
        } else {
535
            drive = GetDisk();
536
            *o++ = drive + 'A';
537
            *o++ = ':';
538
        }
539
        if (!is_slash(*i))
540
            o = GetCwd(o, drive, sep);
541
    }
542
 
543
#else   /*unix*/
544
    if (!is_slash(*i))
545
        o = GetCwd(o, -1, sep);
546
#endif
547
 
548
/* Step through the input path */
549
    while (*i != '\0')
550
    {
551
    /* Skip input slashes */
552
        if (is_slash(*i))
553
        {
554
            i++;
555
            continue;
556
        }
557
 
558
    /* Skip "." and output nothing */
559
        if (*i == '.' && is_term(*(i + 1)))
560
        {
561
            i++; continue;
562
        }
563
 
564
    /* Skip ".." and remove previous output directory */
565
        if (*i == '.' && *(i + 1) == '.' && is_term(*(i + 2)))
566
        {
567
        /* Don't back up over drive spec or consume ../.. */
568
            if (o > out+2 && strncmp(o-2, "..", 2) != 0)
569
            {
570
            /* Consume .. and parent directory */
571
                i += 2;
572
                while (--o > out+2 && !is_slash(*o))
573
                    ;
574
                continue;
575
            }
576
        }
577
 
578
    /* Copy path component from in to p */
579
        *o++ = sep;
580
 
581
    /* Copy next filename/directory */
582
        while (!is_term(*i))
583
            *o++ = *i++;
584
    }
585
    *o = '\0';
586
}
587
 
588
 
589
static int
590
is_term(int c)
591
{
592
    return c == '/' || c == '\\' || c == '\0';
593
}
594
 
595
 
596
static int
597
is_slash(int c)
598
{
599
    if (c == '/' || c == '\\')
600
        return 1;
601
    return 0;
602
}
603
 
604
 
605
#if defined(MSDOS)
606
static int
607
GetDisk(void)
608
{
609
#ifdef __WATCOMC__
610
    unsigned drive;
611
    _dos_getdrive(&drive);
612
    return drive - 1;
613
#else
614
    union REGS regs;
615
    regs.h.ah = 0x19;                           /* DOS Get Default Drive call */
616
    regs.h.al = 0;
617
    (void) intdos(&regs, &regs);
618
    return regs.h.al;
619
#endif
620
}
621
 
622
#elif defined(WIN32)
623
static int
624
GetDisk(void)
625
{
626
    char path[ PATH_MAX ];
627
 
628
    getcwd(path, PATH_MAX);
629
    return (toupper(path[0])-'A');              /* A=1, B=2 etc */
630
}
631
#endif
632
 
633
 
634
static char *
635
GetCwd(char *out, int drive, char sep)
636
{
637
#if defined(MSDOS)
638
    static   char cwd[ PATH_MAX ];
639
    register char *p, *o;
640
 
641
/* Get current work directory */
642
    if (*cwd == '\0')
643
    {
644
        union REGS  regs;
645
 
646
        regs.h.ah   = 0x47;
647
        regs.h.dl   = drive + 1;
648
    #ifdef __386__
649
        regs.x.esi  = (unsigned long) cwd;
650
    #else
651
        regs.x.si   = (unsigned long) cwd;
652
    #endif
653
        (void) intdos(&regs, &regs);
654
    #ifdef __WATCOMC__
655
        if (regs.w.cflag != 0) {
656
            errno = regs.w.ax;
657
            return out;
658
        }
659
    #else
660
        if (regs.x.cflag != 0) {
661
            errno = regs.x.ax;
662
            return out;
663
        }
664
    #endif
665
    }
666
 
667
/* Copy and convert path */
668
    for (p = cwd, o = out + 1; *p; p++)
669
         *o++ = is_slash(*p) ? sep : *p;
670
    *o = '\0';
671
 
672
/* Root path, don't insert "/", it'll be added later */
673
    if (*(out+1) != '\0')
674
        *out = sep;
675
    else *out = '\0';
676
    return (out);
677
 
678
#elif defined(WIN32)
679
    int len;
680
 
681
    out[0] = '\0';
682
    (void) _getdcwd(drive + 1, out, PATH_MAX);
683
    if ((len = strlen(out)) >= 2 && out[1] == ':')
684
    {
685
        memmove(out, (const char *)(out+2), len-1);
686
        len -= 2;
687
    }
688
    return (out + len);
689
 
690
#else
691
    out[0] = '\0';
692
    (void) getcwd(out, PATH_MAX);
693
    return (out + strlen(out));
694
 
695
#endif
696
}
697
 
698
 
699
/*--------------------------------------------------------------  */
700
 
701
static  int          Match(int, const char *, const char *);
702
 
703
/*----------------------------------------------------------------------------
704
    Synopsis:
705
        static int Glob
706
            (
707
                            int flags,
708
                const char *pPath,
709
                Glob_t *pGlob,
710
                const char *pPattern
711
            )
712
        static GlobFree(Glob_t *pGlob)
713
 
714
    MT-Level:
715
        Safe (only one thread may own the Glob_t structure)
716
 
717
    Purpose:
718
        The Glob function stores the number of matched path names
719
        into 'pGlob->gl_argc' and a pointer to a list of pointers
720
        to path names into 'pGlob->gl_argv'.
721
 
722
            typedef struct {
723
                int     gl_argc;
724
                char    **gl_argv;
725
            } Glob_t;
726
 
727
        The path names are sorted as encountered within the directory.
728
        The first pointer after the last path name is a NULL pointer.
729
        If the pattern does not match any path names, the returned
730
        number of matched paths is set to zero, and the contents
731
        of 'pGlob->gl_argv' is undefined.
732
 
733
        The argument 'pPath' is a pointer to a path name to be
734
        searched, using the argument 'pPattern' to be expanded. The
735
        glob function matches all accessible path names against
736
        this pattern and develops a list of all path names that
737
        match. In order to have access to a path name, glob requires
738
        search permission on every component of a path except the
739
        last, and read permission on each directory of any filename
740
        component of pattern that contains any of the following
741
        special characters:
742
 
743
                *   ?   [
744
 
745
        It is the caller's responsibility to create the structure
746
        pointed to by pGlob. The glob function allocates other space
747
        as needed, including the memory pointed to by gl_pathv. The
748
        GlobFree() function frees any space associated with pGlob
749
        from a previous call to Glob.
750
 
751
   Parameters:
752
        pPath,
753
        pGlob,
754
        pPattern
755
 
756
    Returns:
757
        The following values are returned by glob():
758
 
759
    Example:
760
 
761
        Glob_t    globbuf;
762
 
763
        Glob(".", &globbuf, "*.c");
764
        Print(&globbuf);
765
        GlobFree(&globuf);
766
*/
767
static int
768
Glob(int flags, const char *pPath, Glob_t *pGlob, const char *pPattern)
769
{
770
    struct  dirent *dp;
771
    char **ppNames;
772
    int total, cnt;
773
    DIR *pDir;
774
    char  dir_path[ PATH_MAX ];
775
 
776
    /*
777
    **  Remove trailing / from pPath
778
    */
779
    strcpy ( dir_path, pPath );
780
    cnt = strlen(dir_path);
781
    if ( is_slash( dir_path[cnt-1]) )
782
        dir_path[cnt-1] = 0;
783
 
784
    if ((pDir = opendir(dir_path)) == (DIR *)NULL)
785
    {
786
        return (errno);
787
    }
788
    ppNames = NULL;
789
    for (total=0, cnt=0; (dp = readdir(pDir)) != NULL;)
790
    {
791
        if (pPattern == NULL || Match(flags, pPattern, dp->d_name) == 0)
792
        {
793
        /* (re)alloc name storage */
794
            if (cnt >= total)
795
            {
796
                total += 256;
797
                ppNames = (char **)realloc(ppNames, total*sizeof(ppNames[0]));
798
                if (ppNames == NULL)
799
                    goto nomem;
800
            }
801
 
802
         /* Store directory details */
803
            verbose( "  .. matched(%s)", dp->d_name );
804
            if ((ppNames[cnt] = (char *)strdup(dp->d_name)) == (char *)NULL)
805
                goto nomem;
806
            cnt++;
807
        }
808
    }
809
    (void) closedir(pDir);
810
    if (cnt)
811
        ppNames[cnt] = NULL;
812
    pGlob->gl_argv = ppNames;
813
    pGlob->gl_argc = cnt;
814
    return (0);
815
 
816
nomem:
817
    fatalerr("Memory error globing %s", pPattern);
818
    pGlob->gl_argv = ppNames;
819
    pGlob->gl_argc = cnt;
820
    GlobFree(pGlob);
821
    pGlob->gl_argc = 0;
822
    return (ENOMEM);
823
}
824
 
825
 
826
/*
827
 *  Dump the glob list
828
 */
829
static void
830
GlobPrint(
831
    Glob_t *pGlob)
832
{
833
    if (pGlob && pGlob->gl_argc > 0)
834
    {
835
        register int cnt = pGlob->gl_argc;
836
        register int i;
837
 
838
        for(i=0; i < cnt; i++)
839
            printf("[%2d]: %s", i, pGlob->gl_argv[i]);
840
    }
841
}
842
 
843
 
844
/*
845
 *  Free the list of files:
846
 *      The Globfree() function frees any memory allocated by
847
 *      Glob() associated with 'pGlob'.
848
 */
849
static void
850
GlobFree(
851
    Glob_t *pGlob)
852
{
853
    if (pGlob && pGlob->gl_argc > 0)
854
    {
855
        register int cnt = pGlob->gl_argc;
856
 
857
        while (cnt > 0)
858
            free(pGlob->gl_argv[--cnt]);
859
        free(pGlob->gl_argv);
860
    }
861
}
862
 
863
 
864
/*      Match ---
865
 *        Pattern matching
866
 * Usage:
867
 *
868
    An ordinary character is a pattern that matches itself.  It
869
    can be any character in the supported character set except
870
    for NUL, and the following three special pattern characters.
871
 
872
    When unquoted and outside a bracket expression, the following
873
    three characters will have special meaning:
874
 
875
        \   quotes the next character.
876
 
877
        ?   is a pattern that will match any character.
878
 
879
        *   is a pattern that will match multiple characters.
880
 
881
        [   introduces a pattern bracket expression, that will
882
            matches a single collating element contained in the
883
            non-empty set of collating elements.
884
 
885
            The following rules and definitions apply to bracket
886
            expressions:
887
 
888
            1.  A bracket expression is either a matching list
889
                expression or a non-matching list expression.  It
890
                consists of one or more expressions.
891
 
892
            2.  A matching list expression  specifies  a  list  that
893
                matches any one of the expressions represented in the
894
                list.  The first character in the list  must not be
895
                the circumflex (^).  For example, [abc] is a pattern
896
                that matches any of the characters a, b or c.
897
 
898
            3.  A non-matching list expression begins with a circum-
899
                flex (^), and specifies a list that matches any char-
900
                acter or collating element except for the expressions
901
                represented in the list after the leading circumflex.
902
                For example, [^abc] is a pattern that matches any
903
                character or collating element except the characters
904
                a, b or c. The circumflex will have this special
905
                meaning only when it occurs first in the list,
906
                immediately following the left-bracket.
907
 
908
            4.  A range expression represents the set of collating
909
                elements that fall between two elements in the
910
                current collation sequence,  inclusively.  It is
911
                expressed  as the starting point and the ending point
912
                separated by a hyphen (-). For example, [a-z] is a
913
                pattern that matches any of the characters a to z
914
                inclusive.
915
 
916
                The hyphen character will be treated as itself if
917
                it occurs first (after an initial ^, if any) or
918
                last in the list, or as an ending range point in a
919
                range expression.  As examples, the expressions
920
                [-ac] and [ac-] are equivalent and match any of the
921
                characters a,  c,  or  -; [^-ac] and [^ac-] are
922
                equivalent and match any characters except a, c, or -;
923
                the expression [%--] matches any of the characters
924
                between % and - inclusive; the expression [--@]
925
                matches any of the characters between  -  and @
926
                inclusive.
927
 
928
        +   a bracket expression followed by this means one or
929
            more time.
930
 
931
        {   introduces a pattern set expression, that will
932
            match one or the colon seperated patterns.
933
*.........................................................................*/
934
 
935
static int
936
Match(int flags, const char *pPattern, const char *pString)
937
{
938
    register const char *p = pPattern;
939
    register const char *n = pString;
940
    register char ch;
941
 
942
#define __TOLOWER(c)    ((flags & FICASE) && isupper(c)?tolower(c):c)
943
    while ((ch = *p++) != '\0')
944
    {
945
        ch = __TOLOWER(ch);
946
        switch (ch)
947
        {
948
        case '?':       /* Match next character */
949
            if (*n == '\0')
950
                return -1;
951
            break;
952
 
953
        case '*':       /* Match next [n] characters */
954
            for (ch = *p++; ch == '?' || ch == '*'; ch = *p++, n++)
955
            {
956
                if (ch == '?' && *n == '\0')
957
                    return -1;
958
            }
959
            if (ch == '\0')
960
                return 0;
961
            {
962
                char c1 = (char)ch;
963
 
964
                c1 = __TOLOWER(c1);
965
                for (--p; *n != '\0'; ++n)
966
                    if ((ch == '[' || __TOLOWER(*n) == c1) &&
967
                            Match(flags, p, n) == 0)
968
                        return 0;
969
                return -1;
970
            }
971
 
972
        case '[':       /* Match one of the given set */
973
            {
974
                const char *start;
975
                int xnot, cnt=0;
976
 
977
                start = p;                  /* Start of set */
978
                if (*n == '\0')
979
                    return -1;
980
            more:;
981
                xnot = (*p == '!' || *p == '^');
982
                if (xnot)
983
                    ++p;
984
                ch = (int)*p++;
985
                for (;;)
986
                {
987
                    register char cstart = ch, cend = ch;
988
 
989
                    cstart = cend = __TOLOWER(cstart);
990
 
991
                    if (ch == '\0')         /* [... (unterminated) loses.  */
992
                        return -1;
993
 
994
                    ch = *p++;
995
                    ch = __TOLOWER(ch);
996
 
997
                    if (ch == '-' && *p != ']')
998
                    {
999
                        cend = *p++;
1000
                        if (cend == '\0')   /* [... (unterminated) loses.  */
1001
                            return -1;
1002
                        cend = __TOLOWER(cend);
1003
                        ch = *p++;
1004
                    }
1005
 
1006
                    if (__TOLOWER(*n) >= cstart && __TOLOWER(*n) <= cend)
1007
                        goto matched;
1008
 
1009
                    if (ch == ']')
1010
                        break;
1011
                }
1012
 
1013
            /* nomatch */
1014
                if (!xnot)
1015
                {
1016
                /* Match expected, at least one previous match required */
1017
                    if (!cnt)
1018
                        return -1;
1019
                    if (*p == '+')
1020
                        p++;                /* remove attribute */
1021
                    n--;                    /* push terminator */
1022
                }
1023
                else
1024
                {
1025
                /* No match expected, loop if required otherwise success */
1026
                    if (*p == '+')
1027
                    {
1028
                        cnt++;
1029
                        if (n[1])
1030
                        {   /* Additional characters to scan */
1031
                            n++, p = start;
1032
                            goto more;
1033
                        }
1034
                        p++;                /* remove attribute */
1035
                    }
1036
                }
1037
                break;
1038
 
1039
            matched:;
1040
                /* Skip the rest of the [...] that already matched */
1041
                while (ch != ']')
1042
                {
1043
                    if (ch == '\0')         /* [... (unterminated) loses.  */
1044
                        return -1;
1045
                    ch = *p++;
1046
                }
1047
 
1048
                if (xnot)
1049
                {
1050
                /* No match excepted, if [!x]+ previous match required */
1051
                    if (*p == '+')
1052
                    {
1053
                        if (!cnt)
1054
                            return -1;
1055
                        p++;                /* remove attribute */
1056
                    }
1057
                    n--;                    /* push terminator */
1058
                }
1059
                else
1060
                {
1061
                /* Match expected, loop if required otherwise success */
1062
                    if (*p == '+')
1063
                    {
1064
                        cnt++;
1065
                        if (n[1])
1066
                        {   /* Additional characters to scan */
1067
                            n++, p = start;
1068
                            goto more;
1069
                        }
1070
                        p++;                /* remove attribute */
1071
                    }
1072
                }
1073
            }
1074
            break;
1075
 
1076
        case '{':       /* Set */
1077
            {
1078
                const char *se = p;
1079
                char  buf[256];             /* XXX, max set size */
1080
                char  *bp= buf;
1081
                int   i;
1082
 
1083
                while (*se != /*{*/ '}')
1084
                {
1085
                    if (*se++ == '\0')
1086
                        return -1;
1087
                }
1088
                se++;
1089
 
1090
                while (*p != /*{*/ '}')
1091
                {
1092
                    for (i=0, bp=buf; i < sizeof(buf)-1 &&
1093
                            *p != '|' && *p != '}'; i++, *bp++ = *p++)
1094
                        /*LINTED*/
1095
                        ;
1096
                    *bp = '\0';
1097
                    if (*se != '\0') {
1098
                        strncpy(bp, se, sizeof(buf)-1);
1099
                        buf[ sizeof(buf)-1 ] = '\0';
1100
                    }
1101
                    if (Match(flags, buf, n) == 0)
1102
                        return 0;
1103
                    if (*p == '|')          /* treat '|' as sep */
1104
                        p++;
1105
                }
1106
                return -1;
1107
            }
1108
            break;
1109
 
1110
        case '\\':      /* Quote */
1111
            if ((ch = *p++) == '\0')        /* \... (unterminated) loses.  */
1112
                return -1;
1113
 
1114
        default:
1115
            if (ch != __TOLOWER(*n))
1116
                return -1;
1117
        }
1118
        n++;
1119
    }
1120
#undef  __TOLOWER
1121
 
1122
    if (*n == '\0')
1123
        return 0;
1124
    return -1;
1125
}
1126
 
1127
/*----------------------------------------------------------------------------
1128
** FUNCTION           : from_env
1129
**
1130
** DESCRIPTION        : Get data from the users environment
1131
**
1132
**
1133
** INPUTS             : str     - output string
1134
**                      s       - input arguments
1135
**
1136
** RETURNS            : length of arguments consumed
1137
**
1138
----------------------------------------------------------------------------*/
1139
 
1140
int
1141
from_env(String_t *str, const char *s)
1142
{
1143
    char varname[ 32 ];
1144
    int len = 0, len2;
1145
    char *sp;
1146
 
1147
    if (expected(s++, ',') > 0 &&
1148
            (len2 = argument(s, varname, sizeof(varname))) > 0)
1149
    {
1150
        len = 1+len2, s += len2;
1151
        sp = getenv(varname);
1152
        if ( ! sp )
1153
            fatalerr( "Environment Variable not found: '%s'\n", varname );
1154
 
1155
        verbose( " EnvVar %s  = %s", varname, sp );
1156
        StringCat(str, sp);
1157
    }
1158
    return (len);
1159
}
1160
 
1161