home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!zaphod.mps.ohio-state.edu!swrinde!network.ucsd.edu!ucsbcsl!mcl!urge
- From: urge@mcl.ucsb.edu (Scott Bronson)
- Newsgroups: comp.sys.mac.programmer
- Subject: To (?) Evan Shandev - my stream search source
- Summary: stream search source
- Keywords: stream search
- Message-ID: <urge.724309451@mcl>
- Date: 14 Dec 92 05:04:11 GMT
- Sender: root@ucsbcsl.ucsb.edu
- Lines: 180
-
-
- Sorry for butchering your name, but I forgot what it was exactly.
- I was forced to switch Email accounts, and in the move I lost my
- entire mail queue with your name and address safely tucked
- away. I apologize for all this.
-
- Anyway, I've decided to distribute this. It's simply a cool
- little algorithm to search an incoming stream. If you use this
- in one of your projects, I'd really like only one little thing
- in return: mail me and tell me how you use this source.
-
- My original letter follows. It first answers why I think that
- the CTB doesn't allow you to look at characters following a found
- CMSearch string, then gives my solution to this problem.
-
- --------------------------------------
-
- You're not doing anything wrong that I know of. The Comm Toolbox simply
- doesn't let you get at any text following your search. Here's my theory
- why (but I don't know, so don't quote me to anyone important):
-
- The connection tool transfers incoming text from the hardware buffer
- (4-byte SCC buffer, 64-byte serial buffer, or whatever) to its own larger
- buffer to hold until the application wants it. While performing this
- transfer, moving one character at a time, it updates its search strings
- in the same manner that I have coded below. When one of the strings
- gets found, it immediately calls your callback routine, without transfer-
- ring even another single character.
-
- When you think about it, this makes sense. You should not be able to get
- at characters further on in the buffer, as there is no definition to how
- many characters you would get. It would make things substantially harder
- for the connection tool, because it would always have to read x many more
- characters after the string was found, and if the buffer overflowed, the
- entire search string and all chars afterwards would have to be shifted
- around to make room.
-
- Not only that, but what standard would you make it? Eight characters more
- after the string found? Someone will need ten more. Okay then, ten. But
- what if someone needs fifty? A hundred? One K... So, best to let the
- application handle searching itself if it needs these special requirements.
- I think the search function was only implemented to allow comm programs
- to recognize automatic file transfer requests as demoed in the sample app
- that came with the CTB developer's kit.
-
- So, you're stuck without a standard and with no way to get at the next
- few characters after your search string. The only solution I see is for
- you to write your own. I did. Here's my version (you'll have to change
- all serial calls to be CTB calls, but other than that it's straightforward).
-
- Note that all of the strings used in this code are C strings, because
- they are far more buffer-friendly than Pascal strings. Also, some of this
- code was changed so I could send it to you, but it should (SHOULD--I'm
- not certian that I didn't add bugs when I edited it) remain bug-free.
- It is currently in use in a commercial application that I wrote, so I
- hope it will work without a flaw...
-
- // By Scott Bronson
- //
- // The only structure used...
- typedef struct searchrec {
- char *first, *cur;
- } searchrec;
-
- // We can search for this many strings maximum:
- #define kNumSearches 16
-
- // Global variables used...
- short numsearches = 0;
- long gStringFound;
- searchrec search[kNumSearches];
-
- // This is my actual idle loop. It should
- // be able to be used right out of the box.
- //
- // Idle process:
- // % read chars into inbuff
- // - strip the eighth bit
- // - check against current searches
- // - Strip newlines
- // - Write to OldLines buffer
- // - Put in our log file buffer
- // % flush log file buffer
-
- void WhatMeIdle( void )
- {
- char inbuff[64], outbuff[64];
- // 64-byte input buffer. The output buffer is used to store the 8th-bit
- // and newline stripped data that we will be displaying on screen. The
- // search algorithm will not be hurt at all by the disappearance of the
- // ouptut buffer.
-
- register char c; // indexes through each char in the input buffer.
- long count; // The number of characters read into inbuff.
- long j; // The number of characters in outbuff.
- short i, l; // Indexes for loops.
- OSErr err; // Stores possible errors returned by OS.
-
- err = SerGetBuf( inDriverRefNum, &count );
- if( err == noErr && count > 0 ) {
- if( count > 64 ) count = 64;
- err = FSRead( inDriverRefNum, &count, inbuff );
-
- // Now inbuff is filled with the next (count) characters
- // from the incoming data stream.
-
- if( err == noErr ) {
-
- // We'll loop through every character in the buffer...
- for( i=0,j=0; i<count; i++ ) {
- c = inbuff[i] & 0x7F;
-
- // Now c contains the next 7-bit character.
- // Here is the search algorithm. If there are
- // any searches pending, loop through them and
- // update the found character counts.
-
- if(numsearches) for( l=0; l<numsearches; l++ ) {
- if( c == *(search[l].cur++) ) {
- if( !*search[l].cur ) {
-
- // Ah! We found a string. Leave its index
- // in a global variable, clear all searches,
- // and finish reading the current buffer.
- // You can do whatever you want here.
-
- gStringFound = l+1;
- numsearches = 0;
- }
- } else search[l].cur = search[l].first;
- }
-
- // If c is a newline character, we're done with it.
- if( c == '\n' ) continue;
-
- // I performed some other actions here that were removed
- // for clarity. Now all we have to do is store c in the
- // output buffer so it will get written to our disk file.
-
- outbuff[j++] = c;
- } // end of for loop.
-
- // If we are storing the incoming data, then write it out.
- if( gLogToFile && j ) {
- FSWrite( gLogFileRef, &j, outbuff );
- }
- }
- } // else no chars to be read.
- }
-
-
- // This is used to add a string to search for, same as CMAddSearch.
- // The string passed to AddSearch MUST remain untouched from the time
- // it is added until the time CheckStringFound returns a non-empty
- // string (meaning AddSearch doesn't make a copy of the string it is
- // passed--it just uses it in-place).
-
- void AddSearch( char *cs )
- {
- if( numsearches < kNumSearches ) {
- search[numsearches].cur = search[numsearches].first = cs;
- numsearches++;
- } // else search buffer is full.
- }
-
-
- // This is called periodically to see if a string is found. It is passed
- // the address of a buffer large enough to hold the longest of all the
- // strings that are currently being searched for. The buffer will contain
- // the actual string found, or a 0-lenth string if none have been found yet.
-
- void CheckStringFound( char *ss )
- {
- if( gStringFound ) {
- strcpy( ss, search[--gStringFound].first );
- } else {
- ss[0] = 0;
- }
- }
-
-