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, ¶Style, (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, ¶Style, (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 ---