🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

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
#31
Author: Paul DuBois
Date: Mon, 08 Dec 1986 16:05
1734 lines
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 (&paraInfo3, (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