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 ---