[mod.mac.sources] MakeWrite Source

macintosh@felix.UUCP (03/21/87)

[MakeWrite Source - part 1 of 3]

---
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	MW/ListEdit.h
#	MW/MWFileStuff.h
#	MW/MWMaca.h
#	MW/MWMapInfo.h
#	MW/MachDep.h
#	MW/MakeWrite.h
#	MW/ListEdit.c
#	MW/MWCheckMark.c
#	MW/MWFileStuff.c
sed 's/^X//' << 'SHAR_EOF' > MW/ListEdit.h
X/*
X	ListEdit.h - ListEdit header file
X*/
X
X#ifndef	_ListEdit_
X
X# define	_ListEdit_
X
X
X# ifndef	_MachDep_
X# include	"MachDep.h"
X# endif
X
X
X# ifndef	_ControlMgr_
X# include	<ControlMgr.h>
X# endif
X
X
X# ifndef	nil
X# define	nil		(0L)
X# endif
X
X
X# ifndef	New
X# define	New(x)		(x **) NewHandle ((Size) sizeof (x))
X# endif
X
X
X/*
X	A LineList object consists of the following:
X
X	o	owning port
X	o	scroll bar
X	o	rectangle indicating the text display area
X	o	maximum number of lines
X	o	number of lines visible in text display area
X	o	index of top visible line
X	o	height of each line in the display
X	o	current number of lines
X	o	currently selected line (noLine if none)
X	o	activation state
X	o	number of fields in each line
X	o	array indicating horizontal offset of each field
X	o	array of handles to information for each line.
X
X	Lines are lists of fields.
X	A field consists of a string and a handle to the next field.
X	A LineHandle is equivalent to a FieldHandle because a line is
X	simply a list of fields.
X*/
X
X# define	noLine		(-1)	/* "current line" value of no line selected */
X
X
Xtypedef struct Field
X{
X	Str255			fStr;
X	struct Field	**fNext;
X} Field, **FieldHandle, **LineHandle;
X
X
Xtypedef LineHandle	LineArray[1];
Xtypedef LineArray	**LAHandle;
X
X
Xtypedef struct LineList
X{
X	GrafPtr			port;		/* port                          */
X	ControlHandle	scroll;		/* scroll bar                    */
X	Rect			textRect;	/* text display rectangle        */
X	Integer				maxLines;	/* maximum number of lines       */
X	Integer				visLines;	/* number of visible lines       */
X	Integer				topVisLine;	/* index of top visible line     */
X	Integer				lineHeight;	/* height of each line           */
X	Integer				nLines;		/* number of lines               */
X	Integer				curLine;	/* currently selected line       */
X	Boolean			hilite;		/* whether to hilite             */
X	Integer				nFields;	/* number of fields in each line */
X	Integer				*offset;	/* offsets of each field         */
X	LAHandle		lines;		/* lines in list                 */
X} LineList, *ListPtr;
X
X
X# define	NextField(hField)	((**hField).fNext)
X# define	ListLine(list, line)	((**list->lines)[line])
X
XLineHandle	NewLine ();
XBoolean		InsertLine ();
XBoolean		ListTestScroll ();
XBoolean		ListTestText ();
X
X# endif
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > MW/MWFileStuff.h
X/*
X	MWFileStuff.h - File operation header file
X*/
X
X
X#ifndef	_MWFileStuff_
X
X# define	_MWFileStuff_
X
X# ifndef	_MacTypes_
X# include	<MacTypes.h>
X# endif
X
X
X# ifndef	_MachDep_
X# include	"MachDep.h"
X# endif
X
X
X# ifndef	nil
X# define	nil		(0L)
X# endif
X
X
X/*
X	Functions returning non-int
X*/
X
XBoolean	GetInputFile ();
XBoolean	OpenInputFile ();
XBoolean	GetOutputFile ();
XBoolean	OpenOutputFile ();
XBoolean	FileRead ();
XBoolean	FileWrite ();
XLongint	FilePos ();
XBoolean	ZeroPad ();
XBoolean ReadString ();
XBoolean WriteString ();
XBoolean ReadInteger ();
XBoolean WriteInteger ();
XBoolean WriteLongint ();
X
X# endif
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > MW/MWMaca.h
X/*
X	MWMaca.h - MacWrite document structures, version 4.5
X	(actually, lots of this is for version 2.2, I was never took it out.)
X
X	The comments below are mostly non-edifying.  A copy of
X	Macintosh Technical Note 12 is a necessity, as it
X	describes document formats in detail.
X
X	One difference is that the "active face" in the window variables
X	is really a point size (high byte) and style (low byte), not just
X	a style.	
X*/
X
X
X# ifndef	_MWMaca_
X# define	_MWMaca_
X
X
X# ifndef	_MacTypes_
X# include	<MacTypes.h>
X# endif
X
X
X# ifndef	_MachDep_
X# include	"MachDep.h"
X# endif
X
X
X# ifndef	nil
X# define	nil		(0L)
X# endif
X
X
X
Xtypedef enum			/* supported versions of MacWrite */
X{
X	version3 = 3,		/* MacWrite 2.2 */
X	version6 = 6		/* MacWrite 4.5 */
X};
X
X
Xtypedef enum			/* document types */
X{
X	mainDoc = 0,
X	headDoc = 1,
X	footDoc = 2
X};
X
X
Xtypedef enum			/* paragraph types */
X{
X	rulerPara = 0,
X	textPara = 1,
X	pictPara = 2
X};
X
X
Xtypedef enum			/* justification types */
X{
X	leftJust = 0,
X	centerJust = 1,
X	rightJust = 2,
X	fillJust = 3
X} Justification;
X
X
X/*
X	Types common to all versions
X*/
X
Xtypedef Byte	ByteBool;		/* byte-size boolean */
Xtypedef Byte	UPrintRec[120];	/* 120-byte universal printing record */
X								/* (anyone know what's in it?) */
X
X
Xtypedef struct Selection
X{
X	Integer		selPara;	/* selection paragraph number */
X	Integer		selPos;		/* selection char position (start or end) */
X} Selection;
X
X
Xtypedef struct ActiveFace
X{
X	Byte		faceSize;	/* point size */
X	Byte		faceStyle;	/* style */
X} ActiveFace;
X
X
Xtypedef struct Format
X{
X	Integer		fmtPos;		/* pos of first char format applies to */
X	Byte		fmtSize;	/* point size */
X	Byte		fmtStyle;	/* style */
X	Integer		fmtFont;	/* font number */
X} Format;
X
Xtypedef Format	FormatArray[1];		/* actually variable length */
Xtypedef FormatArray	**FAHandle;
X
X
Xtypedef struct Ruler
X{
X	Integer			margLeft;	/* left margin */
X	Integer			margRight;	/* right margin */
X	Justification	just;		/* justification */
X	Byte			nTabs;		/* number of tabs */
X	Integer			spacing;	/* line spacing = 1 + (spacing/2) */
X	Integer			indent;		/* indentation of first line */
X	Integer			tab[10];	/* tab values */
X	Byte			fill[4];	/* unused */
X} Ruler;
X
X
X/*
X	MacWrite 2.2 (version number 3) data structures
X*/
X
X
Xtypedef struct Globals3		/* version 2.2 globals */
X{
X	Integer		version;	/* version number (always 3) */
X	Integer		paraOffset;	/* offset to paragraph information */
X	Integer		mainParas;	/* main doc paragraph count */
X	Integer		headParas;	/* header paragraph count */
X	Integer		footParas;	/* footer paragraph count */
X	ByteBool	titlePage;	/* title page flag */
X	Byte		fill[2];	/* unused */
X	ByteBool	showFoot;	/* true if footer displayed */
X	ByteBool	showHead;	/* true if header displayed */
X	ByteBool	showRuler;	/* true if rulers displayed */
X	Integer		activeDoc;	/* active document */
X	Integer		startPage;	/* starting page number */
X} Globals3;
X
X
Xtypedef struct ParaInfo3
X{
X	Integer		paraHeight;	/* height of paragraph (pixels) */
X	Integer		paraPos;	/* position from top of page */
X	Byte		paraPage;	/* page number */
X	Byte		fill[3];	/* unused */
X} ParaInfo3;
X
X
Xtypedef struct Windows3		/* version 2.2 window variables */
X{
X	Selection	selStart;	/* start of selection */
X	Selection	selEnd;		/* end of selection */
X	Integer		vertOffset;	/* vertical offset */
X	Integer		redrawPara;	/* first paragraph to redraw */
X	Point		pageIconPt;	/* page icon position */
X	Point		dateIconPt;	/* date icon position */
X	Point		timeIconPt;	/* time icon position */
X	Byte		fill[4];	/* unused */
X	ByteBool	iconRedraw;	/* true if icons should be redrawn */
X	ByteBool	iconFlag;	/* true if rulers shown when icons last drawn */
X	Integer		activeFont;	/* font active when saved */
X	ActiveFace	activeFace;	/* face active when saved */
X} Windows3;
X
X
Xtypedef struct DocInfo3		/* version 2.2 document information */
X{
X	Globals3	globals3;	/* globals */
X	UPrintRec	uPrintRec;	/* universal printing record */
X	Windows3	mainWind3;	/* main doc window information */
X	Windows3	headWind3;	/* header window information */
X	Windows3	footWind3;	/* footer window information */
X} DocInfo3;
X
X
X/*
X	MacWrite 4.5 (version number 6) data structures
X*/
X
X
Xtypedef struct Globals6		/* version 4.5 globals */
X{
X	Integer		version;	/* version number (always 6) */
X	Integer		mainParas;	/* main doc paragraph count */
X	Integer		headParas;	/* header paragraph count */
X	Integer		footParas;	/* footer paragraph count */
X	ByteBool	titlePage;	/* title page flag */
X	Byte		fill;		/* unused */
X	ByteBool	showScrap;	/* true if scrap displayed */
X	ByteBool	showFoot;	/* true if footer displayed */
X	ByteBool	showHead;	/* true if header displayed */
X	ByteBool	showRuler;	/* true if rulers displayed */
X	Integer		activeDoc;	/* active document */
X	Integer		startPage;	/* starting page number */
X	Longint		freePos;	/* free list position */
X	Integer		freeLen;	/* free list length */
X	Integer		freeAlloc;	/* bytes allocated for free list on disk */
X	Byte		fill2[14];	/* unused */
X} Globals6;
X
X
Xtypedef enum				/* status byte bitmasks */
X{
X	stJustMask = 0x03,		/* justification code */
X	stInUse = 0x04,			/* bit set if paragraph is in use */
X	stCompress = 0x08,		/* bit set if text is compressed */
X	stOnItsWay = 0x10,		/* bit set if disk i/o started, not done */
X	stInMemory = 0x20,		/* bit set if paragraph is in memory */
X	stJustify = 0x40,		/* bit set if just code above used */
X							/* otherwise use ruler */
X	stDirty = 0x80			/* set if paragraph is dirty */
X};
X
X
Xtypedef enum			/* justification codes relating to stJustMask */
X{
X	stJustLeft = 0x00,
X	stJustCenter = 0x01,
X	stJustRight = 0x02,
X	stJustFull = 0x03
X};
X
X
Xtypedef union ParaStOff
X{
X	Byte		paraStatus;	/* paragraph status */
X	Longint		paraOffset;	/* position of paragraph data */
X							/* (low 3 bytes only) */
X} ParaStOff;
X
X
Xtypedef struct ParaInfo6
X{
X	Integer		paraHeight;	/* height of paragraph (pixels) */
X	Integer		paraPos;	/* position from top of page */
X	Longint		paraHandle;	/* handle to paragraph */
X	ParaStOff	paraStOff;	/* data position/status */
X	Integer		paraLen;	/* length of paragraph data */
X	Integer		paraFmts;	/* common formats */
X} ParaInfo6;
X
Xtypedef ParaInfo6	ParaInfoArray6[1];	/* actually variable length */
Xtypedef ParaInfoArray6	**PIAHandle;
X
X
Xtypedef struct Windows6		/* version 4.5 window variables */
X{
X	Selection	selStart;	/* start of selection */
X	Selection	selEnd;		/* end of selection */
X	Integer		vertOffset;	/* vertical offset */
X	Integer		redrawPara;	/* first paragraph to redraw */
X	Longint		infoPos;	/* position of information array */
X	Integer		infoLen;	/* length of information array */
X	Longint		linePos;	/* position of line height array */
X	Integer		lineLen;	/* length of line height array */
X	Point		pageIconPt;	/* page icon position */
X	Point		dateIconPt;	/* date icon position */
X	Point		timeIconPt;	/* time icon position */
X	Byte		fill[4];	/* unused */
X	ByteBool	iconRedraw;	/* true if ovals (icons) should be redrawn */
X	ByteBool	iconFlag;	/* true if rulers shown when ovals last drawn */
X	ActiveFace	activeFace;	/* face active when saved */
X	Integer		activeFont;	/* font active when saved */
X} Windows6;
X
X
Xtypedef struct DocInfo6		/* version 4.5 document information */
X{
X	Globals6	globals6;	/* globals */
X	UPrintRec	uPrintRec;	/* universal printing record */
X	Windows6	footWind6;	/* footer window information */
X	Windows6	headWind6;	/* header window information */
X	Windows6	mainWind6;	/* main doc window information */
X} DocInfo6;
X
X# endif
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > MW/MWMapInfo.h
X/*
X	MapInfo.h - map structures
X*/
X
X#ifndef	_MWMapInfo_
X
X# define	_MWMapInfo_
X
X# ifndef	_MacTypes_
X# include	<MacTypes.h>
X# endif
X
X
X# ifndef	_MachDep_
X# include	"MachDep.h"
X# endif
X
X
X# ifndef	nil
X# define	nil		(0L)
X# endif
X
X
X/*
X	Font chosen is specified by its number in FontMgr.h.  If no font
X	change is specified, use sameFont.
X	Point size is one of 9, 10, 12, 14, 18 or 24, or none.  If no
X	size change is specified, use sameSize.
X*/
X
X# define	sameFont	(-1)
X# define	sameSize	(-1)
X
X
X/*
X	Style word coded as follows:  high bit never used in a legal MacWrite
X	style spec, so it's used to signify "no style change".  If the high
X	bit is set, others can be anything, but are ignored.  If it's clear
X	the others are set according to the style attributes selected.  If
X	no attributes are selected (low 7 bits = 0), that means plain.
X
X	Warning:  these constants are specified for convience in coding,
X	but the values are really hardcoded, since they're sometimes used
X	in non-obvious ways.  See StyleToStr for an example.
X*/
X
Xtypedef enum				/* bits used in style byte */
X{
X							/* 0 = plain */
X	styleBold = 1,			/* boldface */
X	styleItalic = 2,		/* italic */
X	styleUnder = 4,			/* underline */
X	styleOutline = 8,		/* outline */
X	styleShadow = 16,		/* shadow */
X	styleSuper = 32,		/* superscript */
X	styleSub = 64,			/* subscript */
X	sameStyle = 128			/* high bit unused in any legal style, so */
X							/* it's used to signify no style change */
X};
X
X
X/*
X	A map specification consists of the marker string to look for that
X	signals a format change, and the font, size and style combination
X	to be used to effect the change.  It also holds the beginning and
X	end of the selection points for editing the marker.
X*/
X
X# define	maxMarkLen		20	/* max number of chars in a marker */
X
Xtypedef struct
X{
X	StringHandle	mark;		/* marker string */
X	Integer				selStart;	/* selection range in mark string */
X	Integer				selEnd;
X	Integer				font;		/* sameFont if no change specified */
X	Integer				size;		/* sameSize if no change specified */
X	Integer				style;		/* sameStyle if no change specified, */
X								/* 0 if plain, */
X								/* else bits = attributes selected */
X} MapSpec;
X
X
X/*
X	Structure used for holding text representation of
X	map specifications
X*/
X
Xtypedef struct
X{
X	Str255	markStr;
X	Str255	fontStr;
X	Str255	sizeStr;
X	Str255	styleStr;
X} MapStr;
X
X# endif
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > MW/MachDep.h
X/*
X	"Machine" dependent stuff.  Integer and Longint should be typedef'd
X	to the compiler's two- and four-byte integer types.  This facilitates
X	conversion to other C compilers.
X*/
X
X
X# ifndef	_MachDep_
X
X# define	_MachDep_
X
Xtypedef short	Integer;			/* 16-bit integer */
Xtypedef long	Longint;			/* 32-bit integer */
X
X# endif
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > MW/MakeWrite.h
X# include	"ListEdit.h"
X# include	"MWMapInfo.h"
X
X
X/*
X	# define debug	to enable debug output option
X	# undef  debug	to disable debug output option
X*/
X
X# undef	debug
X
X
X# define	cr		'\r'
X# define	enter	3
X
X
X/*
X	Resource numbers
X*/
X
Xtypedef enum					/* alert/dialog numbers */
X{
X	aboutAlrtNum = 1000,	/* "About FaceLift..." alert */
X	msgeAlrtNum,
X	questAlrtNum,
X	paraDlogNum,
X	conflictAlrtNum,
X	noPeriodAlrtNum,
X	replaceAlrtNum
X};
X
X
Xtypedef enum
X{
X	fileMenuNum = 1000,
X	editMenuNum,
X	specialMenuNum
X};
X
X
Xtypedef enum			/* STR resource numbers */
X{
X	periodStrNum = 1000,	/* default periods list */
X	quoteStrNum				/* default quotes list */
X};
X
X
Xtypedef enum			/* STR# resource numbers */
X{
X	fontStrNum = 1000	/* standard font list */
X};
X
X
X# define	helpTextNum		1000	/* TEXT for help window */
X
X
Xtypedef enum		/* Undo operations */
X{
X	noUndo,			/* = "last op can't be undone" */
X	undoDelete,
X	undoInsert,
X	undoPaste,
X	undoFieldChg,
X	undoTyping,
X	undoMarkerOp
X};
X
X
Xtypedef enum		/* field numbers - don't change */
X{
X	markField = 0,
X	fontField,
X	sizeField,
X	styleField
X};
X
X
X# define	maxMappings	100
X
X# define	extraMarks	2		/* number of special markers */
X
Xtypedef enum					/* special-marker indices */
X{
X	paraMarkIdx = maxMappings,	/* paragraph marker */
X	pageMarkIdx					/* page break marker */
X};
X
X
X/*
X	Paragraph style control
X*/
X
Xtypedef struct
X{
X	Boolean	pEachLine;		/* each line is a paragraph */
X	Boolean	pBlankLine;		/* blank lines are paragraphs */
X	Boolean	pSmartJoin;		/* line-joining smart or not */
X} ParaStyle;
X
X
X# define	mwCreator	'MKWR'	/* map file creator */
X# define	mwType		'MMAP'	/* map file type */
X# define	mapVersion	2		/* current map file structure version */
X
X/*
X	Variable definitions
X*/
X
Xextern WindowPtr	mapWind;
X
Xextern ListPtr	mapList;
Xextern MapSpec	mapSpec[];
X
Xextern Boolean	mapModified;
X
Xextern Integer		undoOp;
Xextern Integer		undoVal;
Xextern Integer		undoPos;
Xextern Integer		undoFieldType;
Xextern MapSpec	undoMSpec;
Xextern Boolean	undoCPMarker;
X
Xextern Boolean	havePasteMSpec;
X
Xextern Boolean	cpMarker;
X
X
Xextern ParaStyle	paraStyle;
Xextern Str255		paraMark;
Xextern Str255		pageMark;
Xextern Str255		periodStr;
Xextern Str255		quoteStr;
X
X# ifdef	debug
Xextern Boolean	debugOut;
X# endif
X
X/*
X	Functions returning non-int
X*/
X
XBoolean SetFontSpec ();
XBoolean	InString ();
XBoolean	InsertMapping ();
XBoolean	EditMarker ();
XBoolean StatMSpec ();
XBoolean	OpenMap ();
XBoolean	AddMap ();
XBoolean	SaveMap ();
XBoolean	MouseClick ();
XBoolean ExpandHandle ();
XBoolean DestroyWarn ();
XBoolean DiscardChanges ();
X
X
XBoolean	WritePrelude ();
XBoolean WritePostlude ();
XBoolean	SetParaInfo ();
X
XBoolean FindEmptyMark ();
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > MW/ListEdit.c
X/*
X	ListEdit.c - LineList manipulations
X
X	The LineList structure is set up to allow an arbitrary number of
X	fields in each line.  Each field contains some text, in string
X	form.  This means that whatever kind of structure underlies the
X	line must be mapped onto the strings externally to the routines
X	in this file.
X
X	All routines that operate on LineList objects assume
X	that there's at least one field in each line.
X*/
X
X# include	"ListEdit.h"
X
X# define	teJustLeft	0
X
X
Xstatic ListPtr	trackList;
Xstatic Integer		trackPart;
X
X
X/* ---------------------------------------------------------------- */
X/*		Line list initialization, line creation and disposal		*/
X/* ---------------------------------------------------------------- */
X
X
X/*
X	Initialize a line list.  It's assumed that everything that
X	can be statically initialized already has been.  What's done
X	here:
X
X	o	set the port
X	o	create the scroll bar
X	o	get a line list big enough for the given number of lines
X
X	The port must be set before InitList is called, since the control
X	calculations depend on that.
X*/
X
XInitList (theList, maxLines)
Xregister ListPtr	theList;
XInteger					maxLines;
X{
XGrafPtr		curPort;
XRect		r;
XInteger			i;
X
X	theList->lines = (LAHandle) NewHandle (maxLines * sizeof (LineHandle));
X	theList->maxLines = maxLines;
X	theList->hilite = false;
X	r = theList->textRect;
X	r.left = r.right + 1;
X	r.right = r.left + 14;
X	InsetRect (&r, -1, -1);
X	GetPort (&curPort);
X	theList->port = curPort;
X	theList->scroll = NewControl (curPort, &r, "\p", true, 0, 0, 0,
X									scrollBarProc, 0L);
X}
X
X
X/*
X	Create a line for a LineList object.  Must pass the number of
X	fields in a line.  NewLine doesn't know anything about the owner
X	of the line except that.  In particular, it doesn't attach the
X	line to the LineList.
X*/
X
XLineHandle NewLine (nFields)
Xregister Integer		nFields;
X{
Xregister FieldHandle	hField1,
X						hField2 = nil;
X
X	while (nFields-- > 0)
X	{
X		hField1 = New (Field);
X		(**hField1).fStr[0] = 0;
X		(**hField1).fNext = hField2;
X		hField2 = hField1;
X	}
X	return (hField1);
X}
X
X
X/*
X	Dispose of a LineList line.  DisposeLine doesn't know anything
X	about the owner of the line.  In particular, it doesn't detach
X	the line from the LineList.
X
X	The case of theLine = nil is handled w/o special treatment.
X*/
X
XDisposeLine (theList, n)
XListPtr	theList;
XInteger		n;
X{
Xregister FieldHandle	hField1,
X						hField2;
X
X	hField1 = ListLine (theList, n);
X	ListLine (theList, n) = nil;
X	while (hField1 != nil)
X	{
X		hField2 = (**hField1).fNext;
X		DisposHandle (hField1);
X		hField1 = hField2;
X	}
X}
X
X
X/*
X	Set the text of a field
X*/
X
XSetFieldStr (field, str)
Xregister FieldHandle	field;
XStringPtr	str;
X{
X	HLock (field);
X	CopyString (str, (**field).fStr);
X	HUnlock (field);
X}
X
X
X/*
X	Return number of the line in which point is located.  First
X	line is line zero.  This does *not* (and *shouldn't*) check
X	whether the point is actually in the text rectangle.
X*/
X
XFindLine (theList, pt)
Xregister ListPtr	theList;
Xregister Point	pt;
X{
Xregister Integer		i, height;
X
X	height = theList->lineHeight;
X	i = pt.v - theList->textRect.top;
X	if (i < 0)
X		i -= height - 1;		/* so next division works properly */
X	i /= height;
X	return (i + theList->topVisLine);
X}
X
X
X/*
X	Scroll a LineList object absolutely to line n, i.e., so line
X	n is the top visible line.
X	This does not set the current line, since the lists are only
X	scrolled - nothing is actually selected.
X*/
X
XScrollToLine (theList, n)
XListPtr	theList;
Xregister Integer		n;
X{
Xregister Integer		nLines;
Xregister Integer		topLine;
Xregister Integer		bottomLine;
Xregister Integer		visLines;
XInteger		scrollAmt;
XInteger		firstRedraw, redrawCount;
XInteger		scrollFrom;
X
X	nLines = theList->nLines;
X	if (nLines == 0)
X		return;				/* nothing to scroll to */
X
X	topLine = theList->topVisLine;
X	visLines = theList->visLines;
X	bottomLine = topLine + visLines - 1;
X
X/*
X	clip n to range 0..nLines-1
X*/
X	if (n < 0)
X		n = 0;
X	if (n >= nLines)
X		n = nLines - 1;
X	
X/*
X	Determine scroll direction
X*/
X	if (n < topLine)
X		scrollAmt = topLine - n;		/* toward beginning */
X	else if (n > bottomLine)
X		scrollAmt = bottomLine - n;	/* toward end */
X	else
X		scrollAmt = 0;				/* already visible, no scroll */
X
X	if (nLines >= visLines)		/* enough to fill window */
X	{
X		if (nLines - visLines < topLine - scrollAmt)
X			scrollAmt += topLine - (nLines - visLines);
X	}
X
X	if (scrollAmt == 0)
X		return;
X
X/*
X	Figure out if any of the currently visible lines can be reused
X	by ScrollRect'ing them, and how many must be redrawn from scratch.
X	firstRedraw is determined as a number from 0..visLines-1, then
X	converted to an absolute line number.  This is because the value
X	of topLine is volatile; firstRedraw isn't tied to it until it
X	settles down.
X*/
X	if (scrollAmt <= -visLines || scrollAmt >= visLines)
X	{
X		firstRedraw = 0;
X		redrawCount = visLines;
X	}
X	else
X	{
X		if (scrollAmt > 0)
X		{
X			firstRedraw = 0;
X			redrawCount = scrollAmt;
X			scrollFrom = topLine;
X		}
X		else	/* scrollAmt < 0 */
X		{
X			firstRedraw = visLines + scrollAmt;
X			redrawCount = -scrollAmt;
X			scrollFrom = topLine - scrollAmt;
X		}
X/*
X	Don't scrollRect the stuff if not front window - might scroll in
X	background pattern if stuff to be scrolled is under another window.
X*/
X		if (theList->port == FrontWindow ())
X			ScrollListLines (theList, scrollFrom, scrollFrom + scrollAmt);
X		else
X		{
X			firstRedraw = 0;					/* draw from first visible */
X			redrawCount = theList->visLines;	/* and draw all visible */
X		}
X	}
X	theList->topVisLine -= scrollAmt;
X	firstRedraw += theList->topVisLine;
X	DrawListLines (theList, firstRedraw, firstRedraw + redrawCount - 1);
X	ListSetScroll (theList);
X}
X
X
X/*
X	Scroll LineList object up or down n lines.  n < 0 means scroll up
X	(towards beginning).
X*/
X
XListScrollRel (theList, n)
Xregister ListPtr	theList;
Xregister Integer		n;
X{
X	if (n < 0)
X		n += theList->topVisLine;
X	else
X		n += theList->topVisLine + theList->visLines - 1;
X	ScrollToLine (theList, n);
X}
X
X
X/*
X	Set the scroll bar value
X*/
X
XListSetScroll (theList)
XListPtr	theList;
X{
X	SetCtlValue (theList->scroll, theList->topVisLine);
X}
X
X
X/*
X	Set the scroll bar maximum value and highlight appropriately.
X	It unhilited if there aren't enough lines to make the scroll bar
X	necessary, or if the list isn't currently activated.
X*/
X
XListScrollMax (theList)
XListPtr	theList;
X{
XControlHandle	scroll;
Xregister Integer	maxScroll;
X
X	scroll = theList->scroll;
X	maxScroll = theList->nLines - theList->visLines;
X	if (maxScroll <= 0)
X	{
X		maxScroll = 0;
X	}
X	SetCtlMax (scroll, maxScroll);
X	HiliteControl (scroll, maxScroll > 0
X							&& theList->hilite
X							&& theList->port == FrontWindow ()
X							? 0 : 255);
X}
X
X
X/*
X	Select a line in the LineList.  The previous selection is
X	unhighlighted and the new selection is highlighted.
X	Selecting noLine unhilites currently selected line.
X
X	If the list isn't currently activated (hilite = true), just
X	set the curLine field and do nothing.
X
X	Note that InvertLine is smart about ignoring line "noLine" and
X	non-visible lines.
X*/
X
XSelectLine (theList, n)
Xregister ListPtr	theList;
Xregister Integer		n;
X{
Xregister Integer		prevCurLine;
X
X	if (n < 0 || n >= theList->nLines)	/* trim to range */
X		n = noLine;
X
X	prevCurLine = theList->curLine;
X	theList->curLine = n;
X
X	if (theList->hilite && n != prevCurLine)
X	{
X		InvertLine (theList, prevCurLine);	/* turn off previous line */
X		InvertLine (theList, n);			/* turn on new line */
X	}
X}
X
X
X/*
X	ListTestScroll
X	Handle clicks in the scroll bar of a LineList object.  If it returns
X	false, the click was not in the scroll bar, otherwise it was and
X	scrolling has already been handled.
X
X	ListTestText
X	Call this to see if the point was in the text rectangle of a
X	LineList object.  If not, ListTestText returns false.  Otherwise,
X	the line clicked on is highlighted and then the mouse is tracked
X	so that the line the mouse is in is hilited even if the mouse is
X	dragged.  If the mouse is dragged off the top or bottom of the
X	text rectangle, autoscrolling occurs.  If the user clicks or
X	drags below the bottom filled line but still in the text rectangle,
X	the current selection is deselected, but true is still returned.
X*/
X
X
X
Xstatic pascal void TrackScroll (theScroll, partCode)
XControlHandle	theScroll;
XInteger				partCode;
X{
Xregister Integer	lDelta;
X
X    if (partCode == trackPart)			/* still in same part? */
X    {
X        switch (partCode)
X        {
X            case inUpButton: lDelta = -1; break;
X            case inDownButton: lDelta = 1; break;
X            case inPageUp: lDelta = -(trackList->visLines-1); break;
X            case inPageDown: lDelta = trackList->visLines-1; break;
X        }
X		ListScrollRel (trackList, lDelta);
X    }
X}
X
X
X/*
X	Test whether the point lies in theList's scroll bar.  Handle scrolling
X	if so and return true, else return false.
X*/
X
XBoolean ListTestScroll (theList, pt)
XListPtr	theList;
XPoint	pt;
X{
XControlHandle	scrollBar;
XBoolean			result = false;
XInteger				line;
X
X	scrollBar = theList->scroll;
X	if ((trackPart = TestControl (scrollBar, pt)) != 0)
X	{
X		if (trackPart == inThumb)
X		{
X			line = GetCtlValue (scrollBar);
X			if (TrackControl (scrollBar, pt, nil) == inThumb)
X				ListScrollRel (theList, GetCtlValue (scrollBar) - line);
X		}
X		else
X		{
X			trackList = theList;
X			(void) TrackControl (scrollBar, pt, TrackScroll);
X		}
X		result = true;
X	}
X	return (result);
X}
X
X
X/*
X	Test whether the point lies in theList's text rect.  If it does,
X	select the correct line.  Handles autoscrolling when the mouse is
X	dragged outside of the text rectangle.
X*/
X
XBoolean ListTestText (theList, pt)
XListPtr	theList;
XPoint	pt;
X{
XBoolean	result = false;
Xregister Integer		line;
Xregister Integer		topLine;
Xregister Integer		bottomLine;
X
X	if (PtInRect (pt, &theList->textRect))
X	{
X		for (;;)
X		{
X			line = FindLine (theList, pt);
X			topLine = theList->topVisLine;
X			bottomLine = topLine + theList->visLines - 1;
X			if (line < topLine)
X				line = topLine - 1;		/* scroll up one */
X			if (line > bottomLine)
X				line = bottomLine + 1;	/* scroll down one */
X			if (line < 0)
X				line = 0;				/* can only scroll to line zero */
X			if (line > theList->nLines - 1)
X			{
X				if (PtInRect (pt, &theList->textRect))
X					line = noLine;
X				else
X					line = theList->nLines - 1;
X			}
X			SelectLine (theList, line);
X			ScrollToLine (theList, line);
X			if (!StillDown ())
X				break;
X			GetMouse (&pt);
X		}
X		result = true;
X	}
X	return (result);
X}
X
X
X/*
X	Insert a line into a line list at position n.  The line is
X	selected but that doesn't cause it to be scrolled into view.
X	The list is redrawn appropriately, i.e. with hiliting if it's
X	turned on.
X
X	Some intelligence is lacking to handle pathological things, so
X	that, for instance, inserting lines above the top visible line
X	will cause the stuff that's visible to be drawn shoved down a line.
X*/
X
XBoolean InsertLine (theList, theLine, n)
XListPtr		theList;
XLineHandle	theLine;
XInteger			n;
X{
XInteger			i;
XLAHandle	lines;
X
X	SelectLine (theList, noLine);	/* unhilite any previous selection */
X
X	if (n >= theList->maxLines)		/* uh-oh - no more room! */
X	{
X		lines = theList->lines;
X		if (ExpandHandle (lines, 1024L) == false)
X			return (false);			/* can't make room */
X		theList->maxLines = GetHandleSize (lines) / sizeof (LineHandle);
X	}
X
X	for (i = theList->nLines; i > n; --i)	/* make empty slot */
X		ListLine (theList, i) = ListLine (theList, i-1);
X	ListLine (theList, n) = theLine;
X	++theList->nLines;
X	ListScrollMax (theList);
X	DrawListLines (theList, n, n + theList->visLines - 1);
X	/*DrawListLines (theList, n, theList->topVisLine + theList->visLines - 1);*/
X	SelectLine (theList, n);
X	return (true);
X}
X
X
X/*
X	Delete a line from a line list.
X*/
X
XDeleteLine (theList, n)
XListPtr	theList;
XInteger		n;
X{
XInteger		i;
X
X	SelectLine (theList, noLine);		/* unhilite previous selection */
X	DisposeLine (theList, n);			/* toss storage for line */
X	for (i = n; i < theList->nLines - 1; ++i)
X		ListLine (theList, i) = ListLine (theList, i+1);	/* close up gap */
X	--theList->nLines;
X	ListScrollMax (theList);
X	DrawListText (theList);
X	/*ScrollToLine (theList, n);*/
X}
X
X
X/*
X	Paste a new string into one of a line's field.  It's redrawn
X	as well.
X*/
X
XPasteField (theList, lineNo, fieldNo, str)
XListPtr		theList;
XInteger			lineNo;
XInteger			fieldNo;
XStringPtr	str;
X{
XFieldHandle	hField;
XInteger			i = fieldNo;
X
X	hField = ListLine (theList, lineNo);
X	while (i-- > 0)
X		hField = NextField (hField);
X	SetFieldStr (hField, str);
X	DrawField (theList, lineNo, fieldNo);
X}
X
X
X
X/*
X	Paste a line into a line list.  It's redrawn as it's pasted,
X	and if it was the selected line before, is drawn hilited.
X
X	This could all be much smarter (and faster) but I don't care.
X	It works, and the speedup wouldn't be enough to make it worth
X	it.
X*/
X
XPasteLine (theList, theLine, n)
XListPtr		theList;
XLineHandle	theLine;
XInteger			n;
X{
XFieldHandle	hField;
XInteger			i;
X
X	for (i = 0, hField = theLine;
X			hField != nil;
X				hField = NextField (hField), ++i)
X	{
X		HLock (hField);
X		PasteField (theList, n, i, (**hField).fStr);
X		HUnlock (hField);
X	}
X}
X
X
X/*
X	Turn list hiliting on or off.  This also affects the scroll bar.
X*/
X
XListActivate (theList, hilite)
XListPtr	theList;
XBoolean	hilite;
X{
X	if (theList->hilite != hilite)		/* do this only on state change */
X	{
X		theList->hilite = hilite;
X		InvertLine (theList, theList->curLine);
X	}
X	ListScrollMax (theList);
X}
X
X
X/*
X	Toss all the lines of a list and redraw.  This doesn't change
X	the list hiliting state.
X*/
X
XResetList (theList)
XListPtr	theList;
X{
Xregister Integer	i;
X
X	for (i = 0; i < theList->nLines; ++i)
X		DisposeLine (theList, i);
X	theList->nLines = 0;
X	ListScrollMax (theList);
X	ListSetScroll (theList);
X	DrawListText (theList);
X}
X
X
X/* ---------------------------------------------------------------- */
X/*					LineList drawing routines						*/
X/* ---------------------------------------------------------------- */
X
X
X/* ---------------------------------------------------------------- */
X/*	There is some code redundancy among these routines.  The		*/
X/*	redundancy is for the purpose of increasing drawing speed.		*/
X/*	It is necessary to save and restore the port properly.  This	*/
X/*	is only done in the routines where that is really necessary.	*/
X/* ---------------------------------------------------------------- */
X
X
X
X/* ---------------------------------------------------------------- */
X/*					Display area calculations						*/
X/* ---------------------------------------------------------------- */
X
X
X/*
X	Get the rectangle enclosing the display area for one of the
X	lines.  The line number is an index in the range 0..visLines-1.
X	The left and right boundaries are the same as the general text
X	display rectangle, so only need to adjust top and bottom.
X*/
X
XGetLineRect (r, theList, lineNo)
XRect	*r;
XListPtr	theList;
XInteger		lineNo;
X{
XInteger		height;
X
X	*r = theList->textRect;
X	height = theList->lineHeight;
X	r->top += lineNo * height;
X	r->bottom = r->top + height;
X}
X
X
X/*
X	Get the rectangle enclosing the display area for one of the
X	fields of a line.  The line number is an index in the range
X	0..visLines-1.  The field number is an index in the range
X	0..nFields-1.
X
X	Must offset horizontally to get the absolute window position
X	since the offsets are relative to the text rectangle.
X	Leave one space to account for the separator line to the
X	left of the next field.
X	
X*/
X
XGetFieldRect (r, theList, lineNo, fieldNo)
XRect	*r;
XListPtr	theList;
XInteger		lineNo;
XInteger		fieldNo;
X{
X	GetLineRect (r, theList, lineNo);
X	r->left = theList->offset[fieldNo];
X	r->right = theList->offset[fieldNo + 1] - 1;
X	OffsetRect (r, theList->textRect.left, 0);
X}
X
X
X/* ---------------------------------------------------------------- */
X/*							Drawing routines						*/
X/* ---------------------------------------------------------------- */
X
X
X/*
X	Scroll the list's text rectangle.  Note that this may not produce
X	the correct effect if the window is not the front window - some
X	of the stuff shifted might not be visible, and when shifted out from
X	under another window, shifts out as the background pattern.
X*/
X
XScrollListLines (theList, from, to)
XListPtr	theList;
XInteger		from, to;
X{
XGrafPtr		curPort;
XRgnHandle	rgn;
X
X	GetPort (&curPort);
X	SetPort (theList->port);
X	rgn = NewRgn ();
X	ScrollRect (&theList->textRect, 0, (to-from) * theList->lineHeight, rgn);
X	DisposeRgn (rgn);
X	SetPort (curPort);
X}
X
X
X/*
X	Check whether a line is currently visible in the list's text
X	rectangle.
X*/
X
XBoolean LineVisible (theList, lineNo)
XListPtr	theList;
XInteger		lineNo;
X{
X	return (lineNo != noLine && lineNo >= theList->topVisLine
X			&& lineNo < theList->topVisLine + theList->visLines);
X}
X
X
X/*
X	Invert a line from a list.  The line number passed is not
X	assumed to be visible.
X
X	This routine will give you trouble if you're not careful!
X*/
X
XInvertLine (theList, lineNo)
XListPtr	theList;
XInteger		lineNo;
X{
XGrafPtr	curPort;
XInteger		i;
XRect	r;
X
X	if (!LineVisible (theList, lineNo))
X			return;
X	GetPort (&curPort);
X	SetPort (theList->port);
X	GetLineRect (&r, theList, lineNo - theList->topVisLine);
X	InvertRect (&r);
X	SetPort (curPort);
X}
X
X
X/*
X	Draw a field from a list.  The line number passed is not assumed to
X	be visible.  If the line doesn't really exist (i.e., lineNo >= nLines)
X	a blank field is drawn.
X*/
X
XDrawField (theList, lineNo, fieldNo)
Xregister ListPtr	theList;
Xregister Integer		lineNo;
XInteger		fieldNo;
X{
XGrafPtr		curPort;
XRect		r;
Xregister FieldHandle	hField;
XBoolean		invert;
XRgnHandle	rgn;
XInteger			textMode;
X
X	if (!LineVisible (theList, lineNo))
X			return;
X
X	GetPort (&curPort);
X	SetPort (theList->port);
X	invert = theList->hilite && (theList->curLine == lineNo);
X	GetFieldRect (&r, theList, lineNo - theList->topVisLine, fieldNo);
X	FillRect (&r, invert ? black : white);
X	if (lineNo < theList->nLines)
X	{
X		hField = ListLine (theList, lineNo);
X		while (fieldNo-- > 0)
X			hField = NextField (hField);
X		rgn = NewRgn ();
X		GetClip (rgn);
X		ClipRect (&r);
X		MoveTo (r.left + 2, r.bottom - 4);
X		textMode = theList->port->txMode;
X		TextMode (invert? srcBic : srcOr);
X		HLock (hField);
X		DrawString ((**hField).fStr);
X		HUnlock (hField);
X		TextMode (textMode);
X		SetClip (rgn);
X		DisposeRgn (rgn);
X	}
X	SetPort (curPort);
X}
X
X
X/*
X	Draw a line from a list.  The line number passed is not assumed to be
X	visible.  If the line doesn't really exist (i.e., lineNo >= nLines)
X	then draw blank fields.
X*/
X
XDrawLine (theList, lineNo)
Xregister ListPtr	theList;
XInteger		lineNo;
X{
XGrafPtr		curPort;
Xregister Integer	i;
Xregister Integer	topLine;
XInteger			top, bottom, left;
XInteger			penMode;
XRect		r;
XFieldHandle	hField;
XBoolean		invert;
X
X	if (!LineVisible (theList, lineNo))
X			return;
X
X	GetPort (&curPort);
X	SetPort (theList->port);
X	topLine = theList->topVisLine;
X	
X	invert = theList->hilite && (lineNo == theList->curLine);
X
X	top = theList->textRect.top + theList->lineHeight * (lineNo - topLine);
X	bottom = top + theList->lineHeight - 1;
X	penMode = theList->port->pnMode;
X	if (invert)
X		PenMode (patBic);
X
X	for (i = 0; i < theList->nFields; ++i)
X	{
X		DrawField (theList, lineNo, i);
X		if (i > 0)
X		{
X			left = theList->textRect.left + theList->offset[i] - 1;
X			MoveTo (left, top);
X			LineTo (left, bottom);
X		}
X	}
X
X	PenMode (penMode);
X	SetPort (curPort);
X}
X
X
XDrawListLines (theList, from, to)
Xregister ListPtr	theList;
Xregister Integer		from, to;
X{
Xregister Integer		i;
X
X	for (i = from;  i <= to; ++i)
X	{
X		DrawLine (theList, i);
X	}
X}
X
X
XDrawListText (theList)
Xregister ListPtr	theList;
X{
X	DrawListLines (theList, theList->topVisLine,
X					theList->topVisLine + theList->visLines - 1);
X}
X
X
XDrawListFrame (theList)
Xregister ListPtr	theList;
X{
XGrafPtr	curPort;
XRect	r;
Xregister Integer		i;
Xregister Integer		offset;
X
X	GetPort (&curPort);
X	SetPort (theList->port);
X	r = theList->textRect;
X	InsetRect (&r, -1, -1);
X	FrameRect (&r);
X	InsetRect (&r, 1, 1);
X
X/*
X	Draw separator lines.  These are drawn one pixel to the left of
X	the field area.
X*/
X
X	for (i = 1; i < theList->nFields; ++i)
X	{
X		offset = r.left + theList->offset[i] - 1;
X		MoveTo (offset, r.top);
X		LineTo (offset, r.bottom);
X	}
X	SetPort (curPort);
X}
X
X
X/*
X	Redraw the list.  Set the control hiliting value to its current
X	value to redraw it.  Draw the text area frame (including field
X	separating bars), then draw all the visible lines.
X*/
X
XDrawList (theList)
Xregister ListPtr	theList;
X{
XControlHandle	scroll;
X
X	scroll = theList->scroll;
X	HiliteControl (scroll, (**scroll).contrlHilite);
X	DrawListFrame (theList);
X	DrawListText (theList);
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > MW/MWCheckMark.c
X# include	"MakeWrite.h"
X
X
X/*
X	markRes holds the result, for each map line, of the current match
X	state.  Element i is true if mark i still matches the input, false
X	if not.
X
X	markRes is big enough to hold one entry for each formatting
X	specification, plus one entry for each special marker.  The special
X	marks must generally be special-cased.
X	
X	Right now there's two special marks - the paragraph indicator
X	mark and the page break.
X
X	markPos is the position in the marks that the current input char is
X	matched against.
X*/
X
X# define	maxMarkers	(maxMappings + extraMarks)
X
X
Xstatic Boolean		markRes[maxMarkers];
Xstatic Integer			markPos;
X
X
X/*
X	Look for marks that are empty.  This is done before any text->write
X	conversion because empty marks are illegal.
X
X	Return false if no empty marks, otherwise true.
X	
X	No check on the paragraph marker:  that's handled by the paragraph
X	style dialog.
X*/
X
XBoolean FindEmptyMark ()
X{
Xregister Integer	i;
X
X	for (i = 0; i < mapList->nLines; ++i)
X	{
X		if ((*mapSpec[i].mark)[0] == 0)
X		{
X			SelectMapping (i);
X			Message1 ("\pCan't have empty format markers");
X			return (true);
X		}
X	}
X	return (false);
X}
X
X
X/*
X	Initialize all the used mark states (every mark eligible) and
X	reset the mark position
X*/
X
XInitMarkStates ()
X{
Xregister Integer	i;
X
X	markPos = 0;
X	for (i = 0; i < mapList->nLines; ++i)
X		markRes[i] = true;
X	for (i = maxMappings; i < maxMarkers; ++i)
X		markRes[i] = true;
X}
X
X
X/*
X	Check current input character against the current mark position
X	of each of the marks that are still in the running for a match.
X	Eliminate those that don't match the char.  For those that do,
X	if the entire mark has been matched, then it's a hit, and the format
X	of the input should be changed to that of the format corresponding
X	to the mark.
X
X	Return -2 if no more marks are in the running, -1 if any marks
X	are still in the running but none have been matched completely,
X	otherwise return the index of the completely matched mark.
X
X	Check format markers first, then paragraph marker (if one is being
X	used).
X*/
X
XCheckMarkers (c)
Xchar	c;
X{
Xregister Integer			i;
Xregister Integer			count = 0;	/* number of matches */
Xregister StringHandle	hStr;
X
X	++markPos;						/* advance to next marker position */
X	for (i = 0; i < mapList->nLines; ++i)
X	{
X		if (markRes[i])				/* if mark still in running */
X		{
X			hStr = mapSpec[i].mark;
X			if (c != (*hStr)[markPos])
X				markRes[i] = false;	/* this one's eliminated now */
X			else
X			{						/* this one still matches -- */
X				++count;			/* has the end been reached? */
X				if (markPos == (*hStr)[0])
X					return (i);		/* yes */
X			}
X		}
X	}
X
X/*
X	Check special marks:  paragraph and page break
X*/
X	if (paraMark[0] > 0 && markRes[paraMarkIdx])
X	{
X	 	if (c != paraMark[markPos])
X	 		markRes[paraMarkIdx] = false;
X	 	else
X		{
X			++count;
X			if (markPos == paraMark[0])
X				return (paraMarkIdx);
X		}
X	}
X
X	if (pageMark[0] > 0 && markRes[pageMarkIdx])
X	{
X	 	if (c != pageMark[markPos])
X	 		markRes[pageMarkIdx] = false;
X	 	else
X		{
X			++count;
X			if (markPos == paraMark[0])
X				return (pageMarkIdx);
X		}
X	}
X
X	return (count > 0 ? -1 : -2);
X}
X
X
X/*
X	Check two markers.  If one is a prefix of the other, put up a
X	warning.  Return false if the user says not to continue.  If the
X	user says to continue, or there's no conflict, return true.
X*/
X
Xstatic Boolean ConflictCheck (s1, s2, type1, type2)
XStringPtr	s1, s2, type1, type2;
X{
Xregister Integer	i, len;
X
X	len = s1[0];
X	if (s2[0] < len)
X		len = s2[0];
X	for (i = 1; i <= len; ++i)
X	{
X		if (s1[i] != s2[i])
X			return (true);		/* not a prefix - continue */
X	}
X	ParamText (type1, s1, type2, s2);
X	return (Alert (conflictAlrtNum, nil) == 1);
X}
X
X
X/*
X	Find conflicts among the set of markers
X*/
X
XFindConflicts ()
X{
Xregister Integer			i, j;
Xregister StringHandle	h1, h2;
Xregister Boolean		loop = true;
X
X	for (i = 0; loop && i < mapList->nLines; ++i)
X	{
X		h1 = mapSpec[i].mark;
X		HLock (h1);
X		for (j = i + 1; loop && j < mapList->nLines; ++j)
X		{
X			h2 = mapSpec[j].mark;
X			HLock (h2);
X			loop = ConflictCheck (*h1, *h2, "\pformat", "\pformat");
X			HUnlock (h2);
X		}
X		if (loop && paraMark[0] > 0)
X			loop = ConflictCheck (*h1, paraMark, "\pformat", "\pparagraph");
X		if (loop && pageMark[0] > 0)
X			loop = ConflictCheck (*h1, pageMark, "\pformat", "\ppage break");
X		if (loop && paraMark[0] > 0 && pageMark[0] > 0)
X			loop = ConflictCheck (paraMark, pageMark, "\pparagraph", "\ppage break");
X		HUnlock (h1);
X	}
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > MW/MWFileStuff.c
X/*
X	MWFileStuff.c - file routines of general usefulness.
X*/
X
X
X# include	"MWFileStuff.h"
X# include	"MWMaca.h"
X# include	<FileMgr.h>
X# include	<StdFilePkg.h>
X# include	<ToolboxUtil.h>
X
X
X/* ---------------------------------------------------------------- */
X/*					Generic Error Message Routine					*/
X/* ---------------------------------------------------------------- */
X
X
X/*
X	If errNo isn't noErr, then print a message.  The message is found
X	in the 'STR ' resource of the same number as the file err.  If
X	no resource is found with that number, use a default message.
X*/
X
XFileErr (errNo)
XOSErr		errNo;
X{
Xregister StringHandle	h;
XStr255					numStr;
XStr255					meaning;
X
X	if (errNo == noErr)
X		return;
X
X	CopyString ("\pNo error message available", meaning);	/* default */
X
X	h = GetString (errNo);
X	if (h != nil && HomeResFile (h) == CurResFile ())
X	{
X		HLock (h);
X		CopyString (*h, meaning);
X		HUnlock (h);
X		ReleaseResource (h);
X	}
X
X	NumToString ((Longint) errNo, numStr);
X	Message ("\pI/O error ", numStr, "\p: ", meaning);
X}
X
X
X/* ---------------------------------------------------------------- */
X/*			Routines to get or open files for input or output		*/
X/* ---------------------------------------------------------------- */
X
X
Xstatic Point	dlogWhere = { 70, 100 };	/* Get/PutFile dlog location */
Xstatic Str255	buttonTitle;				/* "Open" button title */
X
X
X/*
X	GFFilter is a SFGetFile filter to set the name of the "Open"
X	button.
X*/
X
Xtypedef	Ptr	DialogPtr;		/* not right, but... */
X
Xstatic pascal Integer GFFilter (theItem, theDialog)
XInteger			theItem;
XDialogPtr	theDialog;
X{
XInteger		itemNo;
XInteger		itemType;
XHandle	itemHandle;
XRect	r;
X
X	if (theItem == -1)	/* change "Open" button name */
X	{
X		GetDItem (theDialog, 1, &itemType, &itemHandle, &r);
X		SetCTitle (itemHandle, buttonTitle);
X	}
X	return (theItem);
X}
X
X
X/*
X	Get a filename for input.
X*/
X
XBoolean GetInputFile (bTitle, type, inFile)
XStringPtr	bTitle;
XOSType		type;
XSFReply		*inFile;
X{
X	CopyString (bTitle, buttonTitle);	/* set title for "Open" button */
X	SFGetFile (dlogWhere, "\p", nil, 1, &type, GFFilter, inFile);
X	DoUpdates ();
X	return (inFile->good);
X}
X
X
X/*
X	Open a filename for input.
X*/
X
XBoolean OpenInputFile (inFile, f)
XSFReply		*inFile;
XInteger			*f;
X{
XOSErr		result;
X
X	result = FSOpen (inFile->fName, inFile->vRefNum, f);
X	if (result != noErr)
X	{
X		FileErr (result);
X		Message3 ("\pCannot open \"", inFile->fName, "\p\".");
X	}
X	return (result == noErr);
X}
X
X
X/*
X	Get a filename for output.
X	Pass the current name and volume reference, and whether to
X	ask for a name even if one is known.  Return the information
X	in the SFReply record.
X
X	Note: if ask is false and the name isn't "Untitled", the name
X	passed is assumed to be the correct name to use and is returned.
X	This may seem odd, but eliminates making the check every place
X	from which this is called.
X*/
X
XBoolean GetOutputFile (ask, fName, vRefNum, outFile)
XBoolean		ask;
XStringPtr	fName;
XInteger			vRefNum;
XSFReply		*outFile;
X{
X	CopyString (fName, outFile->fName);
X	outFile->vRefNum = vRefNum;
X	if (ask || CompareString ("\pUntitled", fName) == 0)
X	{
X		SFPutFile (dlogWhere, "\pWrite to...", fName, nil, outFile);
X		DoUpdates ();
X		if (!outFile->good)
X			return (false);
X	}
X	return (true);
X}
X
X
X/*
X	Open output file, creating if necessary.  Truncate contents as well.
X*/
X
XBoolean OpenOutputFile (outFile, creator, type, f)
Xregister SFReply		*outFile;
XOSType		creator;
XOSType		type;
XInteger			*f;
X{
XFInfo	fndrInfo;
XOSErr	result;
X
X	if (GetFInfo (outFile->fName, outFile->vRefNum, &fndrInfo) == noErr)
X	{
X		if (fndrInfo.fdCreator != creator || fndrInfo.fdType != type)
X		{
X			Message3 ("\p\"", outFile->fName, "\p\" is not a file of the proper type");
X			return (false);
X		}
X	}
X	else	/* Doesn't exist.  Try to create it. */
X	{
X		result = Create (outFile->fName, outFile->vRefNum, creator, type);
X		if (result != noErr)
X		{
X			FileErr (result);
X			Message3 ("\pCan't create \"", outFile->fName, "\p\"");
X			return (false);
X		}
X		else				/* new file now - set Finder info */
X		{
X			(void) GetFInfo (outFile->fName, outFile->vRefNum, &fndrInfo);
X			fndrInfo.fdFlags &= ~1;		/* clear init'ed bit */
X			fndrInfo.fdLocation.h = 0;
X			fndrInfo.fdLocation.v = 0;
X			fndrInfo.fdFldr = 0;
X			(void) SetFInfo (outFile->fName, outFile->vRefNum, &fndrInfo);
X		}
X	}
X
X	result = FSOpen (outFile->fName, outFile->vRefNum, f);
X	if (result != noErr)
X	{
X		FileErr (result);
X		Message3 ("\pCan't write to \"", outFile->fName, "\p\".");
X	}
X	else
X		(void) SetEOF (*f, 0L);	/* clear contents */
X
X	return (result == noErr);
X}
X
X
X/* ---------------------------------------------------------------- */
X/*					Seek, Read, Write on open files					*/
X/* ---------------------------------------------------------------- */
X
X
X/*
X	Seek to given position in file
X*/
X
XFileSeek (f, pos)
XInteger		f;
XLongint	pos;
X{
X	(void) SetFPos (f, fsFromStart, pos);
X}
X
X
X/*
X	Return current file position
X*/
X
XLongint FilePos (f)
XInteger		f;
X{
XLongint	pos;
X
X	(void) GetFPos (f, &pos);
X	return (pos);
X}
X
X
X/*
X	Read the given number of bytes from a file.  Return false
X	if fail.  Note that false is returned if something is read, but
X	not the full amount, thus the caller should know exactly how
X	much to read when close to the end of the file.
X*/
X
XBoolean FileRead (f, p, amount)
XInteger		f;
XPtr		p;
XLongint	amount;
X{
XOSErr	result;
XLongint	read;
XBoolean	ok = false;
X
X	read = amount;
X	if ((result = FSRead (f, &read, p)) != noErr && result != eofErr)
X		FileErr (result);
X	else
X		ok = (amount == read);
X	return (ok);
X}
X
X
X/*
X	Write the given number of bytes from a file.  Return false
X	if fail.
X*/
X
XBoolean FileWrite (f, p, amount)
XInteger		f;
XPtr		p;
XLongint	amount;
X{ 
XOSErr	result;
XLongint	written;
XBoolean	ok = false;
X
X	written = amount;
X	if ((result = FSWrite (f, &written, p)) != noErr)
X		FileErr (result);
X	else if (amount != written)
X		Message1 ("\pIncomplete write operation");
X	else
X		ok = true;
X	return (ok);
X}
X
X
X/* ---------------------------------------------------------------- */
X/*						Read, Write on data types					*/
X/* ---------------------------------------------------------------- */
X
X
XBoolean ReadInteger (f, val)
XInteger		f;
XInteger	*val;
X{
X	return (FileRead (f, val, (Longint) sizeof (Integer)));
X}
X
X
XBoolean WriteInteger (f, val)
XInteger		f;
XInteger	val;
X{
X	return (FileWrite (f, &val, (Longint) sizeof (Integer)));
X}
X
X
XBoolean WriteLongint (f, val)
XInteger		f;
XLongint	val;
X{
X	return (FileWrite (f, &val, (Longint) sizeof (Longint)));
X}
X
X
XBoolean WriteString (f, s)
XInteger			f;
XStringPtr	s;
X{
X	return (FileWrite (f, s, (Longint) (s[0] + 1)));
X}
X
X
XBoolean ReadString (f, s)
XInteger			f;
XStringPtr	s;
X{
X	return (FileRead (f, s, 1L) && FileRead (f, s + 1, (Longint) s[0]));
X}
X
X
X/*
X	Write n zero bytes, and make sure the file position ends up on
X	a word boundary (by writing an extra zero byte if necessary).
X	ZeroPad (0) to just align the boundary.
X	Return false if file error.
X*/
X
XBoolean ZeroPad (f, n)
XInteger		f;
XInteger		n;
X{
Xchar	c = 0;
X
X	if ((FilePos (f) + n) % 2 != 0)		/* write enough to align on boundary */
X		++n;
X	while (n-- > 0)
X	{
X		if (!FileWrite (f, &c, 1L))
X			return (false);
X	}
X	return (true);
X}
SHAR_EOF
exit
--- end of part 1 ---

macintosh@felix.UUCP (03/21/87)

[MakeWrite Source - part 2 of 3]

---
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	MW/MWFontOps.c
#	MW/MWGen.c
#	MW/MWIO.c
#	MW/MWMSpecOps.c
#	MW/MWMain.c
#	MW/MWMapOps.c
#	MW/MWMapWind.c
sed 's/^X//' << 'SHAR_EOF' > MW/MWFontOps.c
X# include	"MakeWrite.h"
X# define	applFont	1
X
X
X/*
X	Query user whether to replace the current font list with the
X	selected font, or just add them to the list.  Return false if
X	Cancel clicked.  If Replace clicked, then warn user that the
X	map will be destroyed (if it has been changed) and return false
X	if he declines.  Otherwise return true.
X	
X	If Replace is selected, then the map and the font list are
X	cleared as well as setting some state variables.  The map is
X	really modified by clearing it, but that was ok'd by user, so is
X	now considered clean (unmodified) - just like after New Map.
X*/
X
Xstatic Boolean ReplaceOrAdd ()
X{
Xtypedef enum	/* alert button numbers */
X{
X	cancel = 1,
X	add,
X	replace
X};
Xregister Integer	i;
X
X	i = Alert (replaceAlrtNum, nil);
X	DoUpdates ();
X
X	if (i == cancel)
X		return (false);
X
X	if (i == replace)
X	{
X		if (!DestroyWarn ())
X			return (false);
X		ClobberMap ();
X		ClearMapName ();
X		ResetFontList ();
X		mapModified = false;
X		undoOp = noUndo;
X	}
X	return (true);
X}
X
X
X/*
X	Add the names of the FONT resources in the open resource files
X	to the font list (or replace the list with those fonts).
X
X	Not all FONT resources have a name, so check it first.  This could
X	equally well be done by using only those FONT resources corresponding
X	to a point size of zero (bits 0-6 of the resource id equal to zero).
X*/
X
XResourceFonts (ask)
XBoolean	ask;
X{
XHandle			h;
Xregister Integer	i;
XInteger				fNum, nFonts;
XInteger				resId;
XResType			resType;
XStr255			resName;
X
X	if (ask)
X	{
X		if (ReplaceOrAdd () == false)
X			return;
X	}
X
X	nFonts = CountResources ('FONT');
X	SetResLoad (false);
X	for (i = 1; i <= nFonts; ++i)
X	{
X		h = GetIndResource ('FONT', i);
X		GetResInfo (h, &resId, &resType, &resName);
X		if (resName[0] != 0)	/* not all font resources have names! */
X		{
X			GetFNum (resName, &fNum);
X			if (!SetFontSpec (fNum, resName))
X				break;
X		}
X	}
X	SetResLoad (true);
X	SyncFontSpecs ();
X}
X
X
X/*
X	Add the fonts contained in the STR# whose id is  fontStrNum
X	to the font list (or replace the list with those fonts).
X*/
X
XStrFonts (ask)
XBoolean	ask;
X{
XHandle			h;
Xregister Integer	i, j, len;
XInteger				nStrings;
XStr255			s;
XLongint			fNum;
X
X	if (ask)
X	{
X		if (ReplaceOrAdd () == false)
X			return;
X	}
X
X	h = GetResource ('STR#', fontStrNum);
X	nStrings = * (Integer *) *h;
X
X	for (i = 0; i < nStrings; ++i)
X	{
X		GetIndString (s, fontStrNum, i + 1);
X		if (s[1] == '#')
X			continue;			/* comment - ignore */
X		len = s[0];
X		j = 1;
X		while (j <= len && s[j] != '/')
X			++j;
X		if (j > len)	/* error */
X		{
X			NumToString ((Longint) fontStrNum, s);
X			Message3 ("\pA font list resource (STR# ", s,
X						"\p) is messed up.");
X			break;
X		}
X		s[0] = j - 1;	/* length of numeric part */
X		StringToNum (s, &fNum);
X		s[j] = len - j;
X		if (!SetFontSpec ((Integer) fNum, &s[j]))
X			break;
X	}
X	ReleaseResource (h);
X	SyncFontSpecs ();
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > MW/MWGen.c
X# include	"MWMaca.h"
X# include	"MWFileStuff.h"
X
X
X/*
X	Prototype for data of empty paragraph
X*/
X
Xtypedef struct EmptyParaData6
X{
X	Integer	pTextLen;
X	Integer	pFmtLen;
X	Format	pFormat;
X} EmptyParaData6;
X
X
XEmptyParaData6	emptyParaData =
X{
X	0,								/* text length = 0 (no text) */
X	6,								/* format data length (1 format) */
X	{ 0, 12, 0, 1}					/* format: pos 0, size 12, style */
X									/* plain, application font */
X};
X
X
XUPrintRec	uPrintRec;	/* not initialized - doesn't matter? */
X
X
XRuler	stdRuler =
X{
X	10,								/* left margin */
X	480,							/* right margin */
X	leftJust,						/* justification */
X	10,								/* number of tabs */
X	0,								/* line spacing = single */
X	10,								/* indentation of first line */
X	{ 40, 80, 120, 160, 200,		/* tab values */
X	  240, 280, 320, 360, 400 },	/* tab values */
X	{ 0, 0, 0, 0 }					/* four bytes fill */
X};
X
X
X
XGlobals6	globals =
X{
X	6,								/* MacWrite 4.5 = version 6 */
X	0,								/* main doc para count - fill in later */
X	2,								/* header para count */
X									/* (one ruler + 1 empty text para) */
X	2,								/* footer para count */
X									/* (one ruler + 1 empty text para) */
X	0,								/* title page flag */
X	0,								/* unused */
X	0,								/* scrap not displayed */
X	0,								/* footer not displayed */
X	0,								/* header not displayed */
X	0,								/* rulers displayed */
X	-1,								/* active document: -1 tells MacWrite */
X									/* to recalc display information */
X	1,								/* starting page = 1 */
X	0L,								/* free list position - fill in later */
X	8,								/* free list length */
X	8,								/* # bytes allocated for list */
X	{ 0, 0, 0, 0, 0, 0, 0,			/* unused */
X	  0, 0, 0, 0, 0, 0, 0 }			/* unused */
X};
X
X
XWindows6	windowVars =
X{
X	{ 1, 0 },						/* start of selection (para 1, char 0) */
X	{ 1, 0 },						/* end of selection (para 1, char 0) */
X	0,								/* vertical offset */
X	0,								/* first paragraph to redraw */
X	0L,								/* position of information array */
X									/* (filled in later) */
X	0,								/* length of information array */
X									/* (filled in later) */
X	0L,								/* position of line height array */
X									/* (filled in later) */
X	0,								/* length of line height array */
X									/* (filled in later) */
X	{ -14, 30 },					/* page icon position */
X	{ -14, 236 },					/* date icon position */
X	{ -14, 442 },					/* time icon position */
X	{ -1, -1, -1, -1 },				/* four bytes fill */
X	-1,								/* redraw ovals (icons) */
X	0,								/* don't redraw rulers */
X	{ -1, -1 },						/* face active when saved */
X									/* (-1 = "has never been set") */
X	-1								/* font active when saved */
X									/* (-1 = "has never been set") */
X};
X
X
XParaInfo6	rulerParaInfo;
XParaInfo6	nullTextParaInfo;
X
X
XBoolean SetParaInfo (p, height, status, dataPos, dataLen, comFormats)
Xregister ParaInfo6	*p;
XInteger			height;
XByte		status;
XLongint		dataPos;
XInteger			dataLen;
XInteger			comFormats;
X{
X
X# ifdef	debug
X	DisplayString ("\p{SetParaInfo}");
X# endif
X
X	p->paraHeight = height;
X	p->paraPos = 0;
X	p->paraHandle = nil;
X	p->paraStOff.paraOffset = dataPos;		/* this first */
X	p->paraStOff.paraStatus = status;		/* *then* this! */
X	p->paraLen = dataLen;
X	p->paraFmts = comFormats;
X
X	return (true);
X}
X
X
X/*
X	Write file prelude, using prototype structures.
X		Global variables
X		Universal print record
X		Footer document variables
X		Header document variables
X		Main document varables
X
X	Some of these will be patched in the postlude.
X
X	Also write as much of the invariant file contents as possible:
X		Footer document contents (1 ruler + 1 empty text paragraph)
X		Header document contents (1 ruler + 1 empty text paragraph)
X		Initial ruler of main document
X*/
X
XBoolean WritePrelude (f)
Xregister Integer	f;
X{
X
X	return (FileWrite (f, &globals, (Longint) sizeof (Globals6))
X		&& FileWrite (f, &uPrintRec, (Longint) sizeof (UPrintRec))
X		&& FileWrite (f, &windowVars, (Longint) sizeof (Windows6))
X		&& FileWrite (f, &windowVars, (Longint) sizeof (Windows6))
X		&& FileWrite (f, &windowVars, (Longint) sizeof (Windows6))
X		&& ZeroPad (f, 6)
X		&& FileWrite (f, &stdRuler, (Longint) sizeof (Ruler))
X		&& FileWrite (f, &emptyParaData, (Longint) sizeof (EmptyParaData6))
X		&& FileWrite (f, &stdRuler, (Longint) sizeof (Ruler))
X		&& FileWrite (f, &emptyParaData, (Longint) sizeof (EmptyParaData6))
X		&& FileWrite (f, &stdRuler, (Longint) sizeof (Ruler))
X	);
X}
X
X
X/*
X	Write line height array, one entry for each paragraph.  First
X	para is always a ruler - write a zero word.  Other paras are
X	faked by writing information that there's one line in the para
X	of height 16 (12-point height).  MacWrite will fix when it reads
X	the file.
X
X	paraCount assumed >= 2.
X*/
X
XBoolean WriteLineHeights (f, paraCount)
XInteger		f;
XInteger	paraCount;
X{
X
X	if (!WriteInteger (f, 0))
X		return (false);
X
X	while (--paraCount > 0)
X	{
X		if (!WriteLongint (f, 0x00011010))
X			return (false);
X	}
X	
X	return (true);
X}
X
X
X/*
X	Write line height and paragraph info positions and lengths
X*/
X
XBoolean WriteArrayInfo (f, seek, piPos, piLen, lhPos, lhLen)
XInteger		f;
XLongint	seek;
XLongint	piPos;
XInteger	piLen;
XLongint	lhPos;
XInteger	lhLen;
X{
X
X	FileSeek (f, seek);
X	return (WriteLongint (f, piPos) && WriteInteger (f, piLen)
X			&& WriteLongint (f, lhPos) && WriteInteger (f, lhLen));
X}
X
X
X/*
X	Paragraph data are all written now.  The line height and paragraph
X	info arrays must now be written, as well as an empty free list.
X	Save the positions of these arrays, as they must be patched into
X	the window variables.
X
X	The paraCount and paraInfo are for the text paragraphs only.
X	When the main document paragraph count and paragraph information
X	are length are patched into the globals, increment to take
X	into account the initial ruler (written during prelude).
X*/
X
XBoolean WritePostlude (f, paraCount, paraInfo)
Xregister Integer	f;
XInteger		paraCount;
XPIAHandle	paraInfo;
X{
XLongint	fLHPos, fPIPos;		/* footer line height, para info array pos */
XLongint	hLHPos, hPIPos;		/* header line height, para info array pos */
XLongint	mLHPos, mPIPos;		/* main line height, para info array pos */
XInteger	paraInfoLen;		/* length of main para info array */
XInteger	defInfoLen;			/* length of header, footer pi array */
XInteger	defLHLen;			/* length of header, footer line height array */
XInteger	mainLHLen;			/* length of main line height array */
XLongint	freeListPos;		/* free list pos */
XBoolean	result;
X
X/*
X	Set up prototype ruler paragraph and null text paragraph
X	information array elements.  The position field must be filled
X	in on a per-window basis.
X*/
X
X	SetParaInfo (&rulerParaInfo, 0, 0, (Longint) 0x130, 34, 0);
X	SetParaInfo (&nullTextParaInfo, 16, 0, (Longint) 0x152, 10, 0);
X
X/*
X	For footer
X*/
X
X	fLHPos = FilePos (f);
X	if (!WriteLineHeights (f, 2))
X		return (false);
X
X	fPIPos = FilePos (f);
X	if (!FileWrite (f, &rulerParaInfo, (Longint) sizeof (ParaInfo6))
X		|| !FileWrite (f, &nullTextParaInfo, (Longint) sizeof (ParaInfo6)))
X			return (false);
X
X/*
X	For header
X*/
X
X	hLHPos = FilePos (f);
X	if (!WriteLineHeights (f, 2))
X		return (false);
X
X	rulerParaInfo.paraStOff.paraOffset += sizeof (Ruler) + sizeof (EmptyParaData6);
X	nullTextParaInfo.paraStOff.paraOffset += sizeof (Ruler) + sizeof (EmptyParaData6);
X
X	hPIPos = FilePos (f);
X
X	if (!FileWrite (f, &rulerParaInfo, (Longint) sizeof (ParaInfo6))
X		|| !FileWrite (f, &nullTextParaInfo, (Longint) sizeof (ParaInfo6)))
X			return (false);
X
X/*
X	For main
X*/
X
X	mLHPos = FilePos (f);
X	if (!WriteLineHeights (f, paraCount + 1))
X		return (false);
X
X	rulerParaInfo.paraStOff.paraOffset += sizeof (Ruler) + sizeof (EmptyParaData6);
X
X	mPIPos = FilePos (f);
X
X	if (!FileWrite (f, &rulerParaInfo, (Longint) sizeof (ParaInfo6)))
X		return (false);
X
X	paraInfoLen = paraCount * sizeof (ParaInfo6);
X	HLock (paraInfo);
X	result = FileWrite (f, *paraInfo, (Longint) paraInfoLen);
X	HUnlock (paraInfo);
X	if (!result)
X		return (false);
X
X/*
X	Write free list.  It's at the end of the file, so set the
X	file EOF here, too.
X*/
X
X	freeListPos = FilePos (f);
X	if (!WriteLongint (f, freeListPos + 8) || !WriteLongint (f, 0L))
X		return (false);
X
X	(void) SetEOF (f, FilePos (f));
X
X/*
X	Now patch  globals and window variables:
X		main doc para count (increment to account for ruler)
X		free list position
X		line height and para info array positions (and para info array
X		length for main document)
X*/
X
X	FileSeek (f, 2L);
X	++paraCount;
X	paraInfoLen += sizeof (ParaInfo6);
X	if (!WriteInteger (f, paraCount))
X		return (false);
X	FileSeek (f, 18L);
X	if (!WriteLongint (f, freeListPos))
X		return (false);
X
X	defInfoLen = 2 * sizeof (ParaInfo6);
X	defLHLen = 3 * sizeof (Integer);
X	mainLHLen = sizeof (Integer) + (paraCount-1) * sizeof (Longint);
X	if (!WriteArrayInfo (f, 172L, fPIPos, defInfoLen, fLHPos, defLHLen)
X		|| !WriteArrayInfo (f, 218L, hPIPos, defInfoLen, hLHPos, defLHLen)
X		|| !WriteArrayInfo (f, 264L, mPIPos, paraInfoLen, mLHPos, mainLHLen))
X			return (false);
X
X	return (true);
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > MW/MWIO.c
X/*
X	MakeWrite File I/O  Routines.
X*/
X
X
X# include	"MakeWrite.h"
X# include	"MWFileStuff.h"
X# include	"MWMaca.h"
X# include	<StdFilePkg.h>
X
X
Xstatic SFReply	inFile;
Xstatic SFReply	outFile;
Xstatic Str255	fName;		/* map name and volume reference number */
Xstatic Integer		vRefNum;
X
X
X/*
X	Clear the current file name, and reset the title of the map
X	window.  Obviously, the first call to this must occur
X	after the map window is initialized.
X*/
X
XClearMapName ()
X{
X	CopyString ("\pUntitled", fName);
X	SetMapName (fName);
X}
X
X
XSetMapName (name)
XStringPtr	name;
X{
XStr255	s;
X
X	CopyString ("\pMap Name:  ", s);
X	AppendString (name, s);
X	SetWTitle (mapWind, s);
X}
X
X
X/*
X	Check a ConvSpec to see that it makes sense
X*/
X
Xstatic Boolean CheckMSpec (m)
XMapSpec	*m;
X{
XInteger		errCnt = 0;
X
X	if (FontIndex (m->font) < 0)
X	{
X		ErrWindMsge ("\pUnknown font number: ", m->font);
X		++errCnt;
X	}
X	if (SizeIndex ((Integer) m->size) < 0)
X	{
X		ErrWindMsge ("\pUnknown size: ", (Integer) m->size);
X		++errCnt;
X	}
X
X	return (errCnt == 0);
X}
X
X
X/*
X	Read paragraph style variables
X*/
X
Xstatic Boolean ReadParaStyle (f, version)
XInteger		f;
XInteger		version;
X{
X	if (version == 1)
X	{
X		InitParaStyle ();		/* use defaults */
X		return (true);
X	}
X	return (FileRead (f, &paraStyle, (Longint) sizeof (ParaStyle))
X			&& ReadString (f, paraMark)
X			&& ReadString (f, pageMark)
X			&& ReadString (f, periodStr)
X			&& ReadString (f, quoteStr));
X}
X
X
X/*
X	Read one map specification from a file.  First read the MapSpec
X	structure, being careful not to clobber the mark string handle.
X	Then read the string that gets put into the handle (first the
X	length byte, then the rest of the string).
X*/
X
Xstatic Boolean ReadMSpec (f, m)
Xregister Integer		f;
Xregister MapSpec	*m;
X{
XStringHandle	hStr;
XBoolean			ok;
X
X	hStr = m->mark;	/* save since clobbered by next read */
X	ok = FileRead (f, m, (Longint) sizeof (MapSpec));
X	m->mark = hStr;
X	if (ok)
X	{
X		HLock (hStr);
X		ok = ReadString (f, *hStr);
X		HUnlock (hStr);
X	}
X	return (ok);
X}
X
X
X/*
X	Read map specifications from a file.  Duplicate or illegal
X	specifications are not added.
X
X	Assumes file is open and all mappings already cleared (for Open) or
X	not (for Append).  If setParaInfo is true (Open), paragraph style
X	info is set.  If it's false (Append), it's not set.
X
X	Does not set undo variables or map-changed variables.
X*/
X
Xstatic ReadMap (f, setParaInfo)
XInteger		f;
XBoolean	setParaInfo;
X{
XMapSpec	mSpec;
XInteger		badCnt = 0;
XInteger	ver;
XInteger	i, nLines;
XStr255	str;
XBoolean	ok;
X
X	InitMSpec (&mSpec);
X	ErrWindInit (inFile.fName);
X	if (!ReadInteger (f, &ver))
X	{
X		Message1 ("\pCan't read map file.");
X	}
X	else if (ver != mapVersion && ver != 1)
X	{
X		NumToString ((Longint) ver, str);
X		Message2 ("\pUnknown map file version:  ", str);
X	}
X	else if (ReadInteger (f, &nLines))
X	{
X		ok = true;
X		for (i = 0; i < nLines; ++i)
X		{
X			ok = false;
X			if (!ReadMSpec (f, &mSpec))
X				break;
X			ok = true;
X	
X/*
X	Need to check legality here, since the file may have been
X	created using the fonts from a font list other than the current
X	one.
X*/
X	
X			if (CheckMSpec (&mSpec) == false)
X			{
X				++badCnt;
X				continue;			/* its bad - don't use it */
X			}
X	
X			if (StatMSpec (&mSpec))
X			{
X				++badCnt;
X				continue;			/* already exists - don't use dups */
X			}
X	
X			if (InsertMapping (&mSpec, mapList->nLines) == false)
X				break;
X		}
X		if (ok && setParaInfo)
X			(void) ReadParaStyle (f, ver);
X	}
X
X	TermMSpec (&mSpec);
X
X	(void) FSClose (f);
X	ScrollToLine (mapList, 0);		/* force scroll to top */
X	SelectMapping (noLine);			/* but leave unselected */
X
X	if (badCnt)
X	{
X		NumToString ((Longint) badCnt, str);
X		Message2 (str, "\p illegal or duplicate specifications were found and ignored");
X	}
X}
X
X
X/*
X	Open a map.  Clobber the current map first, set the map name
X	afterward.
X*/
X
XBoolean OpenMap ()
X{
XInteger		f;
X
X	if (GetInputFile ("\pOpen", mwType, &inFile)
X		&& OpenInputFile (&inFile, &f))
X	{
X		ClobberMap ();
X		ReadMap (f, true);
X		CopyString (inFile.fName, fName);
X		vRefNum = inFile.vRefNum;
X		SetMapName (fName);
X		return (true);
X	}
X	return (false);
X}
X
X
X/*
X	Add a map to the current map.  Doesn't set map name afterward.
X*/
X
XBoolean AddMap ()
X{
XInteger		f;
X
X	if (GetInputFile ("\pAdd", mwType, &inFile)
X		&& OpenInputFile (&inFile, &f))
X	{
X		ReadMap (f, false);
X		return (true);
X	}
X	return (false);
X}
X
X
X/*
X	Save map to file.  askForName is true if should ask for name,
X	otherwise use current name.  If name is "Untitled", ask for a name
X	anyway.  Sets the current name if it wasn't already set.
X
X	The file is deleted if not written properly.
X*/
X
XBoolean SaveMap (askForName)
XBoolean	askForName;
X{
XInteger				f;
Xregister Integer	i;
XOSErr			result;
XLongint			pos;
XBoolean			ok = false;
XStringHandle	hStr;
X
X	if (GetOutputFile (askForName, fName, vRefNum, &outFile) == false)
X		return (false);
X	if (OpenOutputFile (&outFile, mwCreator, mwType, &f) == false)
X		return (false);
X
X	if (WriteInteger (f, (Integer) mapVersion)
X		&& WriteInteger (f, (Integer) mapList->nLines))
X	{
X		ok = true;
X		for (i = 0; i < mapList->nLines; ++i)
X		{
X			ok = FileWrite (f, &mapSpec[i], (Longint) sizeof (MapSpec));
X			if (!ok)
X				break;
X			hStr = mapSpec[i].mark;
X			HLock (hStr);
X			ok = WriteString (f, *hStr);
X			HUnlock (hStr);
X			if (!ok)
X				break;
X		}
X		if (ok)
X		{
X			ok = FileWrite (f, &paraStyle, (Longint) sizeof (ParaStyle))
X				&& WriteString (f, paraMark)
X				&& WriteString (f, pageMark)
X				&& WriteString (f, periodStr)
X				&& WriteString (f, quoteStr);
X		}
X	}
X
X	(void) GetFPos (f, &pos);
X	(void) SetEOF (f, pos);
X	(void) FSClose (f);
X	(void) FlushVol (f, outFile.vRefNum);
X
X	if (!ok)
X	{
X		Message1 ("\pCould not write map");
X		(void) FSDelete (outFile.fName, outFile.vRefNum);
X		return (false);
X	}
X
X	CopyString (outFile.fName, fName);		/* set map name */
X	vRefNum = outFile.vRefNum;
X	SetMapName (fName);
X	return (true);
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > MW/MWMSpecOps.c
X# include	"MWMapInfo.h"
X
X
X/*
X	Initialize a MapSpec by allocating a mark string for it.
X*/
X
XInitMSpec (mSpec)
XMapSpec	*mSpec;
X{
X	mSpec->mark = (StringHandle) NewHandle ((Size) maxMarkLen + 1);
X}
X
X
X/*
X	Terminate a MapSpec by tossing its mark string.  The procedure
X	name is somewhat of a misnomer since it doesn't actually dispose
X	of the MapSpec itself.
X*/
X
XTermMSpec (mSpec)
XMapSpec	*mSpec;
X{
X	DisposHandle (mSpec->mark);
X}
X
X
X/*
X	Copy one init'ed MapSpec to another.  The most difficult part
X	is making sure the mark string gets copied correctly.
X*/
X
XCopyMSpec (srcMSpec, dstMSpec)
Xregister MapSpec	*srcMSpec, *dstMSpec;
X{
Xregister StringHandle	srcStr, dstStr;
X
X	dstStr = dstMSpec->mark;		/* save, since next line clobbers it */
X	*dstMSpec = *srcMSpec;
X	dstMSpec->mark = dstStr;		/* fix this field and copy the handle */
X	srcStr = srcMSpec->mark;
X	HLock (srcStr);
X	HLock (dstStr);
X	CopyString (*srcStr, *dstStr);
X	HUnlock (srcStr);
X	HUnlock (dstStr);
X	/*SetHandleSize (dstStr, (Size) 0);
X	HandAndHand (srcMSpec->mark, dstStr);*/
X}
X
X
X/*
X	Zero the contents of an init'ed MapSpec.
X*/
X
X
XClearMSpec (mSpec)
Xregister MapSpec	*mSpec;
X{
X	mSpec->font = sameFont;
X	mSpec->size = sameSize;
X	mSpec->style = sameStyle;
X	(*mSpec->mark)[0] = 0;
X	mSpec->selStart = 0;
X	mSpec->selEnd = 0;
X}
X
X
X/*
X	Compare two markers for equality.
X*/
X
XCompareMark (s1, s2)
XStringHandle	s1, s2;
X{
XInteger		result;
X
X	HLock (s1);
X	HLock (s2);
X	result = CompareString (*s1, *s2);
X	HUnlock (s1);
X	HUnlock (s2);
X	return (result);
X}
X
X
X/*
X	Compare two map specifications.
X	Return:
X		0		m1 = m2
X		< 0		m1 < m2
X		> 0		m1 > m2
X
X	Mark sorts before font, which sorts before size, which sorts
X	before style.
X
X	For all of font, size and style, the "same" selection is greater,
X	so that generic selections sort to the end of the list.  Font
X	comparisons are otherwise based on the name of the font, rather
X	than its number.   A string compare is avoided by keeping the
X	fonts in alphabetic order in the font information structures.
X
X	Note that the style comparison does not use the manifest constants
X	defined for each style value, and so would break if style coding
X	changed!
X*/
X
XCompareMSpec (m1, m2)
Xregister MapSpec	*m1, *m2;
X{
Xregister Integer	i;
Xregister Integer	s1, s2;
X
X	if ((i = CompareMark (m1->mark, m2->mark)) != 0)
X		return (i);
X
X	if (m1->font != m2->font)
X	{
X		if (m1->font == sameFont)
X			return (1);
X		if (m2->font == sameFont)
X			return (-1);
X		return (FontIndex (m1->font) - FontIndex (m2->font));
X	}
X
X	if ((i = m1->size - m2->size) != 0)
X	{
X		if (m1->size == sameSize)
X			return (1);
X		if (m2->size == sameSize)
X			return (-1);
X		return (i);
X	}
X
X	s1 = m1->style;
X	s2 = m2->style;
X	if (s1 - s2 != 0)
X	{
X		if (s1 == sameStyle)
X			return (1);
X		if (s2 == sameStyle)
X			return (-1);
X		for (i = 0; i < 7; ++i)
X		{
X			if (s1 == 0)
X			{
X				if (s2 != 0)
X					return (-1);
X			}
X			else if (s2 == 0)
X			{
X				return (1);
X			}
X			else if (s1 & 1)
X			{
X				if (!(s2 & 1))
X					return (-1);
X			}
X			else if (s2 & 1)
X				return (1);
X			s1 >>= 1;
X			s2 >>= 1;
X		}
X	}
X	return (0);			/* equal */
X}
X
X
X/*
X	Convert map specs to map text.  Do this by converting input specs
X	and output specs.
X*/
X
XMSpecToMStr (mSpec, mStr)
Xregister MapSpec	*mSpec;
Xregister MapStr		*mStr;
X{
X	HLock (mSpec->mark);
X	CopyString (*mSpec->mark, mStr->markStr);
X	HUnlock (mSpec->mark);
X	FontToStr (mSpec->font, mStr->fontStr);
X	SizeToStr (mSpec->size, mStr->sizeStr);
X	StyleToStr (mSpec->style, mStr->styleStr);
X}
X
X
X/*
X	Convert font number to font name.  The font *must* be legal.
X*/
X
XFontToStr (font, str)
Xregister Integer		font;
Xregister StringPtr	str;
X{
X	FontName (FontIndex (font), str);
X}
X
X
X/*
X	Convert size value to string.
X*/
X
XSizeToStr (size, str)
Xregister Integer		size;
Xregister StringPtr	str;
X{
X	if (size == sameSize)		/* no size specified, use default */
X		CopyString ("\pSame", str);
X	else
X		NumToString ((Longint) size, str);
X}
X
X
X/*
X	Convert style value to string. If the style has only one attribute
X	bit set, use the attribute name, otherwise use abbreviated form with
X	one letter for each attribute.
X*/
X
Xstatic StringPtr	styleStr[7] =
X{
X	(StringPtr) "\pBold",
X	(StringPtr) "\pItalic",
X	(StringPtr) "\pUnder",
X	(StringPtr) "\pOutline",
X	(StringPtr) "\pShadow",
X	(StringPtr) "\pHigh",
X	(StringPtr) "\pLow"
X};
X
X
XStyleToStr (style, str)
Xregister Integer		style;
Xregister StringPtr	str;
X{
Xregister Integer	i, style2;
X
X	if (style == sameStyle)		/* no style specified, use default */
X		CopyString ("\pSame", str);
X	else if (style == 0)			/* no bits set = plain text */
X		CopyString ("\pPlain", str);
X	else
X	{
X		style2 = style;
X		for (i = 0; i < 7; ++i)
X		{
X			if ((style2 & 1))
X			{
X				if (style2 != 1)
X					break;			/* more than 1 bit set */
X				CopyString (styleStr[i], str);
X				return;
X			}
X			style2 >>= 1;
X		}
X		i = 0;
X		if (style & styleBold)
X			str[++i] = 'B';
X		if (style & styleItalic)
X			str[++i] = 'I';
X		if (style & styleUnder)
X			str[++i] = 'U';
X		if (style & styleOutline)
X			str[++i] = 'O';
X		if (style & styleShadow)
X			str[++i] = 'S';
X		if (style & styleSuper)
X			str[++i] = 'H';
X		if (style & styleSub)
X			str[++i] = 'L';
X		str[0] = i;
X	}
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > MW/MWMain.c
X# include	"MakeWrite.h"
X
X
X/*
X	Offsets of each field in the map and font lists.  There is one
X	extra value, which is actually the offset of the right edge of
X	the last field.  These offsets are relative to the text area.
X*/
X
X
X# define	mapFields	4		/* number of fields in mapping */
X
X
Xstatic Integer		mapOffsets[mapFields + 1] =
X{
X	0,
X	100,
X	217,
X	257,
X	313
X};
X
X
Xstatic LineList	mapStruct =
X{
X	nil,						/* port - filled in later        */
X	nil,						/* control - filled in later     */
X	{ 150, 124, 246, 436 },		/* text display rect, t, l, b, r */
X	0,							/* max lines (set by InitList)   */
X	6,							/* max visible lines             */
X	0,							/* top visible line              */
X	16,							/* line height                   */
X	0,							/* number of lines               */
X	noLine,						/* current line                  */
X	false,						/* no hiliting                   */
X	mapFields,					/* number of fields/line         */
X	mapOffsets,					/* field offsets                 */
X	nil							/* line array (set by InitList)  */
X};
X
X
X
XWindowPtr	mapWind;
X
XListPtr		mapList = &mapStruct;
XMapSpec		mapSpec[maxMappings];
X
XBoolean		mapModified = false;
X
XInteger			undoOp = noUndo;
XInteger			undoVal;
XInteger			undoPos;
XInteger			undoFieldType;
XMapSpec		undoMSpec;
XBoolean		undoCPMarker;
X
XBoolean		havePasteMSpec = false;	/* for setting Paste menu item */
X
XBoolean		cpMarker = false;	/* whether cut/paste applies to marker */
X
X
X/*
X	Paragraph style control
X
X	Default is "every line a paragraph", ignore command-only lines
X*/
X
XParaStyle	paraStyle;
X
XStr255	paraMark;	/* paragraph marker string */
XStr255	pageMark;	/* page break marker string */
XStr255	periodStr;	/* sentence "periods" (terminators) */
XStr255	quoteStr;	/* quotes to ignore after periods */
X
X# ifdef	debug
XBoolean	debugOut = false;	/* controls debugging output during format */
X# endif
X
X
Xmain ()
X{
X	SkelInit ();
X	InitParaStyle ();
X	SetupMenus ();
X	MapSetup ();
X	SkelMain ();
X	SkelClobber ();
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > MW/MWMapOps.c
X# include	"MakeWrite.h"
X
X
X/*
X	Check whether a MapSpec already exists in the map
X*/
X
XBoolean StatMSpec (mSpec)
XMapSpec	*mSpec;
X{
Xregister Integer	i;
X
X	for (i = 0; i < mapList->nLines; ++i)
X	{
X		if (CompareMSpec (mSpec, &mapSpec[i]) == 0)
X			return (true);
X	}
X	return (false);
X}
X
X
X
X/*
X	Insert the text of all the fields for the given map list line.
X
X	This routines relies implicitly on the ordering of fields
X	within a map line.
X*/
X
Xstatic SetMapFields (hLine, mStr)
Xregister LineHandle	hLine;
Xregister MapStr		*mStr;
X{
Xregister FieldHandle	hField;
X
X	hField = hLine;
X	SetFieldStr (hField, mStr->markStr);
X	hField = NextField (hField);
X	SetFieldStr (hField, mStr->fontStr);
X	hField = NextField (hField);
X	SetFieldStr (hField, mStr->sizeStr);
X	hField = NextField (hField);
X	SetFieldStr (hField, mStr->styleStr);
X}
X
X
X/*
X	Select a mapping
X*/
X
XSelectMapping (lineNo)
Xregister Integer	lineNo;
X{
X	SelectLine (mapList, lineNo);
X	if (lineNo != noLine)
X		ScrollToLine (mapList, lineNo);
X	SetSelectors (lineNo);
X}
X
X
X/*
X	Insert a new mapping, making it mapping n.  This takes care
X	of both the specification array, and the list of text representations
X	of the mappings.
X
X	Note that there's no explicit count of mappings.  Use the count
X	in the LineList corresponding to the mapping array is used.
X*/
X
XBoolean InsertMapping (mSpec, n)
XMapSpec	*mSpec;
XInteger		n;
X{
XMapStr				mStr;
Xregister LineHandle	hLine;
Xregister Integer		i, nLines;
XStr255				s;
X
X	if (mapList->nLines < mapList->maxLines)
X	{
X
X/*
X	Convert mapping specification into string form and put the strings
X	into a new line to be inserted into the line list.
X
X	Then make room for the new mapping in spec array and insert it.
X*/
X
X		nLines = mapList->nLines;		/* save; InsertLine changes it */
X		MSpecToMStr (mSpec, &mStr);		/* convert specs to strings */
X		hLine = NewLine (mapList->nFields);
X		SetMapFields (hLine, &mStr);
X		if (InsertLine (mapList, hLine, n) == false)
X		{
X			DisposeLine (hLine);
X		}
X		else
X		{
X/*
X	Move specs around to make room, then add the new one
X	in the empty slot.
X*/
X			for (i = nLines; i > n; --i)
X			{
X				CopyMSpec (&mapSpec[i-1], &mapSpec[i]);
X			}
X			CopyMSpec (mSpec, &mapSpec[n]);
X			/*mapSpec[n].selStart = 0;
X			mapSpec[n].selEnd = 32767;*/
X			SelectMapping (n);
X			/*SetCPMarker (true);*/
X			return (true);
X		}
X	}
X	NumToString ((Longint) mapList->maxLines, s);
X	Message3 ("\pMap is full (", s, "\p lines).  Can't add anything to it.");
X	return (false);
X}
X
X
X/*
X	Add a new, blank, mapping to the end of the list.
X	This should be different - the handle should be copied in InsertMapping.
X*/
X
XNewMapping ()
X{
XMapSpec	mSpec;
X
X	InitMSpec (&mSpec);
X	ClearMSpec (&mSpec);
X	(void) InsertMapping (&mSpec, mapList->nLines);
X	TermMSpec (&mSpec);
X}
X
X
X/*
X	Duplicate the currently selected mapping and add right after the
X	selection.
X*/
X
XDupMapping (n)
X{
X	(void) InsertMapping (&mapSpec[n], n+1);
X}
X
X
X/*
X	Replace the currently selected mapping with the given one.
X	(It's assumed that there *is* one selected.)
X*/
X
XPasteMapping (mSpec, n)
XMapSpec	*mSpec;
XInteger		n;
X{
XMapStr			mStr;
Xregister Integer	curLine;
X
X	curLine = mapList->curLine;
X	CopyMSpec (mSpec, &mapSpec[curLine]);
X	MSpecToMStr (mSpec, &mStr);
X	SetMapFields (ListLine (mapList, curLine), &mStr);
X	DrawLine (mapList, curLine);
X	SetSelectors (curLine);				/* set selection controls */
X}
X
X
X/*
X	Clobber the n'th mapping.
X*/
X
XDeleteMapping (n)
Xregister Integer	n;
X{
Xregister Integer	i;
X
X	for (i = n; i < mapList->nLines; ++i)
X	{
X		CopyMSpec (&mapSpec[i+1], &mapSpec[i]);		/* copy specs */
X	}
X	DeleteLine (mapList, n);
X	SelectMapping (noLine);
X	ScrollToLine (mapList, n);
X}
X
X
X/*
X	Clobber entire map.
X*/
X
XClobberMap ()
X{
X	SelectMapping (noLine);
X	ResetList (mapList);
X	InitParaStyle ();
X}
X
X
X
X/*
X	Sort the map specifications on the input format values.  Make
X	sure to keep track of the current spec and redraw the text 
X	and controls properly when done.
X*/
X
XSortMap ()
X{
Xregister Integer		i, j, curLine;
Xregister LineHandle	tmpLine;
XMapSpec				tmpSpec;
X
X	InitMSpec (&tmpSpec);
X	curLine = mapList->curLine;
X	for (i = 0; i < mapList->nLines - 1; ++i)
X	{
X		for (j = i; j < mapList->nLines; ++j)
X		{
X			if (CompareMSpec (&mapSpec[i], &mapSpec[j]) > 0)
X			{
X				CopyMSpec (&mapSpec[i], &tmpSpec);
X				CopyMSpec (&mapSpec[j], &mapSpec[i]);
X				CopyMSpec (&tmpSpec, &mapSpec[j]);
X				tmpLine = ListLine (mapList, i);
X				ListLine (mapList, i) = ListLine (mapList, j);
X				ListLine (mapList, j) = tmpLine;
X				if (curLine == i)
X					curLine = j;
X				else if (curLine == j)
X					curLine = i;
X			}
X		}
X	}
X	DrawListText (mapList);
X	SelectMapping (curLine);
X	TermMSpec (&tmpSpec);
X}
X
X
X/*
X	Eliminate duplicates in the map.  The loops must explicitly
X	test mapList->nLines, not a variable set equal to that before
X	the loops, since DeleteMapping causes mapList->nLines to change.
X*/
X
XSquishMap ()
X{
Xregister Integer	i, j;
X
X	for (i = 0; i < mapList->nLines; ++i)
X	{
X		j = i + 1;
X		while (j < mapList->nLines)
X		{
X			if (CompareMSpec (&mapSpec[i], &mapSpec[j]) == 0)
X				DeleteMapping (j);
X			else
X				++j;
X		}
X	}
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > MW/MWMapWind.c
X# include	<TextEdit.h>
X# include	"MakeWrite.h"
X
X
X# define	tab			'\t'
X# define	shiftKey	0x0200
X# define	applFont	1
X
X
X/*
X	Local data for creating controls
X*/
X
X
X/*
X	maxSize = number of point-size selection radio buttons
X	maxStyle = number of style selection check boxes
X	maxCP = number of edit menu cut/paste indicator controls
X	maxCtrl = sum of above three
X	maxFonts = maximum number of fonts allowed in scrollable list
X*/
X
X# define	maxSize		7
X# define	maxStyle	9
X# define	maxCP		2
X# define	maxCtrl		(maxSize+maxStyle+maxCP)
X# define	maxFonts	102
X
X
Xtypedef enum	/* control types, by function */
X{
X	sizeType,	/* size radio button */
X	styleType,	/* style check box */
X	cpType		/* edit menu check box */
X};
X
X
Xtypedef struct CtrlInfo
X{
X	Str255	cTitle;		/* initial control title */
X	Integer		ch, cv;		/* location of upper left corner */
X} CtrlInfo;
X
X
Xstatic CtrlInfo	ctrlInfo[maxCtrl] =
X{
X	{ "\pSame",				181,	20 },
X	{ "\p9",				172,	40 },
X	{ "\p10",				172,	60 },
X	{ "\p12",				172,	80 },
X	{ "\p14",				217,	40 },
X	{ "\p18",				217,	60 },
X	{ "\p24",				217,	80 },
X	{ "\pSame",				312,	20 },
X	{ "\pPlain",			265,	40 },
X	{ "\pBold",				265,	60 },
X	{ "\pItalic",			265,	80 },
X	{ "\pUnderline",		265,	100 },
X	{ "\pOutline",			355,	40 },
X	{ "\pShadow",			355,	60 },
X	{ "\pSuperscript",		355,	80 },
X	{ "\pSubscript",		355,	100 },
X	{ "\pMarker",			9,		210 },
X	{ "\pMap Lines",		9,		230 }
X};
X
X
Xstatic ControlHandle	sizeCtrl[maxSize];
Xstatic ControlHandle	styleCtrl[maxStyle];
Xstatic ControlHandle	cpCtrl[maxCP];
X
X
X
X/*
X	Standard MacWrite point sizes, plus the "same size" selection.
X	The order of these corresponds to the size radio buttons.
X*/
X
Xstatic Integer		sizeInfo[maxSize] = { sameSize, 9, 10, 12, 14, 18, 24 };
X
X
X/*
X	Masks for manipulating style selections.  The order of these
X	corresponds to the style check boxes.
X*/
X
X
Xstatic Integer		styleMask[maxStyle] =
X{
X	sameStyle,
X	0,				/* plain; special-cased */
X	styleBold,
X	styleItalic,
X	styleUnder,
X	styleOutline,
X	styleShadow,
X	styleSuper,
X	styleSub
X};
X
X
X/*
X	Standard font specifications
X*/
X
X
Xtypedef struct
X{
X	Integer				fontNum;
X	StringHandle	fontName;
X} FontSpec;
X
X
Xstatic FontSpec	fontSpecs[maxFonts];
Xstatic Integer		nFontSpecs;
X
X
Xstatic Integer		fontOffsets[2] = { 0, 137 };
X
X
Xstatic LineList	fontStruct =
X{
X	nil,						/* port - filled in later        */
X	nil,						/* control - filled in later     */
X	{ 20, 5, 116, 141 },		/* text display rect, t, l, b, r */
X	0,							/* max lines                     */
X	6,							/* max visible lines             */
X	0,							/* top visible line              */
X	16,							/* line height                   */
X	0,							/* number of lines               */
X	noLine,						/* current line                  */
X	false,						/* no hiliting                   */
X	1,							/* number of fields/line         */
X	fontOffsets,				/* field offsets                 */
X	nil							/* line array                    */
X};
X
X
Xstatic ListPtr	fontList = &fontStruct;
X
Xstatic MapSpec	*curMSpec;
Xstatic Integer		curMSpecNo;
X
Xstatic TEHandle	markTE;
X
X
X/* ---------------------------------------------------------------- */
X/*					General Control Operations						*/
X/* ---------------------------------------------------------------- */
X
X
X
X/*
X	Set a control value, but only when it changes, to avoid
X	unnecessary redrawing (ugly, since gobs of them are usually
X	changed together).
X
X	Use for check boxes and radio buttons only, not scroll bars!
X*/
X
Xstatic SetControl (ctrl, value)
XControlHandle	ctrl;
XBoolean			value;
X{
X	if (GetCtlValue (ctrl) != value)
X		SetCtlValue (ctrl, value);
X}
X
X
X/* ---------------------------------------------------------------- */
X/*						Font List Operations						*/
X/* ---------------------------------------------------------------- */
X
X
X/*
X	Add a font to the spec list.  Return false if there's overrun.
X*/
X
XBoolean SetFontSpec (fNum, fName)
XInteger			fNum;
XStringPtr	fName;
X{
Xregister StringHandle	h;
XStr255					s;
Xregister Integer			i, result;
X
X	for (i = 0; i < nFontSpecs; ++i)	/* see if already there */
X	{
X		h = fontSpecs[i].fontName;
X		HLock (h);
X		result = CompareString (*h, fName);
X		HUnlock (h);
X		if (result == 0)		/* font name's a duplicate */
X			return (true);		/* but that's ok */
X	}
X
X	if (nFontSpecs >= fontList->maxLines)	/* will list be too full? */
X	{
X		NumToString ((Longint) maxFonts - 2, s);
X		Message3 ("\pSorry, I am such a brain-damaged program that I only allow ",
X					s, "\p fonts!");
X		return (false);
X	}
X
X	h = (StringHandle) NewHandle ((Longint) (fName[0] + 1));
X	HLock (h);
X	CopyString (fName, *h);
X	HUnlock (h);
X	fontSpecs[nFontSpecs].fontName = h;
X	fontSpecs[nFontSpecs++].fontNum = fNum;
X	return (true);
X}
X
X
X/*
X	Set up to construct a new font list.  Note that the other
X	selector controls must have been initialized by this point.
X*/
X
XResetFontList ()
X{
Xregister Integer	i;
X
X	for (i = 0; i < fontList->nLines; ++i)
X		DisposHandle (fontSpecs[i].fontName);
X	nFontSpecs = 0;
X	ResetList (fontList);
X	SetFontSpec (sameFont, "\pSame");
X	SetFontSpec (applFont, "\pApplication");
X}
X
X
X/*
X	Sync information in fontSpec to fontList by constructing the LineList
X	elements.
X*/
X
XSyncFontSpecs ()
X{
Xregister Integer		i, j;
XInteger					tmp;
Xregister FontSpec	*f1, *f2;
XStringHandle		h1, h2;
XLineHandle			hField;
X
X/*
X	Sort font names, except for "Same" and "Application", which
X	stay at the front of the list.
X*/
X
X	for (i = 2; i < nFontSpecs - 1; ++i)
X	{
X		for (j = i + 1; j < nFontSpecs; ++j)
X		{
X			f1 = &fontSpecs[i];
X			f2 = &fontSpecs[j];
X			h1 = f1->fontName;
X			h2 = f2->fontName;
X			HLock (h1);
X			HLock (h2);
X			if (CompareString (*h1, *h2) > 0)
X			{
X				f1->fontName = h2;
X				f2->fontName = h1;
X				tmp = f1->fontNum;
X				f1->fontNum = f2->fontNum;
X				f2->fontNum = tmp;
X			}
X			HUnlock (h1);
X			HUnlock (h2);
X		}
X	}
X
X/*
X	Add names to fontList
X*/
X
X	ResetList (fontList);
X	for (i = 0; i < nFontSpecs; ++i)
X	{
X		h1 = fontSpecs[i].fontName;
X		HLock (h1);
X		hField = NewLine (1);
X		SetFieldStr (hField, *h1);
X		HUnlock (h1);
X		(void) InsertLine (fontList, hField, i);
X	}
X	SelectLine (fontList, 0);
X	ScrollToLine (fontList, 0);		/* force scroll to top */
X}
X
X
X/*
X	Given a font number, find its index in the stdFontSpecs
X	array.  Return -1 if it's not there.
X*/
X
XFontIndex (fontNum)
XInteger		fontNum;
X{
Xregister Integer		i;
X
X	for (i = 0; i < fontList->nLines; ++i)
X	{
X		if (fontNum == fontSpecs[i].fontNum)
X			return (i);
X	}
X	return (-1);
X}
X
X
X/*
X	Return a font name corresponding to the given index
X*/
X
XFontName (fontIndex, str)
XInteger			fontIndex;
XStringPtr	str;
X{
XStringHandle	hStr;
X
X	hStr = fontSpecs[fontIndex].fontName;
X	HLock (hStr);
X	CopyString (*hStr, str);
X	HUnlock (hStr);
X}
X
X
X/* ---------------------------------------------------------------- */
X/*						Size Control Operations						*/
X/* ---------------------------------------------------------------- */
X
X
X/*
X	Given a point size, find its index in the sizeInfo
X	array.  (Return -1 if it's not there.)
X*/
X
XSizeIndex (size)
XInteger		size;
X{
Xregister Integer		i;
X
X	for (i = 0; i < maxSize; ++i)
X	{
X		if (size == sizeInfo[i])
X			return (i);
X	}
X	return (-1);
X}
X
X
Xstatic SetSizeCtrls ()
X{
Xregister Integer		i;
X
X	for (i = 0; i < maxSize; ++i)
X		SetControl (sizeCtrl[i], sizeInfo[i] == curMSpec->size);
X}
X
X
X/* ---------------------------------------------------------------- */
X/*						Style Control Operations					*/
X/* ---------------------------------------------------------------- */
X
X
X/*
X	Set the style controls based on the current value of theStyle.
X
X	The sameStyle bit and the attributes bits cause the corresponding
X	boxes to be checked if they are set.  If the style is zero, it's
X	plain.
X*/
X
Xstatic SetStyleCtrls ()
X{
Xregister Integer		i;
Xregister Boolean	same;
Xregister Integer		theStyle;
X
X	theStyle = curMSpec->style;
X	same = ((theStyle & sameStyle) != 0);
X	SetControl (styleCtrl[0], same);
X
X	if (same)
X	{
X		for (i = 1; i < maxStyle; ++i)
X			SetControl (styleCtrl[i], false);
X	}
X	else if (theStyle == 0)					/* plain */
X	{
X		SetControl (styleCtrl[1], true);
X		for (i = 2; i < maxStyle; ++i)
X			SetControl (styleCtrl[i], false);
X	}
X	else									/* not plain */
X	{
X		SetControl (styleCtrl[1], false);
X		for (i = 2; i < maxStyle; ++i)
X			SetControl (styleCtrl[i], (theStyle & styleMask[i]) != 0);
X	}
X}
X
X
X/*
X	Determine style value.  The argument is an index into the control
X	array not a style value itself.  Style controls interact in
X	wretched complexity.
X
X	If same is toggled on, all the other style boxes are toggled off.
X	If it's toggled off, plain is toggled on.
X
X	If plain is toggled on, all the other style boxes are toggled off.
X	If it's toggled off, same is toggled on.
X
X	The other style boxes correspond to style attributes.  If any of
X	them are toggled on, then same and plain are toggle off if
X	they were on.  If all the attributes are toggled off, plain is
X	toggled on.  Superscript and subscript are mutually exclusive,
X	so that if one of them is toggled on, the other is toggled off.
X*/
X
Xstatic NewStyleValue (i)
Xregister Integer	i;
X{
Xregister Integer	curValue;
Xregister Integer	theStyle;
X
X	curValue = GetCtlValue (styleCtrl[i]);	/* current value - new value */
X											/* will be opposite */
X	theStyle = curMSpec->style;
X
X	if (i == 0)			/* "same" box clicked */
X	{
X		if (curValue)	/*  currently same, turn off (implies plain) */
X			theStyle = 0;
X		else
X			theStyle = styleMask[0];	/* currently off, turn on */
X	}
X	else if (i == 1)	/* plain box clicked */
X	{
X		if (curValue)	/*  currently plain, turn off (implies same) */
X			theStyle = styleMask[0];
X		else
X			theStyle = 0;	/* currently off, turn on */
X	}
X	else
X	{
X	/*
X		Flip box value.
X		Can't have superscript and subscript at the same time.
X	*/
X		if (curValue)	/* currently on, turn off */
X			theStyle &= ~styleMask[i];
X		else			/* currently off, turn on (turn same off) */
X		{
X			theStyle |= styleMask[i];
X			theStyle &= ~styleMask[0];
X		}
X
X		if (i == 7)	/* superscript.  if turning on, turn off sub */
X		{
X			if (curValue == 0)
X				theStyle &= ~styleMask[8];
X		}
X		if (i == 8)	/* subscript.  if turning on, turn off super */
X		{
X			if (curValue == 0)
X				theStyle &= ~styleMask[7];
X		}
X	}
X	return (theStyle);
X}
X
X
X/* ---------------------------------------------------------------- */
X/*				Edit Menu Cut/Paste Control Operations				*/
X/* ---------------------------------------------------------------- */
X
X
Xstatic SetCPCtrls ()
X{
X	SetControl (cpCtrl[0], cpMarker);
X	SetControl (cpCtrl[1], !cpMarker);
X}
X
X
XSetCPMarker (useMarker)
XBoolean	useMarker;
X{
X	cpMarker = useMarker;
X	SetCPCtrls ();
X}
X
X
XBlankCPCtrls ()
X{
X	SetControl (cpCtrl[0], false);
X	SetControl (cpCtrl[1], false);
X}
X
X
X/* ---------------------------------------------------------------- */
X/*							Marker Operations						*/
X/* ---------------------------------------------------------------- */
X
X
X/*
X	Sync the marker edit text to a mapSpec
X*/
X
XMSpecToMark (m)
XMapSpec	*m;
X{
XStringHandle	s;
XRect			r;
X
X	s = m->mark;
X	HLock (s);
X	TESetSelect (0L, 32767L, markTE);
X	TEDelete (markTE);
X	TEInsert (*s + 1, (Longint) (*s)[0], markTE);	/* replace text */
X	HUnlock (s);
X	TESetSelect ((Longint) m->selStart, (Longint) m->selEnd, markTE);
X}
X
X
X/*
X	Sync current mapSpec to the marker edit text
X*/
X
Xstatic MarkToMSpec ()
X{
XStringHandle	hStr;
XHandle			h;
XInteger				len;
X
X	curMSpec->selStart = (**markTE).selStart;
X	curMSpec->selEnd = (**markTE).selEnd;
X	h = TEGetText (markTE);
X	len = (**markTE).teLength;
X	if (len > maxMarkLen)
X		len = maxMarkLen;		/* truncate length if necessary */
X	hStr = curMSpec->mark;
X	HLock (h);
X	HLock (hStr);
X	BlockMove (*h, *hStr + 1, (Longint) len);
X	(*hStr)[0] = len;
X	HUnlock (h);
X	PasteField (mapList, mapList->curLine, markField, *hStr);
X	HUnlock (hStr);
X}
X
X
Xtypedef enum		/* relevant Edit menu item numbers */
X{
X	cut = 3,
X	copy,
X	paste,
X	clear
X};
X
X
XMarkerUndoSetup ()
X{
X	CopyMSpec (curMSpec, &undoMSpec);
X	undoOp = undoMarkerOp;
X	undoPos = mapList->curLine;
X	undoCPMarker = cpMarker;
X}
X
X
XBoolean EditMarker (item)
XInteger		item;
X{
X	if (!cpMarker)
X		return (false);
X
X	switch (item)
X	{
X	
X	case cut:
X		MarkerUndoSetup ();
X		TECut (markTE);
X		(void) ZeroScrap ();
X		(void) TEToScrap ();
X		break;
X	
X	case copy:
X		TECopy (markTE);
X		(void) ZeroScrap ();
X		(void) TEToScrap ();
X		break;
X	
X	case paste:
X		if (curMSpec == nil)	/* ignore if no line selected */
X			return (false);
X		MarkerUndoSetup ();
X		(void) TEFromScrap ();
X		TEPaste (markTE);
X		break;
X	
X	case clear:
X		MarkerUndoSetup ();
X		(void) TEDelete (markTE);
X		break;
X	
X	default:
X		return (false);	/* all others handled by general */
X						/* edit menu handler */
X
X	}
X
X	MarkToMSpec (curMSpec);	/* sync map with change in mark */
X	if (item != copy)
X		mapModified = true;
X	FixMenus ();
X	return (true);
X}
X
X
X/* ---------------------------------------------------------------- */
X
X
X/*
X	Set a field in the currently selected line.  Don't call this if
X	no line is selected, or if the field already has the same value.
X*/
X
XSetMapFieldValue (fieldType, value)
XInteger		fieldType;
XInteger		value;
X{
XStr255		s;
X
X	switch (fieldType)
X	{
X
X	case fontField:
X		undoVal = curMSpec->font;
X		FontToStr (value, s);
X		curMSpec->font = value;
X		SelectLine (fontList, FontIndex (value));
X		break;
X
X	case sizeField:
X		undoVal = curMSpec->size;
X		SizeToStr (value, s);
X		curMSpec->size = value;
X		SetSizeCtrls ();
X		break;
X
X	case styleField:
X		undoVal = curMSpec->style;
X		StyleToStr (value, s);
X		curMSpec->style = value;
X		SetStyleCtrls ();
X		break;
X	}
X
X	PasteField (mapList, mapList->curLine, fieldType, s);
X	mapModified = true;
X	undoOp = undoFieldChg;
X	undoFieldType = fieldType;
X}
X
X
X/*
X	Set the selection controls and font list to reflect currently
X	selected conversion specification.  Also sets current MapSpec
X	pointer.
X*/
X
XSetSelectors (lineNo)
XInteger		lineNo;
X{
Xregister Integer	i;
X
X	if (lineNo == noLine)				/* no map line selected */
X	{
X
X		curMSpec = nil;
X		curMSpecNo = noLine;
X
X		ListActivate (fontList, false);
X	
X		for (i = 0; i < maxSize; ++i)
X			SetControl (sizeCtrl[i], false);
X	
X		for (i = 0; i < maxStyle; ++i)
X			SetControl (styleCtrl[i], false);
X
X		TESetSelect (0L, 32767L, markTE);
X		TEDelete (markTE);
X		TEDeactivate (markTE);
X
X		return;
X	}
X
X	curMSpec = &mapSpec[curMSpecNo = lineNo];
X
X	SelectLine (fontList, FontIndex (curMSpec->font));
X	ListActivate (fontList, true);
X	ScrollToLine (fontList, fontList->curLine);
X	SetSizeCtrls ();
X	SetStyleCtrls ();
X	MSpecToMark (curMSpec);
X	TEActivate (markTE);
X	/*SetCPCtrls ();*/
X}
X
X
X/*
X	Map window mouse handler.
X
X	First test the scroll bars, and return if one was hit; they
X	require no further action.
X
X	Then check for hit in map list.  If a new line was selected, set
X	the selectors to the values, and disable undo.
X
X	Then, if a line is currently selected, check the selection controls.
X	If one is hit, change the values in the current line and reset the
X	controls properly - but only if the current values *change*.
X*/
X
Xstatic Mouse (pt, t, mods)
XPoint	pt;
XLongint	t;
XInteger		mods;
X{
XControlHandle	ctrl;
XInteger				index;
XInteger				type;
XLongint			refCon;
XInteger				newVal;
XBoolean			newIO;
XInteger				curLine;
XRect			r;
X
X	if (ListTestScroll (mapList, pt) || ListTestScroll (fontList, pt))
X		return;
X
X	curLine = mapList->curLine;				/* current line */
X	if (ListTestText (mapList, pt))
X	{
X		if (curLine != mapList->curLine)	/* different now? */
X		{
X			undoOp = noUndo;
X			if ((curLine = mapList->curLine) != noLine)
X			{
X				mapSpec[curLine].selStart = 0;
X				mapSpec[curLine].selEnd = 32767;
X			}
X			/*SetCPMarker (true);*/
X			SetSelectors (curLine);
X			FixMenus ();
X		}
X		return;
X	}
X
X	if (curMSpec == nil)
X		return;				/* no current line - controls irrelevant */
X
X	if (ListTestText (fontList, pt))
X	{
X		if (fontList->curLine == noLine)
X			SelectLine (fontList, fontList->nLines - 1);
X		newVal = fontSpecs[fontList->curLine].fontNum;	
X		if (curMSpec->font != newVal)
X		{
X			SetMapFieldValue (fontField, newVal);
X			FixMenus ();
X		}
X		return;
X	}
X
X/*
X	Check the edittext box
X*/
X
X	r = (**markTE).viewRect;
X	InsetRect (&r, -3, -3);
X	if (PtInRect (pt, &r))
X	{
X		undoOp = noUndo;
X		SetCPMarker (true);
X		TEClick (pt, (mods & shiftKey) != 0, markTE);
X		curMSpec->selStart = (**markTE).selStart;
X		curMSpec->selEnd = (**markTE).selEnd;
X		FixMenus ();
X		return;
X	}
X
X
X/*
X	Don't need to check control type returned from FindControl - at
X	this point, it can't be anything but inCheckBox.  The control type
X	and index is coded in the reference constant (see MakeControl).
X*/
X
X	if (FindControl (pt, mapWind, &ctrl))
X	{
X		if (TrackControl (ctrl, pt, nil) == inCheckBox)
X		{
X			refCon = GetCRefCon (ctrl);
X			index = refCon & 0x00ff;
X			type = (refCon & 0xff00) >> 8;
X
X			switch (type)
X			{
X
X			case sizeType:
X				newVal = sizeInfo[index];
X				if (newVal != curMSpec->size)
X					SetMapFieldValue (sizeField, newVal);
X				break;
X
X			case styleType:
X				newVal = NewStyleValue (index);
X				if (newVal != curMSpec->style)
X					SetMapFieldValue (styleField, newVal);
X				break;
X
X			case cpType:
X				SetCPMarker (index == 0);
X				undoOp = noUndo;
X				break;
X
X			}
X
X			FixMenus ();
X		}
X		return;
X	}
X}
X
X
X/*
X	Process key click in window for mark string.  On the first key
X	after any other operation, save the current mark string state
X	for undo.  And on every key click, save the selection range.  This
X	is so the range can be saved properly if the window is inactivated
X	and later activated, or if another line is selected and then this
X	line is reselected.
X*/
X
Xstatic Key (c, mods)
Xchar	c;
XInteger		mods;
X{
XHandle			h;
XStringHandle	s;
XInteger				len;
X
X	if (curMSpec == nil)
X		return;
X
X	switch (c)
X	{
X	
X	case tab:
X	case enter:
X	case cr:
X		undoOp = noUndo;
X		if (mods & shiftKey)
X		{
X			if (--curMSpecNo < 0)
X				curMSpecNo = mapList->nLines - 1;
X		}
X		else
X		{
X			if (++curMSpecNo >= mapList->nLines)
X				curMSpecNo = 0;
X		}
X		SelectMapping (curMSpecNo);
X		break;
X
X	default:
X		if (undoOp != undoTyping)	/* first char typed */
X		{
X			MarkerUndoSetup ();
X			undoOp = undoTyping;
X		}
X
X		TEKey (c, markTE);
X		MarkToMSpec (curMSpec);
X		SetCPMarker (true);
X		mapModified = true;
X		FixMenus ();
X
X	}
X}
X
X
Xstatic Update (resized)
XBoolean	resized;
X{
Xregister Integer	i;
XRect	r;
X
X	MoveTo (65, 14);
X	DrawString ("\pFont");
X	MoveTo (180, 14);
X	DrawString ("\pPoint Size");
X	MoveTo (322, 14);
X	DrawString ("\pStyle");
X	MoveTo (30, 145);
X	DrawString ("\pMarker");
X	MoveTo (4, 190);
X	DrawString ("\pCut & Paste Ops");
X	MoveTo (4, 206);
X	DrawString ("\pAffect:");
X	MoveTo (212, 143);
X	DrawString ("\pFormat Specifications");
X	DrawControls (mapWind);
X	r = (**markTE).viewRect;
X	EraseRect (&r);
X	TEUpdate (&r, markTE);
X	InsetRect (&r, -3, -3);
X	FrameRect (&r);
X	DrawListFrame (fontList);
X	DrawListFrame (mapList);
X	DrawListText (fontList);
X	DrawListText (mapList);
X}
X
X
X/*
X	When the window is activated, do appropriate map list and font list
X	line and scroll bar hiliting, and set size and style controls to
X	current values.
X
X	When the window is deactivated, all hiliting is turned off, the
X	scroll bars are unhilited and the size and style controls go blank.
X
X	Note that SetSelectrs takes care of setting font list line and scroll
X	bar hiliting; it doesn't have to be done here.  It also activates
X	or deactivates the text field properly.
X*/
X
Xstatic Activate (active)
XBoolean	active;
X{
X	if (active)
X	{
X		DoUpdates ();
X		ListActivate (mapList, true);
X		SetSelectors (mapList->curLine);
X	}
X	else
X	{
X		SetSelectors (noLine);
X		ListActivate (mapList, false);
X	}
X	FixMenus ();
X}
X
X
Xstatic Clobber ()
X{
X	HideWindow (mapWind);
X	TEDispose (markTE);
X	/*DisposeList (mapList);
X	DisposeList (fontList);*/
X	DisposeWindow (mapWind);
X}
X
X
Xstatic Idle ()
X{
X	TEIdle (markTE);
X}
X
X
X/*
X	Create controls.  These are created in the same order as the specs
X	in the ctrlInfo array.
X*/
X
Xstatic ControlHandle MakeControl (proc, type, index)
XInteger				proc;
XInteger				type;
XInteger				index;
X{
Xstatic Integer			i = 0;	/* used to step through ctrlInfo array */
Xregister CtrlInfo	*cInfo;
XRect				r;
XStringPtr			title;
Xregister Integer		h, v;
XControlHandle		ctrl;
X
X	cInfo = &ctrlInfo[i++];
X	title = cInfo->cTitle;
X	h = cInfo->ch;
X	v = cInfo->cv;
X	SetRect (&r, h, v, h + StringWidth (title) + 20, v + 20);
X	ctrl = NewControl (mapWind,
X						&r,
X						title,
X						true,
X						0, 0, 1,
X						proc,
X						(Longint) (type << 8 | index));
X	return (ctrl);
X}
X
X
XMapSetup ()
X{
Xregister Integer	i;
XRect			r;
X
X	SetRect (&r, 24, 60, 480, 311);
X	mapWind = NewWindow (nil, &r, "\p", false, noGrowDocProc,
X							-1L, false, 0L);
X	SkelWindow (mapWind,
X				Mouse,
X				Key,
X				Update,
X				Activate,
X				nil,
X				Clobber,
X				Idle,
X				true);
X
X	TextFont (0);			/* do this so StringWidth calculations */
X	TextSize (0);			/* for controls will be accurate */
X
X	for (i = 0; i < maxSize; ++i)
X		sizeCtrl[i] = MakeControl (radioButProc, sizeType, i);
X
X	for (i = 0; i < maxStyle; ++i)
X		styleCtrl[i] = MakeControl (checkBoxProc, styleType, i);
X
X	for (i = 0; i < maxCP; ++i)
X		cpCtrl[i] = MakeControl (radioButProc, cpType, i);
X
X	SetRect (&r, 7, 152, 107, 168);
X	markTE = TENew (&r, &r);
X	(void) ZeroScrap ();
X
X	InitList (fontList, maxFonts);		/* initialize empty list */
X	InitList (mapList, maxMappings);
X	for (i = 0; i < maxMappings; ++i)
X		InitMSpec (&mapSpec[i]);
X
X/*
X	Add default set of fonts:  ImageWriter fonts and LaserWriter fonts.
X	Reset the list and add the two sets without asking whether to add to
X	or replace the current list, since there's not really any current
X	list.
X*/
X
X	ResetFontList ();
X	StrFonts (false);
X
X	ClearMapName ();
X	ShowWindow (mapWind);
X}
SHAR_EOF
exit
--- end of part 2 ---

macintosh@felix.UUCP (03/22/87)

[MakeWrite Source - part 3 of 3]

---
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	MW/MWMenu.c
#	MW/MWMisc.c
#	MW/MWParaDlog.c
#	MW/MWTextToWrite.c
#	MW/MWWindMisc.c
sed 's/^X//' << 'SHAR_EOF' > MW/MWMenu.c
X# include	"MakeWrite.h"
X# include	<MenuMgr.h>
X
X
X
Xtypedef enum		/* File menu item numbers */
X{
X	newMap = 1,
X	openMap,
X	appendMap,
X	saveMap,
X	saveMapAs,
X	close,
X	/* --- */
X	makeWrite = 8,
X	/* --- */
X	quit = 10
X};
X
X
Xtypedef enum		/* Edit menu item numbers */
X{
X	undo = 1,
X	/* --- */
X	cut = 3,
X	copy,
X	paste,
X	clear,
X	/* --- */
X	new = 8,
X	duplicate,
X	/* --- */
X	sort = 11,
X	squish
X};
X
X
Xtypedef enum			/* Special menu items */
X{
X	stdFontList = 1,
X	systemFontList,
X	/* --- */
X	pgraphStyle = 4,
X	/* --- */
X	conflicts = 6,
X	/* --- */
X	getInfo = 8,
X	/* --- */
X	debugOption = 10
X};
X
X
Xstatic MenuHandle	fileMenu;
Xstatic MenuHandle	editMenu;
Xstatic MenuHandle	specialMenu;
X
Xstatic MapSpec		clipMSpec;				/* clipboard specification */
X
X
X/*
X	Enable or disable menu or menu items, according to the string.
X	First char of string is for entire menu, following chars are
X	for successive items.  '0' disables, '1' enables.
X
X	Return true if the status of the menu itself changed
X	value, i.e., if the menu bar now needs redrawing.
X*/
X
XBoolean	SetMenuStatus (m, s)
XMenuHandle	m;
XStringPtr	s;
X{
Xregister Integer	i;
XInteger				menuState;
X
X	menuState = ((**m).enableFlags & 1);	/* current state of menu */
X	for (i = 1; i <= s[0]; ++i)
X	{
X		if (s[i] == '0')
X			DisableItem (m, i - 1);
X		else
X			EnableItem (m, i - 1);
X	}
X	return (menuState != ((**m).enableFlags & 1));
X}
X
X
X/*
X	Fix up menus to match window states.  There will always be some
X	window.
X
X	Note the handling of strings.  Those that may change need to be
X	CopyString'ed into the string, otherwise the string constant
X	itself will be changed.
X
X	This routine is stupid about setting cut&paste types of items.
X*/
X
XFixMenus ()
X{
XWindowPtr			frontWind;
XInteger					theKind;
XInteger					nLines;
XInteger					curLine;
XBoolean				drawBar = false;
XStr255				eString;
Xregister StringPtr	fStr,
X					eStr = eString,		/* initial setting, may change */
X					oStr;
X
X	curLine = mapList->curLine;
X	nLines = mapList->nLines;
X	frontWind = FrontWindow ();
X	theKind = ((WindowPeek) frontWind)->windowKind;
X
X	if (frontWind == mapWind)
X	{
X		fStr = (StringPtr) "\p11111100101";
X		oStr = (StringPtr) "\p11101010101";
X		CopyString ("\p1101111011011", eStr);	/* points to eString */
X
X		if (undoOp == noUndo)
X			eStr[undo + 1] = '0';
X
X		if (curLine == noLine)
X		{
X			cpMarker = false;	/* no line - *can't* apply to marker */
X			eStr[cut + 1] = '0';
X			eStr[copy + 1] = '0';
X			eStr[clear + 1] = '0';
X			eStr[duplicate + 1] = '0';
X			if (havePasteMSpec == false)
X				eStr[paste + 1] = '0';
X		}
X		else if (cpMarker == false)	/* line but c/p applies to map */
X		{
X			if (havePasteMSpec == false)
X				eStr[paste + 1] = '0';
X		}
X
X		if (nLines < 2)
X		{
X			eStr[sort + 1] = '0';
X			eStr[squish + 1] = '0';
X		}
X		else if (nLines >= mapList->maxLines)
X		{
X			if (cpMarker == false && curLine == noLine)
X				eStr[paste + 1] = '0';
X			eStr[new + 1] = '0';
X			eStr[duplicate + 1] = '0';
X		}
X
X/*
X	now figure out how to set the cut/paste indicators.  They're
X	blank if there's no current line and can't paste.  Else set
X	according to the current state of indicator flag.
X*/
X
X		if (curLine == noLine && eStr[paste+1] == '0')
X			BlankCPCtrls ();
X		else
X			SetCPMarker (cpMarker);
X	}
X	else
X	{
X
X/*
X	Settings for File and Special menus are same for DA's and display
X	windows
X*/
X		fStr = (StringPtr) "\p10000010001";
X		oStr = (StringPtr) "\p10001000101";
X
X		if (theKind < 0)				/* DA in front */
X			eStr = (StringPtr) "\p1101111000000";
X		else							/* some display window in front */
X			eStr = (StringPtr) "\p0";
X
X		BlankCPCtrls ();
X	}
X
X	drawBar = SetMenuStatus (fileMenu, fStr);
X	drawBar |= SetMenuStatus (editMenu, eStr);
X	drawBar |= SetMenuStatus (specialMenu, oStr);
X
X	if (drawBar)
X		DrawMenuBar ();
X}
X
X
X/*
X	Handle "About MakeWrite..." selection from Apple menu.
X*/
X
XDoAbout ()
X{
X	(void) Alert (aboutAlrtNum, nil);
X}
X
X
X/*
X	Process selection from File menu
X*/
X
XDoFileMenu (item)
XInteger		item;
X{
XWindowPeek	theWind;
XInteger			theKind;
X
X	switch (item)
X	{
X
X	case newMap:
X		if (DiscardChanges ())
X		{
X			ClobberMap ();
X			ClearMapName ();
X			undoOp = noUndo;
X			mapModified = false;
X		}
X		break;
X
X	case openMap:
X		if (DiscardChanges ())
X		{
X			if (OpenMap ())
X			{
X				undoOp = noUndo;
X				mapModified = false;
X			}
X		}
X		break;
X
X	case appendMap:
X		if (AddMap ())
X		{
X			undoOp = noUndo;
X			mapModified = true;
X		}
X		break;
X
X	case saveMap:
X		if (SaveMap (false))
X			mapModified = false;
X		break;
X
X	case saveMapAs:
X		if (SaveMap (true))
X			mapModified = false;
X		break;
X	
X	case close:
X		theWind = (WindowPeek) FrontWindow ();
X		theKind = theWind->windowKind;
X		if (theKind < 0)				/* DA being closed */
X			CloseDeskAcc (theKind);
X		else							/* Display window - just hide */
X			HideWindow (theWind);		/* it.  Activation proc will */
X		break;							/* dispose of it */
X	
X	case makeWrite:
X		TextToWrite ();
X		break;
X	
X	case quit:
X		if (DiscardChanges ())
X			SkelWhoa ();
X		break;
X	}
X	FixMenus ();
X}
X
X
XDoUndo ()
X{
XMapSpec	tempSpec;
XStringHandle	hStr;
XStr255			tempStr;
XInteger				selStart, selEnd;
XBoolean			tmpCPMarker;
X
X	tmpCPMarker = cpMarker;
X	cpMarker = undoCPMarker;
X	undoCPMarker = tmpCPMarker;
X
X	InitMSpec (&tempSpec);
X	switch (undoOp)
X	{
X
X	case undoInsert:
X		undoOp = undoDelete;
X		CopyMSpec (&mapSpec[undoPos], &undoMSpec);
X		DeleteMapping (undoPos);
X		break;
X
X	case undoDelete:
X		undoOp = undoInsert;
X		InsertMapping (&undoMSpec, undoPos);
X		break;
X
X	case undoPaste:
X		CopyMSpec (&mapSpec[undoPos], &tempSpec);
X		PasteMapping (&undoMSpec, undoPos);
X		CopyMSpec (&tempSpec, &undoMSpec);
X		break;
X
X	case undoFieldChg:
X		SetMapFieldValue (undoFieldType, undoVal);
X		break;
X
X	case undoTyping:
X	case undoMarkerOp:
X		undoOp = undoMarkerOp;
X		CopyMSpec (&mapSpec[undoPos], &tempSpec);
X		CopyMSpec (&undoMSpec, &mapSpec[undoPos]);
X		CopyMSpec (&tempSpec, &undoMSpec);
X
X		hStr = mapSpec[undoPos].mark;
X		HLock (hStr);
X		PasteField (mapList, undoPos, markField, *hStr);
X		HUnlock (hStr);
X		SetSelectors (undoPos);
X		break;
X
X	}
X	TermMSpec (&tempSpec);
X}
X
X
X/*
X	Process selection from Edit menu
X*/
X
XDoEditMenu (item)
XInteger		item;
X{
Xregister Integer	curLine;
X
X	if (SystemEdit (item - 1))
X		return;
X
X	if (EditMarker (item))
X		return;					/* it was a marker edit operation */
X
X	curLine = mapList->curLine;
X	switch (item)
X	{
X	
X	case undo:
X		DoUndo ();
X		break;
X	
X	case cut:
X		undoCPMarker = cpMarker;
X		CopyMSpec (&mapSpec[curLine], &clipMSpec);
X		CopyMSpec (&clipMSpec, &undoMSpec);
X		undoOp = undoDelete;
X		undoPos = curLine;
X		havePasteMSpec = true;
X		DeleteMapping (curLine);
X		break;
X	
X	case copy:
X		CopyMSpec (&mapSpec[curLine], &clipMSpec);
X		havePasteMSpec = true;
X		break;
X	
X	case paste:
X		undoCPMarker = cpMarker;
X		if (curLine != noLine)
X		{
X			CopyMSpec (&mapSpec[curLine], &undoMSpec);
X			undoOp = undoPaste;
X			undoPos = curLine;
X			PasteMapping (&clipMSpec, curLine);
X		}
X		else										/* no selection; */
X		{											/* add at end */
X			undoOp = undoInsert;
X			undoPos = mapList->nLines;
X			if (InsertMapping (&clipMSpec, mapList->nLines) == false)
X				undoOp = noUndo;
X		}
X		break;
X	
X	case clear:
X		undoCPMarker = cpMarker;
X		CopyMSpec (&mapSpec[curLine], &undoMSpec);
X		undoOp = undoDelete;
X		undoPos = curLine;
X		DeleteMapping (curLine);
X		break;
X	
X	case new:
X		undoCPMarker = cpMarker;
X		NewMapping ();
X		/*SetCPMarker (true);*/
X		undoOp = undoInsert;
X		break;
X	
X	case duplicate:
X		undoCPMarker = cpMarker;
X		DupMapping (curLine);	/* changes mapList->curLine */
X		SetCPMarker (true);
X		undoOp = undoInsert;
X		undoPos = mapList->curLine;
X		break;
X
X	case sort:
X		SortMap ();
X		undoOp = noUndo;	/* can't undo this */
X		break;
X
X	case squish:
X		SquishMap ();
X		undoOp = noUndo;	/* can't undo this */
X		break;
X
X	}
X
X	if (item != copy)
X		mapModified = true;
X	FixMenus ();
X}
X
X
XDoSpecialMenu (item)
XInteger		item;
X{
X	switch (item)
X	{
X
X	case stdFontList:
X		StrFonts (true);
X		SetSelectors (mapList->curLine);
X		break;
X
X	case systemFontList:
X		ResourceFonts (true);
X		SetSelectors (mapList->curLine);
X		break;
X
X	case pgraphStyle:
X		DoParaDialog ();
X		break;
X
X	case conflicts:
X		FindConflicts ();
X		break;
X
X	case getInfo:
X		HelpWindow ();
X		break;
X
X# ifdef	debug
X	case debugOption:
X		debugOut = !debugOut;
X		CheckItem (specialMenu, debugOption, debugOut);
X		break;
X# endif
X
X	}
X	FixMenus ();
X}
X
X
X/*
X	Menu initialization.
X*/
X
XSetupMenus ()
X{
X	SkelApple ("\pAbout MakeWrite...", DoAbout);
X
X	fileMenu = GetMenu (fileMenuNum);
X	SkelMenu (fileMenu, DoFileMenu, nil);
X
X	editMenu = GetMenu (editMenuNum);
X	SkelMenu (editMenu, DoEditMenu, nil);
X
X	specialMenu = GetMenu (specialMenuNum);
X# ifdef	debug
X	AppendMenu (specialMenu, "\p(-;Debug Output");
X# endif
X	SkelMenu (specialMenu, DoSpecialMenu, nil);
X
X	InitMSpec (&undoMSpec);
X	InitMSpec (&clipMSpec);
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > MW/MWMisc.c
X# include	"MakeWrite.h"
X# include	<EventMgr.h>
X
X
X/* ---------------------------------------------------------------- */
X/*							String Operations						*/
X/* ---------------------------------------------------------------- */
X
X/*
X	Copy src to dst
X*/
X
XCopyString (src, dst)
XStringPtr	src, dst;
X{
X	BlockMove (src, dst, (Longint) (src[0] + 1));
X}
X
X
X/*
X	Append src to dst
X*/
X
XAppendString (src, dst)
XStringPtr	src, dst;
X{
X	BlockMove (&src[1], dst + dst[0] + 1, (Longint) src[0]);
X	dst[0] += src[0];
X}
X
X
X/*
X	Compare two strings.
X	Return:
X		0		s1 = s2
X		< 0		s1 < s2
X		> 0		s1 > s2
X*/
X
XCompareString (s1, s2)
Xregister StringPtr	s1, s2;
X{
Xregister Integer	i, len, diff;
X
X	len = s1[0];
X	if (len > s2[0])
X		len = s2[0];
X	for (i = 1; i <= len; ++i)
X	{
X		if ((diff = s1[i] - s2[i]) != 0)
X			return (diff);
X	}
X	return (s1[0] - s2[0]);
X}
X
X
XBoolean InString (s, c)
XStringPtr	s;
Xchar		c;
X{
Xregister Integer	i, len;
X
X	for (len = s[0], i = 1; i <= len; ++i)
X	{
X		if (s[i] == c)
X			return (true);
X	}
X	return (false);
X}
X
X/* ---------------------------------------------------------------- */
X/*							Event Operations						*/
X/* ---------------------------------------------------------------- */
X
X
X/*
X	Return true if there's a mouse-down event pending (also flush the
X	event so that it's not used in some way other than as a signal.
X*/
X
XBoolean	MouseClick ()
X{
XEventRecord	theEvent;
X
X	if (EventAvail (mDownMask, &theEvent))
X	{
X		FlushEvents (mDownMask, 0);
X		return (true);
X	}
X	return (false);
X}
X
X
Xstatic Integer	eventTypes;
X
X
X/*
X	Make sure any events of proper type are processed before
X	proceeding.
X*/
X
XCheckEvents ()
X{
XEventRecord	event;
X
X	if (!EventAvail (eventTypes, &event))
X		SkelWhoa ();
X}
X
X
XDoEvents (doTypes)	/* can be called recursively */
XInteger		doTypes;
X{
XInteger		types;
XInteger		mask;
XProcPtr	bkGnd;
X
X	SkelGetBackground (&bkGnd);		/* get current background proc */
X	SkelGetEventMask (&mask);		/* and event mask */
X	types = eventTypes;				/* and processing types */
X
X	SkelBackground (CheckEvents);	/* install new background & mask */
X	SkelEventMask (doTypes);
X	eventTypes = doTypes;
X
X	SkelMain ();					/* handle updates only */
X
X	SkelBackground (bkGnd);			/* restore old background & mask */
X	SkelEventMask (mask);
X	eventTypes = types;
X}
X
X
XDoUpdates ()
X{
X	DoEvents (updateMask);
X}
X
X
X/*
X	Make a window the front window and update it before proceeding.
X*/
X
XMakeFrontWind (w)
XWindowPtr	w;
X{
X	HiliteMenu (0);
X	SelectWindow (w);
X	ShowWindow (w);
X	DoEvents (updateMask + activMask);
X	SetPort (w);
X}
X
X
X/* ---------------------------------------------------------------- */
X/*							Memory Operations						*/
X/* ---------------------------------------------------------------- */
X
X
XBoolean ExpandHandle (h, delta)
XHandle	h;
XSize	delta;
X{
XSize	newSize;
X
X	newSize = GetHandleSize (h) + delta;
X	SetHandleSize (h, newSize);
X	return (GetHandleSize (h) == newSize);
X}
X
X
X/* ---------------------------------------------------------------- */
X/*								Miscellaneous						*/
X/* ---------------------------------------------------------------- */
X
X
XBoolean DiscardChanges ()
X{
XBoolean	result;
X
X	if (!mapModified)
X		return (true);
X	ParamText ("\pDiscard changes to current map?", "\p", "\p", "\p");
X	result = (Alert (questAlrtNum, nil) == 2);	/* 2 is "OK" */
X	DoUpdates ();
X	return (result);
X}
X
X
X
XBoolean DestroyWarn ()
X{
XBoolean	result;
X
X	if (mapList->nLines == 0)	/* if nothing there, don't bother, */
X	{							/* unless map has changed, then ask */
X		if (mapModified)		/* different question */
X			return (DiscardChanges ());
X		return (true);
X	}
X	ParamText ("\pThis operation destroys the current map.",
X				"\p Do you wish to proceed?", "\p", "\p");
X	result = (Alert (questAlrtNum, nil) == 2);	/* 2 is "OK" */
X	DoUpdates ();
X	return (result);
X}
X
X
X/*
X	Display a message in a generic alert.
X*/
X
XMessage (s1, s2, s3, s4)
XStringPtr	s1, s2, s3, s4;
X{
X	ParamText (s1, s2, s3, s4);
X	(void) Alert (msgeAlrtNum, nil);
X	DoUpdates ();
X}
X
X
XMessage1 (s1)
XStringPtr	s1;
X{
X	Message (s1, "\p", "\p", "\p");
X}
X
X
XMessage2 (s1, s2)
XStringPtr	s1, s2;
X{
X	Message (s1, s2, "\p", "\p");
X}
X
X
XMessage3 (s1, s2, s3)
XStringPtr	s1, s2, s3;
X{
X	Message (s1, s2, s3, "\p");
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > MW/MWParaDlog.c
X/*
X	Paragraph style dialog
X*/
X
X
X# include	<DialogMgr.h>
X# include	<EventMgr.h>
X# include	<ToolboxUtil.h>
X# include	"MakeWrite.h"
X
X
Xtypedef enum		/* paragraph style dialog item numbers */
X{
X	paraOK = 1,
X	paraCancel,
X	paraEach,
X	paraBlank,
X	paraSmart,
X	paraMText,
X	paraPText,
X	paraQText,
X	paraLine1,
X	paraLine2
X};
X
X
X/*
X	Initialize paragraph style to default:  blank lines and lines
X	beginning with whitespace initiate paragraphs,  line joining
X	is smart, there's no explicit paragraph or page break marker.
X*/
X
X
Xstatic ParaStyle	defStyle =  { false, true, true };
Xstatic Str255		defPeriodStr = "\p.!?";
Xstatic Str255		defQuoteStr = { 5, '"', '\'', 0xd3, 0xd5, ')' };
X
X
X/*
X	Set the contents of a string using the contents of the 'STR '
X	resource whose id is passed as strResId.
X*/
X
Xstatic ResSetString (strResId, str)
XInteger			strResId;
XStringPtr	str;
X{
XStringHandle	hStr;
X
X	hStr = GetString (strResId);
X	HLock (hStr);
X	if ((*hStr)[0] > maxMarkLen)
X		(*hStr)[0] = maxMarkLen;
X	CopyString (*hStr, str);
X	HUnlock (hStr);
X	ReleaseResource (hStr);
X}
X
X
XInitParaStyle ()
X{
X	paraStyle = defStyle;
X	paraMark[0] = 0;
X	pageMark[0] = 0;
X	ResSetString (periodStrNum, periodStr);
X	ResSetString (quoteStrNum, quoteStr);
X}
X
X
Xstatic pascal void DoLine (dlog, item)
XDialogPtr	dlog;
XInteger			item;
X{
XHandle	itemHandle;
XInteger		itemType;
XRect	itemRect;
X
X	GetDItem (dlog, item, &itemType, &itemHandle, &itemRect);
X	FrameRect (&itemRect);
X}
X
X
Xstatic Boolean GetDCtl (dlog, item)
XDialogPtr	dlog;
XInteger			item;
X{
XHandle	itemHandle;
XInteger		itemType;
XRect	itemRect;
X
X	GetDItem (dlog, item, &itemType, &itemHandle, &itemRect);
X	return (GetCtlValue (itemHandle));
X}
X
X
Xstatic SetDCtl (dlog, item, value)
XDialogPtr	dlog;
XInteger			item;
XBoolean		value;
X{
XHandle	itemHandle;
XInteger		itemType;
XRect	itemRect;
X
X	GetDItem (dlog, item, &itemType, &itemHandle, &itemRect);
X	SetCtlValue (itemHandle, (Integer) value);
X}
X
X
Xstatic GetDText (dlog, item, str)
XDialogPtr	dlog;
XInteger			item;
XStringPtr	str;
X{
XHandle	itemHandle;
XInteger		itemType;
XRect	itemRect;
XStr255	s;
X
X	GetDItem (dlog, item, &itemType, &itemHandle, &itemRect);
X	GetIText (itemHandle, s);
X	if (s[0] > maxMarkLen)
X		s[0] = maxMarkLen;
X	CopyString (s, str);
X}
X
X
Xstatic SetDText (dlog, item, str)
XDialogPtr	dlog;
XInteger			item;
XStr255		str;
X{
XHandle	itemHandle;
XInteger		itemType;
XRect	itemRect;
X
X	GetDItem (dlog, item, &itemType, &itemHandle, &itemRect);
X	SetIText (itemHandle, str);
X	SelIText (dlog, item, 0, 32767);
X}
X
X
X/*
X	Get the text of an item, and return true if it's different than
X	the current value
X*/
X
Xstatic Boolean CheckDText (dlog, item, str)
XDialogPtr	dlog;
XInteger			item;
XStr255		str;
X{
XStr255		tmpStr;
XBoolean		changed;
X
X	GetDText (dlog, item, tmpStr);
X	changed = (CompareString (str, tmpStr) != 0);
X	CopyString (tmpStr, str);
X	return (changed);
X}
X
X
Xstatic SetDProc (dlog, item, p)
XDialogPtr	dlog;
XInteger			item;
XProcPtr		p;
X{
XHandle	itemHandle;
XInteger		itemType;
XRect	itemRect;
X
X	GetDItem (dlog, item, &itemType, &itemHandle, &itemRect);
X	SetDItem (dlog, item, itemType, p, &itemRect);
X}
X
X
Xstatic SetParaCheck (theDialog, each, blank, smart)
XDialogPtr	theDialog;
XBoolean		each, blank, smart;
X{
X	SetDCtl (theDialog, paraEach, each);
X	SetDCtl (theDialog, paraBlank, blank);
X	SetDCtl (theDialog, paraSmart, smart);
X}
X
X
X
XDoParaDialog ()
X{
Xregister DialogPtr	theDialog;
XInteger			itemHit = 0;
XBoolean		loop = true;
Xregister Boolean	curEach, curBlank, curSmart;
XBoolean		changed;
XStr255		s;
X
X	theDialog = GetNewDialog (paraDlogNum, nil, -1L);
X	SetParaCheck (theDialog, curEach = paraStyle.pEachLine,
X							 curBlank = paraStyle.pBlankLine,
X							 curSmart = paraStyle.pSmartJoin);
X	SetDText (theDialog, paraPText, periodStr);
X	SetDText (theDialog, paraQText, quoteStr);
X	SetDText (theDialog, paraMText, paraMark);
X	SetDProc (theDialog, paraLine1, DoLine);
X	SetDProc (theDialog, paraLine2, DoLine);
X	ShowWindow (theDialog);
X
X	while (loop)
X	{
X		ModalDialog (nil, &itemHit);
X		switch (itemHit)
X		{
X
X/*
X	If smart join is selected but there aren't any sentence terminators,
X	put up an alert and don't quit.
X*/
X		case paraOK:
X			GetDText (theDialog, paraPText, s);
X			if (curSmart && s[0] == 0)
X			{
X				(void) Alert (noPeriodAlrtNum, nil);
X				continue;
X			}
X
X			changed = (paraStyle.pEachLine != curEach);
X			paraStyle.pEachLine = curEach;
X
X			changed |= (paraStyle.pBlankLine != curBlank);
X			paraStyle.pBlankLine = curBlank;
X
X			changed |= (paraStyle.pSmartJoin != curSmart);
X			paraStyle.pSmartJoin = curSmart;
X
X			changed |= CheckDText (theDialog, paraMText, paraMark);
X			changed |= CheckDText (theDialog, paraPText, periodStr);
X			changed |= CheckDText (theDialog, paraQText, quoteStr);
X
X			if (changed)
X				mapModified = true;
X			loop = false;
X			break;
X
X		case paraCancel:
X			loop = false;
X			break;
X
X		case paraEach:
X			curEach = !curEach;
X			if (curEach)
X				curBlank = false;
X			break;
X
X		case paraBlank:
X			curBlank = !curBlank;
X			if (curBlank)
X				curEach = false;
X			break;
X
X		case paraSmart:
X			curSmart = !curSmart;
X			break;
X
X		}
X		SetParaCheck (theDialog, curEach, curBlank, curSmart);
X	}
X	DisposDialog (theDialog);
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > MW/MWTextToWrite.c
X/*
X	Convert text file to MacWrite document, using formatting
X	specifications contained in current map.
X
X	Possibly add:
X		Text compression
X*/
X
X
X# include	"MakeWrite.h"
X# include	"MWMaca.h"
X# include	"MWFileStuff.h"
X# include	<StdFilePkg.h>
X
X
X# define	applFont	1
X
X# define	maxTBufSize	1024	/* text file input buffer size */
X# define	maxCBufSize	4000	/* MacWrite limit on chars in paragraph */
X
X/*
X	MacWrite's maximum main doc text para count is something over
X	2000.  I choose 2000 as a reasonable limit.
X*/
X
X# define		maxMWParas	2000
X
X
X/*
X	Vars for text file streaming
X*/
X
Xstatic Integer	fText;					/* input text file reference number */
Xstatic char	tFileBuf[maxTBufSize];	/* file buffer */
Xstatic Longint	tFileSize;				/* file size */
Xstatic Longint	tFileRead;				/* # chars read */
Xstatic Longint	tFileLeft;				/* # chars still to read */
Xstatic Longint	tBufSize;				/* number of chars currently in buffer */
Xstatic Integer	tBufPos;				/* current text buffer position */
Xstatic Integer	percent;				/* percent of input read so far */
X
X
X/*
X	fWord - output MacWrite file reference number
X	pushBack - text file input pushback queue
X	outBuf - output paragraph buffer
X	outChars - number of chars into current output paragraph so far
X	blankCount - number of blanks to put out for line joining
X	fmtCount - number of formats in the current paragraph so far
X	fmtBuf - format information storage array
X	maxFormats - number of formats the format array handle can hold
X		before needing expansion
X	needFormat - true if need to generate a format when the next output
X		char is added to current paragraph
X	paraInfo - paragraph information storage array
X	maxParas - number of elements paraInfo can hold before needing expansion
X	paraCount - current number of paragraphs (doesn't count initial ruler)
X
X	font, size, style - current format
X*/
X
Xstatic Integer	fWord;
Xstatic Str255	pushBack;
Xstatic char		outBuf[maxCBufSize];
Xstatic Integer	outChars;
Xstatic Integer		blankCount;
X
Xstatic FAHandle		fmtBuf;
Xstatic Integer		fmtCount;
Xstatic Integer		maxFormats;
Xstatic Boolean		needFormat;
X
Xstatic PIAHandle	paraInfo;
Xstatic Integer		maxParas;
Xstatic Integer		paraCount;
X
Xstatic Integer		font;
Xstatic Integer		size;
Xstatic Integer		style;
X
X
X/*
X	Initialize text streaming variables
X*/
X
Xstatic InitTextStream (f)
XInteger		f;
X{
X	(void) GetEOF (f, &tFileSize);	/* set up streaming variables */
X	tFileLeft = tFileSize;
X	tFileRead = 0;
X	tBufSize = 0;
X	tBufPos = 0;
X	percent = -1;
X}
X
X
X/*
X	Get next char from text file.  This has to take account of the
X	state of the pushback stack.  File is read from disk a block
X	at a time and dribbled out to avoid making a file system call
X	for every character.
X
X	Return false on end of file or file read error.
X*/
X
Xstatic Boolean ReadTextChar (c)
Xregister char	*c;
X{
XInteger		newPercent;
X
X	if (pushBack[0] > 0)				/* pushback stack not empty */
X	{
X		*c = pushBack[pushBack[0]--];	/* return top char */
X		return (true);
X	}
X
X	if (tBufPos >= tBufSize)	/* need to read in a new block */
X	{
X		tBufSize = tFileLeft;
X		if (tBufSize == 0)				/* end of file */
X			return (false);
X		if (tBufSize > maxTBufSize)		/* don't read more than a block */
X			tBufSize = maxTBufSize;
X		tFileLeft -= maxTBufSize;
X		if (tFileLeft < 0)
X			tFileLeft = 0;
X
X		if (!FileRead (fText, tFileBuf, (Longint) tBufSize))
X			return (false);				/* read error */
X		tBufPos = 0;
X	}
X	*c = tFileBuf[tBufPos++];
X
X# ifdef	debug
X	DisplayChar (*c);
X# endif
X
X	newPercent = (++tFileRead * 100) / tFileSize;
X	if (newPercent != percent)
X	{
X		percent = newPercent;
X		SetMeterPercent (percent);
X	}
X	return (true);
X}
X
X
X/*
X	FIgure out how many blanks need to be added to the output buffer
X	if another line is joined on.  Default is one.  If smart join is
X	on, then two spaces if something like a period is at the end now.
X	Remember to account for spaces that may already be on the end.  If
X	a tab is found at the end, then throw hands up in disgust, because
X	who knows how wide it is?
X*/
X
Xstatic SetBlankCount ()
X{
Xregister Integer	i, endBlanks, needBlanks = 1;
Xregister char	c;
X
X	i = outChars;
X	while (i > 0)	/* count up spaces on end currently */
X	{
X		if ((c = outBuf[i-1]) == '\t')
X		{
X			blankCount = 0;
X			return;					/* tab found - give up */
X		}
X		if (c != ' ')
X			break;
X		--i;
X	}
X	endBlanks = outChars - i;
X
X	if (paraStyle.pSmartJoin)	/* smart join - try to be intelligent */
X	{
X		while (i > 0)
X		{
X			c = outBuf[i-1];
X			if (InString (quoteStr, c))	/* quote char - ignore */
X				--i;
X			else			/* not quote char - is it period char? */
X			{
X				if (InString (periodStr, c))
X					needBlanks = 2;		/* yes - need two chars */
X				break;
X			}
X		}
X	}
X
X	if (i == 0)					/* empty buffer - nothing needed */
X		needBlanks = 0;
X
X	needBlanks -= endBlanks;	/* account for those already there */
X	if (needBlanks < 0)
X		needBlanks = 0;
X	blankCount = needBlanks;
X}
X
X
X/*
X	Push saved text back onto the pushback stack
X*/
X
Xstatic PushSavedText (s)
XStringPtr	s;
X{
X	while (s[0] > 0)
X	{
X		pushBack[++pushBack[0]] = s[s[0]--];
X	}
X}
X
X
Xstatic Boolean NewFormat ()
X{
Xregister Format	*f;
X
X# ifdef	debug
X	DisplayString ("\p {NewFormat}");
X# endif
X
X	if (fmtCount >= maxFormats)	/* need to make format array bigger */
X	{
X		if (!ExpandHandle (fmtBuf, 1024L))
X		{
X			Message1 ("\pOut of memory, can't continue (NewFormat)");
X			return (false);
X		}
X		maxFormats = GetHandleSize (fmtBuf) / sizeof (Format);
X	}
X
X	f = &((**fmtBuf)[fmtCount++]);
X	f->fmtPos = outChars;			/* starting pos of format */
X	f->fmtFont = font;				/* current font */
X	f->fmtSize = size;				/* current size */
X	f->fmtStyle = style;			/* current style */
X	return (true);
X}
X
X
Xstatic Boolean AddChar (c)
Xchar	c;
X{
XStr255	s;
X
X	if (needFormat)
X	{
X		needFormat = false;
X		if (!NewFormat ())
X			return (false);		/* couldn't get memory for format */
X	}
X	if (outChars >= maxCBufSize)
X	{
X		NumToString ((Longint) maxCBufSize, s);
X		Message ("\pParagraph contains more than ", s,
X					"\p chars (MacWrite limit exceeded).",
X					"\p  Check your Paragraph Style settings.");
X		return (false);
X	}
X	outBuf[outChars++] = c;
X	return (true);
X}
X
X
Xstatic ChangeCurFormat (m)
Xregister MapSpec	*m;
X{
XStr255	infoStr;
X
X	if (m->font != sameFont && m->font != font)
X	{
X		font = m->font;
X		needFormat = true;
X	}
X	if (m->size != sameSize && m->size != size)
X	{
X		size = m->size;
X		needFormat = true;
X	}
X	if (m->style != sameStyle && m->style != style)
X	{
X		style = m->style;
X		needFormat = true;
X	}
X
X# ifdef	debug
X	if (needFormat)
X	{
X		DisplayChar ('{');
X		FontToStr (font, infoStr);
X		DisplayString (infoStr);
X		DisplayChar ('/');
X		DisplayInt (size);
X		DisplayChar ('/');
X		StyleToStr (style, infoStr);
X		DisplayString (infoStr);
X		DisplayString ("\p} ");
X	}
X# endif
X}
X
X
X/*
X	Write stored paragraph contents to disk:
X		number bytes of text (word)
X		the text
X		zero pad if necessary to align to word boundary
X		number bytes of format information
X		the format information
X
X	Construct a new element in the paragraph information array
X	as well, and reset the paragraph state vars.
X	
X	The data position pointer in the para info element is set
X	to the current file position, since that's where the data
X	will be written.
X*/
X
Xstatic Boolean FlushPara ()
X{
XInteger	fmtLen, dataLen;
XBoolean	result;
XStr255	s;
X
X# ifdef	debug
X	DisplayString ("\p{FlushPara}");
X# endif
X
X	if (paraCount >= maxMWParas)
X	{
X		NumToString ((Longint) maxMWParas, s);
X		Message3 ("\pYour document contains more than ",
X						s, "\p paragraphs.  Split the input file and try again.");
X		return (false);
X	}
X		
X	if (paraCount >= maxParas)	/* need to make para info array bigger */
X	{
X		if (!ExpandHandle (paraInfo, 1024L))
X		{
X			Message1 ("\pOut of memory, can't continue (FlushPara)");
X			return (false);
X		}
X		maxParas = GetHandleSize (paraInfo) / sizeof (ParaInfo6);
X	}
X
X	fmtLen = fmtCount * sizeof (Format);
X	dataLen = sizeof (Integer)			/* word for length of text */
X			+ ((outChars + 1) & ~1)	/* text ( + pad if necessary) */
X			+ sizeof (Integer)			/* word for length of formats */
X			+ fmtLen;					/* formats */
X	HLock (paraInfo);
X	SetParaInfo (&((**paraInfo)[paraCount++]),
X					16, 0, FilePos (fWord), dataLen, 0);
X	HUnlock (paraInfo);
X	HLock (fmtBuf);
X	result =
X		   WriteInteger (fWord, outChars)
X		&& FileWrite (fWord, outBuf, (Longint) outChars)
X		&& ZeroPad (fWord, 0)
X		&& WriteInteger (fWord, fmtLen)
X		&& FileWrite (fWord, *fmtBuf, (Longint) fmtLen);
X	HUnlock (fmtBuf);
X	outChars = 0;			/* reset para state vars */
X	fmtCount = 0;
X	needFormat = true;
X	blankCount = 0;			/* don't need blanks for line joining now */
X	return (result);
X}
X
X
X/*
X	Flush current paragraph, if there's any text in it
X*/
X
Xstatic Boolean DoBreak ()
X{
X	return (outChars == 0 || (AddChar (cr) && FlushPara ()));
X}
X
X
X/*
X	Flush current paragraph, regardless of whether there's anything
X	in it or not.
X*/
X
Xstatic Boolean DoSpace ()
X{
X	return (AddChar (cr) && FlushPara ());
X}
X
X
X/*
X	FormatText - convert text file to MacWrite file
X
X	Winner of 1987 "Ugliest Function" award.  That goes for the
X	comments, too.  They've been revised so often, even I barely
X	understand them, so good luck.
X
X	saveQueue is the text that's been matched partially.  It's saved
X	for writing to output in case no match is found:  the text is
X	put back on the pushback stack, the first char is written out
X	and a match is sought starting with the next char.
X
X	The biggest headache about this thing is getting it to work properly
X	with all legal combinations of paragraph style settings.
X
X	"Each line a paragraph" is never on if blank line paragraphing is
X	on, and vice-versa.  Use of a paragraph marker is compatible with
X	all options.
X
X	Input lines containing only imbedded commands are always ignored
X	for paragraphing purposes - that is, they're not treated as blank
X	lines.
X*/
X
Xstatic Boolean FormatText ()
X{
Xchar			c;				/* input char */
XStr255			saveQueue;		/* input save queue */
XInteger				index;			/* command index */
Xregister Integer	inLineChars;	/* # chars from current line added to */
X								/* output (for blank line and beginning */
X								/* of line detection) */
XBoolean			cmdsInLine;		/* whether commands were found in line */
XBoolean			xNeedFormat;
X
X	if (!WritePrelude (fWord))
X		return (false);
X
X	font = applFont;
X	size = 12;
X	style = 0;	/* plain */
X
X	InitMarkStates ();				/* clear match info */
X	pushBack[0] = 0;				/* and file queues */
X	saveQueue[0] = 0;
X	inLineChars = 0;			/* no chars added from current line */
X	blankCount = 0;				/* no blanks needed for line joining yet */
X	cmdsInLine = false;			/* no commands in line yet */
X	paraCount = 0;				/* no paragraphs yet */
X	outChars = 0;				/* no chars in current paragraph */
X	fmtCount = 0;				/* no formats yet, either */
X	needFormat = true;			/* generate format on next char written */
X
X	while (ReadTextChar (&c))			/* while not eof on text file */
X	{
X		saveQueue[++saveQueue[0]] = c;
X		switch (index = CheckMarkers (c))
X		{
X
X		case -2:						/* no match */
X/*
X	Push back saved text, read first char and add to current
X	paragraph.  If the paragraph is done, flush it to disk, and
X	start looking for a new marker.
X
X	Note what happens on cr.  It is read, saved, fails to match, and
X	is pushed back.  If there are other chars before it in pushback,
X	they'll be reprocessed (except first of them, which is added to
X	para).  Eventually, the cr becomes first thing in pushback.  It is
X	read, saved, fails to match, and is pushed back,  Then it's read
X	again, and causes para flushing according to para style rules.
X
X	Carriage return check is here only.  Cr never matches any marker
X	char, since it can't be typed into one.  Therefore it's not possible
X	to get any other return value from CheckMarkers when c == cr.
X*/
X
X			PushSavedText (saveQueue);
X			InitMarkStates ();
X			(void) ReadTextChar (&c);
X
X/*
X	If the character is not a carriage return, then it is simply
X	added to the current paragraph.  The exception occur if this is
X	the first char of the line:
X
X	(i) If the character is whitespace at the beginning of the line,
X	then the line begins a new paragraph, so flush the previous
X	paragraph, if there's anything there.
X
X	(ii) Dribble out any blanks needed to take care of any line
X	joining that might be going on.  Delay putting out any format
X	change that might be pending until right before the char following
X	the blanks - it's safe to do this because a format must have
X	already been written for there to be any need to join with spaces.
X*/
X
X			if (c != cr)
X			{
X				if (inLineChars == 0)			/* if start of line... */
X				{
X					if (c == ' ' || c == '\t')
X					{
X						if (!DoBreak ())
X							return (false);
X					}
X					else
X					{
X						xNeedFormat = needFormat;
X						needFormat = false;
X						while (blankCount > 0)
X						{
X							if (!AddChar (' '))
X								return (false);
X							--blankCount;
X						}
X						needFormat = xNeedFormat;
X					}
X				}
X				if (!AddChar (c))
X					return (false);
X				++inLineChars;
X			}
X
X/*
X	Char is cr.  If line only contained commands, ignore it.
X	Else if every line begins a paragraph, flush it.  Else if
X	line is blank and blank lines begin paragraphs.  Else it's just
X	the end of the current line and it will be joined to the text of
X	the next line unless the paragraph gets flushed first - so figure
X	out how many spaces to put out before the next line is written.
X	The writing happens when we actually get a line to be joined, not
X	here, so that spaces don't get tacked onto lines that may not need
X	them.
X*/
X
X			else
X			{
X				if (!(cmdsInLine && inLineChars == 0))
X				{
X					if (paraStyle.pEachLine)		/* always force line */
X					{
X						if (!DoSpace ())
X							return (false);
X					}
X					else if (inLineChars == 0)			/* if blank line */
X					{
X						if (paraStyle.pBlankLine)	/* and they are paras */
X						{
X							if (!DoBreak () || !DoSpace ())
X								return (false);
X						}
X						else	/* ignore the line, but set blank count */
X						{
X							SetBlankCount ();
X						}
X					}
X					else
X					{
X						SetBlankCount ();
X					}
X				}
X				inLineChars = 0;
X				cmdsInLine = false;
X			}
X			break;
X	
X		case -1:						/* match, but not entirely yet */
X			break;						/* just keep looking */
X
X		default:						/* found complete match */
X/*
X	Since the text matched a marker, it either appears in the
X	output as a format change or signals the beginning of a
X	paragraph.  In either case, it doesn't appear in the output
X	as literal text, so can toss the save queue.
X
X	If it's a format, process the format spec, setting the flag
X	indicating that a new format will be needed on the next char
X	written out (but only if the format actually *changes*).
X
X	If it's a para marker, flush the current paragraph.
X*/
X			cmdsInLine = true;
X
X			if (index == paraMarkIdx)
X			{
X				if (!DoSpace ())
X					return (false);
X			}
X			else if (index == pageMarkIdx)
X			{
X				/* not implemented */
X# ifdef	debug
X				DisplayString ("\p{Page break not implemented}");
X# endif
X			}
X			else
X				ChangeCurFormat (&mapSpec[index]);
X
X			saveQueue[0] = 0;		/* toss pushback */
X			InitMarkStates ();		/* start looking for new marker */
X			break;
X		
X		}
X	}
X
X/*
X	It's the end of the file, but we might have been left in the middle
X	of matching a mark, so return saved text to the pushback queue and
X	write it out.  Note that if we *were* in the middle of mark testing,
X	then this is not the beginning of a line and no spaces need to be
X	dribbled.
X*/
X
X	PushSavedText (saveQueue);
X	while (ReadTextChar (&c))
X	{
X		if (!AddChar (c))
X			return (false);
X	}
X
X/*
X	There must be at least one text paragraph.  If there aren't any
X	make sure one is generated.  If nothing at all has been formatted,
X	there won't even be any formats generated, so force one.  Then
X	flush the paragraph.
X
X	If there already were paragraphs, then see whether unflushed
X	characters are being held and flush if so.
X*/
X
X	if (paraCount == 0)
X	{
X		if (fmtCount == 0)
X		{
X			if (!NewFormat ())
X				return (false);
X		}
X		if (!FlushPara ())
X			return (false);
X	}
X	else if (outChars != 0)
X	{
X		if (!FlushPara ())
X			return (false);
X	}
X
X	if (!WritePostlude (fWord, paraCount, paraInfo))
X		return (false);
X
X	return (true);
X}
X
X
XTextToWrite ()
X{
XSFReply	inFile;
XSFReply	outFile;
XBoolean	result;
X
X	if (FindEmptyMark ())
X		return;
X
X	if (!GetInputFile ("\pOpen", 'TEXT', &inFile))
X		return;
X	CopyString (inFile.fName, outFile.fName);	/* make default output name */
X	AppendString ("\p.mw", outFile.fName);
X	if (!GetOutputFile (true, outFile.fName, 0, &outFile))
X		return;
X
X	if (!OpenInputFile (&inFile, &fText))
X		return;
X
X	InitTextStream (fText);
X	
X	if (!OpenOutputFile (&outFile, 'MACA', 'WORD', &fWord))
X	{
X		(void) FSClose (fText);
X		return;
X	}
X
X	MeterBegin ();
X	MeterPos (5, 0);
X	MeterString ("\pFormatting:  ");
X	MeterString (inFile.fName);
X	MeterPos (64, 1);
X	MeterString ("\pTo:  ");
X	MeterString (outFile.fName);
X	StartMeterPercentInfo ();
X
X/*
X	Fire up a debug output window if that option is true.  If it's
X	false, then not executing DisplayWindow results in all output calls
X	being ignored. Not as quick as testing them all, but easier.
X	(None of it will be true if compilation has all this stuff turned
X	off, anyway.)
X*/
X
X# ifdef	debug
X	if (debugOut)
X		DisplayWindow (outFile.fName, true);
X	DisplayString ("\pInput file size ");
X	DisplayLong (tFileSize);
X	DisplayLn ();
X# endif
X
X	fmtBuf = (FAHandle) NewHandle (0L);	/* get format array buffer */
X	maxFormats = 0;
X	paraInfo = (PIAHandle) NewHandle (0L);	/* get para info array buffer */
X	maxParas = 0;
X
X	result =  FormatText ();
X	(void) FSClose (fText);
X	(void) FSClose (fWord);
X	(void) FlushVol (fWord, outFile.vRefNum);
X	if (result == false)
X		FSDelete (outFile.fName, outFile.vRefNum);
X
X	DisposHandle (fmtBuf);
X	DisposHandle (paraInfo);
X	MeterEnd ();
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > MW/MWWindMisc.c
X# include	"MakeWrite.h"
X
X
XWindowPtr	NewDWindow ();
X
Xstatic WindowPtr	meterWind = nil;
Xstatic WindowPtr	helpWind = nil;
Xstatic Integer			errCount;
Xstatic Str255		errWindName;
Xstatic Integer			hPercent;
X
X/* ---------------------------------------------------------------- */
X/*					General Display Window Routines					*/
X/* ---------------------------------------------------------------- */
X
X
Xstatic DWindActivate (active)
XBoolean	active;
X{
XWindowPeek	w;
X
X	if (!active)	/* deactivated - was it closed? */
X	{
X		GetPort (&w);
X		if (w->visible == 0)
X		{
X			SkelRmveWind (w);	/* yes - remove it */
X			if ((WindowPtr) w == helpWind)
X				helpWind = nil;
X		}
X	}
X	FixMenus ();
X}
X
X
X/*
X	Build a display window.  NewDWindow makes it the current output
X	window for display output.  The window comes up in front unless
X	the meter is present, in which case it comes up under the meter.
X*/
X
XDisplayWindow (title, visible)
XStringPtr	title;
XBoolean		visible;
X{
Xregister WindowPtr	w;
XRect				r;
Xstatic Integer			i = 0;
Xregister Integer		h, v;
X
X	if (meterWind != nil && i < 1)
X		i = 1;
X	h = i * 23 + 5;
X	v = h + 65;
X	SetRect (&r, h, v, h + 350, v + 200);
X	SetDWindowNotify (nil, DWindActivate);
X	w = NewDWindow (&r, title, visible, -1L, true, 0L);
X	if (visible)
X		MakeFrontWind (w);
X	if (++i == 4)
X		i = 0;
X}
X
X
X/* ---------------------------------------------------------------- */
X/*						Meter Window Routines						*/
X/* ---------------------------------------------------------------- */
X
X
XMeterPos (h, lineNo)
XInteger		h, lineNo;
X{
X	SetPort (meterWind);
X	MoveTo (h, (Integer) (lineNo * 16 + 14));
X}
X
X
XMeterString (s)
XStringPtr	s;
X{
X	SetPort (meterWind);
X	DrawString (s);
X}
X
X
XMeterInt (i)
XInteger		i;
X{
XStr255	s;
X
X	NumToString ((Integer) i, s);
X	MeterString (s);
X}
X
X
XStartMeterPercentInfo ()
X{
XPenState	p;
X
X	MeterString ("\p     ");
X	GetPenState (&p);
X	hPercent = p.pnLoc.h;
X}
X
X
XSetMeterPercent (i)
XInteger		i;
X{
X	MeterPos (hPercent, 1);
X	MeterInt (i);
X	MeterString ("\p%");
X}
X
X
Xstatic MeterClobber ()
X{
X	DisposeWindow (meterWind);
X	meterWind = nil;
X}
X
X
XMeterBegin ()
X{
XRect	r;
X
X	SetRect (&r, 80, 29, 420, 65);
X	meterWind = NewWindow (nil, &r, "\p", true, dBoxProc, -1L, false, 0L);
X	SkelWindow (meterWind, nil, nil, nil, nil, nil, MeterClobber, nil, false);
X	TextFont (0);
X	TextSize (0);
X	TextMode (srcCopy);
X	MakeFrontWind (meterWind);
X}
X
X
XMeterEnd ()
X{
X	SkelRmveWind (meterWind);
X}
X
X
X/* ---------------------------------------------------------------- */
X/*						Error Window Routines						*/
X/* ---------------------------------------------------------------- */
X
X
X/*
X	Initialize an error window.  This just clears the error count
X	and sets the name that will be given the window if an error
X	occurs.  The window doesn't actually appear unless the error
X	message routine is called.
X*/
X
XErrWindInit (fName)
XStringPtr	fName;
X{
X	errCount = 0;
X	CopyString (fName, errWindName);
X}
X
X
XErrWindMsge (thing, value)
XStringPtr	thing;
XInteger			value;
X{
X	if (errCount++ == 0)	/* first error */
X	{
X		DisplayWindow (errWindName, true);
X	}
X	DisplayString (thing);
X	DisplayInt (value);
X	DisplayLn ();
X}
X
X
X/* ---------------------------------------------------------------- */
X/*						Help Window Routine							*/
X/* ---------------------------------------------------------------- */
X
X
X/*
X	Create help window, unless it already exists - in which case 
X	simply pull it to the front.
X*/
X
X
XHelpWindow ()
X{
XRect			r;
Xregister Handle	h;
X
X	if (helpWind == nil)
X	{
X		SetRect (&r, 40, 50, 450, 280);
X		SetDWindowNotify (nil, DWindActivate);
X		helpWind = NewDWindow (&r, "\pInformation Window", false, -1L, true, 0L);
X	
X		h = GetResource ('TEXT', helpTextNum);	/* read help text */
X		HLock (h);							/* lock it and write to window */
X		DisplayText (*h, GetHandleSize (h));
X		HUnlock (h);
X		ReleaseResource (h);			/* done with it, so goodbye */
X		SetDWindowPos (helpWind, 0);	/* scroll back to top */
X		SetDWindow (nil);				/* no more output to this window */
X	}
X	MakeFrontWind (helpWind);
X}
SHAR_EOF
exit
--- end of part 3 ---