/*----------------------------------------------------------------------*/ /* NUFIND.EXE - Enhanced MS DOS implementation of the Unix find * command. NUFIND will find all files matching a set * of specified criteria and perform any of several * operations (move, copy, delete, etc.) on each file * that matches the search criteria. * * Version: 2.1.0 * Date: June 13, 1990 * Author: Don A. Williams * ********************* NOTICE ************************ * Contrary to the current trend in MS-DOS software * * this program, for whatever it is worth, is NOT * * copyrighted (with the exception of the runtime * * library from the C compiler)! The program, in * * whole or in part, may be used freely in any * * fashion or environment desired. If you find this * * program to be useful to you, do NOT send any * * contribution to the author; in the words of Rick * * Conn, 'Enjoy!' However, if you make any * * improvements, I would enjoy receiving a copy of * * the modified source. I can be reached, usually * * within 24 hours, by messages on any of the * * following Phoenix, AZ systems (the Phoenix systems * * can all be reached through StarLink node #9532): * * * * The Tool Shop BBS [PCBOARD] [PC-Pursuit] * * (602) 279-2673 1200/2400/9600 bps * * Technoids Anonymous [PCBOARD] * * (602) 899-4876 300/1200/2400 bps * * (602) 899-5233 * * (602) 786-9131 * * Inn On The Park [PCBOARD] * * (602) 957-0631 1200/2400/9600 bps * * Pascalaholics Anonymous [WBBS] * * (602) 484-9356 1200/2400 bps * * * * or: * * Blue Ridge Express [RBBS] Richmond, VA * * (804) 790-1675 2400 bps [StarLink #413] * * * * The Lunacy BBS [PCBOARD] Van Nuys, CA * * (805) 251-7052 2400/9600 [StarLink 6295] * * (805) 251-8637 2400/9600 [StarLink 6295] * * * * or: * * GEnie, mail address: DON-WILL * * CompuServ: 75410,543 * * * * Every effort has been made to avoid error and * * moderately extensive testing has been performed * * on this program, however, the author does not * * warrant it to be fit for any purpose or to be * * free from error and disclaims any liability for * * actual or any other damage arising from the use * * of this program. * ******************************************************* */ #include #include #include #include #include #include #include #include #include #include "nufind.h" #include "queue.h" struct DateSel { unsigned Date; int Swt; }; QUE_DEF Paths, ExcPaths, IncNameQueue, ExcNameQueue; QUE_DEF IncPathQueue, ExcPathQueue, NoCreateQ; char ProgName[9]; char CurDir[66] = ""; char DestDir[66] = ""; char *CommandString; int BaseLength = 0; long TotalSize = 0L; int RecurSwt = 1; int PrtSwt = 1; int LsSwt = 0; int LdSwt = 0; int RmSwt = 0; int RmDirSwt = 0; int RmSwtA = 0; int AttrSwt = 0; int NotAttrSwt = 0; int AttrOnSwt = 0; int AttrOffSwt = 0; int CopySwt = 0; int MoveSwt = 0; int TreeSwt = 0; int SizeSwt = 0; int ExecSwt = 0; int SumSwt = 0; int RelSwt = 0; int OldDate = 0; struct DateSel Since = {0, 0}; struct DateSel Before = {0, 0}; char AttrMask = 0; char NotAttrMask = 0; char AttrOnMask = 0; char AttrOffMask = 0; long Size = 0; char *ExistRef = NULL; char *NotExistRef = NULL; char *CompRef = NULL; char *NotCompRef = NULL; INFO_BLOCK *LT_Ref = NULL; INFO_BLOCK *LE_Ref = NULL; INFO_BLOCK *GT_Ref = NULL; INFO_BLOCK *GE_Ref = NULL; INFO_BLOCK *LT_DateRef = NULL; INFO_BLOCK *LE_DateRef = NULL; INFO_BLOCK *GT_DateRef = NULL; INFO_BLOCK *GE_DateRef = NULL; struct date Today; unsigned TodayDate; void GetProgName (char *Name, char *argv); char *RootPath (char *CurDir, char *RelPath, char *FullPath); void GetCurrentDisk (int *CurDisk); int GetCurrentDirectory (int Disk, char *CurDir); void GetArgs (char *argv[], int i); void QueuePath (QUE_DEF *Q, char *Name); void ProcessPaths (char *Name, int Level); int Select (INFO_BLOCK *Name); void Action (INFO_BLOCK *Name); char *PrintNumber (long Number); void Replace (char *Str1, int n, char *Str2); void ErrorMsg (char *Format, ...); void ExceptionMsg (char *Format, ...); void ErrorExit (char *Format, ...); void GetPath (QUE_DEF *Q, char *Arg); char P_Name[70]; void main (int argc, char *argv[]) { int i; int CurDisk; QUE_ENTRY *t; GetProgName(ProgName, argv[0]); fprintf(stderr, "%s: NewUFind - Version %s: Date - %s\n", ProgName, VERSION, VER_DATE); getdate(&Today); TodayDate = ( (Today.da_year - 1980) << 9) | (Today.da_mon << 5) | Today.da_day; GetCurrentDisk(&CurDisk); CurDir[0] = (char) (CurDisk + 'A'); CurDir[1] = ':'; CurDir[2] = '\\'; GetCurrentDirectory(0, CurDir+3); strlwr(CurDir); if (CurDir[strlen(CurDir)-1] != '\\') strcat(CurDir, "\\"); InitQueue(&Paths); InitQueue(&IncNameQueue); InitQueue(&ExcNameQueue); InitQueue(&IncPathQueue); InitQueue(&ExcPathQueue); InitQueue(&NoCreateQ); for (i=1; i < argc && argv[i][0] != '-'; ++i) GetPath(&Paths, argv[i]); GetArgs(argv, i); if (Paths.Count == 0) if ( (Enque(&Paths, CurDir)) == NULL) ErrorExit("Insufficient memory for Path list.\n"); for (t=Paths.Head; t != NULL; t = t->Next) ProcessPaths(t->Body, 0); if (SumSwt) printf("Total Size = %16s\n", PrintNumber(TotalSize)); } void QueuePath (QUE_DEF *Q, char *Name) { char FullPath[66]; if (RootPath(CurDir, Name, FullPath) != NULL) { if (FullPath[strlen(FullPath)-1] != '\\') strcat(FullPath, "\\"); if ( (Enque(Q, FullPath)) == NULL) ErrorExit("Insufficient memory for Path list.\n"); } } void ProcessPaths (char *Body, int Level) { QUE_DEF *Dirs; QUE_ENTRY *u, *v; char Name[66], DirName[66]; struct ffblk DirBlk; int Status, i; INFO_BLOCK FileInfo; for (u=ExcPaths.Head; u != NULL; u = u->Next) if (!strcmp(Body, u->Body)) return; if (!Level) BaseLength = strlen(Body); if ( (Dirs = malloc(sizeof(QUE_DEF))) == NULL) { ErrorMsg("Insufficient memory for directory list.\n"); return; } InitQueue(Dirs); strcpy(Name, Body); DirName[0] = '\0'; if ( (i = strlen(Name)) > 3 && Name[i-2] != ':' && Name[i-1] == '\\') Name[i-1] = '\0'; if (Name[i-1] != '\\' && (Status = findfirst(Name, &DirBlk, 0xFF)) != 0) return; if ( Name[i-1] == '\\' || (DirBlk.ff_attrib & FA_DIREC) != 0 ) { strcpy(DirName, Name); if (Name[i-1] != '\\') strcat(Name, "\\"); strcat(Name, "*.*"); Status = findfirst(Name, &DirBlk, 0xFF); while (Status == 0) { strcpy(FileInfo.Name, Body); strcat(FileInfo.Name, DirBlk.ff_name); strlwr(FileInfo.Name); FileInfo.Attrib = DirBlk.ff_attrib; FileInfo.FTime.Time = DirBlk.ff_ftime; FileInfo.FDate.Date = DirBlk.ff_fdate; FileInfo.Size = DirBlk.ff_fsize; if ( (DirBlk.ff_attrib & FA_DIREC) != 0 ) { if (!strcmp(DirBlk.ff_name, "..") || !strcmp(DirBlk.ff_name, ".") ) { Status = findnext(&DirBlk); continue; } strcpy(Name, Body); strcat(Name, DirBlk.ff_name); if ( (Enque(Dirs, Name)) == NULL) { ErrorMsg("Insufficient memory for directory list.\n"); return; } if (Select(&FileInfo)) Action(&FileInfo); } else if ( (DirBlk.ff_attrib & FA_LABEL) != 0 ); else if (Select(&FileInfo)) Action(&FileInfo); Status = findnext(&DirBlk); } if (RecurSwt && Dirs->Count != 0) { u = Dirs->Head; while (u != NULL) { strcpy(Name, u->Body); strcat(Name, "\\"); strlwr(Name); ProcessPaths(Name, Level + 1); free(u->Body); v = u->Next; free(u); u = v; } InitQueue(Dirs); } } else { strcpy(FileInfo.Name, Name); FileInfo.Attrib = DirBlk.ff_attrib; FileInfo.FTime.Time = DirBlk.ff_ftime; FileInfo.FDate.Date = DirBlk.ff_fdate; FileInfo.Size = DirBlk.ff_fsize; if (Select(&FileInfo)) Action(&FileInfo); } if (RmDirSwt && DirName[0] != '\0' ) { if (DirName[strlen(DirName)-2] == ':') return; printf("RMDIR: %s\n", DirName); CurDir[strlen(CurDir)-1] = '\0'; if (!strcmp(DirName, CurDir)) { *(strrchr(CurDir, '\\')) = '\0'; chdir(CurDir); } strcat(CurDir, "\\"); if (rmdir(DirName)) perror(" FAILED"); } } void GetProgName (char *Name, char *argv) { char *p, *p1; if ( (p = strrchr(argv, '\\')) != NULL) ++p; else p = argv; if ( (p1 = strchr(p, '.')) != NULL) *p1 = '\0'; strcpy(Name, p); } /**************************************************************************** * PrintNumber -- Print a long number, inserting ","s where needed. ****************************************************************************/ char * PrintNumber (long Number) { static char Temp[20]; int l, i; sprintf(Temp, "%lu", Number); l = strlen(Temp); for (i=0; i < l; ++i) { if ( i && ((i) % 3) == 0) { memmove(&Temp[l-i+1], &Temp[l-i], strlen(&Temp[l-i])+1); Temp[l-i] = ','; } } return(Temp); } void ErrorExit (char *Format, ...) { va_list ArgPtr; extern char ProgName[]; extern int errno; fprintf(stderr, "%s: ", ProgName); va_start(ArgPtr, Format); vfprintf(stderr, Format, ArgPtr); va_end(ArgPtr); if (errno) perror(" "); fprintf(stderr, "\n"); exit(1); } void Execute (char *Name) { extern char *CommandString; char *Command, Dir[65], FName[9]; char *q, *p1, *p2; int n; if ( (Command = malloc(129)) == NULL) { ErrorMsg("Insufficient memory for command.\n"); return; } strcpy(Command, CommandString); n = 0; while ( (q = strchr(&Command[n], '%')) != NULL ) { switch(toupper(*(q+1))) { case 'F': p1 = strrchr(Name, '\\'); Replace(q, 2, ++p1); break; case 'P': Replace(q, 2, Name); break; case 'N': p1 = strrchr(Name, '\\'); p2 = strchr(++p1, '.'); strncpy(FName, p1, (int) (p2 - p1) ); FName[(int) (p2 - p1)] = '\0'; Replace(q, 2, FName); break; case 'E': p1 = strrchr(Name, '.'); Replace(q, 2, ++p1); break; case 'D': p1 = strrchr(Name, '\\'); strncpy(Dir, Name, (int) (p1 - Name) ); Dir[(int) (p1 - Name)] = '\0'; Replace(q, 2, Dir); break; } n = (int) (q - Command) + 2; } system(Command); free(Command); } /************************************************************************** * Replace - Replaces a number of characters equal to the length of Str2 * in Str1 with the contents of Str2. The position is Str1 is * specified by n. *************************************************************************/ void Replace (char *Str1, int n, char *Str2) { int l, r; l = strlen(Str1); r = strlen(Str2); memmove(&Str1[r], &Str1[n], l - n + 1); strncpy(Str1, Str2, r); } void ErrorMsg (char *Format, ...) { va_list ArgPtr; extern char ProgName[]; extern int errno; fprintf(stderr, "%s: - ", ProgName); va_start(ArgPtr, Format); vfprintf(stderr, Format, ArgPtr); va_end(ArgPtr); if (errno) perror(" "); fprintf(stderr, "\n"); } void ExceptionMsg (char *Format, ...) { va_list ArgPtr; fprintf(stderr, " "); va_start(ArgPtr, Format); vprintf(Format, ArgPtr); va_end(ArgPtr); fputc('\n', stdout); if (errno) { perror(" "); fputc('\n', stdout); } } int GetYorN (char *Message, ...) { va_list ArgPtr; char Reply; while (1) { va_start(ArgPtr, Message); fprintf(stderr, " "); vfprintf(stderr, Message, ArgPtr); fprintf(stderr, "('Y', 'N' or A)bort)? "); Reply = toupper(getch()); if (Reply == 'A') exit(1); if (Reply == 'Y' || Reply == 'N') break; fprintf(stderr, "%c is invalid.\n \007", Reply); } va_end(ArgPtr); fprintf(stderr, "%c\n", Reply); return( (Reply == 'Y') ); } void GetPath (QUE_DEF *Q, char *Arg) { extern char P_Name[70]; char *p, Temp[65]; int i, j; CurDir[strlen(CurDir)-1] = '\0'; if ( !strcmp(Arg, ".") ) strcpy(P_Name, CurDir); else if ( !strcmp(Arg, "..") ) { p = strrchr(CurDir, '\\'); *p = '\0'; strcpy(P_Name, CurDir); *p = '\\'; } else strcpy(P_Name, Arg); strcat(CurDir, "\\"); if ( (p = strchr(P_Name, ':')) != NULL) { if ( (i = (int) (p - P_Name) ) > 1) { for (j=0; j < i; ++j) { Temp[0] = P_Name[j]; Temp[1] = '\0'; strcat(Temp, p); if (Temp[strlen(Temp)-1] != '\\') strcat(Temp, "\\"); if (Enque(Q, Temp) == NULL) ErrorExit("Insufficient memory for Path List.\n"); } } else { strcpy(Temp, P_Name); if (Temp[strlen(Temp)-1] != '\\') strcat(Temp, "\\"); if (Enque(Q, Temp) == NULL) ErrorExit("Insufficient memory for Path List.\n"); } } else { Temp[0] = CurDir[0]; Temp[1] = ':'; Temp[2] = '\0'; strcat(Temp, P_Name); if (Temp[strlen(Temp)-1] != '\\') strcat(Temp, "\\"); if (Enque(Q, Temp) == NULL) ErrorExit("Insufficient memory for Path List.\n"); } }