Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!utgpu!water!watnot!watmath!clyde!rutgers!lll-lcc!pyramid!oliveb!felix!macintosh From: macintosh@felix.UUCP Newsgroups: mod.mac.sources Subject: MakeWrite Source (part 1 of 3) Message-ID: <2455@felix.UUCP> Date: Sat, 21-Mar-87 02:31:24 EST Article-I.D.: felix.2455 Posted: Sat Mar 21 02:31:24 1987 Date-Received: Mon, 23-Mar-87 00:29:39 EST Sender: macintosh@felix.UUCP Reply-To: dubois@uwmacc.UUCP (Paul DuBois) Organization: UWisconsin-Madison Academic Comp Center Lines: 2162 Approved: bytebug@felix.UUCP (Roger L. Long) [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 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 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 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 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 X# include X# include 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 ---