Thread View: mod.mac.sources
1 messages
1 total messages
Started by Paul DuBois
Mon, 08 Dec 1986 16:05
Grep-Wc 1.1 sources
Author: Paul DuBois
Date: Mon, 08 Dec 1986 16:05
Date: Mon, 08 Dec 1986 16:05
1734 lines
39292 bytes
39292 bytes
#!/bin/sh
# shar: Shell Archiver
# Run the following text with /bin/sh to create:
# Grep.src/Grep.h
# Grep.src/GrepGrep.c
# Grep.src/GrepIO.c
# Grep.src/GrepMain.c
# Grep.src/GrepPattern.c
sed 's/^X//' << 'SHAR_EOF' > Grep.src/Grep.h
X/*
X Grep.h - Grep-Wc header file
X*/
X
X# include <ControlMgr.h>
X# include <MenuMgr.h>
X# include <TextEdit.h>
X# include <pascal.h>
X
X# define nil (0L)
X# define bufSiz 512
X# define monaco 4
X
X
Xtypedef enum /* menu item numbers */
X{
X about = 1,
X /* --- */
X count = 3,
X search,
X setPattern,
X saveOutput
X};
X
X
Xtypedef enum /* resource offsets from resource base number */
X{
X aboutBox = 0,
X alarmBox,
X patBox
X};
X
X
Xtypedef enum /* input file types */
X{
X text, /* text file */
X mwrt3, /* MacWrite 2.2 (version 3) */
X mwrt6 /* MacWrite 4.5 (version 6) */
X};
X
X
Xextern WindowPtr theWind;
Xextern MenuHandle theMenu;
Xextern TEHandle teHand;
Xextern int streamType;
Xextern Boolean fileOpen; /* whether output file is open */
Xextern int outFile; /* output file reference number */
X
Xextern int resBase; /* base DA resource number */
Xextern Boolean prtMatches; /* true: print lines w/pattern */
Xextern Boolean prtLineNum; /* print line numbers if true */
Xextern Boolean ignoreCase; /* ignore letter case if true */
Xextern Boolean havePat; /* whether have good pattern or not */
X
Xextern Boolean grepping; /* true if currently searching */
Xextern Boolean paused; /* true if pause button was hit */
X
Xextern ControlHandle pauseCtl;
Xextern ControlHandle cancelCtl;
X
Xextern char rawPattern[bufSiz]; /* pattern user types in */
X
X
X/*
X Stream input defines.
X*/
X
X/* functions returning non-integer values */
X
XOSErr OpenStream ();
XStringPtr StreamGetS ();
XBoolean GetStream ();
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > Grep.src/GrepGrep.c
X/*
X GrepGrep.c - Grep and Word Count functions
X*/
X
X
X# include "Grep.h"
X
Xstatic long lineNum;
X
X
X/*
X Set the grep state. Val is either 0 (false) or 255 (true).
X*/
X
XGrepState (val)
Xint val;
X{
X HiliteControl (pauseCtl, val);
X HiliteControl (cancelCtl, val);
X grepping = ! (Boolean) val;
X}
X
X
X/*
X Display lines matching (or not matching) pattern. This is
X called to get a line at a time. Mouse clicks control the
X state of the pause variable.
X*/
X
XGrepLine ()
X{
Xchar buf[bufSiz];
X
X if (!paused)
X {
X if (StreamGetS (buf) == nil)
X {
X StopGrep ();
X }
X else
X {
X ++lineNum;
X PtoCstr (buf);
X if (match (buf) == prtMatches)
X {
X if (prtLineNum)
X {
X DisplayLong (lineNum);
X DisplayString ("\p: ");
X }
X CtoPstr (buf);
X DisplayString (buf);
X DisplayLn ();
X }
X }
X }
X}
X
X
X/*
X Cancel any current grep operation.
X*/
X
XStopGrep ()
X{
X if (grepping)
X {
X CloseStream ();
X GrepState (255);
X }
X}
X
X
X/*
X Start grepping a file
X*/
X
XStartGrep ()
X{
X
X StopGrep (); /* terminate any ongoing grep operation */
X if (!havePat)
X GetGrepPat ();
X if (/* now */ havePat)
X {
X if (GetStream ()) /* do grep setup */
X {
X lineNum = 0;
X paused = false;
X SetCTitle (pauseCtl, "\pPause");
X GrepState (0); /* turn controls on, grepping true */
X }
X }
X}
X
X
X/*
X Word Count
X*/
X
X
XWc ()
X{
Xregister long lines = 0;
Xlong nonEmptyLines = 0;
Xlong words = 0;
Xregister long chars = 0;
Xregister Boolean inToken = false;
Xregister int c, lastc;
X
X for (lastc = '\r'; /* empty */ ; lastc = c)
X {
X c = StreamGetC ();
X if (c == -1)
X break; /* eof */
X ++chars;
X switch (c)
X {
X case '\r':
X {
X ++lines;
X if (lastc != '\r')
X ++nonEmptyLines;
X inToken = false;
X break;
X }
X case ' ':
X case '\t':
X {
X inToken = false;
X break;
X }
X default:
X {
X if (inToken == false)
X {
X ++words;
X inToken = true;
X }
X }
X }
X }
X
X if (lastc != '\r') /* in case of missing cr on last line */
X {
X ++lines;
X ++nonEmptyLines;
X }
X DisplayLong (chars);
X DisplayString ("\p Chars, ");
X DisplayLong (words);
X DisplayString ("\p Words, ");
X DisplayLong (lines);
X if (streamType == text)
X DisplayString ("\p Lines\r");
X else
X {
X DisplayString ("\p Paragraphs (");
X DisplayLong (nonEmptyLines);
X DisplayString ("\p non-empty)\r");
X }
X}
X
X
X/*
X Add string to display area. First insert it at the end. Test if
X must scroll lines off top to get the new stuff to show up. If yes,
X then do the scroll. To keep from filling up the TERec, delete
X whatever got scrolled out of view every once in a while. (The number
X of lines scrolled off the top to check for is arbitrary - I clobber
X stuff after every 25 lines.) To avoid unnecessary redrawing, set to
X no clip before doing the delete (which would redraw) and the scroll
X back down (which would also redraw).
X
X Also write string to output file, if one is open.
X*/
X
XDisplayString (theStr)
XStringPtr theStr;
X{
Xregister int dispLines; /* number of lines displayable in window */
Xregister int topLines; /* number of lines currently scrolled off top */
Xregister int scrollLines; /* number of lines to scroll up */
Xregister int height;
Xlong len;
XRect r;
X
X len = theStr[0];
X height = (**teHand).lineHeight;
X TESetSelect (32760L, 32760L, teHand); /* set to insert at end */
X TEInsert (theStr+1, len, teHand);
X r = (**teHand).viewRect;
X dispLines = (r.bottom - r.top) / height;
X topLines = (r.top - (**teHand).destRect.top) / height;
X scrollLines = (**teHand).nLines - topLines - dispLines;
X if (scrollLines > 0) /* must scroll up */
X {
X TEScroll (0, -height * scrollLines, teHand); /* scroll up */
X topLines += scrollLines;
X if (topLines > 25) /* keep TERec from filling up */
X {
X/*
X clobber first line(s), and scroll back down to resync what will then
X be the first line. Set clipping empty, so that the redraw from the
X delete and the scroll down are not shown.
X*/
X SetRect (&r, 0, 0, 0, 0);
X ClipRect (&r);
X TESetSelect (0L, (**teHand).lineStarts[topLines], teHand);
X TEDelete (teHand);
X TEScroll (0, height * topLines, teHand);
X ClipRect (&theWind->portRect);
X }
X }
X
X if (fileOpen)
X {
X if (FSWrite (outFile, &len, theStr+1) != noErr)
X {
X Alarm ("\pWrite Error (Closing File)");
X FileOutput ();
X }
X }
X}
X
X
XDisplayLn ()
X{
X DisplayString ("\p\r");
X}
X
X
XDisplayLong (l)
Xlong l;
X{
XStr255 s;
X
X NumToString (l, s);
X DisplayString (s);
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > Grep.src/GrepIO.c
X/*
X GrepIO - routines for treating TEXT or WORD (MacWrite)
X files as a stream of characters or lines, and for output file
X setup and termination.
X*/
X
X# include <FileMgr.h>
X# include <StdFilePkg.h>
X# include "Grep.h"
X
X
X# define bufSize 1024 /* input buffer size */
X# define lineLen 65 /* output line len before break */
X
X
Xtypedef Byte ByteBuf[];
X
X
Xtypedef struct
X{
X int version;
X int paraOffset;
X int paraCount;
X} DocInfo3;
X
Xtypedef struct
X{
X int paraType;
X int paraLen;
X} ParaInfo3;
X
X
Xtypedef struct
X{
X long iArrayPos;
X int iArrayLen;
X} DocInfo6;
X
X
Xtypedef struct /* information array element */
X{
X int height;
X int pagePos;
X long **paraHand;
X union
X {
X Byte st; /* first byte is status */
X long pos;
X } stPos;
X int dataLength;
X int formats;
X} ParaInfo6, InfoArray[];
X
X
X
XSFReply outReply; /* output file */
XSFReply theStream; /* SFGetFile reply record */
XBoolean streamOpen = false; /* whether stream currently open */
Xint streamType; /* file type of stream */
Xint f; /* input file reference number */
X
X
X/* vars needed for TEXT stream only */
X
Xchar filBuf[bufSize]; /* file buffer */
Xlong fLen;
Xint fChars;
X
X/* vars needed for WORD stream only */
X
XByteBuf **paraBuf = nil;
XInfoArray **infoHand = nil;
XBoolean compressed;
XBoolean inPara;
Xint nParas; /* number of paragraphs */
Xint paraNum; /* current paragraph number */
Xint pIndex; /* index into paragraph */
Xint pChars; /* number of chars extracted from paragraph */
Xint pLen; /* number of chars in paragraph */
X
X/* decompression variables */
X
XBoolean firstHalf; /* which half of current index char */
XBoolean needNib; /* true = 2nd nibble needed for ascii */
XBoolean nextAsc; /* true = two nibbles needed */
XByte lastNib; /* holds last nibble */
X
X/* miscellaneous */
X
XPoint dlogWhere = { 70 /* = y */, 100 /* = x */ };
XOSType type[2] = { 'WORD', 'TEXT' };
X
X
XMyFRead (p, amount)
XPtr p;
Xlong amount;
X{
X (void) FSRead (f, &amount, p);
X}
X
XMyFSeek (pos)
Xlong pos;
X{
X (void) SetFPos (f, fsFromStart, pos);
X}
X
X
X/*
X _FSOpen - like FSOpen, but has open mode parameter.
X
X CloseStream - close current stream, if one is open. Releases any
X heap storage currently used, if stream is WORD type.
X
X OpenStream - open 'TEXT' or 'WORD' stream.
X Return noErr if file opened OK, fnOpnErr or mFulErr if not.
X if OK, set fileOpen true.
X*/
X
X
XOSErr _FSOpen (fName, vRefNum, refNum, mode)
XStringPtr fName;
Xint vRefNum;
Xint *refNum;
Xint mode;
X{
XParamBlockRec p;
Xregister OSErr result;
X
X p.ioParam.ioNamePtr = fName;
X p.ioParam.ioVRefNum = vRefNum;
X p.ioParam.ioPermssn = mode;
X p.ioParam.ioVersNum = 0;
X p.ioParam.ioMisc = 0;
X result = PBOpen (&p, false);
X *refNum = p.ioParam.ioRefNum;
X return (result);
X}
X
X
XCloseStream ()
X{
X if (streamOpen)
X {
X (void) FSClose (f);
X /*(void) FlushVol (nil, theStream.vRefNum);*/
X streamOpen = false;
X if (paraBuf != nil)
X {
X DisposHandle (paraBuf);
X paraBuf = nil;
X }
X if (infoHand != nil)
X {
X DisposHandle (infoHand);
X infoHand = nil;
X }
X }
X}
X
X
XOSErr OpenStream ()
X{
XDocInfo3 docInfo3;
XDocInfo6 docInfo6;
Xregister OSErr result = fnOpnErr;
Xregister int curRes;
X
X CloseStream (); /* close any currently open stream */
X
X curRes = CurResFile ();
X UseResFile (0);
X SFGetFile (dlogWhere, "\p", nil, 2, &type, nil, &theStream);
X UseResFile (curRes);
X Update (); /* refresh screen immediately */
X if (theStream.good)
X {
X if (_FSOpen (theStream.fName, theStream.vRefNum,
X &f, fsRdPerm) == noErr)
X {
X streamOpen = true;
X result = noErr;
X }
X }
X
X if (result == noErr) /* so far, so good */
X {
X if (theStream.fType == 'TEXT')
X {
X streamType = text;
X fChars = 0; /* set these to trigger a read on the first */
X fLen = 0; /* call to StreamGetC() */
X }
X else /* must be WORD file - determine version */
X {
X paraBuf = (ByteBuf **) NewHandle (0L);
X MyFRead (&docInfo3, (long) sizeof (DocInfo3));
X
X if (docInfo3.version == 3) /* MacWrite 2.2 file */
X {
X streamType = mwrt3;
X nParas = docInfo3.paraCount;
X MyFSeek ((long) docInfo3.paraOffset);
X }
X else if (docInfo3.version == 6) /* MacWrite 4.5 file */
X {
X streamType = mwrt6;
X MyFSeek (264L); /* 252 + 12 */
X MyFRead (&docInfo6, (long) sizeof (DocInfo6));
X MyFSeek (docInfo6.iArrayPos);
X infoHand = (InfoArray **) NewHandle (docInfo6.iArrayLen);
X if (infoHand == nil)
X {
X CloseStream ();
X result = mFulErr;
X }
X else
X {
X HLock (infoHand);
X MyFRead (*infoHand, (long) docInfo6.iArrayLen);
X HUnlock (infoHand);
X nParas = docInfo6.iArrayLen / sizeof (ParaInfo6);
X }
X }
X else
X {
X CloseStream ();
X Alarm ("\pFile created by unsupported MacWrite version");
X result = fnOpnErr;
X }
X paraNum = -1;
X inPara = false; /* not in any paragraph yet */
X }
X }
X return (result);
X}
X
X
XBoolean GetStream ()
X{
X
X if (OpenStream () != noErr)
X return (false);
X DisplayString (theStream.fName);
X DisplayString ("\p (");
X DisplayString (streamType == text ? "\pText" : "\pMacWrite");
X DisplayString ("\p file)\r");
X return (true);
X}
X
X
X/*
X _Decompress takes a nibble at a time of compressed text. If more
X nibbles are needed to complete the next character, return -1, else
X returns the character.
X*/
X
X_Decompress (b)
XByte b;
X{
Xregister int result = -1;
X
X if (needNib) /* Low half of ascii nibble is needed. */
X {
X needNib = false;
X result = lastNib | b; /* Put the two halves together */
X }
X else if (nextAsc) /* Two nibbles are needed */
X {
X nextAsc = false;
X lastNib = b << 4; /* Save this one as the high nibble */
X needNib = true; /* Need one more nibble */
X }
X else if (b == 15) /* Nibble of 15 means the next char is ascii */
X nextAsc = true;
X else /* Add the nibble value to the English decompression */
X /* key (saved as Resource Type 'STR ' 700 in file) */
X /* to get the proper character */
X {
X result = " etnroaisdlhcfp" [b]; /* note: C string */
X }
X return (result);
X}
X
X
XBoolean ReadParaBuf ()
X{
X SetHandleSize (paraBuf, pLen); /* make big enough */
X if (MemError () != noErr)
X {
X Alarm ("\pCan't read paragraph buffer");
X paraNum = nParas; /* force stream close and exit of GetC loop */
X return (false);
X }
X HLock (paraBuf);
X MyFRead (*paraBuf, (long) pLen);
X HUnlock (paraBuf);
X return (true);
X}
X
X
XWordStreamGetC () /* return -1 on EOF */
X{
Xregister int c;
Xregister int result;
XParaInfo3 paraInfo3;
X
X if (!inPara) /* must read in next paragraph */
X {
X for (;;)
X {
X if (++paraNum >= nParas)
X {
X CloseStream ();
X return (-1);
X }
X if (streamType == mwrt3)
X {
X MyFRead (¶Info3, (long) sizeof (ParaInfo3));
X pLen = paraInfo3.paraLen;
X if (ReadParaBuf () == false)
X continue;
X if (paraInfo3.paraType != 1)
X {
X continue; /* not text */
X }
X /* adding two skips length word */
X if ((pLen = ((int *) **paraBuf)[0] + 2) == 2)
X continue; /* empty paragraph */
X pChars = 2;
X compressed = false;
X inPara = true;
X break;
X }
X else /* mwrt6 */
X {
X if ((**infoHand)[paraNum].height <= 0)
X {
X continue; /* not text */
X }
X
X/*
X Seek to this paragraph's data (must mask the high byte to get the
X correct value). Move to the paragraph, get its length, make
X the pointer big enough, and read it in. (skip to next para if this
X one is empty, though.)
X compressed will be set true if the paragraph is compressed.
X*/
X
X MyFSeek ((**infoHand)[paraNum].stPos.pos & 0x00FFFFFF);
X MyFRead (&pLen, (long) sizeof (int)); /* get length */
X if (pLen == 0)
X {
X continue; /* empty para - skip */
X }
X if (ReadParaBuf () == false)
X continue;
X compressed = ((**infoHand)[paraNum].stPos.st >> 3) & 1;
X inPara = true;
X nextAsc = false;
X needNib = false;
X pIndex = 0; /* index into current paragraph */
X pChars = 0; /* chars extracted from current paragraph */
X firstHalf = true; /* use first half of current index char */
X break;
X }
X }
X }
X
X/*
X At this point, know either that we have a new non-empty paragraph, or
X are still in the previous one.
X*/
X
X if (!compressed) /* uncompressed */
X {
X c = (**paraBuf)[pChars];
X }
X else
X {
X do
X {
X c = (**paraBuf)[pIndex];
X if (firstHalf)
X {
X c = _Decompress (((Byte) c) >> 4);
X }
X else
X {
X c = _Decompress ((Byte) (c & 0x0f));
X ++pIndex; /* go to next char at next index */
X }
X firstHalf = !firstHalf;
X } while (c == -1);
X }
X if (++pChars >= pLen) /* see if need new paragraph next time */
X inPara = false;
X return (c);
X}
X
X
X/*
X StreamGetC - get character from stream.
X*/
X
XStreamGetC ()
X{
X
X if (!streamOpen)
X return (-1);
X
X if (streamType != text)
X return (WordStreamGetC ());
X
X if (fChars >= fLen) /* need to read in a new block */
X {
X fLen = bufSize;
X (void) FSRead (f, &fLen, filBuf);
X if (fLen == 0)
X {
X CloseStream ();
X return (-1);
X }
X fChars = 0;
X }
X return (filBuf[fChars++]);
X}
X
X
X/*
X StreamGetS - get string from stream.
X
X Returns nil if no string obtained, otherwise a pointer to the argument.
X*/
X
XStringPtr StreamGetS (s)
Xregister StringPtr s;
X{
Xregister int c;
Xregister StringPtr result = nil;
X
X s[0] = 0; /* clear string */
X while ((c = StreamGetC ()) != -1)
X {
X result = s; /* got something, so StreamGetS succeeds */
X if (c == '\r' || (s[0] > lineLen && c == ' '))
X break;
X s[++s[0]] = c; /* add char to end */
X }
X return (result);
X}
X
X
X
XFileOutput ()
X{
XFInfo f;
Xlong pos;
Xregister int curRes;
X
X if (fileOpen) /* close it */
X {
X fileOpen = false;
X (void) GetFPos (outFile, &pos);
X (void) SetEOF (outFile, pos);
X (void) FSClose (outFile);
X (void) FlushVol (nil, outReply.vRefNum);
X SetItem (theMenu, saveOutput, "\pSave Output...");
X }
X else
X {
X curRes = CurResFile ();
X UseResFile (0);
X SFPutFile (dlogWhere, "\pWrite To...", "\p", nil, &outReply);
X UseResFile (curRes);
X Update (); /* refresh screen immediately */
X if (outReply.good)
X {
X if (GetFInfo (outReply.fName, outReply.vRefNum, &f) == noErr) /* exists */
X {
X if (f.fdType != 'TEXT')
X {
X Alarm ("\pNot a TEXT File");
X return;
X }
X }
X else /* doesn't exist. create it. */
X {
X if (Create (outReply.fName, outReply.vRefNum,
X 'Grep', 'TEXT') != noErr)
X {
X Alarm ("\pCan't Create");
X return;
X }
X }
X
X if (_FSOpen (outReply.fName, outReply.vRefNum,
X &outFile, fsWrPerm) != noErr)
X Alarm ("\pCan't Open");
X else
X {
X fileOpen = true;
X SetItem (theMenu, saveOutput, "\pStop Saving Output");
X }
X }
X }
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > Grep.src/GrepMain.c
X/*
X Grep-Wc
X
X Grep - Globally search for Regular Expressions and Print, i.e.,
X g/r.e./p
X
X Wc - char, word, line/paragraph count
X
X Works on text or MacWrite files
X
X Special characters for patterns
X
X ^ Match beginning of line (if at beginning of pattern)
X $ Match end of line (if at end of pattern)
X . Match any character
X [..] Match class of characters. If first character following
X the [ is ^, match all BUT the range of characters. A range
X of characters may be specified by separating them with a
X dash, e.g., [a-z]. The dash itself may be included as a class
X member by giving it as the first class char (e.g., [-a-z]).
X * Match any number of preceding things (if does not follow
X *, ^ or $)
X
X Characters which have special meanings only in certain places in
X the pattern do not have that meaning elsewhere. Special meaning
X may be turned off otherwise by escaping it with '\'. The backslash
X may be entered into a pattern by doubling it.
X
X
X Paul DuBois
X Wisconsin Regional Primate Research Center
X 1220 Capitol Court
X University of Wisconsin-Madison
X Madison, WI 53706 USA
X
X UUCP: {allegra, ihnp4, seismo}!uwvax!uwmacc!dubois
X ARPA: dubois@rhesus.primate.wisc.edu
X dubois@unix.macc.wisc.edu
X
X Version 1.0 12 March 1986 (written in Rascal)
X Version 1.1 22 August 1986 (written in LightspeedC)
X Fixed:
X Menu goes away when window not active.
X Can be selected from Apple menu while open w/o crashing.
X Doesn't pass handle-ized rects to ToolBox routines.
X Upper limits on window sizing are machine sensitive.
X Always uses System file Get/PutFile dialogs (e.g., in MacWrite).
X*/
X
X
X
X# include "Grep.h"
X# include <DeviceMgr.h>
X# include <EventMgr.h>
X# include <MenuMgr.h>
X# include <FileMgr.h>
X
X
X
X/* global variables */
X
XBoolean isOpen = false; /* true if DA already open */
XWindowPtr theWind;
XDCtlPtr dce;
Xint dCtlRefNum;
XTEHandle teHand;
XMenuHandle theMenu;
XRect growRect;
Xint resBase; /* base DA resource number */
XBoolean fileOpen = false; /* whether output file is open */
Xint outFile; /* output file reference number */
X
X/*
X search options
X*/
X
XBoolean prtMatches = true; /* true: print lines w/pattern */
XBoolean prtLineNum = false; /* print line numbers if true */
XBoolean ignoreCase = false; /* ignore letter case if true */
X
X/*
X other information about search
X*/
X
XBoolean grepping; /* true if currently searching */
XBoolean paused; /* true if pause button was hit */
XBoolean havePat = true; /* whether have good pattern or not */
X
XControlHandle pauseCtl;
XControlHandle cancelCtl;
X
X
X
XAlarm (mesg)
XStringPtr mesg;
X{
X ParamText (mesg, "\p", "\p", "\p");
X (void) Alert (resBase + alarmBox, nil);
X}
X
X
X
X/*
X Redraw the window. It is assumed that the port is set correctly.
X The ValidRect is done because sometimes this is called before any
X update event is obtained. The ValidRect cancels any that might be
X pending, preventing two redraws.
X*/
X
XUpdate ()
X{
XRect r;
X
X DrawControls (theWind);
X MoveTo (0, 24);
X LineTo (30000, 24);
X r = (**teHand).viewRect;
X TEUpdate (&r, teHand);
X ValidRect (&theWind->portRect);
X}
X
X
XFiddleMenu (activate)
XBoolean activate;
X
X{
X if (activate)
X InsertMenu (theMenu, 0);
X else
X DeleteMenu (dCtlRefNum);
X
X DrawMenuBar ();
X}
X
X
Xmain(p, d, n)
Xregister cntrlParam *p; /* ==> parameter block */
Xregister DCtlPtr d; /* ==> device control entry */
Xint n; /* entry point selector */
X
X{
XPoint thePt;
XRect r;
XEventRecord *theEvent;
XControlHandle ctl;
X
X dCtlRefNum = (dce = d)->dCtlRefNum;
X
X /* check to make sure data area was allocated */
X
X if (d->dCtlStorage == 0)
X {
X if (n == 0) /* open */
X CloseDriver(dCtlRefNum);
X }
X else switch (n) /* dispatch */
X {
X
X case 0: /* open */
X
X /*
X Need to set these values each time, because the OS resets
X them before every call...
X */
X
X d->dCtlFlags |= dNeedLock | dNeedTime | dNeedGoodBye;
X d->dCtlDelay = 0;
X d->dCtlEMask = updateEvt | activateEvt | mouseDown ;
X d->dCtlMenu = dCtlRefNum;
X
X/*
X Check to see whether already open or not. If not, set up window,
X window growing limits, etc. The SelectWindow is for the case where
X the DA is already open but hidden behind some other window.
X Selecting Grep from the DA menu when already open simply has the
X effect of bringing it to the front.
X*/
X
X if (!isOpen)
X {
X isOpen = true;
X
X theMenu = NewMenu (dCtlRefNum, "\pGrep-Wc");
X AppendMenu (theMenu, "\pAbout Grep-Wc;(-;Count...");
X AppendMenu (theMenu, "\pSearch...;Set Pattern...;Save Output...");
X
X GetWMgrPort (&theWind);
X growRect = theWind->portRect;
X growRect.left = 180;
X growRect.top = 60;
X SetRect (&r, 25, 80, 490, 320);
X theWind = NewWindow (nil, &r, "\pGrep-Wc", true,
X documentProc, -1L, true, 0L);
X ((WindowPeek) theWind)->windowKind = dCtlRefNum;
X SetPort (theWind);
X TextFont (monaco);
X TextSize (9);
X
X /* Create TERec and build controls */
X
X OffsetRect (&r, -r.left, -r.top); /* move to (0, 0) */
X r.top += 25; /* leave room for buttons */
X r.left += 6;
X teHand = TENew (&r, &r);
X (**teHand).crOnly = -1; /* no word wrap */
X
X SetRect (&r, 5, 2, 85, 22);
X pauseCtl =
X NewControl (theWind, &r, "\pPause", true,
X 0, 0, 0, pushButProc, nil);
X OffsetRect (&r, 90, 0);
X cancelCtl =
X NewControl (theWind, &r, "\pCancel", true,
X 0, 0, 0, pushButProc, nil);
X
X GrepState (255); /* set grepping false, inactivate buttons */
X
X /* determine base resource number */
X
X resBase = 0xc000 + (~dCtlRefNum << 5);
X
X }
X
X SelectWindow (theWind);
X
X break;
X
X case 2: /* control */
X
X SetPort (theWind);
X switch (p->csCode)
X {
X
X case accEvent: /* need glasses for next statement */
X
X theEvent = (EventRecord *) * (long *) &p->csParam;
X switch (theEvent->what)
X {
X
X case activateEvt:
X
X /*
X Set up or destroy menu, depending
X on activate type.
X */
X FiddleMenu (theEvent->modifiers & activeFlag);
X break;
X
X case updateEvt:
X
X BeginUpdate (theWind);
X Update ();
X EndUpdate (theWind);
X break;
X
X case mouseDown:
X
X/*
X Check mouse click and whether it's a window grow event.
X Must do the test explicitly, since DA's don't get told about
X clicks in the inGrow region.
X*/
X thePt = theEvent->where;
X GlobalToLocal (&thePt);
X r = theWind->portRect;
X r.left = r.right - 15;
X r.top = r.bottom - 15;
X if (PtInRect (thePt, &r))
X {
X LocalToGlobal (&thePt);
X * (long *) &thePt = GrowWindow (theWind, thePt, &growRect);
X SizeWindow (theWind, thePt.h, thePt.v, true);
X r = theWind->portRect;
X ClipRect (&r);
X /*InvalRect (&r); /* force update event */
X /*
X Reset the text viewRect. It's
X not necessary to reset the destRect,
X since only the top and left are
X used, and they haven't changed.
X */
X r.top += 25;
X r.left += 6;
X (**teHand).viewRect = r;
X }
X else if (FindControl (thePt, theWind, &ctl))
X {
X if (TrackControl (ctl, thePt, nil))
X {
X if (ctl == cancelCtl)
X {
X StopGrep ();
X }
X else if (ctl == pauseCtl)
X {
X if (paused)
X SetCTitle (pauseCtl, "\pPause");
X else
X SetCTitle (pauseCtl, "\pResume");
X paused = !paused;
X }
X }
X }
X break;
X }
X break;
X
X case accMenu:
X
X switch (* (int *) ((Ptr) &p->csParam + 2))
X {
X case about:
X (void) Alert (resBase + aboutBox, nil);
X break;
X
X case count:
X StopGrep (); /* terminate any ongoing grep operation */
X if (GetStream ())
X Wc ();
X break;
X
X case search:
X StartGrep ();
X break;
X
X case setPattern:
X GetGrepPat ();
X break;
X
X case saveOutput:
X FileOutput ();
X break;
X }
X
X HiliteMenu (0);
X break;
X
X case accRun:
X if ((theWind == FrontWindow ()) && grepping)
X GrepLine ();
X break;
X
X case goodBye:
X CloseStream (); /* close any open input file */
X if (fileOpen) /* close output file if open */
X FileOutput ();
X break;
X
X }
X break;
X
X case 4: /* close */
X CloseStream (); /* close any open input file */
X if (fileOpen) /* close output file if open */
X FileOutput ();
X FiddleMenu (false);
X DisposeMenu (theMenu); /* toss menu */
X TEDispose (teHand); /* toss text record */
X DisposeWindow (theWind); /* get rid of window and controls */
X break;
X }
X
X /* done */
X
X return (0);
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > Grep.src/GrepPattern.c
X/*
X GrepCompile - routines for compiling patterns into internal form,
X and for matching strings against the compiled pattern.
X*/
X
X
X# include <DialogMgr.h>
X# include "Grep.h"
X
X/* special internal chars for compiled pattern */
X
X# define CCL 1 /* match characters in class */
X# define NCCL 2 /* all but characters in class */
X# define CRANGE 3 /* range of chars */
X# define ENDCCL 4 /* end char class */
X# define ANY 5 /* match any char */
X# define CLOSURE 6 /* closure */
X# define EOL 7 /* end of line */
X
X
X/* pattern compilation and matching vars */
X
Xstatic Boolean matchBol; /* match beginning of line? */
Xstatic int pix; /* index into pattern */
Xstatic int pMark;
Xstatic Boolean canClose;
X
X/*
X Pattern buffers. rawPattern is the text typed by user into
X the dialog box. cmpPattern is the compiled pattern. Initially
X they are both empty. (Format of the nil compiled pattern is
X dependent on algorithm used to compile rawPattern.) This is
X legal - it matches every line. If a file is grepped without
X specifying a pattern, therefore, the whole file will be
X displayed. A side effect of this is to turn grep on WORD files
X into a WORD-to-TEXT file converter when the save output option
X is turned on.
X*/
X
Xchar rawPattern[bufSiz] = "";
Xstatic char cmpPattern[bufSiz] = "";
X
X
X/* ----------------------------------------------------------------------- */
X/* pattern-compilation routines */
X/* ----------------------------------------------------------------------- */
X
X
X
X/*
X Add char to pattern (may be a metachar, not necessarily
X a literal character to match)
X*/
X
XAddPatChar (c)
Xchar c;
X{
X if (ignoreCase && c >= 'A' && c <= 'Z')
X c += 'a' - 'A';
X cmpPattern[pix] = c;
X ++pix;
X cmpPattern[pix] = 0;
X
X} /* AddPatChar */
X
X
X/*
X Put a closure indicator into the pattern, in front of the
X stuff that's to be closed.
X*/
X
XAddClosure ()
X{
Xregister int i;
X
X ++pix;
X for (i = pix; i > pMark; --i)
X /*loop (, i = pix, , --i <= pMark)*/
X cmpPattern [i] = cmpPattern [i-1];
X cmpPattern [pMark] = CLOSURE;
X canClose = false;
X
X} /* AddClosure */
X
X
X/*
X have found something that may be followed by a closure. set
X canClose to indicate that fact, and set a mark to remember where
X the closable thing is.
X*/
X
XMarkIt ()
X{
X pMark = pix; /* set mark in case closure comes up next */
X canClose = true;
X}
X
X
X/*
X Get escaped char (char following '\'). The only special one
X right now is '\t', which is turned into a tab. Caller must check
X that return value isn't zero.
X*/
X
Xchar EscapeChar (c)
Xchar c;
X{
X return (c == 't' ? '\t' : c);
X}
X
X/*
X compile character class. pass pointer to char after '[' that begins
X the class pattern. Return nil if (error, else pointer to char
X after closing ']' bracket.
X*/
X
XStringPtr Class (p)
Xregister StringPtr p;
X{
Xregister char c, type, low, high;
X
X type = CCL; /* 'character class' metachar */
X if (*p == '^')
X {
X type = NCCL; /* 'match all but this class' metachar */
X ++p;
X }
X AddPatChar (type);
X for (;;)
X {
X c = *p;
X ++p;
X if (c == '\\')
X {
X c = EscapeChar (*p);
X ++p;
X }
X else if (c == ']')
X break; /* end of class pattern */
X if (c == 0)
X return (nil); /* missing ']' - pattern error */
X if (*p != '-')
X AddPatChar (c);
X else /* range */
X {
X low = c; /* low end */
X ++p;
X high = *p; /* high end */
X ++p;
X if (high == 0)
X return (nil); /* pattern error */
X AddPatChar (CRANGE);
X AddPatChar (low);
X AddPatChar (high);
X }
X }
X AddPatChar (ENDCCL);
X return (p); /* all ok */
X
X} /* class */
X
X
X/*
X COMPILE - compile string into internal form suitable for efficient
X pattern matching. String should be in C format.
X*/
X
XBoolean Compile (p)
Xregister StringPtr p;
X{
Xregister char c;
X
X pix = 0;
X cmpPattern[0] = 0;
X canClose = false;
X matchBol = false;
X/*
X check for ^ - it's only special at beginning of line
X*/
X if (*p == '^')
X {
X matchBol = true;
X ++p;
X }
X for (;;)
X {
X c = *p;
X ++p;
X
X if (c == '*')
X {
X/*
X if (canClose is true, there was a preceding pattern which can be
X closed (not closure, ^ or $), so close it. otherwise, take *
X literally.
X*/
X if (canClose) /* something to close */
X {
X AddClosure ();
X continue;
X }
X }
X
X/*
X $ only special at end of line
X*/
X if (c == '$' && *p == 0)
X {
X AddPatChar ((char) EOL);
X continue;
X }
X/*
X at this point we know we have a character that can be followed by a
X closure, so mark the pattern position.
X*/
X MarkIt ();
X
X/*
X use most escaped chars literally, except null, which is an error,
X and \t, which is a tab.
X*/
X if (c == '\\')
X {
X c = EscapeChar (*p++);
X if (c == 0)
X return (false); /* pattern error */
X AddPatChar (c);
X continue;
X }
X if (c == 0) break; /* done compiling */
X switch (c)
X {
X case '.': AddPatChar (ANY); break; /* match any char */
X case '[': /* match character class */
X {
X if ((p = Class (p)) == nil)
X return (false); /* class pattern error */
X break;
X }
X default: AddPatChar (c); /* match char literally */
X }
X
X } /* loop */
X
X return (true); /* all ok */
X
X} /* compile */
X
X
X/* ----------------------------------------------------------------------- */
X/* pattern-matching routines */
X/* ----------------------------------------------------------------------- */
X
X/*
X NEXTPOS - find position in pattern of next component to match
X*/
X
XStringPtr NextPos (p)
Xregister StringPtr p;
X{
Xregister char c;
X
X c = *p;
X ++p;
X if (c == CCL || c == NCCL)
X {
X do /* look for end of class stuff */
X {
X c = *p;
X ++p;
X } while (c != ENDCCL);
X }
X return (p);
X
X} /* NextPos */
X
X
XBoolean InClass (c, p)
Xregister char c;
Xregister StringPtr p;
X{
Xregister char high, low, pc;
X
X for (;;)
X {
X pc = *p;
X ++p;
X if (pc == ENDCCL)
X return (false);
X if (pc == CRANGE) /* range */
X {
X low = *p;
X ++p;
X high = *p;
X ++p;
X if (low <= c && c <= high)
X break; /* it's within the range */
X }
X else if (c == pc)
X break; /* it matched this char of class */
X }
X return (true);
X
X} /* InClass */
X
X/*
X OMATCH - match character c against the current pattern position.
X*/
X
XBoolean omatch (c, p)
Xregister char c;
Xregister StringPtr p;
X{
Xregister char pc;
X
X if (ignoreCase && c >= 'A' && c <= 'Z')
X c += 'a' - 'A';
X pc = *p;
X ++p;
X switch (pc)
X {
X case CCL: return (InClass (c, p));
X case NCCL: return (!InClass (c, p));
X case ANY: return (c != 0); /* don't match end of line */
X default: return (c == pc);
X }
X
X} /* omatch */
X
X
X/*
X try to match pattern p at the given position in string s
X*/
X
XBoolean amatch (s, p)
Xregister StringPtr s, p;
X{
Xregister StringPtr cursp;
X
X if (*p == 0)
X return (true); /* end of pattern, have matched it */
X if (*p == EOL)
X return (*s == 0); /* must be end of string to match EOL */
X
X if (*p == CLOSURE)
X {
X
X/*
X advance as far as possible, matching the current pattern position.
X when omatch fails, s will point 1 past the character that failed.
X then back up one and try to match rest of pattern. if that fails,
X keep retreating until back at point of original closure start
X*/
X
X ++p; /* skip closure marker */
X cursp = s; /* save current string position */
X
X while (omatch (*s++, p))
X /* march! */ ;
X
X do /* keep backing up */
X {
X --s;
X if (amatch (s, NextPos (p)))
X return (true);
X } while (s > cursp);
X return (false);
X }
X
X if (omatch (*s++, p))
X return (amatch (s, NextPos (p)));
X return (false);
X
X} /* amatch */
X
X
X/*
X MATCH - match string s against the compiled pattern
X
X if matchBol is true, then anchor the match to the beginning of the
X string, else try the pattern against successive string positions until
X the match succeeds or the end of the string is reached.
X
X s should be in C format.
X*/
X
XBoolean match (s)
Xregister StringPtr s;
X{
X if (matchBol) /* anchored match */
X {
X return (amatch (s, cmpPattern));
X }
X for (;;) /* floating match */
X {
X if (amatch (s, cmpPattern))
X return (true);
X if (*s == 0)
X return (false); /* end of string but no match */
X ++s;
X }
X
X} /* match */
X
X
X/*
X Routines for presenting the pattern entry dialog.
X*/
X
X
X/*
X pattern dialog items
X
X item type
X 1 ok button
X 2 cancel button
X 3 prompt
X 4 edittext item for typing in pattern
X 5 "lines not containing pattern" radio button
X 6 "print line numbers" check box
X 7 "ignore case" check box
X
X Puts the string entered into theString, which on return is
X empty if either the user clicked Cancel or typed no string
X and clicked ok.
X*/
X
Xenum
X{
X okButton = 1,
X cancelButton,
X promptStatText,
X patText,
X lineOption,
X numberOption,
X caseOption
X};
X
X
Xstatic DialogPtr theDialog;
X
X
X
X/*
X Set or get the value of a checkbox (i.e., boolean) dialog item
X*/
X
XSetDBoolean (itemNo, itemValue)
Xint itemNo;
XBoolean itemValue;
X{
XHandle itemHandle;
Xint itemType;
XRect r;
X
X GetDItem (theDialog, itemNo, &itemType, &itemHandle, &r);
X/*
X Note type conversion here. True turns the control on.
X*/
X SetCtlValue (itemHandle, (int) itemValue);
X}
X
X
XBoolean GetDBoolean (itemNo)
Xint itemNo;
X{
XHandle itemHandle;
Xint itemType;
XRect r;
X
X GetDItem (theDialog, itemNo, &itemType, &itemHandle, &r);
X return ((Boolean) GetCtlValue (itemHandle));
X}
X
X
XBoolean GetPatDlog ()
X{
Xint itemNo, itemType;
XHandle itemHandle;
XRect r;
Xregister Boolean result;
X
X theDialog = GetNewDialog (resBase + patBox, nil, -1L);
X SetDBoolean (lineOption, !prtMatches);
X SetDBoolean (numberOption, prtLineNum);
X SetDBoolean (caseOption, ignoreCase);
X GetDItem (theDialog, patText, &itemType, &itemHandle, &r);
X SetIText (itemHandle, rawPattern);
X SelIText (theDialog, patText, 0, 32760);
X ShowWindow (theDialog);
X for (;;)
X {
X ModalDialog (nil, &itemNo);
X if (itemNo == cancelButton)
X {
X result = false;
X break;
X }
X else if (itemNo == okButton)
X {
X GetDItem (theDialog, patText, &itemType, &itemHandle, &r);
X GetIText (itemHandle, rawPattern);
X prtMatches = !GetDBoolean (lineOption);
X prtLineNum = GetDBoolean (numberOption);
X ignoreCase = GetDBoolean (caseOption);
X result = true;
X break;
X }
X else /* must be option check box - flip value */
X {
X SetDBoolean (itemNo, !GetDBoolean (itemNo));
X }
X }
X
X DisposDialog (theDialog);
X return (result);
X
X} /* GetPatDlog */
X
X
XGetGrepPat ()
X{
X if (GetPatDlog ())
X {
X PtoCstr (rawPattern);
X havePat = Compile (rawPattern);
X CtoPstr (rawPattern);
X if (!havePat)
X Alarm ("\pBad Pattern");
X }
X}
SHAR_EOF
exit
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads