home *** CD-ROM | disk | FTP | other *** search
- /*
-
- File: Search.c
- Author: Neil Cafferkey
- Placed in the public domain by Neil Cafferkey.
-
- */
-
-
- #include <proto/exec.h>
- #include <proto/dos.h>
- #include <proto/locale.h>
- #include <exec/memory.h>
- #include <dos/dos.h>
-
-
- typedef ULONG UPINT;
-
- #define DOS_VERSION 37
- #define LOCALE_VERSION 38
- #define PATH_BUF_SIZE 512
- #define SPACES_SIZE 160+1
- #define MARGIN 3
- #define INDENT 5
- #define DIR_MARGIN 2
-
- struct ExecBase *SysBase;
- struct DosLibrary *DOSBase;
- struct LocaleBase *LocaleBase;
-
-
- enum
- {
- ARG_FROM,
- ARG_SEARCH,
- ARG_ALL,
- ARG_NONUM,
- ARG_QUIET,
- ARG_QUICK,
- ARG_FILE,
- ARG_PATTERN,
- ARG_COUNT
- };
-
-
- VOID PrintFullName(TEXT *buffer,UWORD cut_off,struct AnchorPath *anchor);
- UWORD GetDirName(struct AnchorPath *anchor,TEXT *buffer);
- BOOL FindString(struct AnchorPath *anchor,UPINT *args,TEXT *pattern,
- struct Locale *locale,UBYTE *pi);
- BOOL MatchStringNoCase(TEXT *string,TEXT *text,TEXT *text_end,UBYTE *pi,
- struct Locale *locale);
- ULONG strlen(STRPTR s);
-
- extern const TEXT template[];
- extern const TEXT dos_name[];
- extern const TEXT locale_name[];
- extern const TEXT control_codes[];
- extern const TEXT line_show[];
- extern const TEXT wild_card[];
- extern const TEXT new_line[];
- extern const TEXT abandon_msg[];
-
-
- ULONG Search(VOID)
- {
- UPINT *args;
- struct RDArgs *read_args;
- struct DosLibrary *dos_base;
- struct LocaleBase *locale_base;
- struct AnchorPath *anchor;
- LONG error,return_code=RETURN_WARN;
- TEXT *text,*spaces,*pattern=NULL,*path_buffer,*user_pattern=NULL,*p,ch,
- **from;
- BOOL found,success=TRUE,new_dir,print_names;
- UWORD indent=0,pat_buf_length,cut_off,pat_length;
- UBYTE k,q;
- struct Locale *locale;
-
- /* Open libraries */
-
- SysBase=*((APTR *)sizeof(APTR));
- dos_base=(struct DosLibrary *)OpenLibrary(dos_name,DOS_VERSION);
- if(!dos_base)
- return RETURN_FAIL;
- DOSBase=dos_base;
- locale_base=(struct LocaleBase *)OpenLibrary(locale_name,LOCALE_VERSION);
-
- /* Allocate buffers */
-
- spaces=AllocMem(SPACES_SIZE,MEMF_CLEAR);
- anchor=AllocMem(sizeof(struct AnchorPath),MEMF_CLEAR);
- args=AllocMem(ARG_COUNT*sizeof(APTR),MEMF_CLEAR);
- path_buffer=AllocMem(PATH_BUF_SIZE,MEMF_ANY);
-
- if(args&&anchor&&locale_base&&spaces&&path_buffer)
- {
- LocaleBase=locale_base;
- locale=OpenLocale(NULL);
-
- for(text=spaces+SPACES_SIZE-1;text>spaces;*(--text)=' ');
-
- /* Parse arguments */
-
- read_args=ReadArgs(template,args,NULL);
- if(locale&&read_args)
- {
- /* Prepare the pattern to be matched */
-
- pat_length=strlen((TEXT *)args[ARG_SEARCH]);
- pat_buf_length=pat_length*2+3;
- user_pattern=AllocMem(pat_length+5,MEMF_CLEAR);
- pattern=AllocMem(pat_buf_length,MEMF_ANY);
- if(user_pattern&&pattern)
- {
- if(args[ARG_PATTERN]||args[ARG_FILE])
- {
- if(args[ARG_FILE])
- text=user_pattern;
- else
- {
- text=user_pattern+2;
- CopyMem(wild_card,user_pattern,2);
- CopyMem(wild_card,text+pat_length,2);
- }
-
- CopyMem((TEXT *)args[ARG_SEARCH],text,pat_length);
-
- if(ParsePatternNoCase(user_pattern,pattern,pat_buf_length)<0)
- success=FALSE;
- }
- else
- {
- /* Copy the search string and convert it to uppercase */
-
- text=pattern;
- for(p=(TEXT *)args[ARG_SEARCH];(ch=*p)!='\0';p++)
- *(text++)=ConvToUpper(locale,ch);
- *text='\0';
-
- /* Construct prefix table for Knuth-Morris-Pratt algorithm */
-
- *user_pattern=0;
- k=0;
- for(q=1;q<pat_length;q++)
- {
- while(k&&(pattern[k]!=pattern[q]))
- k=user_pattern[k-1];
- if(pattern[k]==pattern[q])
- k++;
- user_pattern[q]=k;
- }
- }
- }
- else
- success=FALSE;
-
- /* Get the next starting point */
-
- for(from=*(((TEXT ***)args)+ARG_FROM);*from&&success;from++)
- {
-
- /* Initialise file search */
-
- anchor->ap_BreakBits=SIGBREAKF_CTRL_C;
- anchor->ap_FoundBreak=0;
- anchor->ap_Flags=0;
- error=MatchFirst(*from,anchor);
-
- /* Work out if more than one file is being searched */
-
- print_names=(*(*(((TEXT ***)args)+ARG_FROM)+1))
- ||(anchor->ap_Flags&APF_ITSWILD);
-
- /* Enter sub-dir if the pattern was an explicitly named dir */
-
- if(!(anchor->ap_Flags&APF_ITSWILD)
- &&(anchor->ap_Info.fib_DirEntryType>0))
- anchor->ap_Flags|=APF_DODIR;
-
- /* Set flag to get name of starting directory */
-
- new_dir=TRUE;
-
- /* Traverse the directory */
-
- while(!error&&success)
- {
- found=FALSE;
-
- if(anchor->ap_Info.fib_DirEntryType>0)
- {
- /* Enter sub-dir if the ALL switch was supplied and we're
- not on the way out of it */
-
- if(!(anchor->ap_Flags&APF_DIDDIR))
- {
- if(!(args[ARG_FILE]||args[ARG_QUIET]||args[ARG_QUICK]))
- {
- WriteChars(spaces,MARGIN+INDENT*indent+DIR_MARGIN);
- text=(TEXT *)&(anchor->ap_Info.fib_FileName);
- VPrintf("%s (dir)\n",&text);
- }
- if(args[ARG_ALL]||(anchor->ap_Flags&APF_DODIR))
- {
- anchor->ap_Flags|=APF_DODIR;
- indent++;
- print_names=TRUE;
- }
- }
- else
- {
- indent--;
- }
-
- new_dir=TRUE;
- anchor->ap_Flags&=~APF_DIDDIR;
- }
- else
- {
- /* Deal with a file */
-
- if(anchor->ap_Flags&APF_DirChanged)
- new_dir=TRUE;
-
- if(new_dir)
- {
- if(!(cut_off=GetDirName(anchor,path_buffer)))
- success=FALSE;
- new_dir=FALSE;
- }
-
- if(args[ARG_FILE])
- {
- found=MatchPatternNoCase(pattern,
- (TEXT *)&(anchor->ap_Info.fib_FileName));
- }
- else
- {
- if(args[ARG_QUICK])
- {
- PrintFullName(path_buffer,cut_off,anchor);
- WriteChars(control_codes,3);
- }
- else if(!args[ARG_QUIET]&&print_names)
- {
- WriteChars(spaces,MARGIN+INDENT*indent);
- text=(TEXT *)&(anchor->ap_Info.fib_FileName);
- VPrintf("%s..\n",&text);
- }
-
- found=FindString(anchor,args,pattern,locale,
- user_pattern);
-
- }
-
- if(found)
- {
- if(args[ARG_FILE]||args[ARG_QUIET]&&!args[ARG_QUICK])
- {
- PrintFullName(path_buffer,cut_off,anchor);
- PutStr(new_line);
- }
- return_code=RETURN_OK;
- }
- }
-
- error=MatchNext(anchor);
- if(error&&(error!=ERROR_NO_MORE_ENTRIES))
- {
- success=FALSE;
- SetIoErr(error);
- }
-
- }
- }
-
- /* Clear line for next shell prompt */
-
- if(args[ARG_QUICK]&&!args[ARG_FILE])
- WriteChars(control_codes,2);
-
- MatchEnd(anchor);
-
- if(success)
- SetIoErr(0);
- }
-
- FreeArgs(read_args);
-
- CloseLocale(locale);
- }
- else
- {
- SetIoErr(ERROR_NO_FREE_STORE);
- }
-
- /* Free memory */
-
- if(args)
- FreeMem(args,ARG_COUNT*sizeof(APTR));
- if(anchor)
- FreeMem(anchor,sizeof(struct AnchorPath));
- if(spaces)
- FreeMem(spaces,SPACES_SIZE);
- if(path_buffer)
- FreeMem(path_buffer,PATH_BUF_SIZE);
- if(user_pattern)
- FreeMem(user_pattern,pat_length+5);
- if(pattern)
- FreeMem(pattern,pat_buf_length);
-
- /* Close libraries and exit */
-
- if(locale_base)
- CloseLibrary((struct Library *)LocaleBase);
- CloseLibrary((struct Library *)DOSBase);
-
- /* Check and reset signals */
-
- if(SetSignal(0,-1)&SIGBREAKF_CTRL_C)
- SetIoErr(ERROR_BREAK);
-
- /* Exit */
-
- if(error=IoErr())
- {
- PrintFault(error,NULL);
- return RETURN_FAIL;
- }
-
- return return_code;
- }
-
-
-
- VOID PrintFullName(TEXT *buffer,UWORD cut_off,struct AnchorPath *anchor)
- {
- buffer[cut_off]='\0';
- if(AddPart(buffer,(TEXT *)&(anchor->ap_Info.fib_FileName),PATH_BUF_SIZE))
- {
- PutStr(buffer);
- }
-
- return;
- }
-
-
-
- UWORD GetDirName(struct AnchorPath *anchor,TEXT *buffer)
- {
- if(NameFromLock(anchor->ap_Current->an_Lock,buffer,
- PATH_BUF_SIZE))
- return strlen(buffer);
- return 0;
- }
-
-
-
- BOOL FindString(struct AnchorPath *anchor,UPINT *args,TEXT *pattern,
- struct Locale *locale,UBYTE *pi)
- {
- BOOL found=FALSE,end_early=FALSE,line_matches,at_end;
- BPTR old_lock,file;
- TEXT *p,*q,*r,*line,*buffer=NULL,ch;
- UPINT max_line_length=0,line_length,offset=0,file_size,buf_size,
- line_start=0,line_count=1;
- ULONG sigs;
- LONG read_length=1;
-
- /* Move into the file's directory */
-
- old_lock=CurrentDir(anchor->ap_Current->an_Lock);
-
- /* Open the file for reading */
-
- if(file=Open((TEXT *)&(anchor->ap_Info.fib_FileName),MODE_OLDFILE))
- {
- /* Get a buffer for the file */
-
- file_size=anchor->ap_Info.fib_Size;
- buf_size=file_size+1;
-
- while(!buffer&&buf_size)
- {
- if(!(buffer=AllocMem(buf_size,MEMF_ANY)))
- buf_size>>=1;
- }
-
- /* Check size of buffer */
-
- if((buf_size<=file_size)&&buffer)
- {
- /* Get length of longest line */
-
- while(read_length>0)
- {
- read_length=Read(file,buffer,buf_size-1);
- q=buffer+read_length;
- if(!read_length)
- q++;
- for(p=buffer;p<q;p++)
- if((*p=='\n')||!read_length)
- {
- line_length=offset+(p-buffer)-line_start;
- if(line_length>max_line_length)
- max_line_length=line_length;
- line_start=offset+(p-buffer)+1;
- }
- offset+=read_length;
- }
-
- /* Ensure buffer is big enough for longest line */
-
- if(buf_size<=max_line_length)
- {
- buf_size=max_line_length+1;
- buffer=AllocMem(buf_size,MEMF_ANY);
- }
- }
-
- /* Test every line against the pattern */
-
- if(buffer&&pattern)
- {
-
- read_length=Seek(file,0,OFFSET_BEGINNING)+1;
- while(((read_length=Read(file,buffer,buf_size-1))>0)&&!end_early)
- {
- q=buffer+read_length;
- at_end=Seek(file,0,OFFSET_CURRENT)==file_size;
- if(at_end)
- *(q++)='\0';
- line=buffer;
- for(p=buffer;(p<q)&&!end_early;p++)
- {
- ch=*p;
- if((ch=='\n')||(ch=='\0'))
- {
- *p='\0';
-
- if(args[ARG_PATTERN])
- line_matches=MatchPatternNoCase(pattern,line);
- else
- line_matches=
- MatchStringNoCase(pattern,line,p,pi,locale);
-
- if(line_matches)
- {
-
- if(!found&&args[ARG_QUICK])
- PutStr(new_line);
-
- found=TRUE;
-
- if(args[ARG_QUIET])
- {
- end_early=TRUE;
- }
- else
- {
- if(!args[ARG_NONUM])
- VPrintf("%6lu ",&line_count);
-
- /* Replace invisible characters with dots */
-
- for(r=line;r<p;r++)
- if(!IsPrint(locale,*r))
- *r='.';
-
- VPrintf("%s\n",&line);
- }
- }
- line=p+1;
- if(ch=='\n')
- line_count++;
-
- sigs=SetSignal(0,SIGBREAKF_CTRL_D);
- if(sigs&(SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D))
- {
- end_early=TRUE;
- if(sigs&SIGBREAKF_CTRL_D)
- {
- PutStr(abandon_msg);
- }
- }
- }
- }
-
- /* Start reading again at start of most recent line */
-
- if(!at_end)
- Seek(file,line-q,OFFSET_CURRENT);
- }
-
- }
-
- if(buffer)
- FreeMem(buffer,buf_size);
-
- Close(file);
- }
-
- CurrentDir(old_lock);
-
- return found;
- }
-
-
-
- const TEXT template[]=
- "FROM/M,SEARCH/A,ALL/S,NONUM/S,QUIET/S,QUICK/S,FILE/S,PATTERN/S";
- const TEXT version_string[]="$VER: Search 41.2 (14.10.2000)";
- const TEXT dos_name[]=DOSNAME;
- const TEXT locale_name[]="locale.library";
-
- const TEXT control_codes[]={0x9b,'K',13};
- const TEXT wild_card[]={'#','?'};
- const TEXT new_line[]="\n";
- const TEXT abandon_msg[]="** File abandoned\n";
-
-
-
- BOOL MatchStringNoCase(TEXT *string,TEXT *text,TEXT *text_end,UBYTE *pi,
- struct Locale *locale)
- {
- TEXT *s,ch;
-
- s=string;
- while(text<text_end)
- {
- ch=ConvToUpper(locale,*(text++));
- while((s!=string)&&(*s!=ch))
- s=string+pi[s-string-1];
- if(ch==*s)
- s++;
-
- if(!*s)
- return TRUE;
- }
- return FALSE;
- }
-
-
-
- ULONG strlen(STRPTR s)
- {
- STRPTR p;
-
- p=s;
- for(p=s;*p!='\0';p++);
- return p-s;
- }
-
-
-
-