Article View: mod.mac.sources
Article #51MakeWrite Source (part 3 of 3)
From: macintosh
Date: Sun, 22 Mar 1987 07:00
Date: Sun, 22 Mar 1987 07:00
1947 lines
44377 bytes
44377 bytes
[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 ---
Technical Details
Message-ID:
<2458@felix.UUCP>Path:
arc1-ca.pugleaf.net!utzoo!utgpu!water!watnot!watmath!clyde!rutgers!sri-unix!hplabs!pyramid!oliveb!felix!macintoshReferences:
<2455@felix.UUCP> <2457@felix.UUCP>Show Full Headers
Complete Article Headers
Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: arc1-ca.pugleaf.net!utzoo!utgpu!water!watnot!watmath!clyde!rutgers!sri-unix!hplabs!pyramid!oliveb!felix!macintosh From: macintosh@felix.UUCP Newsgroups: mod.mac.sources Subject: MakeWrite Source (part 3 of 3) Message-ID: <2458@felix.UUCP> Date: Sun, 22-Mar-87 02:00:06 EST Article-I.D.: felix.2458 Posted: Sun Mar 22 02:00:06 1987 Date-Received: Mon, 23-Mar-87 01:58:34 EST References: <2455@felix.UUCP> <2457@felix.UUCP> Sender: root@felix.UUCP Reply-To: dubois@uwmacc.UUCP (Paul DuBois) Organization: UWisconsin-Madison Academic Comp Center Lines: 1947 Approved: bytebug@felix.UUCP (Roger L. Long)