/* * $Id$ */ /* * DIR.C: Returns a Harbour array of specified directory contents filtered * by the optional file and attribute mask. * * Latest mods: * 1.28 19990722 ptucker Corrected? NT Extended modes * 1.21 19990722 ptucker Implimented directory for MSVC * Includes new attributes * 1.20 19990722 ptucker Corrected hang when attribute types have * been requested. * */ #if defined(__IBMCPP__) #define INCL_DOSFILEMGR #define INCL_DOSERRORS #endif #include #include "extend.h" #include "itemapi.h" #if defined(__GNUC__) #include #include #include #include #include #include #include #if defined(__DJGPP__) #include #endif #if !defined(HAVE_POSIX_IO) #define HAVE_POSIX_IO #endif #endif #if defined(__CYGWIN__) #include #endif #if defined(__WATCOMC__) || defined(_MSC_VER) #include #include #include #include #include #include #include #if !defined(HAVE_POSIX_IO) #define HAVE_POSIX_IO #endif #endif #if defined(__IBMCPP__) #include /* #include */ /* #include */ /* #include */ /* #include */ /* #include */ #include #if !defined(HAVE_POSIX_IO) #define HAVE_POSIX_IO #endif #endif #if defined(__BORLANDC__) #include #include #include #include #include #include #include #include #include #if !defined(HAVE_POSIX_IO) #define HAVE_POSIX_IO #ifndef S_IEXEC #define S_IEXEC 0x0040 /* owner may execute */ #endif #ifndef S_IRWXU #define S_IRWXU 0x01c0 /* RWE permissions mask for owner */ #endif #ifndef S_IRUSR #define S_IRUSR 0x0100 /* owner may read */ #endif #ifndef S_IWUSR #define S_IWUSR 0x0080 /* owner may write */ #endif #ifndef S_IXUSR #define S_IXUSR 0x0040 /* owner may execute */ #endif #endif #endif #if !defined(FA_RDONLY) #define FA_RDONLY 1 #define FA_HIDDEN 2 #define FA_SYSTEM 4 #define FA_LABEL 8 #define FA_DIREC 16 #define FA_ARCH 32 #endif /* this may not work, but lets find out (only implimented for msvc) */ #if !defined(FA_ENCRYPTED) #define FA_ENCRYPTED 64 #define FA_NORMAL 128 #define FA_TEMPORARY 256 #define FA_SPARSE 512 #define FA_REPARSE 1024 #define FA_COMPRESSED 2048 #define FA_OFFLINE 4096 #define FA_NOTINDEXED 8192 #define FA_VOLCOMP 32764 #endif HARBOUR HB_DIRECTORY( void ) { #if defined(HAVE_POSIX_IO) PHB_ITEM arg1_it = hb_param( 1, IT_STRING ); PHB_ITEM arg2_it = hb_param( 2, IT_STRING ); struct stat statbuf; struct tm * ft; #if defined(_MSC_VER ) struct _finddata_t entry; long hFile; #elif defined(__IBMCPP__) FILEFINDBUF3 entry; HDIR hFind = HDIR_CREATE; ULONG fileTypes = FILE_ARCHIVED | FILE_DIRECTORY | FILE_SYSTEM | FILE_HIDDEN | FILE_READONLY; ULONG findSize = sizeof( entry ); ULONG findCount = 1; #else struct dirent *entry; DIR * dir; #endif char fullfile[ _POSIX_PATH_MAX + 1 ]; char filename[ _POSIX_PATH_MAX + 1 ]; char pattern[ _POSIX_PATH_MAX + 1 ]; char dirname[ _POSIX_PATH_MAX + 1 ]; char string[ _POSIX_PATH_MAX + 1 ]; char pfname[ _POSIX_PATH_MAX + 1 ]; char pfext[ _POSIX_PATH_MAX + 1 ]; char fname[ _POSIX_PATH_MAX + 1 ]; char fext[ _POSIX_PATH_MAX + 1 ]; char filesize[ 10 ]; char ddate[ 9 ]; char ttime[ 9 ]; char aatrib[ 8 ]; int attrib; long fsize; time_t ftime; char * pos; int iDirnameLen; PHB_ITEM pdir; PHB_ITEM psubarray; PHB_ITEM pfilename; PHB_ITEM psize; PHB_ITEM pdate; PHB_ITEM ptime; PHB_ITEM pattr; dirname[ 0 ] = '\0'; pattern[ 0 ] = '\0'; if( arg1_it ) { strcpy( string, hb_parc( 1 ) ); pos = strrchr( string, OS_PATH_DELIMITER ); if( pos ) { strcpy( pattern, pos + 1 ); *( pos + 1 ) = '\0'; strcpy( dirname, string ); } else { strcpy( pattern, string ); strcpy( dirname, ".X" ); dirname[ 1 ] = OS_PATH_DELIMITER; } } if( strlen( pattern ) < 1 ) strcpy( pattern, "*.*" ); iDirnameLen = strlen( dirname ); if( iDirnameLen < 1 ) { strcpy( dirname, ".X" ); dirname[ 1 ] = OS_PATH_DELIMITER; iDirnameLen = 2; } if( strlen( pattern ) > 0 ) { strcpy( string, pattern ); pos = strrchr( string, '.' ); if( pos ) { strcpy( pfext, pos + 1 ); *pos = '\0'; strcpy( pfname, string ); } else { strcpy( pfname, string ); pfext[ 0 ] = '\0'; } } /* redundant if( strlen( pfext ) < 1 ) pfext[ 0 ] = '\0'; */ if( strlen( pfname ) < 1 ) strcpy( pfname, "*" ); /* debug code printf( "\n dirname pattern %s %s ", dirname, pattern ); printf( "\n pfname pfext %s %s ", pfname, pfext ); while( 0 == getchar() ); */ /* should have drive,directory in dirname and filespec in pattern */ tzset(); pdir = hb_itemArrayNew( 0 ); #if defined(_MSC_VER) strcpy( string, dirname ); strcat( string, pattern ); if( ( hFile = _findfirst( string, &entry ) ) != -1L ) { do { strcpy( string, entry.name ); #elif defined(__IBMCPP__) strcpy( string, dirname ); strcat( string, pattern ); if( DosFindFirst( string, &hFind, fileTypes, &entry, findSize, &findCount, FIL_STANDARD ) == NO_ERROR && findCount > 0 ) { do { strcpy( string, entry.achName ); #else #if defined(__WATCOMC__) /* opendir in Watcom doesn't like the path delimiter at the end of a string */ dirname[ iDirnameLen ] = '.'; dirname[ iDirnameLen+1 ] = '\x0'; #endif dir = opendir( dirname ); #if defined(__WATCOMC__) dirname[ iDirnameLen ] = '\x0'; #endif if( NULL == dir ) { /* TODO: proper error handling */ printf( "\n invalid dirname %s ", dirname ); while( 0 == getchar() ); } /* now put everything into an array */ while( ( entry = readdir( dir ) ) != NULL ) { strcpy( string, entry->d_name ); #endif pos = strrchr( string, '.' ); if( pos ) { strcpy( fext, pos + 1 ); *pos = '\0'; strcpy( fname, string ); } else { strcpy( fname, string ); fext[ 0 ] = '\0'; } /* redundant if( strlen( fext ) < 1 ) fext[ 0 ] = '\0'; */ if( strlen( fname ) < 1 ) strcpy( fname, "*" ); /* debug code printf( "\n fname fext %s %s ", fname, fext ); while( 0 == getchar() ); */ if( hb_strMatchRegExp( fname, pfname ) && hb_strMatchRegExp( fext, pfext ) ) { attrib = 0; aatrib[ 0 ] = '\0'; filesize[ 0 ] = '\0'; #if defined(_MSC_VER) strcpy( filename, entry.name ); #elif defined(__IBMCPP__) strcpy( filename, entry.achName ); #else strcpy( filename, entry->d_name ); #endif strcpy( fullfile, dirname ); strcat( fullfile, filename ); if( -1 == stat( fullfile, &statbuf ) ) { /* TODO: proper error handling */ printf( "\n invalid file %s ", fullfile ); while( 0 == getchar() ); } else { /* This might be a problem under Novell when the file is a directory */ /* needs test */ fsize = statbuf.st_size; sprintf( filesize, "%ld", fsize ); ftime = statbuf.st_mtime; ft = localtime( &ftime ); sprintf( ddate, "%04d%02d%02d", ft->tm_year + 1900, ft->tm_mon + 1, ft->tm_mday ); sprintf( ttime, "%02d:%02d:%02d", ft->tm_hour, ft->tm_min, ft->tm_sec ); /* debug code printf( "\n name date time %s %s %s ", filename, ddate, ttime ); while( 0 == getchar() ); */ } #if defined(OS_UNIX_COMPATIBLE) /* GNU C on Linux or on other UNIX */ aatrib[ 0 ] = '\0'; if( S_ISREG( statbuf.st_mode ) ) strcat( aatrib, "A" ); if( S_ISDIR( statbuf.st_mode ) ) strcat( aatrib, "D" ); if( S_ISLNK( statbuf.st_mode ) ) strcat( aatrib, "L" ); if( S_ISCHR( statbuf.st_mode ) ) strcat( aatrib, "C" ); if( S_ISBLK( statbuf.st_mode ) ) strcat( aatrib, "B" ); if( S_ISFIFO( statbuf.st_mode ) ) strcat( aatrib, "F" ); if( S_ISSOCK( statbuf.st_mode ) ) strcat( aatrib, "K" ); #else #if defined(__IBMCPP__) attrib = entry.attrFile; if( attrib & FILE_ARCHIVED ) strcat( aatrib, "A" ); if( attrib & FILE_DIRECTORY ) strcat( aatrib, "D" ); if( attrib & FILE_HIDDEN ) strcat( aatrib, "H" ); if( attrib & FILE_READONLY ) strcat( aatrib, "R" ); if( attrib & FILE_SYSTEM ) strcat( aatrib, "S" ); #else #if defined(_MSC_VER) attrib = entry.attrib; #elif defined(__BORLANDC__) || defined(__DJGPP__) attrib = _chmod( fullfile, 0 ); #else attrib = 0; #endif if( attrib & FA_ARCH ) strcat( aatrib, "A" ); if( attrib & FA_DIREC ) strcat( aatrib,"D" ); if( attrib & FA_HIDDEN ) strcat( aatrib,"H" ); if( attrib & FA_RDONLY ) strcat( aatrib,"R" ); if( attrib & FA_SYSTEM ) strcat( aatrib,"S" ); if( attrib & FA_LABEL ) { strcat( aatrib, "V" ); if( attrib & FA_VOLCOMP ) strcat( aatrib, "L" ); /* volume supports compression. */ } /* some of these are known to work under NT - I picked the letters to use.*/ /* needs testing on a Novell drive */ #if defined(USE_NT) if( attrib & FA_ENCRYPTED ) strcat( aatrib, "E" ); /* if( attrib & FA_NORMAL ) */ /* strcat( aatrib, "N" ); */ if( attrib & FA_TEMPORARY ) strcat( aatrib, "T" ); if( attrib & FA_SPARSE ) strcat( aatrib, "P" ); if( attrib & FA_REPARSE ) strcat( aatrib, "Z" ); if( attrib & FA_COMPRESSED ) strcat( aatrib, "C" ); if( attrib & FA_OFFLINE ) strcat( aatrib, "O" ); if( attrib & FA_NOTINDEXED ) strcat( aatrib, "X" ); #endif #endif #endif /* TODO: attribute match rtn */ pos = string; if( arg2_it && hb_parclen( 2 ) >= 1 ) { strcpy( string, hb_parc( 2 ) ); while( *pos != '\0' ) { *pos = ( char ) toupper( *pos ); pos++; } pos = strchr( string, *aatrib ); } if( pos ) { /* array cname, csize, ddate, ctime, cattributes */ pfilename = hb_itemPutC( NULL, filename ); psize = hb_itemPutC( NULL, filesize ); pdate = hb_itemPutDS( NULL, ddate ); ptime = hb_itemPutC( NULL, ttime ); pattr = hb_itemPutC( NULL, aatrib ); psubarray = hb_itemArrayNew( 5 ); hb_itemArrayPut( psubarray, 1, pfilename ); hb_itemArrayPut( psubarray, 2, psize ); hb_itemArrayPut( psubarray, 3, pdate ); hb_itemArrayPut( psubarray, 4, ptime ); hb_itemArrayPut( psubarray, 5, pattr ); /* NOTE: Simply ignores the situation where the array length limit is reached. */ hb_arrayAdd( pdir, psubarray ); hb_itemRelease( pfilename ); hb_itemRelease( psize ); hb_itemRelease( pdate ); hb_itemRelease( ptime ); hb_itemRelease( pattr ); hb_itemRelease( psubarray ); } } } #if defined(_MSC_VER) while( _findnext( hFile, &entry ) == 0 ); _findclose( hFile ); #elif defined(__IBMCPP__) while( DosFindNext( hFind, &entry, findSize, &findCount ) == NO_ERROR && findCount > 0 ); DosFindClose( hFind ); #else closedir( dir ); #endif hb_itemReturn( pdir ); /* DIRECTORY() returns an array */ hb_itemRelease( pdir ); #if defined(_MSC_VER) || defined(__IBMCPP__) } #endif #endif /* HAVE_POSIX_IO */ }