Sender: Date: Thu, 20 Oct 1994 14:59:13 +0100 From: "DR. SOLYOM ANDRAS" Reply-To: SOLYOM AT HUBME51 DOT bitnet To: DJGPP AT SUN DOT soe DOT clarkson DOT edu Cc: solyom AT bmeik DOT eik DOT bme DOT hu Subject: LS for DOS Dear Everyone, It would really be good to have the unix utilities running on MSDOS. Or it would even be better if had MSDOS utilities on MSDOS that works like their UNIX counterpart, but which are especially developed for MSDOS. I personally was so in love with the UNIX style file name globbing that I wrote an LS for DOS for myself, and I am using it ever since. It is not a complete LS clone, so it has only a tiny subset of its options ('l','a' and I created a 'd' options to list only directori es), and instead of the owner/ group/others set access modes it displays the MSDOS modes: r/w/x/h/d/a, but you can say that 'ls -la [a-c]*doc' and it works. If anyone intrested, here is the code (I hope the comments in it are good enough for documentation). To compile it you need a C compiler, this file and the files FNMATCH.C and FNMATCH.H from the GNU/DJGPP distribution. (I also wrote a windows 'shell' for the most common DOS commands that let me use the UNIX style globbing, so e.g. while ru nning WINDOWS I can type 'copy *a*doc b:' or 'del [^a]*exe' or simply 'dir *c'. If anyone is interested please contact me! As it uses the WINIO Library from the book 'Undocumented Windows' I can only send you the EXE file and my source, not the libraries you need to compile it) ----------- CUT HERE ---------- /*==========================================================================*/ /* Name: LS.C (C) A. S˘lyom */ /* Task: LS a'la UNIX. */ /* To compile as a full program define the macro */ /* _USE_FNMATCH */ /* and compile it together with FNMATCH.C/FNMATCH.H from the GNU */ /* sources */ /* Example with Borland C++: * bcc -D_USE_FNMATCH -I(where FNMATCH.H resides) ls.c fnmatch.c */ /* To use it as a function in one of your program define */ /* _FUNCTION_VERSION_ */ /* ------------- FREE PROGRAM USE AT YOUR OWN RI SC ---------------- */ /* Date: 1994 Jan. 27. 09:24:43pm */ /* Changes: 07-29-94 11:08pm option -d to list only directories is added */ /*==========================================================================*/ #include #include #include #include #ifdef __TURBOC__ #include #endif #ifdef _USE_FNMATCH static char wildcard[128]; #include "fnmatch.h" extern int fnmatch(char *, char*, int); #else extern int CreateRanges(char *); #endif extern int IsFileNameMatched(char *); struct _tagFtime { unsigned ft_tsec:5; /* 0-29, double to get real seconds */ unsigned ft_min:6; /* 0-59 */ unsigned ft_hour:5; /* 0-23 */ }; struct _tagFdate { unsigned ft_day:5; /* 1-31 */ unsigned ft_month:4; /* 1-12 */ unsigned ft_year:7; /* since 1980 */ }; typedef struct { int attrib; union { struct _tagFti me fTime; unsigned nTime; }ft; union { struct _tagFdate fDate; unsigned nDate; }fd; long lSize; char d_name[13]; }MYDIRENT; static int isAll = 0; /* ls -a hidden files too */ static int isFull= 0; /* ls -l full names with flags */ static int onlyDirs= 0; /* ls -d only directories */ static int columns = 5; static int numFiles = 0; #define HIDFLAGS (FA_HIDDEN | FA_SYSTEM) /*======================================================================*/ void Usage(char *pszProg) /* TASK: * EXPECTS: * GLOBALS: * RETURNS: */ /*----------------------------------------------------------------------*/ { char *p; p = strrchr(pszProg, '\\'); if(!p) p = strrchr(pszProg, '/'); if(!p) p = pszProg[1] == ':' ? pszProg+2 : pszProg; else ++p; if( strrchr(pszProg, '.') ) *strrchr(pszProg, '.') = 0; printf("%s - UNIX like 'ls' with full regular expression filename match\n" "(C) A. S˘lyom (1994)\n\n" "Usage: %s [-flags] [path]\n" " flags: a - list hidden files too\n" " l - long list format\n" " d - list only directories\n" " ? - help\n" " path: partial or full path to directory to be listed with optional\n" " regular expression template for file names in that directory\n" " The path must contain forward slashes (/) instead of the\n" " backslashes (\\) found in DOS names, as the backslash is\n" " reserved for regular expressions\n" "Special characters in filename expressions:\n" " * any number of any character\n" " ? any character\n" " \\ escapes special meaning of * or ? or \\ \n" " [] character groups (e.g. [ax.] or [1-9a-zA-Z]\n" " [^] any character that is NOT in group. The '^' character\n" " must be the first one in the square bracke t\n" "Examples: \n" " %s -l *.[ch] List all \".c\" and \".h\" files in long format\n" " %s -l *foo* List all file names containing \"foo\" (e.g. \"123foo.c\")\n" " %s -a * List all hidden and normal files\n" #if !defined(_FUNCTION_VERSION_) "This program is FREEWARE ! Use it at your own risk!\n" #endif ,p,p,p,p,p); #if !defined(_FUNCTION_VERSION_) exit(1); #e ndif } /*======================================================================*/ char *StripFileName(char *ps) /* separate file name from path * RETURNS: pointer to that file name of the path in 'ps' * does not cut path */ /*----------------------------------------------------------------------*/ { char *p; p = strrchr(ps, '\\'); if(!p) p = strrchr(ps, '/'); if(!p) if(ps[1] == ':') p = ps+1; if(p) ++p; else p = ps; return p; } /*======================================================================*/ char *_SetupPath(char *s) /*----------------------------------------------------------------------*/ { char *p; static char path[80]; int i; strcpy(path, s); for(p = s; *p; ++p) if(*p == '\\' && *(p+1)!= '\\' && *(p+1)!= '?') *p++ = '/' ; p = StripFileName(s); path[ p - s] = 0; i = 0; if( *p == '.' ) /* "dir .xx" */ { i = 1; wildcard[0] = '*'; } strcpy( &wildcard[i], p); if(!wildcard[0]) strcpy(wildcard, "*"); #ifndef _USE_FNMATCH if(!CreateRanges(wildcard)) { printf("Bad regular expression: '%s'\n", wildcard); return NULL; } # endif strcat(path, "*.*"); return path; } #ifdef _USE_FNMATCH /*======================================================================*/ int IsFileNameMatched(char *psz) /*----------------------------------------------------------------------*/ { //printf("DEBUG\n" // " IsFileNameMatched-> string: '%s'. wildcard: '%s'\n", psz, wildcard); return fnmatch(wildcard, psz, FNM_CASEFOLD) ? 0 : 1; } #endif /*============================================================= =========*/ void BadArgs(char *pszProg) /* TASK: * EXPECTS: * GLOBALS: * RETURNS: */ /*----------------------------------------------------------------------*/ { printf("Invalid arguments !\n"); Usage(pszProg); } /*======================================================================*/ void GetOpts(char *pszProg, char *pszOpts) /* TASK: * EXPECTS: * GLOBALS: * RETURNS: */ /*----------------------------------------------------------------------*/ { while( *++pszOpts) /* skip '-' or to next flag */ { switch(*pszOpts) { case 'a' : isAll = 1; break; case 'l': isFull = 1; columns = 1; break; /* MOD 07-29-94 11:12pm 3 lines added */ case 'd': on lyDirs = 1; break; default: BadArgs(pszProg); break; } } } /*======================================================================*/ int CompFunc(const void *p1, const void *p2) /* TASK: Perform directory name compare * EXPECTS: * GLOBALS: * RETURNS: */ /*----------------------------------------------------------------------*/ { return strcmp( ( (MYDIRENT*)p1)->d_name, ( (MYDIRENT*)p2)->d_name); } /*======================================================================*/ #ifdef _FUNCTION_VERSION_ int ls(int argc, char **argv) #else int main(int argc, char **argv) #endif /* TASK: Perform directory listing * EXPECTS: * GLOBALS: * RETURNS: main() returns 1 if error, 0 otherwise, ls() returns 0 if error, * 1 otherwise */ /*----------------------------------------------------------------------*/ { DIR *pdir; struct dirent *pd; MYDIRENT *pdeFiles=NULL, *pTmp; char szPath[128]; char szName[64]; char *p; int i = 1; long lSum = 0; #ifdef _USE_FNMATCH extern char *_SetupPath(char *s); #endif #ifdef _FUNCTION_VERSION_ isAll = 0; /* ls -a hidden files too */ isFull= 0; /* ls -l full names with flags */ /* MOD 07-29-94 11:23pm 1 line added */ onlyDirs = 0; /* ls -d list directories only */ columns = 5; numFiles = 0; #endif if(argc == 1) strcpy(szPath,"*"); else if(argc > 3) BadArgs(argv[0]); else if(argc == 3 && argv[1][0] != '-' && argv[1][0] != '/') BadArgs(argv[0]); else if (argc == 2 && (argv[1][0] == '?' || (argv[1][0] == '- ' && argv[1][0] == '?')) ) { Usage(argv[0]); #ifdef _FUNCTION_VERSION_ return 1; #endif } else { if(argc > 1 && argv[1][0] == '-') { GetOpts(argv[0], argv[1]); i = 2; } if(argc > i) strcpy(szPath, argv[i]); else strcpy(szPath,"*"); } p = strrchr(szPath, '/'); if(!p) p = strrchr(szPath, '\\'); if(p) ++p; else if(szPath[1] == ':') p = &szPath[2]; else p = szPath; strcpy(szName, p); *p = 0; for(p = szPath; *p; p++) if(*p == '/') *p = '\\'; if(!szName[0]) strcpy(szName, "*"); #ifdef _USE_FNMATCH _SetupPath(szName); / * see SH.C */ #else if(!CreateRanges(szName)) { printf("ls - Bad regular expression: '%s'\n", szName); #ifdef _FUNCTION_VERSION_ return 0; #else exit(1); #endif } #endif /* _USE_FNMATCH */ if(!szPath[0]) strcpy(szPath, ".\\"); pdir = opendir(szPath); if(!pdir) { printf("Directory '%s' does not exist\n"); #ifdef _FUNCTION_VERSION_ return 0; #else exit(1); #endif } while( (pd = readdir(pdir)) != NULL) { #ifdef __TURBOC__ if( ( ( ((struct find_t *)pdir)->attrib & FA_LABEL) != 0) || ( !isAll && ( ( (( (struct find_t *)pdir)->attrib & HIDFLAGS) != 0) || pd->d _name[0] == '.' ) /* MOD 07-29-94 11:19pm 5 lines added */ || ( onlyDirs && (( (struct find_t *)pdir)->attrib & FA_DIREC) == 0 ) ) ) continue; #endif if( IsFileNameMatched(pd->d_name) ) { pTmp = pdeFiles; if(!pdeFiles) pTmp = malloc(sizeof(MYDIRENT)); else pTmp = realloc(pdeFiles, (numFiles + 1) * sizeof(MYDIRENT)); if(pTmp) pdeFil es = pTmp; else { printf("***** Out of memory...\n"); if(pdeFiles) { printf("Files found so far:\n\n"); break; /* out of while */ } else { closedir(pdir); #ifdef _FUNCTION_VERSION_ return 0; #else exit(1); #endif } } strcpy( (pdeFiles + numFiles)->d_name, pd->d_name); (pdeFiles + numFiles)->attrib = ( (struct find_t *)pdir)->attrib; (pdeFiles + numFiles)->fd.nDate = ( (struct find_t *)pdir)->wr_date; (pdeFiles + numFiles)->ft.nTime = ( (struct find_t *)pdir)->wr_time; /* MOD 08-02-94 07:43pm 1 line * (pdeFiles + numFiles++)->lSize = ( (struct find_t *)pdir)->size; */ lSum += (pdeFiles + numFiles++)->lSize = ( (struct find_t *)pdir)->size; } } /* while */ closedir(pdir); if(numFiles) { int i,j; char *p; qsort( (void *) pdeFiles, numFiles, sizeof(MYDIRENT), CompFunc); pTmp = pdeFiles; /* MOD 08-02-94 07:45pm 2 lines added */ if(lSum && isFull) printf("total: %ld\n", lSum); for( i = 0; i < numFiles; i += columns) { for(j = 0; j < columns && (j+i) < numFiles; j++) { if( (pTmp->attrib & FA_DIREC) == 0 ) strlwr(pTmp->d_name); if(isFull) { if(pTmp->attrib & FA_DIREC) fputchar('d'); else fputchar('-'); fputchar('r'); /* all DOS file can be read */ if(pTmp->attrib & FA_RDONLY) fputchar('-'); else fputchar('w'); p = strchr(pTmp->d_name, '.'); if(p) { ++p; if(strcmp(p, "com") == 0 || stricmp(p, "exe") == 0 || stricmp(p, "bat") == 0) { fputchar('x'); } else fputchar('-'); } else if(pTmp->attrib & FA_DIREC) fputchar('x'); else fputchar('-'); if(pTmp->attrib & FA_HIDDEN) fputchar('h'); else fputchar('-'); if(pTmp->attrib & FA_SYSTEM) fputchar('s'); else fputchar('-'); if(pTmp->attrib & FA_ARCH) fputchar('a'); else fputchar('-'); printf("\ %7lu %02d-%02d-%02d %02d:%02d \t%-15s", pTmp->lSize, pTmp->fd.fDate.ft_month, pTmp->fd.fDate.ft_day, pTmp->fd.fDate.ft_year+80, pTmp->ft.fTime.ft_hour, pTmp->ft.fTime.ft_min, pTmp->d_name); } else { printf("%-15s", pTmp->d_name); } ++pTmp; } printf("\n"); } free(pdeFiles); } #ifdef _FUNCTION_VERSION_ return 1; #else return 0; #endif } ----------- CUT HERE ---------- Adras Solyom