unit UMTextBuf; {Contributed by Edward J. Huff } {Copyright is hereby waived: UMTextBuf.p is in the public domain.} {Text Buffer Package. } {access to text windows (incomplete documentation):} {SelectTxW(TxWNum or TxWId)} {MakeTxWSelection(start,len), len may be zero for insertion point} {Copy when TxW is front window copies text} {Paste when TxW is front window pastes text} {nTxWs} {TxWNumber} {TxWIDNumber} {TxBIDNumber} {} {These macro commands add the concept of a text buffer (TxB) to Image.} {} {Basically, there is a place called the text buffer where you can put text limited} {in size only by available memory. Text is always added to the end of the buffer.} {You can delete text from the buffer using DeleteTxB.} {} {You can have more than one text buffer, identified by number, and} {selected by SelectTxB(n). There can be up to 100 text buffers.} {} {To take up to 255 characters from anywhere in the text buffer:} {} {str := FromTxB(start,len); length(str) will be <= len afterward.} {To get the first character, str := FromTxB(1,1);} {} {To add up to 255 characters of text to the end of the text buffer:} {} {AfterTxB(concat('string',3.1415:8:2));} {} {To paste the contents of the clipboard to the end of the text buffer:} {} {PasteAfterTxB; pastes nothing if clipboard is not text. Someday could paste } {images as a series of decimal numbers...} {} {To place the contents of a text file after the end of the text buffer:} {} {ReadAfterTxB('file name');} {} {To stop executing macros and immediately load new macros from} {the text buffer (and erase the contents of the text buffer):} {} {MacrosFromTxb;} {} {To copy characters from the text buffer to the clipboard:} {} {CopyFromTxB(start,len);} {CopyFromTxB(1,LengthTxB); copies the entire buffer} {} {To write the contents of the text buffer to a text file:} {} {WriteTxB('file name');} {} {To find the length of the current text buffer:} {} {len := LengthTxB;} {} {To find the id number of the current text buffer:} {} {idNum := TxBNumber;} {} {To find the largest existing text buffer number:} {} {idNum := nTxBs;} {} {To select a different text buffer:} {} {SelectTxb(idNum); creates all text buffers from nTxBs to idNum if needed.} {} {To delete characters from the current text buffer:} {} {DeleteTxB(start,len);} {DeleteTxB} {} {To copy part of another text buffer after the end of the current text buffer:} {} {CopyTxBToTxB(idNum, start,len);} {User Macro "TextBuf" package. } {Macros which use these extensions should specify "requiresUser('TextBuf',1)".} {These instructions apply if you have received only UMTextBuf.p and} {a copy of UMacroDef.p and UMacroRun.p, and want to install the code} {into your copy of NIH Image.} {You need the Think Pascal compiler to use this source code. } {Installation instructions. At the moment, the UMacroDef.p and UMacroRun.p} {have not been accepted for distribution with standard Image. If they are, then} {these instructions will apply. Otherwise, you will have to obtain a copy of image} {with UMacroDef.p etc. already installed. This will typically be available in} {the /pub/nih-image/contrib directory of zippy.nimh.nih.gov and the file} {name will include "UMX".} {If you have no other user macro extension packages installed,} {then just replace the default UMacroDef.p and UMacroRun.p with the enclosed} {versions. Otherwise, you must merge the changes, which should be found only} {at well marked places. Generally, this means simply adding lines, although you } {may also need to add a comma here and there. Changes should be found at} {one place in UMacroDef.p and seven places in UMacroRun.p.} {You will also have to use the "Project/Add File..." menu item to tell Think Pascal } {to compile this file, and use the "Windows/Image.proj" item to get the project window, } {and drag this file from the bottom of the list to somewhere between UMacroDef.p and } {UMacroRun.p.} {Finally, recompile and rebuild: Use "Run/Build" (command B) and } {"Project/Build Application...".} interface uses QuickDraw, Palettes, PrintTraps, Globals, Utilities, FIle2, Text, Edit, UMacroDef; procedure UMTextBufInit; procedure UMTextBufFinal; procedure UMTextBufAdd; procedure UMTextBufLookup (var uma: UserMacroArgs); procedure UMTextBufRun (var uma: UserMacroArgs); implementation type TxBArray = array[1..1] of Handle; TxBArrayPtr = ^TxBArray; TxBArrayHandle = ^TxBArrayPtr; {TxBidNumber value is kept in two bytes at front of text buffer} TxBHeader = record TxBidNum: integer; end; TxBHeaderPtr = ^TxBHeader; const hs = sizeof(TxBHeader); var nTxBs: Integer; TxBs: TxBArrayHandle; NextTxBidNum: Integer; TxBNumber: Integer; TxBidNumber: Integer; LengthTxB: LongInt; TheTxB: Handle; {Called from procedure InitUserMacros in UMacroRun.p, } {which is called from Image.p early in initialization.} {Do not start timers (see UMTimer.p) in this function.} procedure UMTextBufInit; begin TxBs := TxBArrayHandle(NewHandle(0)); TheTxB := nil; nTxBs := 0; TxBNumber := 0; TxBidNumber := 0; LengthTxB := 0; NextTxBidNum := -1; end; {Called from procedure FinalUserMacros in UMacroRun,p.} {This is guaranteed to run prior to any exit which happens after a call} {to DoUserMacro, and is intended for things which MUST be done prior } {to exit, like removing timers from the system timer list.} {Note well that it is NOT guaranteed to be called prior to any exit} {which might happen after InitUserMacros but before DoUserMacro.} procedure UMTextBufFinal; begin end; {AddUMSym calls:} {Add one call for each macro command, function, or string function} {you wish to add to the macro language.} {First argument is a string, case is ignored, truncated to SymbolSize characters.} {Second argument must be one of UserCommandT, UserFuncT, or UserStrFuncT} {Third argument is the UserCommandType item associated with the name.} {Called from procedure AddUserMacros in UMacroRun.p.} {This runs once each time macros are loaded from a file or a text window.} procedure UMTextBufAdd; begin AddUMSym('FromTxB', UserStrFuncT, FromTxBUC); AddUMSym('FromTxW', UserStrFuncT, FromTxWUC); AddUMSym('AfterTxB', UserCommandT, AfterTxBUC); AddUMSym('PasteAfterTxB', UserCommandT, PasteAfterTxBUC); AddUMSym('ReadAfterTxB', UserCommandT, ReadAfterTxBUC); AddUMSym('CopyFromTxB', UserCommandT, CopyFromTxBUC); AddUMSym('WriteTxB', UserCommandT, WriteTxBUC); AddUMSym('LengthTxB', UserFuncT, LengthTxBUC); AddUMSym('LengthTxW', UserFuncT, LengthTxWUC); AddUMSym('TxBNumber', UserFuncT, TxBNumberUC); AddUMSym('TxBidNumber', UserFuncT, TxBidNumberUC); AddUMSym('TxWNumber', UserFuncT, TxWNumberUC); AddUMSym('TxWidNumber', UserFuncT, TxWidNumberUC); AddUMSym('nTxBs', UserFuncT, nTxBsUC); AddUMSym('nTxWs', UserFuncT, nTxWsUC); AddUMSym('SelectTxB', UserCommandT, SelectTxBUC); AddUMSym('SelectTxW', UserCommandT, SelectTxWUC); AddUMSym('DeleteTxB', UserCommandT, DeleteTxBUC); AddUMSym('CopyTxBToTxB', UserCommandT, CopyTxBToTxBUC); AddUMSym('CopyTxWToTxB', UserCommandT, CopyTxWToTxBUC); AddUMSym('MakeTxWSelec', UserCommandT, MakeTxWSelecUC); AddUMSym('GetTxWSelect', UserCommandT, GetTxWSelectUC); AddUMSym('SearchTxW', UserFuncT, SearchTxWUC); AddUMSym('SearchTxB', UserFuncT, SearchTxBUC); AddUMSym('MacrosFromTxB', UserCommandT, MacrosFromTxBUC); AddUMSym('DisposeTxB', UserCommandT, DisposeTxBUC); AddUMSym('TxBExists', UserFuncT, TxBExistsUC); AddUMSym('TxWExists', UserFuncT, TxWExistsUC); AddUMSym('MakeNewTxB', UserCommandT, MakeNewTxBUC); end; {Called from procedure LookupUserMacro in UMMacroRun.p} {This runs every time the macro is executed, just prior to} {parsing the arguments.} procedure UMTextBufLookup (var uma: UserMacroArgs); begin with uma do case UserMacroCommand of FromTxBUC, FromTxWUC: begin nArgs := 2; arg[1].atype := UMATinteger; arg[2].atype := UMATinteger; end; AfterTxBUC: begin nArgs := 1; arg[1].atype := UMATstring; end; PasteAfterTxBUC: begin nArgs := 0; end; ReadAfterTxBUC: begin nArgs := 1; arg[1].atype := UMATstring; end; CopyFromTxBUC: begin nArgs := 2; arg[1].atype := UMATinteger; arg[2].atype := UMATinteger; end; WriteTxBUC: begin nArgs := 1; arg[1].atype := UMATstring; end; LengthTxBUC, LengthTxWUC: begin nArgs := 0; end; TxBNumberUC, TxBidNumberUC, TxWNumberUC, TxWidNumberUC: begin nArgs := 0; end; nTxBsUC, nTxWsUC: begin nArgs := 0; end; SelectTxBUC, SelectTxWUC: begin nArgs := 1; arg[1].atype := UMATinteger; end; DeleteTxBUC: begin nArgs := 2; arg[1].atype := UMATinteger; arg[2].atype := UMATinteger; end; CopyTxBToTxBUC: begin nArgs := 3; arg[1].atype := UMATinteger; arg[2].atype := UMATinteger; arg[3].atype := UMATinteger; end; CopyTxWToTxBUC: begin nArgs := 2; arg[1].atype := UMATinteger; arg[2].atype := UMATinteger; end; MakeTxWSelecUC: begin nArgs := 2; arg[1].atype := UMATinteger; arg[2].atype := UMATinteger; end; GetTxWSelectUC: begin nArgs := 2; arg[1].atype := UMATintvar; arg[2].atype := UMATintvar; end; SearchTxWUC, SearchTxBUC: begin nArgs := 3; arg[1].atype := UMATinteger; arg[2].atype := UMATinteger; arg[3].atype := UMATstring; end; MacrosFromTxBUC: begin nArgs := 0; end; DisposeTxBUC, MakeNewTxBUC: begin nArgs := 0; end; TxBExistsUC, TxWExistsUC: begin nArgs := 1; arg[1].atype := UMATinteger; end; otherwise begin ErrorOccurred := true; str := 'UMTextBuf.p LookupUserMacro'; end; end; end; {modified from Text.p} function UMOpenTextFile (name: str255): boolean; var err: OSErr; f: integer; TextFileSize: LongInt; RefNum: integer; begin UMOpenTextFile := false; RefNum := DefaultRefNum; if FreeMem < MinFree then begin PutMessage('Not enough memory to open this text file.'); exit(UMOpenTextFile); end; err := FSOpen(name, RefNum, f); if err <> noErr then begin err := fsclose(f);{actually should not need this} if not GetTextFile(name, RefNum) then begin exit(UMOpenTextFile); end;{put up dialog box} err := FSOpen(name, RefNum, f); end; err := GetEof(f, TextFileSize); if mySetHandleSize(TheTxB, hs + LengthTxB + TextFileSize) <> noErr then begin err := fsclose(f); PutMessage('Out of memory.'); exit(UMOpenTextFile); end; err := SetFPos(f, fsFromStart, 0); err := fsRead(f, TextFileSize, Ptr(Ord4(TheTxB^) + hs + LengthTxB)); if err <> noErr then begin SetHandleSize(TheTxB, hs + LengthTxB); err := fsclose(f); exit(UMOpenTextFile); end; LengthTxB := LengthTxB + TextFileSize; err := fsclose(f); UMOpenTextFile := true; end; {modified from File1.p and Text.p (SaveTextAs)} procedure UMSaveAsText (fname: str255); var err, f: integer; TheInfo: FInfo; ByteCount: LongInt; RefNum: integer; where: Point; reply: SFReply; begin if nSaves = 0 then RefNum := 0 else RefNum := DefaultRefNum; if RefNum = 0 then begin where.v := 60; where.h := 100; SFPutFile(where, 'Save Text as?', fname, nil, reply); if reply.good then begin fname := reply.fname; RefNum := reply.vRefNum; end else exit(UMSaveAsText); end; err := GetFInfo(fname, RefNum, TheInfo); case err of NoErr: if TheInfo.fdType <> 'TEXT' then begin TypeMismatch(fname); exit(UMSaveAsText) end; FNFerr: begin err := create(fname, RefNum, TextCreator, 'TEXT'); if CheckIO(err) <> 0 then exit(UMSaveAsText); end; otherwise if CheckIO(err) <> 0 then exit(UMSaveAsText) end; ShowWatch; err := fsopen(fname, RefNum, f); if CheckIO(err) <> 0 then exit(UMSaveAsText); ByteCount := LengthTxB; err := fswrite(f, ByteCount, Ptr(Ord4(TheTxB^) + hs)); if CheckIO(err) <> 0 then begin err := fsclose(f); {don't leave the file open just because of error} exit(UMSaveAsText); end; err := SetEof(f, ByteCount); err := fsclose(f); err := FlushVol(nil, RefNum); nSaves := nSaves + 1; end; procedure AdjustStartLen (var start, len: LongInt; bLen: LongInt); begin start := start - 1; {Pascal uses 1 relative strings so TxB strings are 1 relative} {but the package is coded using zero relative strings} if start < 0 then begin len := len + start; start := 0; end; if len < 0 then len := 0; if bLen < 0 then bLen := 0; if len > bLen then len := bLen; if start > bLen then start := bLen; if start + len > bLen then len := bLen - start; end; function TxBAbsent (var uma: UserMacroArgs): boolean; begin TxBAbsent := false; if TheTxB = nil then with uma do begin errorOccurred := true; TxBAbsent := true; str := 'No text buffers exist'; end; end; {TextInfo is not always set when FrontWindow changes. Probably it should be.} {Until that time, check FrontWindow before using TextInfo. } procedure SetTextInfo; var fwptr: WindowPtr; kind: integer; begin fwptr := FrontWindow; if fwptr = nil then exit(SetTextInfo); kind := WindowPeek(fwptr)^.WindowKind; if Kind = TextKind then TextInfo := TextInfoPtr(WindowPeek(fwptr)^.RefCon); end; function doSearch (var str: str255; fromPtr: Ptr; len: LongInt): LongInt; var c: char; sLen, tLen, oLen: Integer; cPtr, dPtr, sPtr, tPtr: pcp; begin MakeLowerCase(str); sLen := length(str); sPtr := pcp(ord4(@str) + 1); doSearch := 0; len := len - sLen + 1; oLen := len; cPtr := pcp(fromPtr); while oLen > 0 do begin dPtr := cPtr; tLen := sLen; tPtr := sPtr; while tLen > 0 do begin c := dPtr^.c; if (c >= 'A') then if (c <= 'Z') then c := chr(ord(c) + 32); if c <> tPtr^.c then leave; tLen := tLen - 1; dPtr := pcp(ord4(dPtr) + 1); tPtr := pcp(ord4(tPtr) + 1); end; if tLen = 0 then begin doSearch := len - oLen + 1; {return a 1 relative offset to start of match} leave; end; oLen := oLen - 1; cPtr := pcp(ord4(cPtr) + 1); end; end; {Called from procedure DoUserMacro in UMacroRun.p .} {Do not change uma.nArgs or uma.arg[i].argt here.} {This runs once each time the macro is used, after parsing the arguments.} procedure UMTextBufRun (var uma: UserMacroArgs); var start, len, i, n, bLen: LongInt; fromPtr, toPtr, strPtr: Ptr; begin with uma do case UserMacroCommand of FromTxBUC: begin if TxBAbsent(uma) then exit(UMTextBufRun); str := ''; start := arg[1].ival; len := arg[2].ival; AdjustStartLen(start, len, LengthTxB); if len > 255 then len := 255; if len > 0 then if start < LengthTxB then begin strPtr := @str; strPtr^ := len; fromPtr := Ptr(Ord4(TheTxB^) + hs + start); toPtr := Ptr(ord4(strPtr) + 1); BlockMove(fromPtr, toPtr, len); end; end; FromTxWUC: begin SetTextInfo; str := 'not done yet'; end; AfterTxBUC: begin if TxBAbsent(uma) then exit(UMTextBufRun); len := length(str); if len > 0 then begin if mySetHandleSize(TheTxB, hs + LengthTxB + len) <> noErr then begin errorOccurred := true; str := 'out of memory'; exit(UMTextBufRun); end; fromPtr := Ptr(ord4(@str) + 1); toPtr := Ptr(Ord4(TheTxB^) + hs + LengthTxB); BlockMove(fromPtr, toPtr, len); LengthTxB := LengthTxB + len; end; end; PasteAfterTxBUC: begin if TxBAbsent(uma) then exit(UMTextBufRun); if WhatsOnClip = NothingOnClip then ConvertSystemClipboard; if WhatsOnClip = textOnClip then begin len := TextBufSize; if len > 0 then begin if mySetHandleSize(TheTxB, hs + LengthTxB + len) <> noErr then begin errorOccurred := true; str := 'out of memory'; exit(UMTextBufRun); end; fromPtr := Ptr(TextBufP); toPtr := Ptr(Ord4(TheTxB^) + hs + LengthTxB); BlockMove(fromPtr, toPtr, len); LengthTxB := LengthTxB + len; end; end; end; ReadAfterTxBUC: begin if TxBAbsent(uma) then exit(UMTextBufRun); if not UMOpenTextFile(str) then begin errorOccurred := true; str := 'ReadAfterTxB failed'; end; end; CopyFromTxBUC: begin if TxBAbsent(uma) then exit(UMTextBufRun); start := arg[1].ival; len := arg[2].ival; AdjustStartLen(start, len, LengthTxB); WhatsOnClip := NothingOnClip; {It is on System Scrap} if ZeroScrap = noErr then if len > 0 then if PutScrap(len, 'TEXT', Ptr(Ord4(TheTxB^) + hs + start)) <> noErr then beep; end; WriteTxBUC: begin if TxBAbsent(uma) then exit(UMTextBufRun); UMSaveAsText(str); end; LengthTxBUC: FuncResult := LengthTxB; LengthTxWUC: begin SetTextInfo; FuncResult := 0; if TextInfo <> nil then with TextInfo^ do with TextTE^^ do FuncResult := TeLength; end; TxBNumberUC: FuncResult := TxBNumber; TxBidNumberUC: FuncResult := TxBidNumber; TxWNumberUC: begin SetTextInfo; FuncResult := 0; if TextInfo <> nil then with TextInfo^ do FuncResult := WindowNum; end; TxWidNumberUC: begin SetTextInfo; FuncResult := 0; if TextInfo <> nil then with TextInfo^ do FuncResult := TxWidNum; end; nTxBsUC: FuncResult := nTxBs; nTxWsUC: FuncResult := nTextWindows; SelectTxBUC: begin n := arg[1].ival; if n < 0 then begin {search for matching TxBidNum} for i := 1 to nTxBs do begin if n = TxBHeaderPtr(TxBs^^[i]^)^.TxBidNum then begin n := i; leave; end; end; end; if (n < 1) or (n > nTxBs) then begin errorOccurred := true; str := 'Specified TxB does not exist'; exit(UMTextBufRun); end; TxBNumber := n; TheTxB := TxBs^^[TxBNumber]; LengthTxB := getHandleSize(TheTxB) - hs; TxBidNumber := TxBHeaderPtr(TheTxB^)^.TxBidNum; end; SelectTxWUC: begin n := arg[1].ival; if n < 0 then begin {search for matching TxWidNum} for i := 1 to nTextWindows do begin if n = TextInfoPtr(WindowPeek(TextWindow[i])^.RefCon)^.TxWidNum then begin n := i; leave; end; end; end; if (n < 1) or (n > nTextWindows) then begin errorOccurred := true; str := 'Specified Text Window does not exist'; exit(UMTextBufRun); end; SelectWindow(TextWindow[n]); SetTextInfo; end; DeleteTxBUC: begin if TxBAbsent(uma) then exit(UMTextBufRun); start := arg[1].ival; len := arg[2].ival; AdjustStartLen(start, len, LengthTxB); if start < LengthTxB then begin if start + len >= LengthTxB then begin LengthTxB := start; end else begin toPtr := Ptr(Ord4(TheTxB^) + hs + start); fromPtr := Ptr(Ord4(TheTxB^) + hs + start + len); BlockMove(fromPtr, toPtr, LengthTxB - start - len); LengthTxB := LengthTxB - len; end; SetHandleSize(TheTxB, hs + LengthTxB); end; end; CopyTxBToTxBUC: begin if TxBAbsent(uma) then exit(UMTextBufRun); n := arg[1].ival; if n < 0 then begin {search for matching TxBidNum} for i := 1 to nTxBs do begin if n = TxBHeaderPtr(TxBs^^[i]^)^.TxBidNum then begin n := i; leave; end; end; end; if (n < 1) or (n > nTxBs) then begin errorOccurred := true; str := 'Specified TxB does not exist'; exit(UMTextBufRun); end; start := arg[2].ival; len := arg[3].ival; bLen := GetHandleSize(TxBs^^[n]) - hs; AdjustStartLen(start, len, bLen); if mySetHandleSize(TheTxB, hs + LengthTxB + len) <> noErr then begin errorOccurred := true; str := 'out of memory'; exit(UMTextBufRun); end; fromPtr := Ptr(Ord4(TxBs^^[n]^) + start); toPtr := Ptr(Ord4(TheTxB^) + hs + LengthTxB); BlockMove(fromPtr, toPtr, len); LengthTxB := LengthTxB + len; end; CopyTxWToTxBUC: begin if TxBAbsent(uma) then exit(UMTextBufRun); SetTextInfo; if TextInfo = nil then begin errorOccurred := true; str := 'No text window active'; exit(UMTextBufRun); end; start := arg[1].ival; len := arg[2].ival; bLen := TextInfo^.TextTE^^.TeLength; AdjustStartLen(start, len, bLen); if mySetHandleSize(TheTxB, hs + LengthTxB + len) <> noErr then begin errorOccurred := true; str := 'out of memory'; exit(UMTextBufRun); end; fromPtr := Ptr(Ord4(TextInfo^.TextTE^^.hText^) + start); toPtr := Ptr(Ord4(TheTxB^) + hs + LengthTxB); BlockMove(fromPtr, toPtr, len); LengthTxB := LengthTxB + len; end; MakeTxWSelecUC: begin SetTextInfo; if TextInfo = nil then begin errorOccurred := true; str := 'No text window active'; exit(UMTextBufRun); end; start := arg[1].ival; len := arg[2].ival; bLen := TextInfo^.TextTE^^.TeLength; AdjustStartLen(start, len, bLen); if start > 32767 then start := 32767; if len > 32767 then len := 32767; if start + len > 32767 then len := 32767 - start; TESetSelect(start, start + len, TextInfo^.TextTE); UpdateScrollBars; end; GetTxWSelectUC: begin SetTextInfo; if TextInfo = nil then begin errorOccurred := true; str := 'No text window active'; exit(UMTextBufRun); end; with TextInfo^.TextTE^^ do begin arg[1].ival := selStart + 1; arg[2].ival := selEnd - selStart; end; end; SearchTxWUC: begin SetTextInfo; if TextInfo = nil then begin errorOccurred := true; str := 'No text window active'; exit(UMTextBufRun); end; start := arg[1].ival; len := arg[2].ival; bLen := TextInfo^.TextTE^^.TeLength; AdjustStartLen(start, len, bLen); fromPtr := Ptr(Ord4(TextInfo^.TextTE^^.hText^) + start); funcResult := doSearch(str, fromPtr, len); if funcResult <> 0 then funcResult := funcResult + start; end; SearchTxBUC: begin if TxBAbsent(uma) then exit(UMTextBufRun); start := arg[1].ival; len := arg[2].ival; bLen := GetHandleSize(TheTxB) - hs; AdjustStartLen(start, len, bLen); fromPtr := Ptr(Ord4(TheTxB^) + hs + start); funcResult := doSearch(str, fromPtr, len); if funcResult <> 0 then funcResult := funcResult + start; end; MacrosFromTxBUC: begin if TxBAbsent(uma) then exit(UMTextBufRun); Token := DoneT; MacroLoadRequest := true; {overwrite the TxBidNumber value in first two bytes of buffer} toPtr := TheTxB^; toPtr^ := ord('{'); toPtr := Ptr(Ord4(toPtr) + 1); toPtr^ := ord('}'); MacroLoadHandle := TheTxB; nTxBs := nTxBs - 1; SetHandleSize(Handle(TxBs), nTxBs * sizeof(Handle)); for i := TxBNumber to nTxBs do begin TxBs^^[i] := TxBs^^[i + 1]; end; n := TxBNumber; if n > nTxBs then n := nTxBs; TxBNumber := n; if TxBNumber = 0 then begin TheTxB := nil; TxBidNumber := 0; LengthTxB := 0; end else begin TheTxB := TxBs^^[TxBNumber]; LengthTxB := getHandleSize(TheTxB) - hs; TxBidNumber := TxBHeaderPtr(TheTxB^)^.TxBidNum; end; end; DisposeTxBUC: begin if TxBAbsent(uma) then exit(UMTextBufRun); DisposeHandle(TheTxB); nTxBs := nTxBs - 1; SetHandleSize(Handle(TxBs), nTxBs * sizeof(Handle)); for i := TxBNumber to nTxBs do begin TxBs^^[i] := TxBs^^[i + 1]; end; n := TxBNumber; if n > nTxBs then n := nTxBs; TxBNumber := n; if TxBNumber = 0 then begin TheTxB := nil; TxBidNumber := 0; LengthTxB := 0; end else begin TheTxB := TxBs^^[TxBNumber]; LengthTxB := getHandleSize(TheTxB) - hs; TxBidNumber := TxBHeaderPtr(TheTxB^)^.TxBidNum; end; end; TxBExistsUC: begin n := arg[1].ival; if n < 0 then begin {search for matching TxBidNum} for i := 1 to nTxBs do begin if n = TxBHeaderPtr(TxBs^^[i]^)^.TxBidNum then begin n := i; leave; end; end; end; funcResult := ord((n > 0) and (n <= nTxBs)); end; TxWExistsUC: begin n := arg[1].ival; if n < 0 then begin {search for matching TxWidNum} for i := 1 to nTextWindows do begin if n = TextInfoPtr(WindowPeek(TextWindow[i])^.RefCon)^.TxWidNum then begin n := i; leave; end; end; end; funcResult := ord((n > 0) and (n <= nTextWindows)); end; MakeNewTxBUC: begin if mySetHandleSize(Handle(TxBs), (nTxBs + 1) * sizeof(Handle)) <> noErr then begin errorOccurred := true; str := 'out of memory'; exit(UMTextBufRun); end; TheTxB := NewHandle(hs); if TheTxB = nil then begin if TxBNumber <> 0 then TheTxB := TxBs^^[TxBNumber]; errorOccurred := true; str := 'out of memory'; exit(UMTextBufRun); end; nTxBs := nTxBs + 1; TxBs^^[nTxBs] := TheTxB; TxBNumber := nTxBs; TxBidNumber := NextTxBidNum; NextTxBidNum := NextTxBidNum - 1; TxBHeaderPtr(TheTxB^)^.TxBidNum := TxBidNumber; LengthTxB := getHandleSize(TheTxB) - hs; end; otherwise begin ErrorOccurred := true; str := 'UMTextBuf.p DoUserMacro'; end; end; end; end.