/* This is part of ODS2 written by Paul Nankervis, * email address: Paulnank@au1.ibm.com * ODS2 is distributed freely for all members of the * VMS community to use. However all derived works * must maintain comments in their source to acknowledge * the contributions of the original author and * subsequent contributors. This is free software; no * warranty is offered, and while we believe it to be useful, * you use it at your own risk. */ /* Copyright (C) 2016 Timothe Litt, litt at acm dot org. */ #include #include #include #include #include #include #include #include #include "vmsfile.h" #ifndef $SUCCESSFUL #define $SUCCESSFUL(cond) (((cond) & STS$M_SUCCESS)) #endif typedef struct globlist_ { struct globlist_ *next; char path[1]; } globlist_; /******************************************************************* addfile() */ static int addfile( int flags, glob_t *pglob, dsc$descriptor_d *path ) { size_t n, ofs; char ** nl; globlist_ *fp; ofs = pglob->gl_pathc; if( flags & GLOB_DOOFFS ) ofs += pglob->gl_offs; if( (nl = (char **)realloc( pglob->gl_pathv, (ofs + 2) * sizeof( char **) )) == NULL ) { return GLOB_NOSPACE; } pglob->gl_pathv = nl; n = offsetof( globlist_, path ) + path->dsc$w_length; if( (fp = malloc( n + 1 )) == NULL ) return GLOB_NOSPACE; memcpy( fp->path, path->dsc$a_pointer, n - offsetof( globlist_, path ) ); fp->path[n] = '\0'; pglob->gl_pathv[ofs++] = fp->path; pglob->gl_pathv[ofs] = NULL; ++pglob->gl_pathc; fp->next = pglob->list_; pglob->list_ = fp; return 0; } /******************************************************************* globfree() */ void globfree( glob_t *pglob ) { globlist_ *fp; while( (fp = pglob->list_) != NULL ) { pglob->list_ = fp->next; free( fp ); } free( pglob->gl_pathv ); pglob->gl_pathv = NULL; pglob->gl_pathc = 0; } /******************************************************************* cmpglb() */ static int cmpglb( const void *p1, const void *p2 ) { return _stricmp( *((const char *const *)p1), *((const char *const *)p2) ); } /******************************************************************* glob() */ int glob( const char *pattern, int flags, int (*errfunc)( const char *epath, int eerrno ), glob_t *pglob ) { struct dsc$descriptor_d retdsc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_D, NULL }; unsigned long ctx = 0; unsigned long status; struct dsc$descriptor_s patdsc = { 0, DSC$K_TYPE_T, DSC$K_CLASS_S, NULL }; int err; size_t found; if( errfunc != NULL ) abort(); found = err = 0; if( !(flags & GLOB_APPEND) ) { pglob->gl_pathc = 0; pglob->list_ = NULL; pglob->gl_pathv = NULL; } ctx = 0; patdsc.dsc$a_pointer = pattern; patdsc.dsc$w_length = strlen( pattern ); do { if( $SUCCESSFUL(status = lib$find_file( &patdsc, &retdsc, &ctx, NULL, NULL, NULL, 0 )) ) { err = addfile( flags, pglob, &retdsc ); found++; } } while( !err && $SUCCESSFUL(status) ); lib$find_file_end( &ctx ); str$free1_dx(&retdsc ); if( !found ) err = GLOB_NOMATCH; if( err ) { globfree( pglob ); errno = err; } else { if( !(flags & GLOB_NOSORT) ) { qsort( pglob->gl_pathv, pglob->gl_pathc, sizeof( char **), cmpglb ); } } return err; } /******************************************************************* strlcpy() */ static size_t strlcpy( char *dst, const char *src, size_t size ) { size_t srclen; size--; srclen = strlen( src ); if( srclen > size ) srclen = size; memcpy( dst, src, srclen ); dst[srclen] = '\0'; return (srclen); } /******************************************************************* vmsbasename() */ char *vmsbasename( char *path ) { static char buf[NAM$C_MAXRSS + 1]; char *p, *d; if( path == NULL || !*path ) return "."; strlcpy( buf, path, sizeof( buf ) ); if( (p = strrchr( buf, ']' )) != NULL ) return p+1; if( (p = strrchr( buf, ':' )) != NULL ) return p+1; return buf; }