/*************************************************************************** * Program: Whereis (searches for a filename on your [hard]-disk) * * Version: 1.18 for AMIGA-Computers. Last-Update: Thursday 15-02-1990 * * Whereis.c by R. Bless 1989/90. All Rights reserved! Program (exe) is * * free distributable. Compilable under Aztec 3.6a. * * ------------------------------ NOTE :---------------------------------- * * No redistribution of a changed source and/or executable without * * permission of the author!!! Please ask me first. See address below. * * ----------------------------------------------------------------------- * * I'm fed up with all 'whereis' or 'wo' utilities that I had, because the * * one is always case sensitive and can't be aborted, the other is * * horribly slow and can't handle wildcards >:-(! So here is my product * * which uses no recursive procedures. * * Written from 17-10-89 to 24-10-89 (first version then addups) * * (C)opyright by Roland Bless (Byteable Software Products) * ***************************************************************************/ /* Any comments or bug-reports to: +----------------------------------------------------------------------------+ |R o l a n d B l e s s |UUCP: rob@spirit.UUCP (FRG only!) | | | or rob%spirit@impch.imp.com (worldwide) | |Moersenbroicher Weg 151 |FIDO: 2:242/20 Roland Bless | BTX:0211623818-0001 | |FRG- 4000 Duesseldorf 30|---------------------------------------------------| |voice +49 211 623817 | // AMIGA is multi,| "They build machines that | | |\X/ AMIGA is more! | they can't control..." STING| |----------------------------------------------------------------------------| |BANG:...uunet!impch!altger!doitcr!tmpmbx!mfehr!krefcom!spirit!rob | +---------s-p-i-r-i-t-s---i-n---t-h-e---m-a-t-e-r-i-a-l---w-o-r-l-d----------+ Please don't think that I'm not familiar with gotos or breaks and such things of not structured languages, but I won't go back to BASIC-Level with a jump here or there and you don't know where you are... In a mood I just decided to leave these things out... Maybe I should write in Pascal or Modula? :-) */ /* future adds -s|u|D date search -l list format */ #include #include #include #include #include #include "date.h" /* my own date function */ #define MAXPATH 256 /* Maximum pathname length */ #define MEMTYPE 0L /* Memtype: Fast or Chipmem */ #define true 1 /* Right boolean values, because */ #define false 0 /* typedef short BOOL, but TRUE= 1L! */ #define ON true #define OFF false struct ListType { struct FileInfoBlock FIBlock; struct FileLock *FLock; struct ListType *prev; }; /**** external functions & variables ****/ extern int Enable_Abort; void *Lock(); void *AllocMem(); void *ParentDir(); extern void date(); struct Process *FindTask(); struct MsgPort *CreatePort(); long IsInteractive(), SetSignal(); struct FileHandle *Input(), *Output(); struct FileLock *CurrentDir(); /***** globals *****/ char MPath [256], c, casedep; /* Global PathName (MainPath) */ WORD options= 0; /* options switches */ WORD MPathPos= 0; struct StandardPacket *packet; struct MsgPort *replyport, *conid; struct Process *myprocess; char *prgname; enum { CASESENSITIVE=1, DIRSONLY=2, FILESONLY=4, LONGPATH=8 , SIZE=16, TIME=32, NOSUBDIRS=64, JUMPDIR=128 }; /* switches go here */ enum { NOMEM, NODIR, DESTROYEDENTRY, TOOMANYARGS, WRONGNAME, ILLEGALOPTION, NOPATTERN, NOINPUT, STRANGE, INFO, USAGE }; /*** ErrorNumbers for ErrorHandle ***/ char *Msg[]= { "FATAL ERROR: Not enough memory available!\n", "ERROR: Can't find that directory or device:", "ERROR: Destroyed entry! Couldn't examine this '", "ERROR: Can't handle so many arguments. See usage!\n", "ERROR: Please no path in the filename/pattern! See usage!\n", "ERROR: Illegal Option '", "ERROR: I've no filepattern to search for!\n", "ERROR: Input must be interactive! \n", "STRANGE ERROR: Something strange happend...!\n", "INFO: whereis V1.18 15-02-1990 by R. Bless.\n" }; /* Messages for ErrorHandle/Numbers */ /******************/ void ErrorHandle(ErrMsgNr) short ErrMsgNr; { if (ErrMsgNr != USAGE) fprintf(stderr, "%s- %s", prgname, Msg[ErrMsgNr]); else { fprintf(stderr, "usage: %s [-acdfijnpst] [dev:path] filename.", prgname); fprintf(stderr, " Wildcards *,? allowed.\n"); } } int SwitchRaw(RawMode) BOOL RawMode; { replyport= (struct MsgPort *) CreatePort(NULL, NULL); if (!replyport) return 1; packet= (struct StandardPacket *) AllocMem((long)sizeof(*packet),MEMF_PUBLIC | MEMF_CLEAR); if (!packet) { DeletePort(replyport); return 1; } /* init DOS-Packet */ packet->sp_Msg.mn_Node.ln_Name= (char *) &(packet->sp_Pkt); /* link packet- */ packet->sp_Pkt.dp_Link= &(packet->sp_Msg); /* to message */ packet->sp_Pkt.dp_Port= replyport; /* set-up reply port*/ packet->sp_Pkt.dp_Type= ACTION_SCREEN_MODE; /* function */ if (RawMode==ON) { packet->sp_Pkt.dp_Arg1= DOSTRUE; fflush(stdout); } else { packet->sp_Pkt.dp_Arg1= DOSFALSE; } PutMsg(conid,packet); /* send packet */ WaitPort(replyport); /* wait for packet to come back */ GetMsg(replyport); /* pull message */ FreeMem(packet, (long) sizeof(*packet)); DeletePort(replyport); return 0; } void printdate(ds) struct DateStamp *ds; { struct date mydate; date(&mydate, ds->ds_Days); fprintf(stdout," %02d-%02d-%02ld %02ld:%02ld:%02ld", mydate.day, mydate.month, mydate.year-1900, ds->ds_Minute/60L, ds->ds_Minute%60L, ds->ds_Tick/50L); } void Append(s, root) /* Appends the dirname to MPath (MainPath) */ char *s; BOOL root; { int p; for (p= 0; s[p]!= '\0'; p++) MPath[MPathPos+p]= s[p]; MPath[MPathPos+p++]= root==true ? ':' : '/'; MPath[MPathPos+p]= '\0'; MPathPos+=p; } void InsertPath(s, root) /* Inserts a dirname into MPath */ char *s; struct FileLock *root; { int p,len; len= strlen(s)+1; for (p= MPathPos; p >= 0; p--) MPath[p+len]= MPath[p]; MPathPos+=len; for (p= 0; s[p] != '\0'; p++) MPath[p]= s[p]; MPath[p]= root==NULL ? ':' : '/'; } void Cut() /* Removes the last dirname from MPath */ { if (MPathPos) --MPathPos; while (--MPathPos>=0 && MPath[MPathPos] != '/' && MPath[MPathPos] != ':'); MPath[++MPathPos]= '\0'; } struct FileLock *FindRoot(FL) /* Climbs up to root-directory */ struct FileLock *FL; { struct FileLock *PL; PL= FL; while (FL= ParentDir(FL)) { UnLock(PL); PL=FL; } return PL; } long GetFullPath(path) /* Get the full pathname */ char *path; { struct FileLock *FL, *PL; struct FileInfoBlock *FIB; BOOL Error= false; FIB= (struct FileInfoBlock *) AllocMem ((long) sizeof(struct FileInfoBlock), MEMTYPE); if (!FIB) { ErrorHandle(NOMEM); Error= true; } else if (!(FL= (struct FileLock *) Lock(path, (ULONG) ACCESS_READ))) { ErrorHandle(NODIR); fprintf(stderr," %s\n", path); Error= true; } while (FL && !Error) { if (!Examine(FL, FIB)) { ErrorHandle(DESTROYEDENTRY); fprintf(stderr,"%s'. Very strange!\n", path); Error= true; } else { InsertPath(FIB->fib_FileName, PL= ParentDir(FL)); UnLock (FL); FL= PL; } } if (FIB) FreeMem (FIB,(long) sizeof(struct FileInfoBlock)); if (FL) UnLock (FL); return Error; } BOOL Match(s, fpat) char *s,*fpat; { register short p,sp; for (sp= p= 0; fpat[p]!='\0';) { if (fpat[p] == '*') { while (fpat[p]=='*' || fpat[p]=='?') { p++; /* skip following wildcards, until letter or \0 */ } if (fpat[p]!='\0') /* letter/pattern detected! */ while (s[sp]!='\0' && (s[sp]&casedep) != (fpat[p]&casedep)) sp++; else while (s[sp]!='\0') /* ingore all chars till end */ sp++; } else if (fpat[p] == '?') { p++; /* Just ignore that char */ if (s[sp]!='\0') sp++; } else if ((s[sp]&casedep) == (fpat[p]&casedep)) { sp++;p++; } else return false; } return (s[sp]=='\0' ? true : false); } /* Now comes the main-stuff!!! */ BOOL Search (path, fpat) /* not recursive! */ char *path, *fpat; { struct FileLock *FL= NULL; struct FileInfoBlock *FIB= NULL; struct ListType *LChainP= NULL, *OldLChainP= NULL; BOOL Error= false; char cbuf; int p; casedep= (options & CASESENSITIVE) ? 0xFF : 0x5F; /* Mask for match() */ if (!fpat) { ErrorHandle(WRONGNAME); Error= true; } else if (path) { if (options & LONGPATH) Error= GetFullPath(path); /* Full-Pathname */ else { /* "short pathname" */ int p; for (p= 0; path[p]!= '\0'; p++) MPath[MPathPos+p]= path[p]; if (p>0) { p--; if (MPath[MPathPos+p]!='/' && MPath[MPathPos+p]!=':') { p++; MPath[MPathPos+p]= '/'; } p++; } else MPathPos= 0; MPath[MPathPos+p]= '\0'; MPathPos+= p; } } if (!Error) { LChainP= (struct ListType *) AllocMem ((long) sizeof(struct ListType), MEMTYPE); if (!LChainP) { ErrorHandle(NOMEM); Error= true; } else { FIB= &LChainP->FIBlock; if (!(FL= (struct FileLock *) Lock(MPath, (ULONG) ACCESS_READ))) { ErrorHandle(NODIR); fprintf(stderr," %s\n", MPath); Error= true; } else { if (!path) FL= FindRoot(FL); if (!Examine(FL, FIB)) { ErrorHandle(DESTROYEDENTRY); fprintf(stderr,"%s'. Very strange!\n", path); Error= true; } else if (!path) Append(FIB->fib_FileName, true); if (!Error) while (FL) { while (FL && ExNext(FL, FIB) && !Error) { if (Match(FIB->fib_FileName, fpat)) /*Compare filename&pattern*/ { BOOL found= false; if (FIB->fib_DirEntryType >= 0L) /** => it is a dirname **/ { if (!(options & FILESONLY)) { fprintf(stdout, "%s%s", MPath, FIB->fib_FileName); if (options & SIZE) fprintf(stdout, " (dir) "); if (options & TIME) printdate(&(FIB->fib_Date)); fprintf(stdout, "\n"); if (options & JUMPDIR) found= true; } } else /** => it is a filename **/ if (!(options & DIRSONLY)) { fprintf(stdout, "%s%s", MPath, FIB->fib_FileName); if (options & SIZE) fprintf(stdout, " %ld",FIB->fib_Size); if (options & TIME) printdate(&(FIB->fib_Date)); fprintf(stdout, "\n"); if (options & JUMPDIR) found= true; } if (found) { if (SwitchRaw(ON)) Error= true; else { int c; fprintf(stderr,"Change to that dir? [yNq]:"); c= getchar(); fprintf(stderr,"%c\n", c); SwitchRaw(OFF); if (toupper(c)=='Y') { struct FileLock *CDL; struct CommandLineInterface *CLI; char *i; int p; if (FIB->fib_DirEntryType >= 0L) Append(FIB->fib_FileName, false); /* if Directory found append it to mpath, cause we'll: */ /* change the current dir */ CDL=(struct FileLock *) Lock(MPath, (ULONG) ACCESS_READ); if (!CDL) { ErrorHandle(STRANGE); Error= true; } CDL= CurrentDir(CDL); UnLock(CDL); /* The new-lock must be retained and can't be unlocked, the old one must be unlocked */ CLI=(struct CommandLineInterface *) BADDR(myprocess->pr_CLI); i= (char *) ((CLI->cli_SetName) << 2); /* Copy the new name to CLI */ for (p=0; MPath[p]!='\0'; p++) *(i+p+1)= MPath[p]; if (MPath[p-1]=='/') { *i= (char) (p-1); } else *i= (char) p; if (FIB->fib_DirEntryType >= 0L) Cut(); Error= true; } if (toupper(c)=='Q') { Error= true; fprintf(stdout,"Quit!\n"); } } } } if (FIB->fib_DirEntryType >= 0L) /* Dirname? Climb down the tree */ { if (!(options & NOSUBDIRS)) { Append(FIB->fib_FileName, false); LChainP->FLock= FL; LChainP->prev = OldLChainP; OldLChainP= LChainP; cbuf= MPath[MPathPos-1]; MPath[MPathPos-1]= '\0'; FL=(struct FileLock *) Lock(MPath, (ULONG) ACCESS_READ); MPath[MPathPos-1]= cbuf; if (!FL) { ErrorHandle(STRANGE); Error= true; } else { LChainP= (struct ListType *) AllocMem ((long) sizeof(struct ListType), MEMTYPE); if (!LChainP) { ErrorHandle(NOMEM); Error= true; UnLock(FL); /* Free last Lock */ LChainP= OldLChainP; /* To free the whole list */ FL= OldLChainP->FLock; /* Get actual Lock */ OldLChainP= OldLChainP->prev; } else { FIB= &LChainP->FIBlock; Examine(FL, FIB); } } } } } /* Climb-up-the-tree section*/ if (SetSignal(NULL, NULL) & (SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D)) { SetSignal(NULL, (SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D)); if (!Error) { fprintf(stderr, "** BREAK **\n"); /* Just print one break */ Error= true; } } if (LChainP) /* Is there still an entry? */ { UnLock(FL); /* Free actual Lock */ Cut(); FreeMem (LChainP, (long) sizeof(struct ListType)); if (OldLChainP) /* Get next entry to free,climb up list */ { FL = OldLChainP->FLock; FIB= &OldLChainP->FIBlock; LChainP= OldLChainP; OldLChainP= OldLChainP->prev; } else /* Last entry reached */ { FL= NULL; LChainP= NULL; } } else FL= NULL; /* No more entries? -> leave while loop */ } } } } if (LChainP) FreeMem (LChainP,(long) sizeof(struct ListType)); if (OldLChainP) FreeMem (OldLChainP,(long) sizeof(struct ListType)); if (FL) UnLock (FL); return Error; } /******* main(), what else? *******/ main(argc, argv) int argc; char **argv; { int i1, i2, findx= 0; char *args[2], *patharg=NULL, *filepattern=NULL; Enable_Abort= 0; /*** No Ctrl-C please!!! ***/ args[0]= args[1]= NULL; prgname= *argv; SetSignal(NULL, (SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D)); /*** Clear Ctrl-D signal ***/ if (argc == 1) { ErrorHandle(USAGE); exit(RETURN_OK); } for (i1= 1; i1 != argc; i1++) { if (*argv[i1] == '-') for (i2= 1; argv[i1][i2] != '\0'; i2++) { switch (argv[i1][i2]) { case 'a': options|= SIZE | TIME; break; case 'c': options|= CASESENSITIVE; break; case 'd': options|= DIRSONLY; break; case 'f': options|= FILESONLY; break; case 'i': ErrorHandle(USAGE); ErrorHandle(INFO); exit(RETURN_OK); break; case 'j': if (IsInteractive(Input())) { myprocess= (struct Process *) FindTask(NULL); conid = (struct MsgPort *) myprocess->pr_ConsoleTask; /* get con-handler */ options|= (JUMPDIR | LONGPATH); } else { ErrorHandle(NOINPUT); exit(RETURN_FAIL); } break; case 'n': options|= NOSUBDIRS; break; case 'p': options|= LONGPATH; break; case 's': options|= SIZE; break; case 't': options|= TIME; break; default : ErrorHandle(ILLEGALOPTION); fprintf(stderr,"%c' !\n", argv[i1][i2]); ErrorHandle(USAGE); exit (RETURN_ERROR); break; } } else { if (findx > 1) { ErrorHandle(TOOMANYARGS); exit (RETURN_ERROR); } else { args[findx]= argv[i1]; findx++; } } } if (findx==0) { ErrorHandle(NOPATTERN); ErrorHandle(USAGE); exit(RETURN_ERROR); } for (i1= 0; i1 < 2; i1++) { if (args[i1] != NULL) { for (i2= 0; (c= args[i1][i2]) != '\0' && c != ':' && c != '/';i2++); if (c != '\0') patharg= args[i1]; else filepattern= args[i1]; } } if (findx == 2 && !patharg) { patharg= args[0]; filepattern= args[1]; } if (Search(patharg, filepattern) == true) { fprintf(stderr, "%s-- Aborted!\n", prgname); exit(RETURN_ERROR); } }