Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: 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) [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 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 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 X# include X# include 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 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 ---