home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #30 / NN_1992_30.iso / spool / comp / sys / mac / programm / 19804 < prev    next >
Encoding:
Text File  |  1992-12-14  |  6.9 KB  |  192 lines

  1. Path: sparky!uunet!zaphod.mps.ohio-state.edu!swrinde!network.ucsd.edu!ucsbcsl!mcl!urge
  2. From: urge@mcl.ucsb.edu (Scott Bronson)
  3. Newsgroups: comp.sys.mac.programmer
  4. Subject: To (?) Evan Shandev - my stream search source
  5. Summary: stream search source
  6. Keywords: stream search
  7. Message-ID: <urge.724309451@mcl>
  8. Date: 14 Dec 92 05:04:11 GMT
  9. Sender: root@ucsbcsl.ucsb.edu
  10. Lines: 180
  11.  
  12.  
  13. Sorry for butchering your name, but I forgot what it was exactly.
  14. I was forced to switch Email accounts, and in the move I lost my
  15. entire mail queue with your name and address safely tucked
  16. away.  I apologize for all this.
  17.  
  18. Anyway, I've decided to distribute this.  It's simply a cool
  19. little algorithm to search an incoming stream.  If you use this
  20. in one of your projects, I'd really like only one little thing
  21. in return: mail me and tell me how you use this source.
  22.  
  23. My original letter follows.  It first answers why I think that
  24. the CTB doesn't allow you to look at characters following a found
  25. CMSearch string, then gives my solution to this problem.
  26.  
  27. --------------------------------------
  28.  
  29. You're not doing anything wrong that I know of.  The Comm Toolbox simply
  30. doesn't let you get at any text following your search.  Here's my theory
  31. why (but I don't know, so don't quote me to anyone important):
  32.  
  33. The connection tool transfers incoming text from the hardware buffer
  34. (4-byte SCC buffer, 64-byte serial buffer, or whatever) to its own larger
  35. buffer to hold until the application wants it.  While performing this
  36. transfer, moving one character at a time, it updates its search strings
  37. in the same manner that I have coded below.  When one of the strings
  38. gets found, it immediately calls your callback routine, without transfer-
  39. ring even another single character.
  40.  
  41. When you think about it, this makes sense.  You should not be able to get
  42. at characters further on in the buffer, as there is no definition to how
  43. many characters you would get.  It would make things substantially harder
  44. for the connection tool, because it would always have to read x many more
  45. characters after the string was found, and if the buffer overflowed, the
  46. entire search string and all chars afterwards would have to be shifted
  47. around to make room.
  48.  
  49. Not only that, but what standard would you make it?  Eight characters more
  50. after the string found?  Someone will need ten more.  Okay then, ten.  But
  51. what if someone needs fifty?  A hundred?  One K...  So, best to let the
  52. application handle searching itself if it needs these special requirements.
  53. I think the search function was only implemented to allow comm programs
  54. to recognize automatic file transfer requests as demoed in the sample app
  55. that came with the CTB developer's kit.
  56.  
  57. So, you're stuck without a standard and with no way to get at the next
  58. few characters after your search string.  The only solution I see is for
  59. you to write your own.  I did.  Here's my version (you'll have to change
  60. all serial calls to be CTB calls, but other than that it's straightforward).
  61.  
  62. Note that all of the strings used in this code are C strings, because
  63. they are far more buffer-friendly than Pascal strings.  Also, some of this
  64. code was changed so I could send it to you, but it should (SHOULD--I'm
  65. not certian that I didn't add bugs when I edited it) remain bug-free.
  66. It is currently in use in a commercial application that I wrote, so I
  67. hope it will work without a flaw...
  68.  
  69. // By Scott Bronson
  70. // 
  71. // The only structure used...
  72. typedef struct searchrec {
  73.     char *first, *cur;
  74. } searchrec;
  75.  
  76. // We can search for this many strings maximum:
  77. #define kNumSearches 16
  78.  
  79. // Global variables used...
  80. short numsearches = 0;
  81. long gStringFound;
  82. searchrec search[kNumSearches];
  83.  
  84. // This is my actual idle loop.  It should
  85. // be able to be used right out of the box.
  86. //
  87. // Idle process:
  88. // % read chars into inbuff
  89. // - strip the eighth bit
  90. // - check against current searches
  91. // - Strip newlines
  92. // - Write to OldLines buffer
  93. // - Put in our log file buffer
  94. // % flush log file buffer
  95.  
  96. void WhatMeIdle( void )
  97. {
  98.     char inbuff[64], outbuff[64];
  99.     // 64-byte input buffer.  The output buffer is used to store the 8th-bit
  100.     // and newline stripped data that we will be displaying on screen.  The
  101.     // search algorithm will not be hurt at all by the disappearance of the
  102.     // ouptut buffer.
  103.     
  104.     register char c; // indexes through each char in the input buffer.
  105.     long count;        // The number of characters read into inbuff.
  106.     long j;            // The number of characters in outbuff.
  107.     short i, l;        // Indexes for loops.
  108.     OSErr err;        // Stores possible errors returned by OS.
  109.     
  110.     err = SerGetBuf( inDriverRefNum, &count );
  111.     if( err == noErr && count > 0 ) {
  112.         if( count > 64 ) count = 64;
  113.         err = FSRead( inDriverRefNum, &count, inbuff );
  114.         
  115.         // Now inbuff is filled with the next (count) characters
  116.         // from the incoming data stream.
  117.         
  118.         if( err == noErr ) {
  119.             
  120.             // We'll loop through every character in the buffer...
  121.             for( i=0,j=0; i<count; i++ ) {
  122.                 c = inbuff[i] & 0x7F;
  123.                 
  124.                 // Now c contains the next 7-bit character.
  125.                 // Here is the search algorithm.  If there are
  126.                 // any searches pending, loop through them and
  127.                 // update the found character counts.
  128.                 
  129.                 if(numsearches) for( l=0; l<numsearches; l++ ) {
  130.                     if( c == *(search[l].cur++) ) {
  131.                         if( !*search[l].cur ) {
  132.                         
  133.                             // Ah!  We found a string.  Leave its index
  134.                             // in a global variable, clear all searches,
  135.                             // and finish reading the current buffer.
  136.                             // You can do whatever you want here.
  137.                             
  138.                             gStringFound = l+1;
  139.                             numsearches = 0;
  140.                         }
  141.                     } else search[l].cur = search[l].first;
  142.                 }
  143.                 
  144.                 // If c is a newline character, we're done with it.
  145.                 if( c == '\n' ) continue;
  146.                 
  147.                 // I performed some other actions here that were removed
  148.                 // for clarity.  Now all we have to do is store c in the
  149.                 // output buffer so it will get written to our disk file.
  150.                 
  151.                 outbuff[j++] = c;
  152.             } // end of for loop.
  153.             
  154.             // If we are storing the incoming data, then write it out.
  155.             if( gLogToFile && j ) {
  156.                 FSWrite( gLogFileRef, &j, outbuff );
  157.             }
  158.         }
  159.     } // else no chars to be read.    
  160. }
  161.  
  162.  
  163. // This is used to add a string to search for, same as CMAddSearch.
  164. // The string passed to AddSearch MUST remain untouched from the time
  165. // it is added until the time CheckStringFound returns a non-empty
  166. // string (meaning AddSearch doesn't make a copy of the string it is
  167. // passed--it just uses it in-place).
  168.  
  169. void AddSearch( char *cs )
  170. {
  171.     if( numsearches < kNumSearches ) {
  172.         search[numsearches].cur = search[numsearches].first = cs;
  173.         numsearches++;
  174.     } // else search buffer is full.
  175. }
  176.  
  177.  
  178. // This is called periodically to see if a string is found.  It is passed
  179. // the address of a buffer large enough to hold the longest of all the
  180. // strings that are currently being searched for.  The buffer will contain
  181. // the actual string found, or a 0-lenth string if none have been found yet.
  182.  
  183. void CheckStringFound( char *ss )
  184. {
  185.     if( gStringFound ) {
  186.         strcpy( ss, search[--gStringFound].first );
  187.     } else {
  188.         ss[0] = 0;
  189.     }
  190. }
  191.  
  192.