home *** CD-ROM | disk | FTP | other *** search
/ Carousel Volume 2 #1 / carousel.iso / mactosh / code / ras_stre.sit < prev    next >
Encoding:
Text File  |  1988-06-20  |  73.2 KB  |  2,549 lines

  1. 18-Jun-88 14:46:48-MDT,77448;000000000000
  2. Return-Path: <u-lchoqu%sunset@cs.utah.edu>
  3. Received: from cs.utah.edu by SIMTEL20.ARPA with TCP; Sat, 18 Jun 88 14:45:17 MDT
  4. Received: by cs.utah.edu (5.54/utah-2.0-cs)
  5.     id AA22671; Sat, 18 Jun 88 14:45:16 MDT
  6. Received: by sunset.utah.edu (5.54/utah-2.0-leaf)
  7.     id AA24809; Sat, 18 Jun 88 14:45:08 MDT
  8. Date: Sat, 18 Jun 88 14:45:08 MDT
  9. From: u-lchoqu%sunset@cs.utah.edu (Lee Choquette)
  10. Message-Id: <8806182045.AA24809@sunset.utah.edu>
  11. To: rthum@simtel20.arpa
  12. Subject: StreamLib.ras
  13.  
  14.  
  15.  
  16.  
  17.                     __StreamLib:  A Rascal Library
  18.  
  19.                            for Stream Input
  20.  
  21.  
  22.  
  23. Introduction
  24. -----------------------------------------------------------------------
  25.  
  26.  
  27. __StreamLib comprises a set of routines which allow programs to read
  28. TEXT and/or WORD (MacWrite) files as a stream of characters, without
  29. having to know or care about which type of file is being read.  A
  30. stream can be opened and then read by operations that return either a
  31. character at a time or a line at a time.  There are also sets of
  32. operations that work exclusively on each type of file, should the user
  33. wish to restrict program operation to TEXT files only or to WORD files
  34. only.  Explicit use of a single stream type reduces the amount of code
  35. linked in (although the amount is small).  Use of the routines that
  36. work on both kinds of files incurs a small penalty in code size but
  37. increases the generality of the program:  any program that operates on
  38. simple text files can be made to operate on MacWrite files as well.
  39.  
  40.  
  41. To use the library, one first initializes it, then opens a stream and
  42. reads its contents.  Streams are closed automatically when the end of
  43. the stream is reached.  The stream can be read a character or a line at
  44. a time.  Two small programs to read a file and display it follow.
  45.  
  46.         Proc CharReadStream (); (* read stream a character at a time *)
  47.         Var
  48.                 c: Integer;
  49.         {
  50.                 InitStream ();
  51.                 if OpenStream () <> noErr then
  52.                 {
  53.                         loop (,,,)
  54.                         {
  55.                                 c := StreamGetC ();
  56.                                 if c = -1 then
  57.                                         break;  (* end of stream *)
  58.                                 WriteChar (c);
  59.                                 if c = ' then
  60.                                         WriteChar (');
  61.                         };
  62.                 };
  63.         };
  64.  
  65.  
  66.         Proc LineReadStream (); (* read stream a line at a time *)
  67.         Var
  68.                 buf: Byte[512]; (* should be big enough! *)
  69.         {
  70.                 InitStream ();
  71.                 if OpenStream () <> noErr then
  72.                 {
  73.                         loop (,,,)
  74.                         {
  75.                                 if StreamGetS (buf) = nil then
  76.                                         break;  (* end of stream *)
  77.                                 WriteString (buf);
  78.                                 WriteLn ();
  79.                         };
  80.                 };
  81.         };
  82.  
  83. If one wishes to know something about the stream, the procedure
  84. GetStreamInfo is available.  This returns a copy of the SFReply used to
  85. open the stream (i.e., it contains the file name, file type, and volume
  86. reference number.
  87.  
  88. Most of the routines in __StreamLib are described below.  Routines with
  89. names beginning with an underscore are primarily intended for internal
  90. use, but they might be useful in certain contexts.
  91.  
  92.  
  93. Stream Initialization, Opening and Closing
  94. -----------------------------------------------------------------------
  95.  
  96.  
  97. Procedure InitStream ();
  98.  
  99. This procedure must be called to set up the library before any other
  100. stream operations are done.
  101.  
  102.  
  103. Function OpenStream (): OSErr;
  104.  
  105. Open a stream.  Closes any currently open stream, then displays a
  106. GetFile dialog listing both TEXT and WORD files.
  107.  
  108.  
  109. Function OpenTextStream (): OSErr;
  110.  
  111. Like OpenStream, but for TEXT files only.
  112.  
  113.  
  114. Function OpenWordStream (): OSErr;
  115.  
  116. Like OpenStream, but for WORD files only.
  117.  
  118.  
  119. OpenStream, OpenTextStream and OpenWordStream return:
  120.  
  121.         noErr           stream opened successfully
  122.         fnOpnErr        stream not opened successfully
  123.         mFulErr         (occurs for WORD files only) stream could be
  124.                         opened, but there was not enough memory to read
  125.                         in initialization information (the stream is
  126.                         closed before returning)
  127.  
  128.  
  129. Procedure CloseStream ();
  130.  
  131. Close the currently open stream.  The character and line input routines
  132. (described below) close the stream automatically upon reaching end of
  133. stream, but CloseStream may be called safely any time after InitStream
  134. is called (even before the first stream is opened!).
  135.  
  136.  
  137. Character Input Routines
  138. -----------------------------------------------------------------------
  139.  
  140.  
  141. Function StreamGetC (): Integer;
  142.  
  143. Determine the type of the stream and get the next character
  144. appropriately.
  145.  
  146.  
  147. Function TextStreamGetC (): Integer;
  148.  
  149. Get the next character from the currently open TEXT stream.  Results
  150. meaningless if the stream is a WORD stream.
  151.  
  152.  
  153. Function WordStreamGetC (): Integer;
  154.  
  155. Get the next character from the currently open WORD stream.  Results
  156. meaningless if the stream is a TEXT stream.
  157.  
  158.  
  159. StreamGetC, TextStreamGetC and WordStreamGetC return:
  160.  
  161.         -1              end of stream
  162.         otherwise       next character of stream
  163.  
  164. Note that the result must be assigned to an integer variable, since -1
  165. is not a legal byte value.
  166.  
  167. When the end of the stream is reached, these routines close the stream.
  168. Further calls return -1 repeatedly until another stream is opened.
  169.  
  170.  
  171. Line Input Routines
  172. -----------------------------------------------------------------------
  173.  
  174.  
  175. Function StreamGetS (str: StringPtr): StringPtr;
  176.  
  177. Determine the type of the stream and get the next line appropriately.
  178. Place the line in the given string.
  179.  
  180.  
  181. Function TextStreamGetS (str: StringPtr): StringPtr;
  182.  
  183. Get the next line (all characters up to the next carriage return or end
  184. of stream) from the currently open TEXT stream.  Place the line in the
  185. given string.  The carriage return is not placed in the string.
  186. Results meaningless if the stream is a WORD stream.
  187.  
  188.  
  189. Function WordStreamGetS (str: StringPtr): StringPtr;
  190.  
  191. Get the next line from the currently open WORD stream.  A "line" is
  192. defined as a string of characters up to the next carriage return or end
  193. of stream, or up to the first space past the current linewrap length.
  194. Lines must be broken at some point, since WORD files contain carriage
  195. returns only at the ends of paragraphs, and it cannot be assumed that
  196. paragraphs will be less than any reasonable length.  Therefore, once a
  197. certain number of characters have been read without a carriage return
  198. being found, the next space causes the call to terminate.  (If you
  199. really need to read in a whole paragraph, use WordStreamGetC until it
  200. returns a carriage return.)
  201.  
  202. The line is placed in the given string.  The carriage return (or space
  203. if the line is broken) is not placed in the string.  Results
  204. meaningless if the stream is a TEXT stream.
  205.  
  206.  
  207. StreamGetS, TextStreamGetS and WordStreamGetS return:
  208.  
  209.         nil             end of stream
  210.         otherwise       pointer to the argument
  211.  
  212. When the end of the stream is reached, these routines close the stream.
  213. Further calls return nil repeatedly until another stream is opened.
  214.  
  215.  
  216. Miscellaneous Routines
  217. -----------------------------------------------------------------------
  218.  
  219.  
  220. Procedure GetStreamInfo (streamInfo: SFReply);
  221.  
  222. Returns, in the argument, a copy of the SFReply record used to open the
  223. stream (from which the file name, file type and file volume reference
  224. number can be determined).  This information is meaningless unless a
  225. stream is actually open.
  226.  
  227.  
  228. Procedure SetLineLen (len: Integer);
  229.  
  230. Sets the line wrap length for WordStreamGetS.
  231.  
  232.  
  233. Function _FSOpen (fName: PtrB; vRefNum: Integer; refNum: ^Integer;
  234.                                 mode: Integer): OSErr;
  235.  
  236. This function is similar to FSOpen (in Inside Macintosh) except that it
  237. allows an open mode to be specified.
  238.  
  239.  
  240. Procedure _ffRead (f: Integer; b: PtrB; amount: LongInt);
  241.  
  242. Reads amount bytes from the file f into the buffer pointed to by b.
  243.  
  244.  
  245. Procedure _fMoveTo (f: Integer; pos: LongInt);
  246.  
  247. Moves to position pos in file f.
  248.  
  249.  
  250. Limitations
  251. -----------------------------------------------------------------------
  252.  
  253.  
  254. Only one file at a time can be streamed.
  255.  
  256.  
  257. Acknowledgments
  258. -----------------------------------------------------------------------
  259.  
  260.  
  261. The code which extracts the text from WORD files is modelled after the
  262. programs ReadMacWrite and Index, by Scott Gillespie (Reed College).
  263. Scott is of course not responsible for any glaring ugliness in my code.
  264. The main differences between his code and mine are:  In ReadMacWrite
  265. the text extractor is a high-level routine that repeatedly passes
  266. characters to subsidiary routines, while in __SteamLib the extractor is
  267. a subsidiary routine repeatedly called by higher-level operations in
  268. the host program.  Also, I used a Handle rather than a Ptr for reading
  269. in each paragraph.  I found that DA's using the library would not
  270. execute properly when they were run inside of other programs not
  271. created with Rascal - SetPtrSize always failed.  I don't know why.
  272.  
  273. --
  274.  
  275.  
  276. Program __StreamLib;
  277.  
  278. (*
  279.     __StreamLib - set of routines for treating TEXT or WORD files as a
  280.     stream of characters or lines.  To use:
  281.  
  282.     Call InitStream() first.  Call OpenStream() to open a stream.  If it
  283.     returns noErr, a stream was opened ok.  To read characters, call
  284.     StreamGetC().  This returns the next character or -1 on end of stream
  285.     (and closes the stream).  To read lines, call StreamGetS(buf).  This
  286.     fills up the buffer passed to it and returns a pointer to it, or nil
  287.     on end of stream (and closes the stream).  To close a stream early,
  288.     call CloseStream().
  289.  
  290.     There are also corresponding routines for reading TEXT files only, or
  291.     WORD files only.  See below.  These are useful if you want to end up
  292.     with less code linked into your program.
  293.  
  294.     To compile this library:
  295.  
  296.         Select Batch... from the Options Menu
  297.         Select Compile Same (or Compile...) for Step 1).
  298.         Select Combine Same for Step 2).
  299.         Click OK.
  300.  
  301.     Version 1.0     11 March 1986
  302.  
  303.     Paul DuBois
  304.     Wisconsin Regional Primate Research Center
  305.     1220 Capitol Court
  306.     University of Wisconsin-Madison
  307.     Madison, WI  53706
  308.  
  309.     UUCP: {allegra, ihnp4, seismo}!uwvax!uwmacc!dubois
  310.  
  311. *)
  312.  
  313. Uses
  314.     __OSTraps
  315.     (*$U+*)
  316.     uOSIntf
  317.     uPackIntf
  318.     ;
  319.  
  320. Link
  321.     __OSTraps
  322.     :;
  323.  
  324. Const
  325.     bufSiz = 1024;
  326.  
  327.     wordStream = 1; (* stream is of 'WORD' file *)
  328.     textStream = 2; (* stream is of 'TEXT' file *)
  329.  
  330.     paraLen = 16;   (* paragraph information 16 bytes long *)
  331.  
  332. Type
  333.     IArray = Record         (* Information array element *)
  334.         height: integer;
  335.         pagepos: integer;
  336.         parahand: ^^longint;
  337.         StPos: Union
  338.             St: byte;       (* first byte is status *)
  339.             Pos: longint;
  340.         End;
  341.         DataLength: integer;
  342.         formats: Integer;
  343.     End;
  344.  
  345. Var
  346.     theReply: SFReply;      (* SFGetFile reply record *)
  347.     f: Integer;             (* input file reference number *)
  348.     streamOpen: Boolean;    (* whether stream currently open *)
  349.     streamType: Integer;    (* wordStream or textStream *)
  350.  
  351. (*  vars needed for TEXT stream only *)
  352.  
  353.     filBuf: Byte[bufSiz];   (* file buffer *)
  354.     fChars: LongInt;        (* number of chars gotten on last read *)
  355.     fIndex: Integer;        (* current position in filBuf *)
  356.  
  357. (*  vars needed for WORD stream only *)
  358.  
  359.     paraBuf: ^^Byte[1];
  360.     infoHand: ^^Iarray[1];
  361.     compressed: Boolean;
  362.     inPara: Boolean;
  363.     nParas: Integer;    (* number of paragraphs *)
  364.     paraNum: Integer;   (* current paragraph number *)
  365.     pIndex: Integer;    (* index into paragraph *)
  366.     pChars: Integer;    (* number of chars extracted from paragraph *)
  367.     firstHalf: Boolean; (* which half of current index char *)
  368.     pLen: Integer;      (* number of chars in paragraph *)
  369.     needNib,            (* For Decompr.: true = 2nd Nibble needed for ascii *)
  370.     nextAsc: boolean;   (* For Decompr.: true = Two Nibbles needed *)
  371.     lastNib: byte;      (* For Decompr.: Holds last nibble *)
  372.     lineLen: Integer;   (* for line wrapping *)
  373.  
  374.  
  375. (* -------------------------------- *)
  376. (*  miscellaneous utility routines  *)
  377. (* -------------------------------- *)
  378.  
  379. Proc _ffRead (f: Integer; b: PtrB; amount: LongInt);
  380. {
  381.     amount := FSRead(f, @amount, b);
  382. };
  383.  
  384. Proc _fMoveTo (f: Integer; amt: LongInt);
  385. Var
  386.     result: Integer;
  387. {
  388.     result := SetFPos (f, fsFromStart, amt);
  389. };
  390.  
  391.  
  392. (* --------------------------------- *)
  393. (*  stream init/open/close routines  *)
  394. (* --------------------------------- *)
  395.  
  396.  
  397. (*
  398.     InitStream - must be called before you do anything else.
  399.  
  400.     _FSOpen - like FSOpen (in __OSTraps), but has open mode parameter.
  401.  
  402.     _OpenStream - Open a file for stream I/O.  numTypes is either 1 or 2,
  403.         and typeList is either 'TEXT', 'WORD', or 'TEXTWORD'.
  404.         Return noErr if file opened OK, or fnOpnErr if not.
  405.         if OK, set streamType to wordStream or textStream,
  406.         according to the type of the opened file, and set
  407.         fileOpen true.
  408.  
  409.     OpenTextSream - open 'TEXT' file stream.  Returns:
  410.         noErr - file open OK
  411.         fnOpnErr - file not open
  412.  
  413.     OpenWordSream - open 'WORD' file stream.  Returns:
  414.         noErr - file open OK
  415.         fnOpnErr - file not open
  416.         mFulErr - couldn't get memory to read paragraph info into memory.
  417.             file not open.
  418.  
  419.     OpenSream - open 'TEXT' or 'WORD' stream.  Return values same as for
  420.         OpenWordS.  Returns stream type in function argument sType.
  421.  
  422.     _WordStreamInit does special handling necessary for 'WORD' stream:
  423.     Open the file, advance 252 + 12 bytes (to start of main document info
  424.     + offset of Information Array.  Then read position and length of Info
  425.     Array, move to it, read it in, and calculate number of paragraphs.
  426.     (16 bytes info per paragraph.)  _TextStreamInit does TEXT stream
  427.     specific initialization.
  428. *)
  429.  
  430. Proc InitStream ();
  431. {
  432.     streamOpen := false;
  433.     lineLen := 65;
  434.     paraBuf := nil;
  435.     infoHand := nil;
  436. };
  437.  
  438.  
  439. Proc CloseStream ();
  440. Var
  441.     result : OSErr;
  442. {
  443.     if streamOpen then
  444.     {
  445.         result := FSClose (f);
  446.         streamOpen := false;
  447.         if streamType = wordStream then
  448.         {
  449.             if paraBuf <> nil then DisposHandle (paraBuf);
  450.             if infoHand <> nil then DisposHandle (infoHand);
  451.         };
  452.     };
  453. };
  454.  
  455.  
  456. Func _FSOpen (fName: PtrB; vRefNum: Integer;
  457.               refNum: ^Integer; mode: Integer): OSErr;
  458. Var
  459.     p: ParamBlockRec;
  460. {
  461.     p.ioNamePtr := fName;
  462.     p.ioVRefNum := vRefNum;
  463.     p.ioPermssn := mode;
  464.     p.ioVersNum := 0;
  465.     p.ioMisc := 0;
  466.     _FSOpen := PBOpen (p, false);
  467.     refnum^ := p.ioRefNum;
  468. };
  469.  
  470.  
  471. Func _OpenStream (numTypes: Integer; typeList: OSType): OSErr;
  472. {
  473.     CloseStream ();         (* close any currently open stream *)
  474.     _OpenStream := fnOpnErr;
  475.     streamOpen := false;
  476.  
  477.     ToolBox ($A9EA, 100, 70, "", nil, numTypes, typeList, nil, @theReply, 2);
  478.     if theReply.good then
  479.     {
  480.         if _FSOpen(theReply.fName, theReply.vRefNum, @f, fsRdPerm) = noErr then
  481.         {
  482.             streamType := wordStream;
  483.             if theReply.fType = PtrL (" TEXT"+2)^ then
  484.                 streamType := textStream;
  485.             streamOpen := true;
  486.             _OpenStream := noErr;
  487.         };
  488.     };
  489. };
  490.  
  491.  
  492. Proc _TextStreamInit ();
  493. {
  494.     fChars := 0;    (* set these to trigger a read on the first *)
  495.     fIndex := 0;    (* call to TextStreamGetC() *)
  496. };
  497.  
  498.  
  499. Func _WordStreamInit (): OSErr;
  500. Type
  501.     DocVars = Record
  502.         IApos: Longint;
  503.         IAlength: Integer;
  504.     End;
  505. Var
  506.   docVars: DocVars;
  507. {
  508.     paraBuf := NewHandle (0L);  (* Will be used for reading in paragraphs *)
  509.     _fmoveto (f, 264L);       (* 252 + 12 *)
  510.     _ffRead (f, docVars, LongInt (SizeOf (DocVars)));
  511.     _fMoveTo (f, docVars.IAPos);
  512.     infoHand := NewHandle (Longint (docVars.IALength));
  513.     if infoHand = nil then
  514.     {
  515.         CloseStream ();
  516.         _WordStreamInit := mFulErr;
  517.     }
  518.     else
  519.     {
  520.         HLock (InfoHand);
  521.         _ffRead (f, infoHand^, Longint (docVars.IALength));
  522.         HUnlock (InfoHand);
  523.  
  524.         nParas := docVars.IALength/paraLen;
  525.         paraNum := -1;
  526.         inPara := false;            (* not in any paragraph yet *)
  527.         _WordStreamInit := noErr;
  528.     };
  529. };
  530.  
  531.  
  532. Func OpenTextStream (): OSErr;
  533. {
  534.     OpenTextStream := _OpenStream (1, " TEXT"+2);
  535.     _TextStreamInit ();
  536. };
  537.  
  538.  
  539. Func OpenWordStream (): OSErr;
  540. Var
  541.     result: OSErr;
  542. {
  543.     OpenWordStream := fnOpnErr;
  544.     if _OpenStream (1, " WORD"+2) = noErr then
  545.         OpenWordStream := _WordStreamInit ();
  546. };
  547.  
  548.  
  549. Func OpenStream (): OSErr;
  550. {
  551.     OpenStream := fnOpnErr;
  552.     if _OpenStream (2, " TEXTWORD"+2) = noErr then
  553.     {
  554.         OpenStream := noErr;
  555.         case streamType of
  556.             wordStream: OpenStream := _WordStreamInit ();
  557.             textStream: _TextStreamInit ();
  558.         end;
  559.     };
  560. };
  561.  
  562.  
  563. Proc GetStreamInfo (reply: SFReply);
  564. {
  565.     reply := theReply;
  566. };
  567.  
  568.  
  569. (*
  570.     'Get a character' routines
  571.  
  572.     TextStreamGetC - get character from 'TEXT' stream.
  573.     WordStreamGetC - get character from 'WORD' stream.
  574.     StreamGetC - get character from stream.
  575. *)
  576.  
  577. Func TextStreamGetC (): Integer;
  578. Var
  579.     err: OSErr;
  580. {
  581.     TextStreamGetC := -1;
  582.     if streamOpen = false then return;
  583.     if fIndex >= fChars then    (* need to read in a new block *)
  584.     {
  585.         fChars := bufSiz;
  586.         err := FSRead (f, @fChars, filBuf);
  587.         if fChars = 0 then
  588.         {
  589.             CloseStream ();
  590.             return;
  591.         };
  592.         fIndex := 0;
  593.     };
  594.     TextStreamGetC := filBuf[fIndex];
  595.     ++fIndex;
  596. };
  597.  
  598.  
  599. (*
  600.     _Decompress takes a nibble at a time of compressed text.  If more
  601.     nibbles are needed to complete the next character, return -1, else
  602.     returns the character.
  603. *)
  604.  
  605. Func _Decompress (b: Byte): Integer;
  606. {
  607.     _Decompress := -1;
  608.     if needNib then             (* Low half of ascii nibble is needed. *)
  609.     {
  610.         needNib := false;
  611.         _Decompress := (lastNib or b);  (* Put the two halves together *)
  612.     }
  613.     else if nextasc then        (* Two nibbles are needed *)
  614.     {
  615.         nextAsc := false;
  616.         lastNib := b << 4;      (* Save this one as the high nibble *)
  617.         needNib := true;        (* Need one more nibble *)
  618.     }
  619.     else if b = 15 then         (* Nibble of 15 means the next char is ascii *)
  620.         nextAsc := true
  621.     else          (* Add the nibble value to the English decompression *)
  622.                   (* key (saved as Resource Type "STR " 700 in file)   *)
  623.                   (* to get the proper character *)
  624.     {
  625.         _Decompress := PtrB (++b + " etnroaisdlhcfp")^;
  626.     };
  627. };
  628.  
  629.  
  630. Func WordStreamGetC (): Integer;   (* return -1 on EOF *)
  631. Var
  632.     c: Integer;
  633.     offset: LongInt;
  634. {
  635.     WordStreamGetC := -1;
  636.     if streamOpen = false then return;
  637.     if inPara = false then      (* must read in next paragraph *)
  638.     {
  639.         loop (,,,)
  640.         {
  641.             if ++paraNum >= nparas then
  642.             {
  643.                 CloseStream ();
  644.                 return;
  645.             };
  646.             if infoHand^^[paranum].height <= 0 then continue;
  647. (*
  648.     offset will contain the file offset to this paragraph's data.  must
  649.     mask the high byte.  Move to the paragraph, get its length, make
  650.     the pointer big enough, and read it in.  (skip to next para if this
  651.     one is empty, though.)
  652.     compressed will be set true if the paragraph is compressed.
  653. *)
  654.             offset := infoHand^^[paranum].stpos.pos and $00FFFFFF;
  655.             _fMoveTo (f, offset);
  656.             _ffRead (f, @plen, LongInt (SizeOf (Integer))); (* get length *)
  657.             if plen = 0 then continue;
  658.             SetHandleSize (paraBuf, LongInt (plen));    (* make big enough *)
  659.             if MemError () <> noErr then
  660.             {
  661.                 paranum := nparas;  (* force close and exit of loop *)
  662.                 continue;
  663.             };
  664.             _ffRead (f, paraBuf^, LongInt (plen));
  665.             compressed := (infoHand^^[paranum].stpos.st >> 3) and 1;
  666.             inPara := true;
  667.             nextAsc := false;
  668.             needNib := false;
  669.             pIndex := 0;        (* index into current paragraph *)
  670.             pChars := 0;        (* chars extracted from current paragraph *)
  671.             firstHalf := true;  (* use first half of current index char *)
  672.             break;
  673.         };
  674.     };
  675. (*
  676.     At this point, know eitherthat we have a new non-empty paragraph, or
  677.     are still in the previous one.
  678. *)
  679.     if !compressed then  (* uncompressed *)
  680.     {
  681.         c := paraBuf^^[pchars];
  682.     }
  683.     else
  684.     {
  685.         loop (,,, c <> -1)
  686.         {
  687.             c := paraBuf^^[pIndex];
  688.             if firstHalf then
  689.             {
  690.                 c := _Decompress (Byte (c >> 4));
  691.             }
  692.             else
  693.             {
  694.                 c := _Decompress (Byte (c and $0f));
  695.                 ++pIndex;   (* go to next char at next index *)
  696.             };
  697.             firstHalf := !firstHalf;
  698.         };
  699.     };
  700.     if ++pChars >= pLen then    (* see if need new paragraph next time *)
  701.         inPara := false;
  702.     WordStreamGetC := c;
  703. };
  704.  
  705.  
  706. Func StreamGetC (): Integer;
  707. {
  708.     case streamType of
  709.         wordStream: StreamGetC := WordStreamGetC ();
  710.         textStream: StreamGetC := TextStreamGetC ();
  711.     end;
  712. };
  713.  
  714.  
  715. (*
  716.     'Get a string' routines
  717.  
  718.     TextStreamGetS - get string from 'TEXT' stream.
  719.     WordStreamGetS - get string from 'WORD' stream.
  720.     StreamGetS - get string from stream.
  721.  
  722.     All return nil if no string obtained, otherwise a pointer to the argument.
  723. *)
  724.  
  725.  
  726. Func TextStreamGetS (s: StringPtr): StringPtr;
  727. Var
  728.     c: Integer;
  729. {
  730.     TextStreamGetS := nil;
  731.     if !streamOpen then return;
  732.     s[0] := 0;  (* clear string *)
  733.     loop (,,,)
  734.     {
  735.         c := TextStreamGetC ();
  736.         if c = -1 then
  737.             break;
  738.         TextStreamGetS := s;   (* got something, so NextLine succeeds *)
  739.         if c = 13 then break;
  740.         s[++s[0]] := c;       (* add char to end *)
  741.     };
  742. };
  743.  
  744.  
  745. Func WordStreamGetS (s: StringPtr): StringPtr;
  746. Var
  747.     c: Integer;
  748. {
  749.     WordStreamGetS := nil;
  750.     if !streamOpen then return;
  751.     s[0] := 0;  (* clear string *)
  752.     loop (,,,)
  753.     {
  754.         c := WordStreamGetC ();
  755.         if c = -1 then
  756.             break;
  757.         WordStreamGetS := s;   (* got something, so NextLine succeeds *)
  758.         if (c = 13) or ((s[0] > lineLen) and (c = ' ')) then
  759.             break;
  760.         s[++s[0]] := c;       (* add char to end *)
  761.     };
  762. };
  763.  
  764.  
  765. Func StreamGetS (s: StringPtr): StringPtr;
  766. {
  767.     case streamType of
  768.         wordStream: StreamGetS := WordStreamGetS (s);
  769.         textStream: StreamGetS := TextStreamGetS (s);
  770.     end;
  771. };
  772.  
  773.  
  774. (*
  775.     Set wrap length (number of chars after which point the line will be
  776.     broken at the next space if a carriage return is not seen first).  This
  777.     only affects TextStreamGetS (or StreamGetS when the current stream is
  778.     a WORD stream).
  779. *)
  780.  
  781. Proc SetLineLen (len: Integer);
  782. {
  783.     lineLen := len;
  784. };
  785.  
  786.  
  787. --
  788.                                                                     |
  789. Paul DuBois     {allegra,ihnp4,seismo}!uwvax!uwmacc!dubois        --+--
  790.                                                                     |
  791.                                                                     |
  792. Path: utah-cs!seismo!uwvax!uwmacc!dubois
  793. From: dubois@uwmacc.UUCP (Paul DuBois)
  794. Newsgroups: net.sources.mac
  795. Subject: Source for Grep-Wc DA
  796. Message-ID: <2035@uwmacc.UUCP>
  797. Date: 17 Mar 86 17:00:33 GMT
  798. Distribution: net
  799. Organization: UW-Madison Primate Center
  800. Lines: 1752
  801.  
  802.  
  803. This posting contains several files:
  804.  
  805. uGrep.src     "Uses" file with all constants and types needed to
  806.          compile Grep-Wc
  807. GrepPatStuff.src Pattern-compiling, matching and entry routines
  808. Grep-Wc.src     Main program
  809. Grep-Wc.rsrc.Hqx BinHex of Grep-Wc resources
  810. AddRes.src     Utility for transferring resources (not necessary,
  811.          but very helpful)
  812.  
  813. You will also need the stream library stuff (__StreamLib.src - separate
  814. posting).
  815.  
  816. The pattern compilation and matching routines are based in algorithms
  817. found in the Software Tools (Kernighan and Plauger).  The resource
  818. copying stuff in AddRes is similar to some parts of the Rascal program
  819. MakeAppl.  uGrep.src is a conglomeration of parts of Rascal "Uses" files,
  820. but since there is very little there that isn't listed explicitly in
  821. Inside Macintosh, I don't expect that I am violating any rules by posting
  822. it.
  823.  
  824.  
  825. To recreate Grep-Wc from the source code, do the following
  826. steps:
  827.  
  828. Launch Rascal
  829. Compile __StreamLib.src to get __StreamLib.ras
  830. Compile uGrep.src to get uGrep.ras
  831. Compile GrepPatStuff.src to get GrepPatStuff.ras
  832. Compile Grep-Wc.src to get Grep-Wc.ras
  833. Link Grep-Wc.ras to get Grep-Wc.obj.  DON'T execute it!!  (It needs
  834. its own resources to run properly.)
  835. Express AddRes.src to get AddRes.obj.  This program is a simple utility
  836. which asks you to select two files, then copies all the resources from
  837. the first one into the resource fork of the second one.  When you
  838. run this, select Grep-Wc.rsrc as the first file ("Copy From") and
  839. Grep-Wc.obj as the second file ("Copy To").  (You could use ResEdit
  840. to accomplish the same task.)
  841. Execute Grep-Wc.obj in Rascal to see if it works.  Assuming it does,
  842. go on to the next step.
  843. Execute DeskMaker.obj (you must have the version from the new Rascal
  844. release).  Stretch/move the window to where you want it, select the
  845. Object -> Desk Acc. menu item.  When the dialog comes up, change
  846. the window type to 0 (zero).  Do NOT select "Test after make" (the
  847. DA file that DeskMaker won't have the necessary owned resources).
  848. Note the driver number that DeskMaker assigns to the new DA.  If
  849. it's 26, then quit DeskMaker and use AddRes to copy Grep-Wc.rsrc into
  850. the new DA file.  You're all set.
  851. If the id was not 26, then use ResEdit to copy the resources from
  852. Grep-Wc.rsrc into the new DA file, and change their owner id's to match
  853. the driver number (don't change the sub-id's).  There are ALRT, DITL
  854. and DLOG resources.  If you don't renumber them properly, Font/DA Mover
  855. won't move them when you move the DA around.  See the discussion on
  856. owned resources in the Resource Manager manual of Inside Macintosh
  857. if you don't know what I'm talking about here.
  858.  
  859.  
  860. #    This is a shell archive.
  861. #    Remove everything above and including the cut line.
  862. #    Then run the rest of the file through sh.
  863. -----cut here-----cut here-----cut here-----cut here-----
  864. #!/bin/sh
  865. # shar:    Shell Archiver
  866. #    Run the following text with /bin/sh to create:
  867. #    uGrep.src
  868. #    GrepPatStuff.src
  869. #    Grep-Wc.src
  870. #    Grep-Wc.rsrc.Hqx
  871. #    AddRes.src
  872. # This archive created: Mon Mar 17 10:50:22 1986
  873. # By:    Paul DuBois (UW-Madison Primate Center)
  874. echo shar: extracting uGrep.src '(8926 characters)'
  875. sed 's/^XX//' << \SHAR_EOF > uGrep.src
  876. XX
  877. XXProgram uGrep;
  878. XX
  879. XX(*
  880. XX    uGrep.  Uses file containing all Toolbox Types and Constants needed
  881. XX             for Grep-Wc (gleaned from various u* files).  Many of the
  882. XX             handles and pointers I simply declared as ^LongInt, however.
  883. XX
  884. XX*)
  885. XX
  886. XX(*$U+*)
  887. XX(*$L+*)
  888. XX
  889. XX
  890. XXCONST
  891. XX
  892. XX(*  from uMemTypes  *)
  893. XX
  894. XX   True = 1B;
  895. XX   False = 0B;
  896. XX   Nil = 0L;
  897. XX
  898. XX(*  from uQuickDraw  *)
  899. XX
  900. XX(*  from uToolIntf  *)
  901. XX
  902. XX    inGrow = 5;
  903. XX
  904. XX  (*control definition proc ID's*)
  905. XX
  906. XX  pushButProc   = 0;
  907. XX
  908. XX(*  from uOSIntf  *)
  909. XX
  910. XX  NoErr       =      0;     (* All is well *)
  911. XX
  912. XX  fsWrPerm  = 2;
  913. XX
  914. XX(*  from uPackIntf *)
  915. XX
  916. XXTYPE
  917. XX
  918. XX(*  from uMemTypes  *)
  919. XX
  920. XX   Boolean = Byte;
  921. XX   char = Integer;
  922. XX   SignedByte   = Byte;         (* any byte in memory *)
  923. XX   Ptr         = PtrB;         (* blind pointer *)
  924. XX   Handle       = ^PtrB;        (* pointer to a master pointer *)
  925. XX   ProcPtr      = Ptr;         (* pointer to a procedure *)
  926. XX   Fixed        = LongInt;      (* fixed point arithmetic type *)
  927. XX
  928. XX   Str255       =  Byte[256];   (* maximum string size *)
  929. XX   StringPtr    = ^Str255;      (* pointer to maximum string *)
  930. XX   StringHandle = ^StringPtr;   (* handle to maximum string *)
  931. XX
  932. XX(*  from uQuickDraw  *)
  933. XX
  934. XX     Style     =  Integer;  (* use this one. *)
  935. XX     Pattern   =  Byte[8];
  936. XX
  937. XX   Point = Record
  938. XX     Variant
  939. XX         { v,h: integer ;};
  940. XX     or  { vh:  longint ; };
  941. XX   End;
  942. XX
  943. XX     Rect = Record
  944. XX       Variant
  945. XX          { top,left,bottom,right:  Integer ;};
  946. XX       Or
  947. XX          { topLeft,botRight: Point ; };
  948. XX     End;
  949. XX
  950. XX
  951. XX     BitMap = Record
  952. XX       baseAddr: Ptr;
  953. XX       rowBytes: Integer;
  954. XX       bounds:  Rect;
  955. XX     End;
  956. XX
  957. XX
  958. XX
  959. XX     RgnHandle = ^LongInt;
  960. XX     QDProcsPtr = ^LongInt;
  961. XX
  962. XX
  963. XX     GrafPtr  = ^GrafPort;
  964. XX     GrafPort = Record
  965. XX       device:     Integer;
  966. XX       portBits:    BitMap;
  967. XX       portRect:    Rect;
  968. XX       visRgn:     RgnHandle;
  969. XX       clipRgn:     RgnHandle;
  970. XX       bkPat:     Pattern;
  971. XX       fillPat:     Pattern;
  972. XX       pnLoc:     Point;
  973. XX       pnSize:     Point;
  974. XX       pnMode:     Integer;
  975. XX       pnPat:     Pattern;
  976. XX       pnVis:     Integer;
  977. XX       txFont:     Integer;
  978. XX       txFace:     Style;
  979. XX       txMode:     Integer;
  980. XX       txSize:     Integer;
  981. XX       spExtra:     Fixed;
  982. XX       fgColor:     LongInt;
  983. XX       bkColor:     LongInt;
  984. XX       colrBit:     Integer;
  985. XX       patStretch:  Integer;
  986. XX       picSave:     Handle;
  987. XX       rgnSave:     Handle;
  988. XX       polySave:    Handle;
  989. XX       grafProcs:   QDProcsPtr;
  990. XX     End;
  991. XX
  992. XX(*  from uToolIntf  *)
  993. XX
  994. XX
  995. XX  (*for TextEdit*)
  996. XX
  997. XX  TERec = Record
  998. XX    destRect: Rect;      (*Destination rectangle*)
  999. XX    viewRect: Rect;      (*view rectangle*)
  1000. XX    selRect: Rect;      (*Select rectangle*)
  1001. XX    lineHeight: Integer;     (*Current font lineheight*)
  1002. XX    fontAscent: Integer;     (*Current font ascent*)
  1003. XX    selPoint: Point;      (*Selection point(mouseLoc)*)
  1004. XX
  1005. XX    selStart: Integer;      (*Selection start*)
  1006. XX    selEnd: Integer;      (*Selection end*)
  1007. XX
  1008. XX    active: Integer;      (*<>0 if active*)
  1009. XX
  1010. XX    wordBreak:  ProcPtr;     (*Word break routine*)
  1011. XX    clikLoop:  ProcPtr;      (*Click loop routine*)
  1012. XX
  1013. XX    clickTime: LONGINT;      (*Time of first click*)
  1014. XX    clickLoc: Integer;      (*Char. location of click*)
  1015. XX
  1016. XX    caretTime: LONGINT;      (*Time for next caret blink*)
  1017. XX    caretState: Integer;     (*On/active booleans*)
  1018. XX
  1019. XX    just: Integer;      (*fill style*)
  1020. XX
  1021. XX    TELength: Integer;      (*Length of text below*)
  1022. XX    hText: Handle;      (*Handle to actual text*)
  1023. XX
  1024. XX    recalBack: Integer;      (*<>0 if recal in background*)
  1025. XX    recalLines: Integer;     (*Line being recal'ed*)
  1026. XX    clikStuff: Integer;      (*click stuff (internal)*)
  1027. XX
  1028. XX    crOnly: Integer;      (*Set to -1 if CR line breaks only*)
  1029. XX
  1030. XX    txFont: Integer;      (*Text Font*)
  1031. XX    txFace: Style;      (*Text Face*)
  1032. XX    txMode: Integer;      (*Text Mode*)
  1033. XX    txSize: Integer;      (*Text Size*)
  1034. XX
  1035. XX    inPort: GrafPtr;      (*Grafport*)
  1036. XX
  1037. XX    highHook: ProcPtr;      (*Highlighting hook*)
  1038. XX    caretHook: ProcPtr;      (*Highlighting hook*)
  1039. XX
  1040. XX    nLines: Integer;      (*Number of lines*)
  1041. XX    lineStarts: Integer[16000];     (*Actual line starts themselves*)
  1042. XX  END; (*Record*)
  1043. XX
  1044. XX  TEPtr = ^TERec;
  1045. XX  TEHandle = ^TEPtr;
  1046. XX
  1047. XX
  1048. XX  (*for Resource Manager*)
  1049. XX
  1050. XX  ResType = Longint; (* Packed Array of 4 Chars *)
  1051. XX
  1052. XX
  1053. XX  (*for Control Manager*)
  1054. XX
  1055. XX
  1056. XX  ControlHandle    = ^LongInt;
  1057. XX
  1058. XX  (*for Dialog Manager*)
  1059. XX
  1060. XX  DialogPtr=    ^LongInt;
  1061. XX
  1062. XX
  1063. XX  (*for Menu Manager*)
  1064. XX
  1065. XX  MenuHandle = ^LongInt;
  1066. XX
  1067. XX
  1068. XX(*  from uOSIntf  *)
  1069. XX
  1070. XX  (*for Event Manager*)
  1071. XX  EventRecord = Record
  1072. XX    what:      Integer;
  1073. XX    message:   LongInt;
  1074. XX    when:      LongInt;
  1075. XX    where:     Point;
  1076. XX    modifiers: Integer;
  1077. XX  End;
  1078. XX
  1079. XX  OSErr = Integer;
  1080. XX
  1081. XX
  1082. XX  QElemPtr = ^LongInt;
  1083. XX
  1084. XX
  1085. XXIOParam = Record
  1086. XX   ioRefNum: Integer;       (*refNum for I/O operation*)
  1087. XX   ioVersNum: SignedByte;   (*version number*)
  1088. XX   ioPermssn: SignedByte;   (*Open: permissions (byte)*)
  1089. XX
  1090. XX   ioMisc: Ptr;      (*Rename: new name*)
  1091. XX                            (*GetEOF,SetEOF: logical End of file*)
  1092. XX                            (*Open: optional ptr to buffer*)
  1093. XX                            (*SetFileType: new type*)
  1094. XX   ioBuffer: Ptr;           (*data buffer Ptr*)
  1095. XX   ioReqCount: LongInt;     (*requested byte count*)
  1096. XX   ioActCount: LongInt;     (*actual byte count completed*)
  1097. XX   ioPosMode: Integer;      (*initial file positioning*)
  1098. XX   ioPosOffset: LongInt ;   (*file position offset*)
  1099. XXEnd;
  1100. XX
  1101. XX  OSType = Longint; (* Packed array of 4 chars *)
  1102. XX
  1103. XX  FInfo = Record      (*Record of finder info*)
  1104. XX            fdType: OSType;         (*the type of the file*)
  1105. XX            fdCreator: OSType;      (*file's creator*)
  1106. XX            fdFlags: Byte;       (*flags ex. hasbundle,invisible,locked, etc.*)
  1107. XX            filler: Byte;
  1108. XX            fdLocation: Point;      (*file's location in folder*)
  1109. XX            fdFldr: Integer;        (*folder containing file*)
  1110. XX          End; (*FInfo*)
  1111. XX
  1112. XXFileParam = Record
  1113. XX   ioFRefNum: Integer;      (*reference number*)
  1114. XX   ioFVersNum: SignedByte;  (*version number*)
  1115. XX   filler1: SignedByte;
  1116. XX   ioFDirIndex: Integer;    (*GetFileInfo directory index*)
  1117. XX   ioFlAttrib: SignedByte;  (*GetFileInfo: in-use bit=7, lock bit=0*)
  1118. XX   ioFlVersNum: SignedByte; (*file version number*)
  1119. XX   ioFlFndrInfo: FInfo;     (*user info*)
  1120. XX   ioFlNum: LongInt;        (*GetFileInfo: file number*)
  1121. XX   ioFlStBlk: Integer;      (*start file block (0 if none)*)
  1122. XX   ioFlLgLen: LongInt;      (*logical length (EOF)*)
  1123. XX   ioFlPyLen: LongInt;      (*physical lenght*)
  1124. XX   ioFlRStBlk: Integer;     (*start block rsrc fork*)
  1125. XX   ioFlRLgLen: LongInt;     (*file logical length rsrc fork*)
  1126. XX   ioFlRPyLen: LongInt;     (*file physical length rsrc fork*)
  1127. XX   ioFlCrDat: LongInt;      (*file creation date & time (32 bits in secs)*)
  1128. XX   ioFlMdDat: LongInt ;     (*last modified date and time*)
  1129. XXEnd;
  1130. XX
  1131. XXVolumeParam = Record
  1132. XX   filler2: LongInt;
  1133. XX   ioVolIndex: Integer;     (*volume index number*)
  1134. XX   ioVCrDate: LongInt;      (*creation date and time*)
  1135. XX   ioVLsBkUp: LongInt;      (*last backup date and time*)
  1136. XX   ioVAtrb: Integer;        (*volume attrib*)
  1137. XX   ioVNmFls: Integer;       (*number of files in directory*)
  1138. XX   ioVDirSt: Integer;       (*start block of file directory*)
  1139. XX   ioVBlLn: Integer;        (*GetVolInfo: length of dir in blocks*)
  1140. XX   ioVNmAlBlks: Integer;    (*GetVolInfo: num blks (of alloc size)*)
  1141. XX   ioVAlBlkSiz: LongInt;    (*GetVolInfo: alloc blk byte size*)
  1142. XX   ioVClpSiz: LongInt;      (*GetVolInfo: bytes to allocate at a time*)
  1143. XX   ioAlBlSt: Integer;       (*starting disk(512-byte) block in block map*)
  1144. XX   ioVNxtFNum: LongInt;     (*GetVolInfo: next free file number*)
  1145. XX   ioVFrBlk: Integer ;      (*GetVolInfo: # free alloc blks for this vol*)
  1146. XXEnd;
  1147. XX
  1148. XX
  1149. XXCntrlParam = Record
  1150. XX  ioCRefNum: Integer;       (*refNum for I/O operation*)
  1151. XX  CSCode: Integer;          (*word for control status code*)
  1152. XX  CSParam: Integer[10];     (*operation-defined parameters*)
  1153. XXEnd;
  1154. XX
  1155. XX  ParamBlockRec = Record
  1156. XX
  1157. XX        (*12 byte header used by the file and IO system*)
  1158. XX        qLink: QElemPtr;     (*queue link in header*)
  1159. XX        qType: Integer;      (*type byte for safety check*)
  1160. XX        ioTrap: Integer;     (*FS: the Trap*)
  1161. XX        ioCmdAddr: Ptr;      (*FS: address to dispatch to*)
  1162. XX
  1163. XX        (*common header to all variants*)
  1164. XX        ioCompletion: ProcPtr;  (*completion routine addr (0 for synch calls)*)
  1165. XX        ioResult: OSErr;        (*result code*)
  1166. XX        ioNamePtr: StringPtr;   (*ptr to Vol:FileName string*)
  1167. XX        ioVRefNum: Integer;     (*volume refnum (DrvNum for Eject and MountVol)*)
  1168. XX
  1169. XX        (*different components for the different type of parameter blocks*)
  1170. XX
  1171. XX        Variant
  1172. XX          Insert ioParam;
  1173. XX          Insert FileParam;
  1174. XX          Insert VolumeParam;
  1175. XX          Insert CntrlParam;
  1176. XX
  1177. XX      End; (*ParamBlockRec*)
  1178. XX
  1179. XX(*  from uPackIntf *)
  1180. XX
  1181. XX   SFReply = Record
  1182. XX     good: BOOLEAN;  (*ignore command if FALSE*)
  1183. XX     copy: BOOLEAN;  (*not used*)
  1184. XX     fType: OsType;  (*file type or not used*)
  1185. XX     vRefNum: Integer;  (*volume reference number*)
  1186. XX     version: Integer;  (*file's version number*)
  1187. XX     fName: Byte[64];  (*file name*)
  1188. XX   END; (*SFReply*)
  1189. XX
  1190. XX
  1191. XXprocedure z_z_z();{};
  1192. SHAR_EOF
  1193. if test 8926 -ne "`wc -c uGrep.src`"
  1194. then
  1195. echo shar: error transmitting uGrep.src '(should have been 8926 characters)'
  1196. fi
  1197. echo shar: extracting GrepPatStuff.src '(13365 characters)'
  1198. sed 's/^XX//' << \SHAR_EOF > GrepPatStuff.src
  1199. XXProgram GrepPatStuff;
  1200. XX
  1201. XX(*
  1202. XX    GrepPatStuff - routines for compiling patterns into internal form,
  1203. XX    for matching strings against the compiled pattern, and for presenting
  1204. XX    the pattern entry dialog.
  1205. XX*)
  1206. XX
  1207. XX
  1208. XXUses
  1209. XX    __ToolTraps
  1210. XX    (*$U+*)
  1211. XX    uGrep
  1212. XX    ;
  1213. XX
  1214. XXConst
  1215. XX
  1216. XX    bufSiz = 512;
  1217. XX
  1218. XX(*  pattern dialog items  *)
  1219. XX
  1220. XX    okButton = 1;
  1221. XX    cancelButton = 2;
  1222. XX    (* prompt statText = 3 *)
  1223. XX    patText = 4;
  1224. XX    linesRadioButton = 5;
  1225. XX    noLinesRadioButton = 6;
  1226. XX    numbersCheckBox = 7;
  1227. XX
  1228. XX(*  pattern special internal chars  *)
  1229. XX
  1230. XX    CCL = 1;           (* match characters in class *)
  1231. XX    NCCL = 2;          (* all but characters in class *)
  1232. XX    CRANGE = 3;        (* range of chars *)
  1233. XX    ENDCCL = 4;        (* end char class *)
  1234. XX    ANY = 5;           (* match any char *)
  1235. XX    CLOSURE = 6;       (* closure *)
  1236. XX    EOL = 7;           (* end of line *)
  1237. XX
  1238. XX
  1239. XXVar
  1240. XX    theDialog:  DialogPtr;
  1241. XX
  1242. XX(*  pattern compilation and matching vars  *)
  1243. XX
  1244. XX    rawPattern: Byte[bufSiz];   (* pattern user types in *)
  1245. XX    thePattern: Byte[bufSiz];   (* compiled pattern *)
  1246. XX
  1247. XX    matchBol: boolean;          (* match beginning of line? *)
  1248. XX    pix: integer;               (* index into pattern *)
  1249. XX    pMark: integer;
  1250. XX    canClose: boolean;
  1251. XX
  1252. XXExtDef  (* externals from main program *)
  1253. XX
  1254. XX    resBase:    Integer;    (* base resource id *)
  1255. XX    matchType:  Boolean;    (* true: print lines w/pattern. false: inverse *)
  1256. XX    prtLineNum: Boolean;    (* print line numbers if true *)
  1257. XX    havePat:    Boolean;    (* whether have good pattern or not *)
  1258. XX    lineNum:    LongInt;
  1259. XX
  1260. XX(*
  1261. XX    PToCStr - convert Pascal string to C string, in place
  1262. XX    CToPStr - convert C string to Pascal string, in place
  1263. XX
  1264. XX    These are here because this program was originally written in C
  1265. XX    and it was easier simply to convert the strings to work with the
  1266. XX    same algorithm, than to convert the algorithm to work with Pascal
  1267. XX    strings.
  1268. XX*)
  1269. XX
  1270. XXProc PToCStr (s: ptrb);
  1271. XXvar
  1272. XX    i, len: integer;
  1273. XX{
  1274. XX    len := s[0];
  1275. XX    loop (len > 0, i := 0, ++i, i >= len)   (* move contents down one *)
  1276. XX        s[i] := s[i+1];
  1277. XX    s[len] := 0;        (* add terminating null byte *)
  1278. XX};
  1279. XX
  1280. XXProc CToPStr (s: ptrb);
  1281. XXvar
  1282. XX    i, len: integer;
  1283. XX{
  1284. XX    loop (, len := 0, ++len, )    (* determine length of string *)
  1285. XX        if s[len] = 0 then break;
  1286. XX    loop (len > 0, i := len, --i, i < 1)    (* move contents up one *)
  1287. XX        s[i] := s[i-1];
  1288. XX    s[0] := len;        (* set length byte *)
  1289. XX};
  1290. XX
  1291. XX
  1292. XX
  1293. XX(* ----------------------------------------------------------------------- *)
  1294. XX(*                        pattern-compilation routines                     *)
  1295. XX(* ----------------------------------------------------------------------- *)
  1296. XX
  1297. XX(*
  1298. XX    ADD - add char to pattern (may be a metachar, not necessarily
  1299. XX        a literal character to match)
  1300. XX*)
  1301. XX
  1302. XXProc add (c: byte);
  1303. XX{
  1304. XX    thePattern[pix] := c;
  1305. XX    ++pix;
  1306. XX    thePattern[pix] := 0;
  1307. XX
  1308. XX};    (* add *)
  1309. XX
  1310. XX(*
  1311. XX    Put a closure indicator into the pattern, in front of the
  1312. XX    stuff that's to be closed.
  1313. XX*)
  1314. XX
  1315. XXProc addclose ();
  1316. XXvar
  1317. XX    i: integer;
  1318. XX{
  1319. XX    ++pix;
  1320. XX    loop (, i := pix, (*--i*), --i <= pMark)
  1321. XX        thePattern [i] := thePattern [i-1];
  1322. XX    thePattern [pMark] := CLOSURE;
  1323. XX    canClose := false;
  1324. XX
  1325. XX};    (* addclose *)
  1326. XX
  1327. XX(*
  1328. XX    have found something that may be followed by a closure.  set
  1329. XX    canClose to indicate that fact, and set a mark to remember where
  1330. XX    the closable thing is.
  1331. XX*)
  1332. XX
  1333. XXProc markit ();
  1334. XX{
  1335. XX    pMark := pix;        (* set mark in case closure comes up next *)
  1336. XX    canClose := true;
  1337. XX};
  1338. XX
  1339. XX(*
  1340. XX    compile character class.  pass pointer to char after '[' that begins
  1341. XX    the class pattern.  Return nil if error, else pointer to char
  1342. XX    after closing ']' bracket.
  1343. XX*)
  1344. XX
  1345. XXFunc Class (p: ptrb): ptrb;
  1346. XXvar
  1347. XX    c, type, low, high: byte;
  1348. XX{
  1349. XX    Class := nil;
  1350. XX    type := CCL;            (* 'character class' metachar *)
  1351. XX    if p^ = '^' then
  1352. XX    {
  1353. XX        type := NCCL;       (* 'match all but this class' metachar *)
  1354. XX        ++p;
  1355. XX    };
  1356. XX    add (type);
  1357. XX    loop (,,,)
  1358. XX    {
  1359. XX        c := p^;
  1360. XX        ++p;
  1361. XX        if c = ']' then break;          (* end of class pattern *)
  1362. XX        if c = 0 then return;           (* missing ']' - pattern error *)
  1363. XX        if p^ <> '-' then
  1364. XX            add (c)
  1365. XX        else        (* range *)
  1366. XX        {
  1367. XX            low := c;                   (* low end *)
  1368. XX            ++p;
  1369. XX            high := p^;                 (* high end *)
  1370. XX            ++p;
  1371. XX            if high = 0 then return;    (* pattern error *)
  1372. XX            add (byte (CRANGE));
  1373. XX            add (low);
  1374. XX            add (high);
  1375. XX        };
  1376. XX    };
  1377. XX    add (byte (ENDCCL));
  1378. XX    Class := p;    (* all ok *)
  1379. XX
  1380. XX};    (* class *)
  1381. XX
  1382. XX(*
  1383. XX    COMPILE - compile string into internal form suitable for efficient
  1384. XX        pattern matching.  String should be in C format.
  1385. XX*)
  1386. XX
  1387. XXFunc Compile (p: ptrb): boolean;
  1388. XXvar
  1389. XX    c: byte;
  1390. XX{
  1391. XX    Compile := false;
  1392. XX    pix := 0;
  1393. XX    thePattern[0] := 0;
  1394. XX    canClose := false;
  1395. XX    matchBol := false;
  1396. XX(*
  1397. XX    check for ^ - it's only special at beginning of line
  1398. XX*)
  1399. XX    if p^ = '^' then
  1400. XX    {
  1401. XX        matchBol := true;
  1402. XX        ++p;
  1403. XX    };
  1404. XX    loop (,,,)
  1405. XX    {
  1406. XX        c := p^;
  1407. XX        ++p;
  1408. XX
  1409. XX        if c = '*' then
  1410. XX        {
  1411. XX(*
  1412. XX    if canClose is true, there was a preceding pattern which can be
  1413. XX    closed (not closure, ^ or $), so close it.  otherwise, take *
  1414. XX    literally.
  1415. XX*)
  1416. XX            if canClose then    (* something to close *)
  1417. XX            {
  1418. XX                addclose ();
  1419. XX                continue;
  1420. XX            };
  1421. XX        };
  1422. XX
  1423. XX        if (c = '$') and (p^ = 0) then
  1424. XX(*
  1425. XX    $ only special at end of line
  1426. XX*)
  1427. XX        {
  1428. XX            add (byte (EOL));
  1429. XX            continue;
  1430. XX        };
  1431. XX(*
  1432. XX    at this point we know we have a character that can be followed by a
  1433. XX    closure, so mark the pattern position.
  1434. XX*)
  1435. XX        markit ();
  1436. XX        if c = '\\' then
  1437. XX        {
  1438. XX(*
  1439. XX    use escaped chars literally, except null, which is an error
  1440. XX*)
  1441. XX            if p^ = 0 then return;      (* pattern error *)
  1442. XX            add (p^);
  1443. XX            ++p;
  1444. XX            continue;
  1445. XX        };
  1446. XX        if c = 0 then break;            (* done compiling *)
  1447. XX        case integer(c) of
  1448. XX            '.': add (byte (ANY));      (* match any char *)
  1449. XX            '[':                        (* match character class *)
  1450. XX            {
  1451. XX                p := class (p);
  1452. XX                if p = nil then return; (* class pattern error *)
  1453. XX            };
  1454. XX            otherwise add (c);          (* match char literally *)
  1455. XX        end;
  1456. XX
  1457. XX    };  (* loop *)
  1458. XX
  1459. XX    Compile := true;    (* all ok *)
  1460. XX
  1461. XX};    (* compile *)
  1462. XX
  1463. XX(* ----------------------------------------------------------------------- *)
  1464. XX(*                         pattern-matching routines                       *)
  1465. XX(* ----------------------------------------------------------------------- *)
  1466. XX
  1467. XX(*
  1468. XX    NEXTPOS - find position in pattern of next component to match
  1469. XX*)
  1470. XX
  1471. XXFunc NextPos (p: ptrb): ptrb;
  1472. XXvar
  1473. XX    c: byte;
  1474. XX{
  1475. XX    c := p^;
  1476. XX    ++p;
  1477. XX    if (c = CCL) or (c = NCCL) then
  1478. XX    {
  1479. XX        loop (,,, c = ENDCCL)        (* look for end of class stuff *)
  1480. XX        {
  1481. XX            c := p^;
  1482. XX            ++p;
  1483. XX        };
  1484. XX    };
  1485. XX    NextPos := p;
  1486. XX
  1487. XX};    (* nextpos *)
  1488. XX
  1489. XXFunc InClass (c: byte; p: ptrb): Boolean;
  1490. XXvar
  1491. XX    high, low, pc: byte;
  1492. XX{
  1493. XX    InClass := false;
  1494. XX    loop (,,,)
  1495. XX    {
  1496. XX        pc := p^;
  1497. XX        ++p;
  1498. XX        if pc = ENDCCL then return;
  1499. XX        if pc = CRANGE then     (* range *)
  1500. XX        {
  1501. XX            low := p^;
  1502. XX            ++p;
  1503. XX            high := p^;
  1504. XX            ++p;
  1505. XX            if (low <= c) and (c <= high) then
  1506. XX                break;          (* it's within the range *)
  1507. XX        }
  1508. XX        else if c = pc then
  1509. XX            break;              (* it matched this char of class *)
  1510. XX    };
  1511. XX    InClass := true;
  1512. XX
  1513. XX};    (* inclass *)
  1514. XX
  1515. XX(*
  1516. XX    OMATCH - match character c against the current pattern position.
  1517. XX*)
  1518. XX
  1519. XXFunc omatch (c: byte; p: ptrb): boolean;
  1520. XXvar
  1521. XX    pc: byte;
  1522. XX{
  1523. XX    pc := p^;
  1524. XX    ++p;
  1525. XX    case integer(pc) of
  1526. XX        CCL: return (inclass (c, p));
  1527. XX        NCCL: return (!inclass (c, p));
  1528. XX        ANY: return (boolean (c <> 0)); (* don't match end of line *)
  1529. XX        otherwise return (boolean (c = pc));
  1530. XX    end;
  1531. XX
  1532. XX};    (* omatch *)
  1533. XX
  1534. XX(*
  1535. XX    try to match pattern p at the given position in string s
  1536. XX*)
  1537. XX
  1538. XXFunc amatch (s, p: ptrb): boolean;
  1539. XXvar
  1540. XX    c: byte;
  1541. XX    cursp: ptrb;
  1542. XX{
  1543. XX    if p^ = 0 then return (true);    (* end of pattern, have matched it *)
  1544. XX    if p^ = EOL then
  1545. XX        return (boolean (s^ = 0));    (* must be end of string to match EOL *)
  1546. XX
  1547. XX    if p^ = CLOSURE then
  1548. XX    {
  1549. XX(*
  1550. XX    advance as far as possible, matching the current pattern position.
  1551. XX    when omatch fails, s will point 1 past the character that failed.
  1552. XX    back up one and try to match rest of pattern.  if that fails, keep
  1553. XX    retreating until back at point of original closure start.
  1554. XX*)
  1555. XX        ++p;        (* skip closure marker *)
  1556. XX        cursp := s;    (* save current string position *)
  1557. XX        loop (,, c := s^; ++s, omatch (c, p) = false)
  1558. XX            ;
  1559. XX        loop (,,, s <= cursp)    (* keep backing up *)
  1560. XX        {
  1561. XX            --s;
  1562. XX            if amatch (s, nextpos (p)) then return (true);
  1563. XX        };
  1564. XX        return (false);
  1565. XX    };
  1566. XX    c := s^;
  1567. XX    ++s;
  1568. XX    if omatch (c, p) then
  1569. XX        return (amatch (s, nextpos (p)));
  1570. XX    amatch := false;
  1571. XX
  1572. XX};    (* amatch *)
  1573. XX
  1574. XX(*
  1575. XX    MATCH - match string s against the compiled pattern
  1576. XX
  1577. XX    if matchBol is true, then anchor the match to the beginning of the
  1578. XX    string, else try the pattern against successive string positions until
  1579. XX    the match succeeds or the end of the string is reached.
  1580. XX
  1581. XX    s should be in C format.
  1582. XX*)
  1583. XX
  1584. XXFunc match (s: PtrB): boolean;
  1585. XX{
  1586. XX    if matchBol then    (* anchored match *)
  1587. XX    {
  1588. XX        return (amatch (s, thePattern));
  1589. XX    };
  1590. XX    loop (,,,)          (* floating match *)
  1591. XX    {
  1592. XX        if amatch (s, thePattern) then return (true);
  1593. XX        if s^ = 0 then return (false);  (* end of string but no match *)
  1594. XX        ++s;
  1595. XX    };
  1596. XX
  1597. XX};    (* match *)
  1598. XX
  1599. XX
  1600. XX(* ----------------------------------------------------------------------- *)
  1601. XX(*                 Display dialog box to get the pattern                   *)
  1602. XX(* ----------------------------------------------------------------------- *)
  1603. XX
  1604. XX(*
  1605. XX    item    type
  1606. XX    1       ok button
  1607. XX    2       cancel button
  1608. XX    3       prompt
  1609. XX    4       edittext item for typing in pattern
  1610. XX    5       "lines containing pattern" radio button
  1611. XX    6       "lines not containing pattern" radio button
  1612. XX    7       "print line numbers" check box
  1613. XX
  1614. XX    Puts the string entered into theString, which on return is
  1615. XX    empty if either the user clicked cancel or typed no string
  1616. XX    and clicked ok.
  1617. XX*)
  1618. XX
  1619. XXProcedure SetValue (itemNo: Integer; itemValue: Boolean);
  1620. XXvar
  1621. XX    itemHandle: Handle;
  1622. XX    itemType: Integer;
  1623. XX    rect: Rect;
  1624. XX{
  1625. XX    GetDItem (theDialog, itemNo, @itemType, @itemHandle, rect);
  1626. XX(*
  1627. XX    Note type conversion here.  True turns the control on.
  1628. XX*)
  1629. XX    SetCtlValue (itemHandle, Integer (itemValue));
  1630. XX};
  1631. XX
  1632. XXFunction GetValue (itemNo: integer): Boolean;
  1633. XXvar
  1634. XX    itemHandle: Handle;
  1635. XX    itemType: integer;
  1636. XX    rect: Rect;
  1637. XX{
  1638. XX    GetDItem (theDialog, itemNo, @itemType, @itemHandle, rect);
  1639. XX(*
  1640. XX    Note implicit type conversion here.  Any non-zero is true.
  1641. XX*)
  1642. XX    GetValue := GetCtlValue (itemhandle);
  1643. XX};
  1644. XX
  1645. XX(*
  1646. XX    Set the type of line to select.  Pass the value for the "Match lines
  1647. XX    containing pattern" button.
  1648. XX*)
  1649. XX
  1650. XXProc SetMatchType (withval: Boolean);
  1651. XX{
  1652. XX    SetValue (linesRadioButton, withval);
  1653. XX    SetValue (noLinesRadioButton, !withval);
  1654. XX};
  1655. XX
  1656. XX
  1657. XXFunc GetPatDlog (): Boolean;
  1658. XXVar
  1659. XX    itemNo, itemType: Integer;
  1660. XX    itemHandle: Handle;
  1661. XX    rect: Rect;
  1662. XX{
  1663. XX    GetPatDlog := false;
  1664. XX    theDialog := GetNewDialog (resBase, nil, -1L);
  1665. XX    SetMatchType (matchType);
  1666. XX    SetValue (numbersCheckBox, prtLineNum);
  1667. XX    GetDItem (theDialog, patText, @itemType, @itemHandle, rect);
  1668. XX    SetIText (itemHandle, rawPattern);
  1669. XX    SelIText (theDialog, patText, 0, 32760);
  1670. XX    ShowWindow (theDialog);
  1671. XX    loop (,,,)
  1672. XX    {
  1673. XX        ModalDialog (nil, @itemNo);
  1674. XX        case itemNo of
  1675. XX            okButton:
  1676. XX            {
  1677. XX                GetDItem (theDialog, patText, @itemType, @itemHandle, rect);
  1678. XX                GetIText (itemHandle, rawPattern);
  1679. XX                matchType := GetValue (linesRadioButton);
  1680. XX                prtLineNum := GetValue (numbersCheckBox);
  1681. XX                GetPatDlog := true;
  1682. XX                break;
  1683. XX            };
  1684. XX            cancelButton: break;
  1685. XX            linesRadioButton: SetMatchType (true);
  1686. XX            noLinesRadioButton: SetMatchType (false);
  1687. XX            numbersCheckBox:
  1688. XX                SetValue (numbersCheckBox, !GetValue (numbersCheckBox));
  1689. XX        end;
  1690. XX    };
  1691. XX    DisposDialog (theDialog);
  1692. XX
  1693. XX};    (* GetPatDlog *)
  1694. XX
  1695. XX
  1696. XXProc GetGrepPat ();
  1697. XX{
  1698. XX    if GetPatDlog () then
  1699. XX    {
  1700. XX        PToCStr (rawPattern);
  1701. XX        havePat := Compile (rawPattern);
  1702. XX        CtoPStr (rawPattern);
  1703. XX        if !havePat then
  1704. XX            Alarm ("Bad Pattern");
  1705. XX    };
  1706. XX};
  1707. XX
  1708. XX
  1709. XX(* ----------------------------------------------------------------------- *)
  1710. XX(*                         Pattern Initialization                          *)
  1711. XX(* ----------------------------------------------------------------------- *)
  1712. XX
  1713. XX(*
  1714. XX    Set pattern initially to empty pattern.  This is legal - it matches
  1715. XX    every line.  If a file is grepped without specifying a pattern, therefore,
  1716. XX    the whole file will be displayed.  A side effect of this is to turn
  1717. XX    grep on WORD files into a WORD-to-TEXT file converter, when the save
  1718. XX    output option is turned on.
  1719. XX*)
  1720. XX
  1721. XXProc InitPat ();
  1722. XX{
  1723. XX    rawPattern[0] := 0;
  1724. XX    havePat := Compile (rawPattern);
  1725. XX};
  1726. SHAR_EOF
  1727. if test 13365 -ne "`wc -c GrepPatStuff.src`"
  1728. then
  1729. echo shar: error transmitting GrepPatStuff.src '(should have been 13365 characters)'
  1730. fi
  1731. echo shar: extracting Grep-Wc.src '(14893 characters)'
  1732. sed 's/^XX//' << \SHAR_EOF > Grep-Wc.src
  1733. XXProgram Grep_Wc;
  1734. XX
  1735. XX(*
  1736. XX    Grep - Globally search for Regular Expressions and Print, i.e.,
  1737. XX        g/r.e./p
  1738. XX
  1739. XX    Wc - char, word, line/paragraph count
  1740. XX
  1741. XX    Special characters for patterns
  1742. XX
  1743. XX    ^       Match beginning of line (if at beginning of pattern)
  1744. XX    $       Match end of line (if at end of pattern)
  1745. XX    .       Match any character
  1746. XX    [..]    Match class of characters.  If first character following
  1747. XX            the [ is ^, match all BUT the range of characters.  A range
  1748. XX            of characters may be specified by separating them with a
  1749. XX            dash, e.g., [a-z].  The dash itself may be included as a class
  1750. XX            member by giving it as the first class char (e.g., [-a-z]).
  1751. XX    *       Match any number of preceding things (if does not follow
  1752. XX            *, ^ or $)
  1753. XX
  1754. XX    characters which have special meanings only in certain places in
  1755. XX    the pattern do not have that meaning elsewhere.  Special meaning
  1756. XX    may be turned off otherwise (except within a class) by escaping
  1757. XX    it with '\'.  The backslash may be entered into a pattern by
  1758. XX    doubling it.
  1759. XX
  1760. XX    Version 1.0     12 March 1986
  1761. XX
  1762. XX    Paul DuBois
  1763. XX    Wisconsin Regional Primate Research Center
  1764. XX    1220 Capitol Court
  1765. XX    University of Wisconsin-Madison
  1766. XX    Madison, WI  53706
  1767. XX
  1768. XX    UUCP: {allegra, ihnp4, seismo}!uwvax!uwmacc!dubois
  1769. XX*)
  1770. XX
  1771. XX
  1772. XXUses
  1773. XX    GrepPatStuff    (* pattern compilation and matching routines *)
  1774. XX    __StreamLib
  1775. XX    __DeskLib
  1776. XX    __ToolTraps
  1777. XX    __QuickDraw
  1778. XX    __OSTraps
  1779. XX    (*$U+*)
  1780. XX    uGrep   (* global constants, types, and variables *)
  1781. XX    ;
  1782. XX
  1783. XXLink
  1784. XX    GrepPatStuff
  1785. XX    __StreamLib
  1786. XX    __DeskLib
  1787. XX    __OSTraps
  1788. XX    : ;
  1789. XX
  1790. XX
  1791. XXConst
  1792. XX
  1793. XX    bufSiz = 512;
  1794. XX    curApplName = $910L;        (* location of name of current application *)
  1795. XX    defaultResID = -15552;      (* DRVR 26 base id *)
  1796. XX
  1797. XX
  1798. XX(*  menu item numbers  *)
  1799. XX
  1800. XX    itemAbout = 1;
  1801. XX    (* --- *)
  1802. XX    itemCount = 3;
  1803. XX    itemSearch = 4;
  1804. XX    itemPattern = 5;
  1805. XX    itemOutput = 6;
  1806. XX
  1807. XXVar
  1808. XX(*
  1809. XX    For a good time, declare thePort: WindowPtr (=GrafPtr!) and try to compile.
  1810. XX    Then look in uToolIntf under WindowPtr and sprout question marks.
  1811. XX*)
  1812. XX    thePort:    GrafPtr;
  1813. XX    teHand:     TEHandle;
  1814. XX    streamInfo: SFReply;
  1815. XX    theMenu:    MenuHandle;
  1816. XX    theMenuID:  Integer;
  1817. XX    resBase:    Integer;    (* base resource id *)
  1818. XX    matchType:  Boolean;    (* true: print lines w/pattern. false: inverse *)
  1819. XX    prtLineNum: Boolean;    (* print line numbers if true *)
  1820. XX    havePat:    Boolean;    (* whether have good pattern or not *)
  1821. XX    lineNum:    LongInt;
  1822. XX    paused:     Boolean;
  1823. XX    fileOpen:   Boolean;
  1824. XX    outFile:    Integer;
  1825. XX    outReply:   SFReply;
  1826. XX
  1827. XX    pauseCtl:   ControlHandle;
  1828. XX    cancelCtl:  ControlHandle;
  1829. XX    grepping:   Boolean;
  1830. XX
  1831. XX
  1832. XX
  1833. XXProc GrepState (val: Integer);
  1834. XX{
  1835. XX    HiliteControl (pauseCtl, val);
  1836. XX    HiliteControl (cancelCtl, val);
  1837. XX    grepping := !Boolean (val);
  1838. XX};
  1839. XX
  1840. XX
  1841. XX(*
  1842. XX    Cancel any current grep operation.
  1843. XX    Must not be called before InitStream.
  1844. XX*)
  1845. XX
  1846. XXProc StopGrep ();
  1847. XX{
  1848. XX    if grepping then
  1849. XX    {
  1850. XX        CloseStream ();
  1851. XX        GrepState (255);
  1852. XX    };
  1853. XX};
  1854. XX
  1855. XX
  1856. XXProc DrawStuff ();
  1857. XX{
  1858. XX    DrawControls (thePort);
  1859. XX    MoveTo (0, 24);
  1860. XX    LineTo (1000, 24);
  1861. XX    TEUpdate (teHand^^.viewRect, tehand);
  1862. XX};
  1863. XX
  1864. XX
  1865. XX
  1866. XXProc Alarm (mesg: PtrB);
  1867. XXVar
  1868. XX    result: Integer;
  1869. XX{
  1870. XX    ParamText (mesg, "", "", "");
  1871. XX    result := Alert (resBase+2, nil);
  1872. XX};
  1873. XX
  1874. XX
  1875. XXProc FileOutput ();
  1876. XXVar
  1877. XX    f: FInfo;
  1878. XX    result: OSErr;
  1879. XX    s: PtrB;
  1880. XX    p: ParamBlockRec;
  1881. XX    ok: Boolean;
  1882. XX{
  1883. XX    s := nil;
  1884. XX    if fileOpen then    (* close it *)
  1885. XX    {
  1886. XX        fileOpen := false;
  1887. XX        p.ioRefNum := outFile;
  1888. XX        result := PBGetFPos (p, false);
  1889. XX        p.ioMisc := p.ioPosOffset;
  1890. XX        result := PBSetEOF (p, false);
  1891. XX        result := FSClose (outFile);
  1892. XX        s := "Save Output...";
  1893. XX    }
  1894. XX    else
  1895. XX    {
  1896. XX        if EqualString ("Finder", curApplName, false, true) then
  1897. XX        {
  1898. XX            Alarm ("Not In Finder");
  1899. XX            return;
  1900. XX        };
  1901. XX        Toolbox($A9EA, 100, 70, "Write To...", "", nil, @outReply, 1);
  1902. XX        if outReply.good then
  1903. XX        {
  1904. XX            if GetFInfo (outReply.fName, outReply.vRefNum, @f) = noErr then  (* exists *)
  1905. XX            {
  1906. XX                if f.fdType <> PtrL (" TEXT"+2)^ then
  1907. XX                {
  1908. XX                    Alarm ("Not A TEXT File");
  1909. XX                    return;
  1910. XX                };
  1911. XX            }
  1912. XX            else    (* doesn't exist.  create it. *)
  1913. XX            {
  1914. XX                if Create (outReply.fName, outReply.vRefNum, PtrL (" Grep"+2)^,
  1915. XX                    PtrL (" TEXT"+2)^) <> noErr then
  1916. XX                {
  1917. XX                    Alarm ("Can't Create");
  1918. XX                    return;
  1919. XX                };
  1920. XX            };
  1921. XX            if _FSOpen (outReply.fName, outReply.vRefNum, @outFile, fsWrPerm)
  1922. XX                    <> noErr
  1923. XX                then Alarm ("Can't Open")
  1924. XX            else
  1925. XX            {
  1926. XX                fileOpen := true;
  1927. XX                s := "Stop Saving Output";
  1928. XX            };
  1929. XX        };
  1930. XX    };
  1931. XX    if s <> nil then
  1932. XX        SetItem (theMenu, itemOutPut, s);
  1933. XX};
  1934. XX
  1935. XX(*
  1936. XX    Add string to display area.  First insert it at the end.  Test if
  1937. XX    must scroll lines off top to get the new stuff to show up.  If yes,
  1938. XX    then do the scroll.  To keep from filling up the TERec, delete
  1939. XX    whatever got scrolled out of view every once in a while.  (The number
  1940. XX    of lines scrolled off the top to check for is arbitrary - I clobber
  1941. XX    stuff after every 25 lines.)  To avoid unnecessary redrawing, set to
  1942. XX    no clip before doing the delete (which would redraw) and the scroll
  1943. XX    back down (which would also redraw).
  1944. XX
  1945. XX    Also write string to output file if one is open.
  1946. XX*)
  1947. XX
  1948. XXProc DisplayString (theStr: PtrB);
  1949. XXVar
  1950. XX    dispLines: Integer;     (* number of lines displayable in window *)
  1951. XX    topLines: Integer;      (* number of lines currently scrolled off top *)
  1952. XX    scrollLines: Integer;   (* number of lines to scroll up *)
  1953. XX    height: Integer;
  1954. XX    r: Rect;
  1955. XX    len: LongInt;
  1956. XX{
  1957. XX    len := theStr[0];
  1958. XX    height := teHand^^.lineHeight;
  1959. XX    TESetSelect (32760L, 32760L, teHand); (* set to insert at end *)
  1960. XX    TEInsert (theStr+1, len, teHand);
  1961. XX    r := teHand^^.viewRect;
  1962. XX    dispLines := (r.bottom - r.top) / height;
  1963. XX    topLines := (r.top-teHand^^.destRect.top) / height;
  1964. XX    scrollLines := teHand^^.nLines - topLines - dispLines;
  1965. XX    if scrollLines > 0 then (* must scroll up *)
  1966. XX    {
  1967. XX        TEScroll (0, Integer (-height * scrollLines), teHand); (* scroll up *)
  1968. XX        topLines += scrollLines;
  1969. XX        if topLines > 25 then    (* keep TERec from filling up *)
  1970. XX        {
  1971. XX(*
  1972. XX    now clobber first line(s), and scroll back down to resync what will
  1973. XX    then be the first line.  Set clipping empty, so that the redraw from the
  1974. XX    delete and the scroll down will not be shown.
  1975. XX*)
  1976. XX            SetRect (r, 0, 0, 0, 0);
  1977. XX            ClipRect (r);
  1978. XX            TESetSelect (0L, LongInt (teHand^^.lineStarts[topLines]), teHand);
  1979. XX            TEDelete (teHand);
  1980. XX            TEScroll (0, Integer (height * topLines), teHand);
  1981. XX            ClipRect (thePort^.portRect);
  1982. XX        };
  1983. XX    };
  1984. XX    if fileOpen then
  1985. XX    {
  1986. XX        if FSWrite (outFile, @len, theStr+1) <> noErr then
  1987. XX        {
  1988. XX            Alarm ("Write Error (Closing File)");
  1989. XX            FileOutput ();
  1990. XX        };
  1991. XX    };
  1992. XX};
  1993. XX
  1994. XX
  1995. XXProc DisplayLn ();
  1996. XX{
  1997. XX    DisplayString ("\r");
  1998. XX};
  1999. XX
  2000. XX
  2001. XXProc DisplayLong (long: LongInt);
  2002. XXVar
  2003. XX    str: Byte[18];
  2004. XX    s: PtrB;
  2005. XX{
  2006. XX    s := str;
  2007. XX    RegCall (Trap $A9EE, s, , long, 0);     (* NumToString *)
  2008. XX    DisplayString (str);
  2009. XX};
  2010. XX
  2011. XX
  2012. XX
  2013. XXFunc GetStream (): Boolean;
  2014. XXVar
  2015. XX    s: Byte[5];
  2016. XX    i: Integer;
  2017. XX{
  2018. XX    GetStream := false;
  2019. XX    if OpenStream () = noErr then
  2020. XX    {
  2021. XX        GetStream := true;
  2022. XX        if thePort <> FrontWindow () then
  2023. XX            SelectWindow (thePort);
  2024. XX        GetStreamInfo (streamInfo);
  2025. XX        DisplayString (streamInfo.fName);
  2026. XX        DisplayString (" (");
  2027. XX        s[0] := 4;
  2028. XX        (*PtrL (@s[1])^ := streamInfo.fType;*)  (* doesn't work - odd addr! *)
  2029. XX        loop ( , i:=0, ++i, i > 3)
  2030. XX            s[i+1] := (PtrB (@streamInfo.fType))[i];
  2031. XX        DisplayString (s);
  2032. XX        DisplayString (" file)\r");
  2033. XX    };
  2034. XX    DrawStuff ();
  2035. XX};
  2036. XX
  2037. XX(*
  2038. XX    Display lines matching (or not matching) pattern.  This is called to
  2039. XX    get a line at a time from _Main.  Mouse clicks in _Mouse control the
  2040. XX    state of the pause variable.
  2041. XX*)
  2042. XX
  2043. XXProc GrepLine ();
  2044. XXVar
  2045. XX    buf: block[bufSiz];
  2046. XX{
  2047. XX    if !paused then
  2048. XX    {
  2049. XX        if StreamGetS (buf) = nil then
  2050. XX        {
  2051. XX            StopGrep ();
  2052. XX        }
  2053. XX        else
  2054. XX        {
  2055. XX            ++lineNum;
  2056. XX            PToCStr (buf);
  2057. XX            if match (buf) = matchType then
  2058. XX            {
  2059. XX                if prtLineNum then
  2060. XX                {
  2061. XX                    DisplayLong (lineNum);
  2062. XX                    DisplayString (": ");
  2063. XX                };
  2064. XX                CtoPStr (buf);
  2065. XX                DisplayString (buf);
  2066. XX                DisplayLn ();
  2067. XX            };
  2068. XX        };
  2069. XX    };
  2070. XX};
  2071. XX
  2072. XX
  2073. XX
  2074. XX(*
  2075. XX    Catch mouse down events, and interpret if window grow event.  This is
  2076. XX    difficult to test inside of Rascal, since it will catch mouse downs
  2077. XX    in the grow region and size the window itself.  Can't use FindWindow
  2078. XX    in _Event when running as a DA, since it returns inSysWindow for a
  2079. XX    part code, not inGrow!
  2080. XX*)
  2081. XX
  2082. XXProc _MOUSE (x, y: Integer);
  2083. XXVar
  2084. XX    ctl: ControlHandle;
  2085. XX    thePt: Point;
  2086. XX    r: Rect;
  2087. XX{
  2088. XX    thePt.h := x;
  2089. XX    thePt.v := y;
  2090. XX    r := thePort^.portRect; (* see the mouse was pressed in grow region *)
  2091. XX    r.left := r.right - 15;
  2092. XX    r.top := r.bottom - 15;
  2093. XX    if PtInRect (thePt.vh, r) then
  2094. XX    {
  2095. XX        LocalToGlobal (@thePt);
  2096. XX        SetRect (r, 170, 60, 512, 342);
  2097. XX        thePt.vh := GrowWindow (thePort, thePt.vh, r);
  2098. XX        SizeWindow (thePort, thePt.h, thePt.v, true);
  2099. XX        r := thePort^.portRect;
  2100. XX        ClipRect (r);
  2101. XX(*
  2102. XX    Reset the text viewRect.  It's not necessary to reset the destRect,
  2103. XX    since only the top and left are used, and they haven't changed.
  2104. XX*)
  2105. XX        r.top += 25;
  2106. XX        r.left += 6;
  2107. XX        teHand^^.viewRect := r;
  2108. XX    }
  2109. XX    else if FindControl (thePt.vh, thePort, @ctl) then
  2110. XX    {
  2111. XX        if TrackControl (ctl, thePt.vh, nil) then
  2112. XX        {
  2113. XX            if ctl = cancelCtl then
  2114. XX            {
  2115. XX                StopGrep ();
  2116. XX            }
  2117. XX            else if ctl = pauseCtl then
  2118. XX            {
  2119. XX                if paused then
  2120. XX                    SetCTitle (pauseCtl, "Pause")
  2121. XX                else
  2122. XX                    SetCTitle (pauseCtl, "Resume");
  2123. XX                paused := !paused;
  2124. XX            };
  2125. XX        };
  2126. XX    };
  2127. XX};
  2128. XX
  2129. XX
  2130. XXProc Wc ();
  2131. XXVar
  2132. XX    lines, nonEmptyLines, words, chars: LongInt;
  2133. XX    inToken: Boolean;
  2134. XX    c, lastc: Integer;
  2135. XX{
  2136. XX    lines := 0;
  2137. XX    nonEmptyLines := 0;
  2138. XX    words := 0;
  2139. XX    chars := 0;
  2140. XX    inToken := false;
  2141. XX    loop (, lastc := '\r', lastc := c,)
  2142. XX    {
  2143. XX        c := StreamGetC ();
  2144. XX        if c = -1 then break;   (* eof *)
  2145. XX        ++chars;
  2146. XX        case c of
  2147. XX            '\r':
  2148. XX            {
  2149. XX                ++lines;
  2150. XX                if lastc <> '\r' then
  2151. XX                    ++nonEmptyLines;
  2152. XX                inToken := false;
  2153. XX            };
  2154. XX            ' ',
  2155. XX            '\t': inToken := false;
  2156. XX            otherwise
  2157. XX                if inToken = false then
  2158. XX                {
  2159. XX                    ++words;
  2160. XX                    inToken := true;
  2161. XX                };
  2162. XX        end;
  2163. XX    };
  2164. XX    if (lastc <> '\r') then    (* in case of missing cr on last line *)
  2165. XX    {
  2166. XX        ++lines;
  2167. XX        ++nonEmptyLines;
  2168. XX    };
  2169. XX    DisplayLong (chars);
  2170. XX    DisplayString (" Chars, ");
  2171. XX    DisplayLong (words);
  2172. XX    DisplayString (" Words, ");
  2173. XX    DisplayLong (lines);
  2174. XX    if streamInfo.fType = PtrL (" TEXT"+2)^ then
  2175. XX        DisplayString (" Lines")
  2176. XX    else
  2177. XX    {
  2178. XX        DisplayString (" Paragraphs (");
  2179. XX        DisplayLong (nonEmptyLines);
  2180. XX        DisplayString (" non-empty)");
  2181. XX    };
  2182. XX    DisplayLn ();
  2183. XX};
  2184. XX
  2185. XX
  2186. XXProc _INIT ();
  2187. XXVar
  2188. XX    r: Rect;
  2189. XX{
  2190. XX    GetPort(@thePort);
  2191. XX
  2192. XX(*  adapt to environment - am I a desk accessory or not?  *)
  2193. XX
  2194. XX    theMenuId := DAMenuInit ();
  2195. XX    resBase := defaultResID;
  2196. XX    if IsDARun () then
  2197. XX    {
  2198. XX        resBase := GetResIDBase ();
  2199. XX    };
  2200. XX
  2201. XX    theMenu := NewMenu (theMenuId, "Grep-Wc");
  2202. XX    InsertMenu (theMenu, 0);
  2203. XX    AppendMenu (theMenu,
  2204. XX    "About Grep-Wc;(-;Count...;Search...;Set Pattern...;Save Output...");
  2205. XX    DrawMenuBar ();
  2206. XX
  2207. XX    InitStream ();              (* set up for stream input *)
  2208. XX    InitPat ();                 (* initialize pattern *)
  2209. XX    fileOpen := false;          (* no output file currently *)
  2210. XX
  2211. XX(*  Initial option settings  *)
  2212. XX
  2213. XX    matchType := true;          (* print lines with pattern *)
  2214. XX    prtLineNum := false;        (* don't print line numbers *)
  2215. XX
  2216. XX(*  Create TERec and build controls  *)
  2217. XX
  2218. XX    r := thePort^.portRect;
  2219. XX    r.top += 25;            (* leave room for buttons *)
  2220. XX    r.left += 6;
  2221. XX    teHand := TENew (r, r);
  2222. XX    teHand^^.crOnly := -1;  (* no word wrap *)
  2223. XX    SetRect (r, 5, 2, 85, 22);
  2224. XX    pauseCtl :=
  2225. XX        NewControl (thePort, r, "Pause", true, 0, 0, 0, pushButProc, nil);
  2226. XX    OffSetRect (r, 90, 0);
  2227. XX    cancelCtl :=
  2228. XX        NewControl (thePort, r, "Cancel", true, 0, 0, 0, pushButProc, nil);
  2229. XX
  2230. XX    GrepState (255);    (* set grepping false, inactivate buttons *)
  2231. XX    DrawStuff ();
  2232. XX};
  2233. XX
  2234. XXProc _HALT ();
  2235. XX{
  2236. XX    CloseStream ();         (* close any open input file *)
  2237. XX    if fileOpen then        (* close output file if one is open *)
  2238. XX        FileOutPut ();
  2239. XX    KillControls (thePort); (* toss controls *)
  2240. XX    TEDispose (teHand);     (* toss text *)
  2241. XX    DeleteMenu (theMenuID); (* toss menu *)
  2242. XX    DisposeMenu (theMenu);
  2243. XX    DrawMenuBar ();
  2244. XX};
  2245. XX
  2246. XX
  2247. XXProc _UPDATE();
  2248. XX{
  2249. XX    DrawStuff ();
  2250. XX};
  2251. XX
  2252. XX
  2253. XXProc _MENU (id, item: Integer);
  2254. XX{
  2255. XX    case item of
  2256. XX        itemAbout:  item := Alert (resBase+1, nil);
  2257. XX        itemCount:
  2258. XX        {
  2259. XX            StopGrep ();        (* terminate any ongoing grep operation *)
  2260. XX            if GetStream () then
  2261. XX                Wc ();
  2262. XX        };
  2263. XX        itemSearch:
  2264. XX        {
  2265. XX            StopGrep ();        (* terminate any ongoing grep operation *)
  2266. XX            if !havePat then
  2267. XX                GetGrepPat ();
  2268. XX            if (* now *) havePat then
  2269. XX                if GetStream () then    (* do grep setup *)
  2270. XX                {
  2271. XX(*
  2272. XX    Don't comment this section out if you don't want the user
  2273. XX    to be able to grep his current output file.
  2274. XX                    if fileOpen then
  2275. XX                    {
  2276. XX                        if EqualString (outReply.fName, streamInfo.fName,
  2277. XX                                        false, true)
  2278. XX                        and (outReply.vRefNum = streamInfo.vRefNum) then
  2279. XX                        {
  2280. XX                            Alarm ("Can't Grep Output File");
  2281. XX                            return;
  2282. XX                        };
  2283. XX                    };
  2284. XX    end commenting out
  2285. XX*)
  2286. XX                    lineNum := 0;
  2287. XX                    paused := false;
  2288. XX                    SetCTitle (pauseCtl, "Pause");
  2289. XX                    GrepState (0);  (* turn controls on, grepping true *)
  2290. XX                };
  2291. XX        };
  2292. XX        itemPattern: GetGrepPat ();
  2293. XX        itemOutput: FileOutput ();
  2294. XX    end;
  2295. XX};
  2296. XX
  2297. XX
  2298. XXProc _MAIN ();
  2299. XX{
  2300. XX    if (thePort = FrontWindow ()) and grepping then GrepLine ();
  2301. XX};
  2302. SHAR_EOF
  2303. if test 14893 -ne "`wc -c Grep-Wc.src`"
  2304. then
  2305. echo shar: error transmitting Grep-Wc.src '(should have been 14893 characters)'
  2306. fi
  2307. echo shar: extracting Grep-Wc.rsrc.Hqx '(1535 characters)'
  2308. sed 's/^XX//' << \SHAR_EOF > Grep-Wc.rsrc.Hqx
  2309. XX(This file must be converted with BinHex 4.0)
  2310. XX
  2311. XX:$%GbCA!Y9f-ZFR0bB`"549K&8N008!#3#!422H%!N!3"!*!$!p%!!!,4!*!$IN(
  2312. XXX!J!J#0#I)%![#"!Z!!JJAa#!3H`%!P*3-#`%!NM!,`""l!)!)!M3Rb"!,`J`2!!
  2313. XX!)&m3J%jH)&rHr!!#6Y"19[rq3H`%!P*33HlrrLm)-#`%!L"I-)"J!!!H3HlrrP0
  2314. XX3-#`%"$m!-#lrrV"IAm"%!%S!CJ!!1M!Zrrj)`#m!3H`#!#!)d*mJ3#m)-$`!!6m
  2315. XX!-#lrrT!!AdM!,`""l!)!)!M3Rb"!%"!JAa#!B!$rVM!X"!4)`#m!3H`#!#!)d*m
  2316. XXJ3#m)-$`!"L"I%)""l!3',`J`2!!!)&m`J%jH6R9"l!3%,`J`,!3#)&m`J%(X"!B
  2317. XX!N!-9!#J!-J#L!E`!!3#3#-0!!*!%Y!!'!*!&3!%c!&3"E`3#6dX!N!9D!6-!EJ&
  2318. XX["!C$B@jMC@`!N!8'!!N!&`"$L!K3BA4dCA*Z1J#3"4d!#!!Y!AQ3!!#3"MN!"J"
  2319. XX0!0N''%aTEQ9c)%0[ER4KD@jTEQFJ8'&dG'9bEJ#3"8i!"J"L!0J'(%aTEQ9c)%j
  2320. XX[G#"$EfjdB@PZD@jR)&"KG(4PFQi!N!9M!!B!G`$B"3a-D@jP)%jeE@*PFR-!N!-
  2321. XX-!#`!%!$N!CE$384%!!!"RJ!%!*!&P!!b!+J!EJ3#6dX!N!8)!!F!KJ#BL(T(FQ9
  2322. XX`)#mJ9fpbC#"$Eh9ZG!ef-5i`)#!a-b"0BA*MD#!a16Jf$5K3G@*XD@-J4'pYB@P
  2323. XXZ+3d08'&eE#"%G8*[DA-0-6)b-#"$BA"TG'pX)%0[GA*d$8eKC'PcEfiJ9dNJ06-
  2324. XXh-$B0999$8$SJGAGYB@0M)@4eBQpTF`#3"4i![J#Z!0D)%&i0*!dZ$9XZ,Pd0$5S
  2325. XX0$9`!N!8H!0S!VJ'&L,"0BA4MD#"cG'&bG#"[CL"XD@jP$8eKG'0S)'9ZC#"[CL"
  2326. XXXD@jP$8eKG'0S)'&ZH5"MD'&bB@0dCA)06@&dBfJJB@jj)'0SBA*KBh4PFL"LCA4
  2327. XXhC@9Z)'*bB@0VCA4c$8eKG'0S)'&ZH5"ZG@eLCA)JEfBJG'KP)("bCACTEh9c)(4
  2328. XXSD@jR$94eFQiJEfCQ)(0`C@0TB@`JE@9KEQPZCb"[CL"ZCAKd)'0SBA*KBh4PFJ#
  2329. XX3"3J![J!D!A1)'P0`C@0TB@`J8'&dG'9bEL"$D'&bB@0dCA*cB@0dCA*cBQaTBb"
  2330. XXNEfeKD@iTG@*[DA-+!*!$)J!"!*!&8`"2!'F!L`3#6dX!N!8(!!B!4`#3!)J#AM!
  2331. XX!N!--!$)!0!#P!-M$3N4%!!!"!*!$!p%!!!,4!*!$IJ!!c"`!2J#3!a`!IJ!#4%P
  2332. XX86!!#!"T%6%p(!*!$2N&-8P3!!3"+`d,rrb!!!TX!N!6$3Irr)!!!i3!"-(,$32r
  2333. XXr)!!!'3#3"-0!rrmJ!*!(`d,rrb!!!X%!!5YS`d(rrb!!!0%!!5YXSC):
  2334. SHAR_EOF
  2335. if test 1535 -ne "`wc -c Grep-Wc.rsrc.Hqx`"
  2336. then
  2337. echo shar: error transmitting Grep-Wc.rsrc.Hqx '(should have been 1535 characters)'
  2338. fi
  2339. echo shar: extracting AddRes.src '(5070 characters)'
  2340. sed 's/^XX//' << \SHAR_EOF > AddRes.src
  2341. XXProgram AddRes;
  2342. XX
  2343. XXUses
  2344. XX    __ToolTraps
  2345. XX    __QuickDraw
  2346. XX    __OSTraps
  2347. XX    __DeskLib
  2348. XX    (*$U+*)
  2349. XX    uOSIntf
  2350. XX    uToolIntf
  2351. XX    uPackIntf
  2352. XX    ;
  2353. XX
  2354. XXLink
  2355. XX    __DeskLib
  2356. XX    __OSTraps
  2357. XX    __NoSysCall
  2358. XX    : ;
  2359. XX
  2360. XX
  2361. XXVar
  2362. XX    buttonTitle: PtrB;
  2363. XX
  2364. XX
  2365. XXProc PrintResType (resType: ResType);
  2366. XXVar
  2367. XX    i: Integer;
  2368. XX{
  2369. XX    loop (, i := 0, , ++i > 3)
  2370. XX    WriteChar (Integer (PtrB (@resType)[i]));
  2371. XX};
  2372. XX
  2373. XXProc CopyResources (srcResFile, dstResFile: Integer);
  2374. XXVar
  2375. XX    curRF: Integer;
  2376. XX    numTypes: Integer;
  2377. XX    numRes: Integer;
  2378. XX    resHand: Handle;
  2379. XX    resType: ResType;
  2380. XX    resId: Integer;
  2381. XX    resName: str255;
  2382. XX    i, j: Integer;
  2383. XX{
  2384. XX    WriteString ("Source, dest files ");
  2385. XX    WriteInt (srcResFile);
  2386. XX    WriteInt (dstResFile);
  2387. XX    WriteLn ();
  2388. XX    numTypes := CountTypes ();
  2389. XX    SetResFileAttrs (srcResFile, 128);  (* source map read only *)
  2390. XX    SetResPurge (true);
  2391. XX    loop (numTypes > 0, i := numTypes, , --i < 1)
  2392. XX    {
  2393. XX        GetIndType (@resType, i);   (* get name of resource type *)
  2394. XX        numRes := CountResources (resType);
  2395. XX        loop (numRes > 0, j := 1, , ++j > numRes)
  2396. XX        {
  2397. XX            curRF := CurResFile ();
  2398. XX            SetResLoad (false);
  2399. XX            resHand := GetIndResource (resType, j);
  2400. XX            SetResLoad (true);
  2401. XX            if HomeResFile (resHand) = srcResFile then
  2402. XX            {
  2403. XX                LoadResource (resHand);
  2404. XX                GetResInfo (resHand, @resId, @resType, resName);
  2405. XX                UseResFile (srcResFile);
  2406. XX                RmveResource (resHand);
  2407. XX                UseResFile (dstResFile);
  2408. XX                AddResource (resHand, resType, resId, resName);
  2409. XX                WriteString ("AddResource ");
  2410. XX                WriteInt (ResError());
  2411. XX                WriteLn ();
  2412. XX                HPurge (resHand);
  2413. XX                UseResFile (curRf);
  2414. XX                WriteString ("Added ");
  2415. XX                PrintResType (resType);
  2416. XX                WriteInt (resId);
  2417. XX                WriteChar (' ');
  2418. XX                WriteString (resName);
  2419. XX                WriteLn ();
  2420. XX            };
  2421. XX        };
  2422. XX    };
  2423. XX};
  2424. XX
  2425. XXFunction GFFilter (theItem: integer; theDialog: Ptrl): Integer; Clean;
  2426. XXvar
  2427. XX    itemNo: integer;
  2428. XX    itemType: integer;
  2429. XX    itemHandle: Handle;
  2430. XX    rect: Integer[4];
  2431. XX{
  2432. XX    DAClean (false);
  2433. XX    if theItem = -1 then    (* change name of "Open" button *)
  2434. XX    {
  2435. XX        GetDItem (theDialog, 1, @itemType, @itemHandle, rect);
  2436. XX        SetCTitle (itemHandle, buttonTitle);
  2437. XX    };
  2438. XX    GFFilter := theItem;
  2439. XX};
  2440. XX
  2441. XX
  2442. XXFunc GetFile(reply: ^SFReply; btnTitle: PtrB): Boolean;
  2443. XX{
  2444. XX    buttonTitle := btnTitle;
  2445. XX    Toolbox ($A9EA, 100, 50, " ", nil, -1, nil, GFFilter, reply, 2);
  2446. XX    GetFile := reply^.good;
  2447. XX};
  2448. XX
  2449. XXFunc myGetVol (): Integer;
  2450. XXVar
  2451. XX    p: ParamBlockRec;
  2452. XX    result: OSErr;
  2453. XX{
  2454. XX    p.ioCompletion := nil;
  2455. XX    p.ioNamePtr := nil;
  2456. XX    result := PBGetVol (p, false);
  2457. XX    myGetVol := p.ioVRefNum;
  2458. XX};
  2459. XX
  2460. XXProc mySetVol (v: Integer);
  2461. XXVar
  2462. XX    p: ParamBlockRec;
  2463. XX    result: OSErr;
  2464. XX{
  2465. XX    p.ioCompletion := nil;
  2466. XX    p.ioNamePtr := nil;
  2467. XX    p.ioVRefNum := v;
  2468. XX    result := PBSetVol (p, false);
  2469. XX};
  2470. XX
  2471. XX
  2472. XXFunc OpenResourceFile (name: PtrB; vRefNum: Integer): Integer;
  2473. XXVar
  2474. XX    curVol: Integer;
  2475. XX{
  2476. XX    curVol := myGetVol ();
  2477. XX    mySetVol (vRefNum);
  2478. XX    OpenResourceFile := OpenResFile (name);
  2479. XX    mySetVol (curVol);
  2480. XX};
  2481. XX
  2482. XX
  2483. XXProc CreateResourceFile (name: PtrB; vRefNum: Integer);
  2484. XXVar
  2485. XX    curVol: Integer;
  2486. XX{
  2487. XX    curVol := myGetVol ();
  2488. XX    mySetVol (vRefNum);
  2489. XX    CreateResFile (name);
  2490. XX    mySetVol (curVol);
  2491. XX};
  2492. XX
  2493. XX
  2494. XXProc _Init ();
  2495. XXVar
  2496. XX    srcResFile, dstResFile: Integer;
  2497. XX    srcReply, dstReply: SFReply;
  2498. XX    thePort: PtrL;
  2499. XX{
  2500. XX    DAClean (true);
  2501. XX    GetPort (@thePort);
  2502. XX    TextFont (0);
  2503. XX    TextSize (0);
  2504. XX    MoveWindow (thePort, 4, 235, false);
  2505. XX    SizeWindow (thePort, 504, 100, false);
  2506. XX    WriteString ("\nSelect the file you wish to copy resources FROM.\n");
  2507. XX    if GetFile (@srcReply, "Copy From") then
  2508. XX    {
  2509. XX        srcResFile := -1;
  2510. XX        WriteString ("Now select the file you wish to copy resources TO.\n");
  2511. XX        if GetFile (@dstReply, "Copy To") then
  2512. XX        {
  2513. XX            srcResFile := OpenResourceFile (srcReply.fName, srcReply.vRefNum);
  2514. XX            if srcResFile = -1 then
  2515. XX                WriteString ("Can't open input file.\n")
  2516. XX            else
  2517. XX            {
  2518. XX                dstResFile := OpenResourceFile (dstReply.fName,
  2519. XX                                                dstReply.vRefNum);
  2520. XX                if dstResFile = -1 then
  2521. XX                {
  2522. XX                    WriteString ("Creating resource fork - output file.\n");
  2523. XX                    CreateResourceFile (dstReply.fName, dstReply.vRefNum);
  2524. XX                    dstResFile := OpenResourceFile (dstReply.fName,
  2525. XX                                                      dstReply.vRefNum);
  2526. XX                    if dstResFile = -1 then
  2527. XX                        WriteString ("Couldn't create resource file.\n");
  2528. XX                };
  2529. XX                if dstResFile <> -1 then
  2530. XX                {
  2531. XX                    CopyResources (srcResFile, dstResFile);
  2532. XX                    CloseResFile (dstResFile);
  2533. XX                };
  2534. XX            };
  2535. XX        };
  2536. XX        if srcResFile <> -1 then
  2537. XX            CloseResFile (srcResFile);
  2538. XX    };
  2539. XX    ReqHalt ();
  2540. XX};
  2541. SHAR_EOF
  2542. if test 5070 -ne "`wc -c AddRes.src`"
  2543. then
  2544. echo shar: error transmitting AddRes.src '(should have been 5070 characters)'
  2545. fi
  2546. #    End of shell archive
  2547. exit 0
  2548.  
  2549.