-- Copyright (C) 1986 by Xerox Corporation. All rights reserved.
-- BWSCEnvUtil.mesa
-- DWR 17-Mar-86 20:27:30
-- NFS 27-May-86 13:16:03
-- MEW 8-May-86 8:57:46
-- Implementation of CEnvUtil for BWS.
DIRECTORY
Ascii,
Atom,
-- BucketAlloc,
-- BWSCEnvUtilExtra,
StartState,
BWSUtil,
CEnvUtil,
Containee,
Context,
CRuntime,
CString,
CWindowLib,
Display,
Emulator,
Format,
FormWindow,
Inline,
MLoader,
MessageWindow,
MFile,
MFileOnNSFile,
MStream,
NSFile,
NSString,
OptionFile,
Pipe,
Process,
Prototype,
Runtime,
Selection,
SimpleTextFont,
StarWindowShell,
Stream,
String,
Time,
TIP,
TTY,
TTYConstants,
UserTerminal,
Window,
XChar,
XString,
XToken;
BWSCEnvUtil: MONITOR
IMPORTS
Atom, --BucketAlloc, --BWSUtil, CEnvUtil, Containee, Context, CRuntime, CString,
Display, Emulator, Format, FormWindow,
Inline, MessageWindow, MFile, MFileOnNSFile, MStream, NSFile, NSString,
OptionFile, Pipe, Process, Prototype, Runtime, Selection,
SimpleTextFont, StartState, StarWindowShell,
Stream, String, Time, TIP,
TTY, UserTerminal, XChar, XString, XToken
EXPORTS CEnvUtil --, BWSCEnvUtilExtra -- SHARES XString = {
OPEN CEnvUtil;
Data:PUBLIC TYPE = --MACHINE DEPENDENT-- RECORD [
-- stdin(0): LONG STRING ← zone.NEW[StringBody[100]],
-- stdout(2): LONG STRING ← zone.NEW[StringBody[100]],
-- stderr(4): LONG STRING ← zone.NEW[StringBody[100]],
debug--(6)--:BOOLEAN ← FALSE,
stopOnError--(7)--:BOOLEAN ← TRUE,
endingToolInstance--(8)--:BOOLEAN ← FALSE,
busy: BOOLEAN ← FALSE, -- for icon dropping in BWS
iomode: INTEGER ← 0,
cToolPart--(9)--:SELECT tool--(9)--:ToolType FROM
ctool => [
msgSW--(10)--: Window.Handle ← NIL,
formSW--(12)--: Window.Handle ← NIL,
ttySW--(14)--: Window.Handle ← NIL,
p--(16)--:PROCESS,
emuPart--(17)--:SELECT tty--(17)--:* FROM
emulation => [
pH--(18)--:Pipe.Handle,
toBuffer--(20)--,ttyStream--(22)--:Stream.Handle,
modeVal--(24)--:LONG CARDINAL ← 0,
mode--(26)--:Stream.SubSequenceType ← TTYConstants.normal ],
regular =>[logStream--(18)--:Stream.Handle ← NIL],
ENDCASE],
cexec => [],
temp => [],
ENDCASE];
Handle:TYPE = LONG POINTER TO Data;
CTHandle:TYPE = LONG POINTER TO ctool Data;
RCTHandle:TYPE = LONG POINTER TO regular ctool Data;
ECTHandle:TYPE = LONG POINTER TO emulation ctool Data;
FileHandle: PUBLIC TYPE = MFile.Handle;
LoadHandle: PUBLIC TYPE = MLoader.Handle;
FileError: PUBLIC ERROR[message:LONG STRING] = CODE;
AcquireFile: PUBLIC PROCEDURE [name: LONG STRING] RETURNS[fh: FileHandle ← NIL] = {
fh ← MFile.Acquire[name:name,access:readOnly,release:[]
!MFile.Error => {
msg:LONG STRING ← [100];
MFile.AppendErrorMessage[msg,code,file];
ERROR FileError[msg];}];
};
ReleaseFile: PUBLIC PROCEDURE [fh: FileHandle] = {
MFile.Release[fh !MFile.Error => CONTINUE];
};
-- check for file, file.archivebcd, file.bcd, file*.archivebcd, file*.bcd
RemoveExtension: PROCEDURE [s: LONG STRING, ext: LONG STRING] = {
IF ext = NIL THEN RETURN;
s.length ← s.length - ext.length };
UniqueFilePrefix: PUBLIC PROCEDURE [fileName: LONG STRING]
RETURNS [matches: CARDINAL] = {
-- complete the fileName and return whether it was unique
-- assume fileName is long enough to be appended to
-- FIX THIS TO USE MFILE ONLY !!!!!!!
scope: NSFile.Scope ← [];
selections: NSFile.Selections ← [interpreted: [name: TRUE]];
Check: PROCEDURE [ext: LONG STRING]
RETURNS [BOOLEAN] = {
matchedName: LONG STRING ← [50];
oldLength: CARDINAL = fileName.length;
List: NSFile.AttributesProc = {
matchedName.length ← 0;
NSString.AppendToMesaString[matchedName, attributes.name];
RETURN[(matches ← matches + 1) = 1] };
EachDirectory: MFileOnNSFile.EachElementProc = {
dfh: NSFile.Handle ← NSFile.OpenByReference [element];
NSFile.List[dfh, List, selections, scope !
NSFile.Error => GOTO FileError];
NSFile.Close[dfh];
IF matches = 1 THEN { -- found a unique name
fileName.length ← 0;
String.AppendString[to: fileName, from: matchedName];
};
RETURN [matches # 0]; -- TRUE if we have a match or an ambiguous name
EXITS FileError => { -- stop enumeration and indicate not found.
matches ← 0;
RETURN [TRUE];};
};
IF ext # NIL THEN String.AppendString[fileName, ext];
scope.filter ← [matches[[name[NSString.StringFromMesaString[fileName]]]]];
MFileOnNSFile.EnumeratePath [EachDirectory];
IF matches # 1 THEN fileName.length ← oldLength; -- undo append;
RETURN [matches # 0] }; -- TRUE if we have a match or an ambiguous name
matches ← 0;
IF Check[NIL] OR
Check[".archivebcd"L] OR
Check[".bcd"L] OR
Check["*.archivebcd"L] OR
Check["*.bcd"L] THEN NULL;
};
GetStdStreams: PUBLIC PROCEDURE [
data: Handle, defaultStdin, defaultStdout, defaultStderr: Stream.Handle]
RETURNS [stdin, stdout, stderr: Stream.Handle] = {
h: ECTHandle = LOOPHOLE[data];
rb, rb1: XString.ReaderBody;
-- The following is a hack until we figure out what to do.
-- We don't have the stdin,... fields in a data object, so
-- we can't get the stream names from there. And when this
-- is the temp variant, there's no form subwindow to use.
WITH data SELECT FROM
temp => RETURN[defaultStdin, defaultStdout, defaultStderr]
ENDCASE;
rb ← FormWindow.LookAtTextItemValue[h.formSW, FormItems.stdin.ORD];
IF XString.Empty[@rb] THEN {
stdin ← defaultStdin;
FormWindow.DoneLookingAtTextItemValue[h.formSW, FormItems.stdin.ORD];
} ELSE {
stdin ← BWSUtil.MakeStreamReader[file: @rb, access: readOnly];
FormWindow.DoneLookingAtTextItemValue[h.formSW, FormItems.stdin.ORD];
IF stdin = NIL THEN StdStreamError[stdin];
};
rb ← FormWindow.LookAtTextItemValue[h.formSW, FormItems.stdout.ORD];
IF XString.Empty[@rb] THEN {
stdout ← defaultStdout;
} ELSE {
stdout ← BWSUtil.MakeStreamReader[file: @rb, access: writeOnly];
IF stdout = NIL THEN {
Stream.Delete[stdin];
FormWindow.DoneLookingAtTextItemValue[h.formSW, FormItems.stdout.ORD];
ERROR StdStreamError[stdout];
};
};
rb1 ← FormWindow.LookAtTextItemValue[h.formSW, FormItems.stderr.ORD];
SELECT TRUE FROM
XString.Empty[@rb1] => stderr ← defaultStderr;
XString.Equivalent[@rb, @rb1] => stderr ← stdout;
ENDCASE => {
stderr ← BWSUtil.MakeStreamReader[file: @rb1, access: writeOnly];
IF stderr = NIL THEN {
Stream.Delete[stdin];
Stream.Delete[stdout];
FormWindow.DoneLookingAtTextItemValue[h.formSW, FormItems.stdout.ORD];
FormWindow.DoneLookingAtTextItemValue[h.formSW, FormItems.stderr.ORD];
ERROR StdStreamError[stderr];
};
};
FormWindow.DoneLookingAtTextItemValue[h.formSW, FormItems.stdout.ORD];
FormWindow.DoneLookingAtTextItemValue[h.formSW, FormItems.stderr.ORD];
};
StdStreamError: PUBLIC ERROR [whichStream: StandardStream] = CODE;
GetFileInputStream: PUBLIC PROCEDURE [buffer: LONG STRING]
RETURNS[sH: Stream.Handle ← NIL] = {
fileName: XString.ReaderBody;
rb: XString.ReaderBody ← XString.FromSTRING[buffer, TRUE];
tH: XToken.Handle ← XToken.ReaderToHandle[@rb];
XToken.Skip[tH, NIL, XToken.WhiteSpace, TRUE];
fileName ← XToken.Item[tH];
IF ~XString.Empty[@fileName] THEN {
sH ← BWSUtil.MakeStreamReader[file: @fileName, access: readOnly];
IF sH = NIL THEN { -- Try adding ".cscript" extension.
ext: XString.ReaderBody ← XString.FromSTRING[".cscript"L, TRUE];
extendedName: XString.WriterBody ← XString.NewWriterBody[
maxLength: XString.ByteLength[@fileName] + XString.ByteLength[@ext],
z: zone];
XString.AppendReader[@extendedName, @fileName];
IF XString.AppendExtensionIfNeeded[
to: @extendedName, extension: @ext] THEN
sH ← BWSUtil.MakeStreamReader[
file: XString.ReaderFromWriter[@extendedName],
access: readOnly];
XString.FreeWriterBytes[@extendedName];
};
};
[] ← XToken.FreeTokenString[@fileName];
[] ← XToken.FreeReaderHandle[tH];
};
AppendLine: PUBLIC PROCEDURE [
line: LONG POINTER TO LONG STRING, getChar: PROC RETURNS [c: CHAR]] = {
DO
c: CHAR ← getChar[! MFile.Error, MStream.Error, Stream.EndOfStream => EXIT];
String.AppendCharAndGrow[to: line, c: c, z: zone];
IF c = Ascii.CR THEN EXIT;
ENDLOOP;
};
contextType: Context.Type;
ToolList: TYPE = LONG POINTER TO ToolInstance;
ToolInstance: TYPE = RECORD [
ref: NSFile.Reference,
file: NSFile.Handle,
bw: Window.Handle,
sws: StarWindowShell.Handle,
next: ToolList
];
tools: ToolList ← NIL;
OpenCTool: ENTRY PROCEDURE [data: Containee.DataHandle]
RETURNS [sws: StarWindowShell.Handle, bw: Window.Handle] = {
tool: ToolList ← FindRunningToolFromIcon[data];
IF tool # NIL AND tool.sws # NIL THEN RETURN [tool.sws, tool.bw];
BEGIN
name: LONG STRING ← [60];
xname: XString.ReaderBody;
String.AppendString[name, "CTool of "L];
Time.Append[name, Time.Unpack[Runtime.GetBcdTime[]]];
xname ← XString.FromSTRING[name, TRUE];
sws ← StarWindowShell.Create[name: @xname, transitionProc: ClientTransition, sleeps: TRUE];
StarWindowShell.SetIsCloseLegalProc[sws, IsCloseLegal];
StarWindowShell.SetPreferredDims[sws, [h: windowDims.h, w: windowDims.w + 15]];
IF tool = NIL THEN {
bw ← MakeSWs[sws];
AddRunningTool[data, sws, bw];
} ELSE {
StarWindowShell.InstallBody[sws, tool.bw];
tool.sws ← sws;
bw ← tool.bw;
};
END;
};
IsCloseLegal: ENTRY StarWindowShell.IsCloseLegalProc = {
tool: ToolList = FindRunningToolFromSWS[sws];
IF tool = NIL THEN RETURN [TRUE];
StarWindowShell.DestallBody[tool.bw];
tool.sws ← [NIL];
RETURN [TRUE];
};
FindRunningToolFromIcon: INTERNAL PROCEDURE [data: Containee.DataHandle]
RETURNS [t: ToolList] = {
FOR t ← tools, t.next UNTIL t = NIL DO
IF t.ref = data.reference THEN RETURN [t];
ENDLOOP;
RETURN [NIL];
};
FindRunningToolFromSWS: INTERNAL PROCEDURE [sws: StarWindowShell.Handle]
RETURNS [t: ToolList] = {
FOR t ← tools, t.next UNTIL t = NIL DO
IF t.sws = sws THEN RETURN [t];
ENDLOOP;
RETURN [NIL];
};
FindSWSFromBW: ENTRY PROCEDURE [bw: Window.Handle]
RETURNS [sws: StarWindowShell.Handle] = {
FOR t: ToolList ← tools, t.next UNTIL t = NIL DO
IF t.bw = bw THEN RETURN [t.sws];
ENDLOOP;
RETURN [[NIL]];
};
AddRunningTool: INTERNAL PROCEDURE [data: Containee.DataHandle,
sws: StarWindowShell.Handle, bw: Window.Handle] = {
tools ← zone.NEW[ToolInstance ← [
ref: data.reference,
bw: bw,
sws: sws,
file: NSFile.OpenByReference[data.reference], -- so icon won't be deleted
next: tools]];
};
DeleteRunningTool: PROCEDURE [bw: Window.Handle] = {
t: ToolList;
sws: StarWindowShell.Handle;
DeleteInstance: ENTRY PROC = {
prev: LONG POINTER TO ToolList ← @tools;
FOR t ← prev↑, prev↑ UNTIL t = NIL DO
IF t.bw = bw THEN {
prev↑ ← t.next;
NSFile.Close[t.file];
zone.FREE[@t];
RETURN;
};
prev ← @t.next;
ENDLOOP;
};
sws ← FindSWSFromBW[bw];
IF sws # NIL THEN
[] ← StarWindowShell.Pop[sws];
DeleteInstance[];
DestroyCToolInstance[bw];
};
DestroyInstance: FormWindow.CommandProc = {
h: CTHandle;
bw: Window.Handle;
[h, bw] ← LocalFind[window];
IF h = NIL THEN RETURN;
IF h.busy THEN {
rb: XString.ReaderBody ←
XString.FromSTRING["CTool is busy. Hit STOP to abort current program."L];
MessageWindow.Post[h.msgSW, @rb, TRUE];
} ELSE {
DeleteRunningTool[bw];
};
};
MakeSWs: INTERNAL PROCEDURE [sws: StarWindowShell.Handle]
RETURNS [bw: Window.Handle] = {
h: ECTHandle ← zone.NEW[emulation ctool Data];
tH: TTY.Handle;
bw ← StarWindowShell.CreateBody[
sws: sws,
box: [place: [x: 0, y: 0], dims: windowDims]];
FormWindow.Create[
window: bw,
makeItemsProc: MakeItems,
layoutProc: DoLayout,
clientData: h];
Context.Create[contextType, h, FreeToolData, bw];
[h:h.pH,producer:h.toBuffer, consumer:h.ttyStream] ← Pipe.Create[200];
h.ttyStream.put ← WriteToWindow;
h.ttyStream.putByte ← Stream.defaultObject.putByte;
-- Pipe.Create set putByte to a proc. that raises Stream.InvalidOperation.
h.ttyStream.setSST ← SetSST;
h.ttyStream.clientData ← h;
tH ← TTY.Create[name:NIL,backingStream:NIL,ttyImpl:h.ttyStream];
TIP.SetAttention[h.ttySW, AbortProgram];
h.p ← FORK ReadAndRunThenCleanUp[h,tH];
};
WriteToWindow:Stream.PutProcedure = {
h:ECTHandle = sH.clientData;
crMode: BOOLEAN ← Inline.BITAND[h.iomode, CWindowLib.crMode] #0;
SELECT h.mode FROM
TTYConstants.normal => {
start: CARDINAL ← block.startIndex;
stop: CARDINAL ← block.stopIndexPlusOne;
IF crMode THEN Emulator.PutBlock[h.ttySW, [block.blockPointer, start, stop]]
ELSE FOR i:CARDINAL IN [block.startIndex..block.stopIndexPlusOne) DO
IF block.blockPointer[i] # Ascii.CR.ORD THEN LOOP;
stop ← i + 1;
Emulator.PutBlock[h.ttySW, [block.blockPointer, start, stop]];
start ← stop;
Emulator.PutChar[h.ttySW,Ascii.LF];
REPEAT FINISHED => IF block.stopIndexPlusOne > start THEN
Emulator.PutBlock[
h.ttySW, [block.blockPointer, start, block.stopIndexPlusOne]];
ENDLOOP;
};
TTYConstants.setBackingSize, TTYConstants.removeChars => {
FOR i: CARDINAL IN [block.startIndex..block.stopIndexPlusOne) DO
h.modeVal ← h.modeVal*256 + block.blockPointer[i];
ENDLOOP;
};
ENDCASE;
};
SetSST:Stream.SetSSTProcedure = {
h:ECTHandle = sH.clientData;
s: LONG STRING ← [3];
s[0] ← s[2] ← Ascii.BS;
s[1] ← Ascii.SP;
s.length ← 3;
SELECT h.mode FROM
TTYConstants.removeChars =>
FOR i: CARDINAL IN [0..Inline.LowHalf[h.modeVal]) DO
Emulator.PutSTRING[h.ttySW,s];
ENDLOOP;
TTYConstants.setBackingSize => {};
TTYConstants.blinkDisplay => UserTerminal.BlinkDisplay[];
ENDCASE;
h.mode ← sst;
h.modeVal ← 0;
};
ReadAndRunThenCleanUp:PROCEDURE[h:ECTHandle,tH:TTY.Handle] = {
AppendCmd:AppendCmdProc = {RETURN[CallGetEditedString[tH,buffer]];};
[] ← ReadAndRun[h,tH,AppendCmd];
TTY.Destroy[tH,TRUE];
Pipe.Delete[h.pH];
Emulator.Destroy[h.ttySW];
};
FormItems: TYPE = {msg, form, tty, --another,-- destroy, debug, stopOnError, stdin, stdout, stderr};
margin: INTEGER = 2;
windowDims: Window.Dims = [w: 630, h: 500];
msgWindowDims: Window.Dims = [w: windowDims.w - 2*margin, h: 20];
msgWindowBox: Window.Box = [
place: [
x: margin,
y: margin],
dims: msgWindowDims];
formWindowDims: Window.Dims = [w: windowDims.w - 2*margin, h: 46];
formWindowBox: Window.Box = [
place: [
x: margin,
y: msgWindowBox.place.y + msgWindowBox.dims.h + 2*margin],
dims: formWindowDims];
ttyWindowDims: Window.Dims = [w: windowDims.w - 2*margin, h: 300];
ttyWindowBox: Window.Box = [
place: [
x: margin,
y: formWindowBox.place.y + formWindowBox.dims.h + 2*margin],
dims: ttyWindowDims];
MakeItems: FormWindow.MakeItemsProc = {
h: ECTHandle = clientData;
h.msgSW ← FormWindow.MakeWindowItem[
window: window,
myKey: FormItems.msg.ORD,
size: msgWindowDims];
MessageWindow.Create[window: h.msgSW, lines: 1];
h.formSW ← FormWindow.MakeWindowItem [ -- the formSW is inside a FormWindow window item
window: window,
myKey: FormItems.form.ORD,
size: formWindowDims];
FormWindow.Create[
window: h.formSW,
makeItemsProc: MakeFormItems,
layoutProc: DoFormLayout,
clientData: h];
h.ttySW ← FormWindow.MakeWindowItem [
window: window,
myKey: FormItems.tty.ORD,
size: ttyWindowDims];
Emulator.Create[
sw: h.ttySW, data:Emulator.table[vt100],
typeIn:WriteToBuffer, otherData: Emulator.table[xvt52], refresh: never,
logfile:NIL ,writeToLog:FALSE];
Emulator.SetRefresh[h.ttySW, always];
};
WriteToBuffer:Emulator.TypeInProcType = {
h: ECTHandle = LOOPHOLE[LocalFind[sw].h];
IF h = NIL THEN RETURN;
Stream.PutBlock[h.toBuffer,input];
};
FormTags: TYPE = ARRAY FormItems[destroy..stderr] OF XString.ReaderBody;
MakeFormItems: FormWindow.MakeItemsProc = {
h: ECTHandle = clientData;
tags: FormTags ← [
XString.FromSTRING["Destroy"L, TRUE],
XString.FromSTRING["Debug"L, TRUE],
XString.FromSTRING["StopScriptOnError"L, TRUE],
XString.FromSTRING["stdin"L, TRUE],
XString.FromSTRING["stdout"L, TRUE],
XString.FromSTRING["stderr"L, TRUE]];
FormWindow.MakeCommandItem[
window: window,
myKey: FormItems.destroy.ORD,
commandProc: DestroyInstance,
commandName: @tags[destroy]];
FormWindow.MakeBooleanItem[
window: window,
myKey: FormItems.debug.ORD,
changeProc: BooleanChange,
label: [string[tags[debug]]],
initBoolean: h.debug];
FormWindow.MakeBooleanItem[
window: window,
myKey: FormItems.stopOnError.ORD,
changeProc: BooleanChange,
label: [string[tags[stopOnError]]],
initBoolean: h.stopOnError];
FormWindow.MakeTextItem[
window: window,
myKey: FormItems.stdin.ORD,
width: 130,
tag: @tags[stdin]];
FormWindow.MakeTextItem[
window: window,
myKey: FormItems.stdout.ORD,
width: 130,
tag: @tags[stdout]];
FormWindow.MakeTextItem[
window: window,
myKey: FormItems.stderr.ORD,
width: 130,
tag: @tags[stderr]];
};
LocalFind: ENTRY PROC [window: Window.Handle]
RETURNS [h: CTHandle, bw: Window.Handle] = {
sws: StarWindowShell.Handle = StarWindowShell.ShellFromChild[window];
tool: ToolList = FindRunningToolFromSWS[sws];
IF tool = NIL THEN RETURN [NIL, NIL];
bw ← tool.bw;
h ← Context.Find[contextType, bw];
};
BooleanChange: FormWindow.BooleanChangeProc = {
h: CTHandle = LocalFind[window].h;
IF h = NIL THEN RETURN;
SELECT item FROM
FormItems.debug.ORD => h.debug ← newValue;
FormItems.stopOnError.ORD => h.stopOnError ← newValue;
ENDCASE;
};
DoFormLayout: FormWindow.LayoutProc = {
line: FormWindow.Line;
line ← FormWindow.AppendLine[window, margin];
-- FormWindow.AppendItem[window, FormItems.another.ORD, line, 20];
FormWindow.AppendItem[window, FormItems.destroy.ORD, line, 50];
FormWindow.AppendItem[window, FormItems.debug.ORD, line, 50];
FormWindow.AppendItem[window, FormItems.stopOnError.ORD, line, 50];
line ← FormWindow.AppendLine[window, margin];
FormWindow.AppendItem[window, FormItems.stdin.ORD, line, 10];
FormWindow.AppendItem[window, FormItems.stdout.ORD, line, 10];
FormWindow.AppendItem[window, FormItems.stderr.ORD, line, 10];
};
DoLayout: FormWindow.LayoutProc = { -- for three windows
FormWindow.SetItemBox[window, FormItems.msg.ORD, msgWindowBox];
FormWindow.SetItemBox[window, FormItems.form.ORD, formWindowBox];
FormWindow.SetItemBox[window, FormItems.tty.ORD, ttyWindowBox];
};
CallReadAndRun: PROCEDURE [h:CTHandle, tH:TTY.Handle] = {
AppendCmd:AppendCmdProc = {
h.busy ← FALSE;
Process.SetPriority[Process.priorityForeground];
lineDeleted ← CallGetEditedString[tH, buffer];
Process.SetPriority[Process.priorityBackground];
h.busy ← TRUE;
};
[] ← ReadAndRun[h,tH,AppendCmd];
};
AbortProgram: TIP.AttentionProc = {
h: CTHandle = LocalFind[window].h;
IF h = NIL THEN RETURN;
CRuntime.NoteAbortedProcess[h.p];
};
FreeToolData: PROCEDURE[d: Context.Data, bw: Window.Handle] = {
h: CTHandle ← LOOPHOLE[d];
-- TTYStringWindow.Destroy[h.ttySW];
-- FormWindow.Destroy[h.formSW]; ++ maybe these are done by BWS
-- MessageWindow.Destroy[h.msgSW];
zone.FREE[@h];
};
FreeData:PUBLIC PROCEDURE[h: Handle] = {};
ClientTransition: StarWindowShell.TransitionProc = {};
DestroyCToolInstance: PROCEDURE [bw: Window.Handle] = {
h: CTHandle ← Context.Find[contextType, bw];
h.endingToolInstance ← TRUE;
Process.Abort[h.p];
JOIN h.p;
Context.Destroy[contextType, bw];
};
CallGetEditedString: PROCEDURE[
tH: TTY.Handle, buffer: LONG POINTER TO LONG STRING]
RETURNS[lineDeleted: BOOLEAN ← FALSE] = {
CommandLineRead: PROCEDURE [c: CHAR] RETURNS [status: TTY.CharStatus] = {
IF c = '\N THEN {
TTY.PutChar[tH,c];
RETURN[stop];}
ELSE RETURN[ok];
};
[] ← TTY.GetEditedString[h:tH,s:buffer↑,t:CommandLineRead
!TTY.LineOverflow => {
ns ← String.CopyToNewString[s:s,z:zone,longer:s.maxlength / 2];
String.FreeString[z:zone, s:s];
buffer↑ ← ns;
RESUME[ns];};
TTY.Rubout => {
TTY.PutString[tH," XXX"L];
lineDeleted ← TRUE;
CONTINUE;}];
};
RegisterItems: PUBLIC PROCEDURE = {};
GetPrompt: PUBLIC PROCEDURE RETURNS [prompt: LONG STRING ← NIL] = {
section, entry: XString.ReaderBody;
CallBack: PROC [value: XString.Reader] = {
ss: String.SubStringDescriptor;
prompt ← zone.NEW[StringBody[XString.ByteLength[value]+1]];
prompt.length ← 0;
String.AppendChar[s: prompt, c: Ascii.CR];
ss ← BWSUtil.SubStringFromXString[value];
String.AppendSubString[prompt, @ss];
};
section ← XString.FromSTRING["CTool"L, TRUE];
entry ← XString.FromSTRING["Prompt"L, TRUE];
OptionFile.GetStringValue[@section, @entry, CallBack ! OptionFile.Error => CONTINUE];
IF prompt = NIL THEN {
prompt ← zone.NEW[StringBody[5]];
prompt.length ← 0;
String.AppendString[to:prompt, from:"\N>>> "L];
};
};
Unload: PUBLIC PROCEDURE [cmdLine: LONG STRING, tty: TTY.Handle]
RETURNS[outcome: Outcome ← normal] = {
rb: XString.ReaderBody ← XString.FromSTRING[cmdLine];
th: XToken.Handle ← NIL;
item: XString.ReaderBody ← XString.nullReaderBody;
sd: String.SubStringDescriptor;
-- fileName:LONG STRING ← zone.NEW[StringBody[100]];
{ENABLE UNWIND => {
IF item # XString.nullReaderBody THEN [] ← XToken.FreeTokenString[@item];
IF th # NIL THEN [] ← XToken.FreeReaderHandle[th];};
th ← XToken.ReaderToHandle[@rb];
item ← XToken.Item[th]; -- Get past "Unload.~"
[] ← XToken.FreeTokenString[@item];
DO
item ← XToken.Item[th];
IF item = XString.nullReaderBody THEN EXIT;
TTY.PutString[tty,"\NUnloading "L];
sd ← BWSUtil.SubStringFromXString[@item];
BEGIN
lh: MLoader.Handle ←LOOPHOLE[
XString.ReaderToNumber[r: @item, radix: 8, signed: FALSE
! XString.InvalidNumber => GOTO mustBeAFile], LONG POINTER];
TTY.PutSubString[tty, @sd];
TTY.PutString[tty,"..."L];
StartState.Unload[lh ! StartState.UnloadError => {
outcome ← error;
Blink[];
TTY.PutString[tty, message];
GOTO done}];
TTY.PutString[tty,"done."L];
EXITS
done => NULL;
mustBeAFile => {
name: LONG STRING ← [50];
fh: MFile.Handle;
found: CARDINAL;
instancesUnloaded:CARDINAL;
String.AppendSubString[name, @sd];
found ← UniqueFilePrefix[name];
IF found # 1 THEN {
TTY.PutSubString[tty, @sd];
TTY.PutString[
tty,IF found = 0 THEN ": not found"L ELSE ": ambiguous"L];
GOTO done;
};
TTY.PutString[tty, name];
TTY.PutString[tty,"..."L];
fh ← MFile.Acquire[name, anchor, [] !MFile.Error => {
TTY.PutString[tty, "Could not aquire file.\n"L];
outcome ← error;
GOTO done;
}];
instancesUnloaded ← StartState.UnloadFromFile[fh ! StartState.UnloadError => {
outcome ← error;
Blink[];
TTY.PutString[tty, message];
instancesUnloaded ← instancesAlreadyUnloaded;
MFile.Release[fh];
GOTO done;}];
MFile.Release[fh];
TTY.PutCR[tty];
TTY.PutNumber[tty, instancesUnloaded, []];
TTY.PutString[tty," instance"L];
IF instancesUnloaded # 1 THEN
TTY.PutChar[tty, 's];
TTY.PutString[tty, " unloaded."L];
EXITS
done => NULL;
};
END;
[] ← XToken.FreeTokenString[@item];
ENDLOOP;
[] ← XToken.FreeTokenString[@item];
th ← XToken.FreeReaderHandle[th];
};
};
ShowHandles:PUBLIC PROCEDURE[cmdLine:LONG STRING,tty:TTY.Handle]
RETURNS[outcome:Outcome ← normal] = {
PrintLoadHandle:StartState.EnumerateProc = {
Write:Format.StringProc = {TTY.PutString[tty,s];};
Format.LongOctal[Write,mh];
TTY.PutChar[tty,' ];
};
rb:XString.ReaderBody ← XString.FromSTRING[cmdLine];
th:XToken.Handle ← NIL;
item:XString.ReaderBody ← XString.nullReaderBody;
{ENABLE UNWIND => {
IF item # XString.nullReaderBody THEN [] ← XToken.FreeTokenString[@item];
IF th # NIL THEN [] ← XToken.FreeReaderHandle[th];};
th ← XToken.ReaderToHandle[@rb];
item ← XToken.Item[th]; -- Get past "ShowHandles.~"
[] ← XToken.FreeTokenString[@item];
DO
file:MFile.Handle;
found: CARDINAL;
name:LONG STRING ← zone.NEW[StringBody[100]];
sd: String.SubStringDescriptor;
item ← XToken.Item[th];
IF item = XString.nullReaderBody THEN EXIT;
sd ← BWSUtil.SubStringFromXString[@item];
String.AppendSubString[name, @sd];
found ← UniqueFilePrefix[name];
IF found # 1 THEN {
TTY.PutSubString[tty, @sd];
TTY.PutString[tty, IF found = 0 THEN ": not found"L ELSE ": ambiguous"L];
GOTO error;
};
TTY.PutChar[tty,'\N];
TTY.PutString[tty,name];
TTY.PutString[tty,": "L];
file ← MFile.Acquire[name, anchor, []! MFile.Error => {
TTY.PutString[tty, "Unable to acquire file."L];
zone.FREE[@name];
outcome ← error;
GOTO Done;
}];
StartState.EnumerateHandles[file,PrintLoadHandle];
MFile.Release[file];
zone.FREE[@name];
[] ← XToken.FreeTokenString[@item];
ENDLOOP;
EXITS Done => NULL; error => outcome ← error;
};
th ← XToken.FreeReaderHandle[th];
};
ChangeStandardStreams: PUBLIC PROCEDURE [buffer: LONG STRING, data: Handle] = {
rb: XString.ReaderBody ← XString.FromSTRING[buffer];
tH: XToken.Handle = XToken.ReaderToHandle[@rb];
token: XString.ReaderBody;
XToken.Skip[tH, NIL, XToken.WhiteSpace, TRUE];
-- stdin, stdout, stderr
FOR std: FormItems IN [stdin..stderr] DO
token ← XToken.Filtered[tH, NIL, FilterFileName];
WITH hh:data SELECT FROM
ctool => FormWindow.SetTextItemValue[hh.formSW, std.ORD, @token];
ENDCASE;
[] ← XToken.FreeTokenString[@token];
ENDLOOP;
[] ← XToken.FreeReaderHandle[tH];
};
FilterFileName: XToken.FilterProcType = {
char: CHARACTER = LOOPHOLE[XChar.Code[c], CHARACTER];
inClass ← char # Ascii.SP AND char # ', AND char # Ascii.CR AND char # Ascii.TAB;};
ChangeSwitches: PUBLIC PROCEDURE [buffer: LONG STRING, data: Handle] = {
rb: XString.ReaderBody ← XString.FromSTRING[buffer];
tH: XToken.Handle = XToken.ReaderToHandle[@rb];
switches: XString.ReaderBody;
sense: BOOLEAN ← TRUE;
XToken.Skip[tH, NIL, XToken.WhiteSpace, TRUE];
switches ← XToken.Filtered[tH, NIL, XToken.Switches];
DO
SELECT XString.Lop[@switches] FROM
'~.ORD, '-.ORD => sense ← ~sense;
'd.ORD => {
data.debug ← sense;
WITH hh:data SELECT FROM
ctool => FormWindow.SetBooleanItemValue[hh.formSW, FormItems.debug.ORD, data.debug];
ENDCASE;
sense ← TRUE;};
's.ORD => {
data.stopOnError ← sense;
WITH hh:data SELECT FROM
ctool => FormWindow.SetBooleanItemValue[hh.formSW, FormItems.stopOnError.ORD, data.stopOnError];
ENDCASE;
sense ← TRUE;};
XChar.not => EXIT;
ENDCASE;
ENDLOOP;
[] ← XToken.FreeTokenString[@switches];
[] ← XToken.FreeReaderHandle[tH];
};
PrintStatus: PUBLIC PROCEDURE [data: Handle, tty: TTY.Handle] = {
ss: String.SubStringDescriptor;
rb: XString.ReaderBody;
FOR std: FormItems IN [stdin..stderr] DO
TTY.PutString[tty, (SELECT std FROM
stdin => "stdin: "L,
stdout => "\Nstdout: "L,
stderr => "\Nstderr: "L,
ENDCASE => "bogus:"L)];
WITH h: data SELECT FROM
ctool => {
rb ← FormWindow.LookAtTextItemValue[h.formSW, std.ORD];
ss ← BWSUtil.SubStringFromXString[@rb];
IF ss.length = 0 THEN
TTY.PutString[tty, "window"L]
ELSE
TTY.PutSubString[tty, @ss];
FormWindow.DoneLookingAtTextItemValue[h.formSW, std.ORD];
};
ENDCASE;
ENDLOOP;
TTY.PutString[tty,"\NDebug: "L];
TTY.PutString[tty,
IF data.debug THEN "TRUE"L ELSE "FALSE"L];
TTY.PutString[tty,"\NStopScriptOnError: "L];
TTY.PutString[tty,
IF data.stopOnError THEN "TRUE"L ELSE "FALSE"L];
};
ParseLine: PUBLIC PROCEDURE [buffer: LONG STRING]
RETURNS [name: LONG STRING ← NIL, argC: CARDINAL ← 1, argV: ArgSeq ← NIL] = {
OPEN CString;
initArgSeqLength:CARDINAL = 8;
tH: XToken.Handle ← NIL;
tempName: XString.ReaderBody ← XString.nullReaderBody;
rb: XString.ReaderBody ← XString.FromSTRING[buffer];
done: BOOLEAN ← FALSE;
{ENABLE UNWIND => {
IF tH # NIL THEN tH ← XToken.FreeReaderHandle[tH];
IF tempName # XString.nullReaderBody THEN
[] ← XToken.FreeTokenString[@tempName];};
IF buffer.length = 0 THEN RETURN;
tH ← XToken.ReaderToHandle[@rb];
WHILE ~done DO
tempName ← XToken.MaybeQuoted[tH, NIL !XToken.UnterminatedQuote => RESUME];
IF ~XString.Empty[@tempName] THEN {
ss: String.SubStringDescriptor ← BWSUtil.SubStringFromXString[@tempName];
s: LONG STRING ← String.MakeString[z: zone, maxlength: ss.length];
String.AppendSubString[s, @ss];
IF argV = NIL THEN {
argV ← zone.NEW[StringSeq[initArgSeqLength]];
argV.length ← 0;
argC ← 0;
name ← String.CopyToNewString[s: s, z: zone, longer: 32];
};
argC ← argC + 1;
IF argV.length < argV.maxlength THEN {
argV[argV.length] ← LongStringToCString[s, zone];
argV.length ← argV.length + 1;
} ELSE {
oldArgV:ArgSeq ← argV;
{ENABLE UNWIND => {
IF argV # NIL THEN zone.FREE[@argV];
IF oldArgV # NIL THEN zone.FREE[@oldArgV];};
argV ← zone.NEW[StringSeq[oldArgV.maxlength * 2]];
FOR i:CARDINAL IN [0..oldArgV.length) DO
argV[i] ← oldArgV[i];
ENDLOOP;
argV.length ← oldArgV.length + 1;
argV[oldArgV.length] ← LongStringToCString[s, zone];
zone.FREE[@oldArgV];};
};
String.FreeString[z: zone, s: s];
} ELSE {
done ← TRUE;
};
[] ← XToken.FreeTokenString[@tempName];
ENDLOOP;
tH ← XToken.FreeReaderHandle[tH];
};};
GetFirstWord: PUBLIC PROCEDURE [buffer: LONG STRING]
RETURNS[firstWord: LONG STRING ← NIL] = {
rb: XString.ReaderBody ← XString.FromSTRING[buffer];
th: XToken.Handle ← NIL;
ts: XString.ReaderBody ← XString.nullReaderBody;
{ENABLE UNWIND => {
IF ts # XString.nullReaderBody THEN [] ← XToken.FreeTokenString[@ts];
IF th # NIL THEN th ← XToken.FreeReaderHandle[th];};
th ← XToken.ReaderToHandle[@rb];
ts ← XToken.Item[th];
IF ~XString.Empty[@ts] THEN {
ss: String.SubStringDescriptor ← BWSUtil.SubStringFromXString[@ts];
firstWord ← String.MakeString[z: zone, maxlength: ss.length];
String.AppendSubString[firstWord, @ss];
};
[] ← XToken.FreeTokenString[@ts];
th ← XToken.FreeReaderHandle[th];
};
};
Blink:PUBLIC PROCEDURE = {UserTerminal.BlinkDisplay[];};
Print:PUBLIC PROCEDURE[msg: LONG STRING, data:Handle] = {
rb: XString.ReaderBody ← XString.FromSTRING[msg, TRUE];
WITH hh:data SELECT FROM
ctool => MessageWindow.Post[window: hh.msgSW, r: @rb, clear: FALSE];
ENDCASE;
};
<<PrintErrorReader: PUBLIC PROCEDURE [msg: XString.Reader, data:Handle, tH: TTY.Handle] = {
ss: String.SubStringDescriptor ← BWSUtil.SubStringFromXString[msg];
WITH hh:data SELECT FROM
ctool => MessageWindow.Post[window: hh.msgSW, r: msg, clear: FALSE];
ENDCASE;
};>>
PrintTTYReader:PUBLIC PROCEDURE[msg:XString.Reader,tH: TTY.Handle] = {
ss: String.SubStringDescriptor ← BWSUtil.SubStringFromXString[msg];
TTY.PutSubString[h: tH, ss: @ss];
};
ClearError:PUBLIC PROCEDURE[data:Handle] = {
WITH hh:data SELECT FROM
ctool => MessageWindow.Clear[hh.msgSW];
ENDCASE;};
Debugging:PUBLIC PROCEDURE[data:Handle] RETURNS[BOOLEAN] = {
RETURN[data.debug];};
StopOnError:PUBLIC PROCEDURE[data:Handle] RETURNS[BOOLEAN] = {
RETURN[data.stopOnError];};
EndingToolInstance:PUBLIC PROCEDURE[data:Handle] RETURNS[BOOLEAN] = {
RETURN[data.endingToolInstance];};
StopIfCExec:PUBLIC PROCEDURE[data:Handle] = {};
UpdateLogReadLength:PUBLIC PROCEDURE[data:Handle] = {};
MakeDataForSystemCall:PUBLIC PROCEDURE RETURNS[newData:Handle] = {
newData ← zone.NEW[temp Data];
newData.cToolPart ← temp[];
};
-- BWS Icon stuff follows;
cToolIconType: NSFile.Type = 30304; -- one past compiler
open, canYouTakeSelection, takeSelection, takeSelectionCopy: Atom.ATOM;
old, new: Containee.Implementation ← [];
ch: XChar.Character;
true: BOOLEAN ← TRUE; -- for GenericProc
false: BOOLEAN ← FALSE;
Picture: TYPE = ARRAY [0..256) OF CARDINAL;
MakeGenericProcAtoms: PROC = {
open ← Atom.MakeAtom["Open"L];
canYouTakeSelection ← Atom.MakeAtom["CanYouTakeSelection"L];
takeSelection ← Atom.MakeAtom["TakeSelection"L];
takeSelectionCopy ← Atom.MakeAtom["TakeSelectionCopy"L];
};
FindOrCreateIconFile: PROC = {
name: XString.ReaderBody ← XString.FromSTRING["CTool Icon"L];
version: CARDINAL = 0;
IF (Prototype.Find[type: cToolIconType, version: version] = NSFile.nullReference)
THEN NSFile.Close[Prototype.Create [
name: @name,
type: cToolIconType,
version: version] ];
};
SetImplementation: PROC = {
old ← new ← Containee.GetImplementation[cToolIconType];
new.genericProc ← GenericProc;
new.pictureProc ← PictureProc;
InitSmallPicture[];
new.smallPictureProc ← SmallPictureProc;
[] ← Containee.SetImplementation[cToolIconType, new];
};
TakeSelection: PROC [data: Containee.DataHandle]
RETURNS [worked: LONG POINTER TO BOOLEAN ← @false] = {
value: Selection.Value ← Selection.Convert[target: file];
bw: Window.Handle = OpenCTool[data].bw; -- not literally, but it gets this one working
h: ECTHandle = Context.Find[contextType, bw];
IF ~h.busy AND value # Selection.nullValue THEN {
rb: XString.ReaderBody;
cr: XString.ReaderBody ← XString.FromSTRING["\n"L];
ticket: Containee.Ticket;
[rb, ticket] ← Containee.GetCachedName[
LOOPHOLE[value.value, Containee.DataHandle]];
Emulator.PutString[h.ttySW, @rb]; -- stuff in the name of the file to CTool
Emulator.CR[h.ttySW];
Containee.ReturnTicket[ticket];
worked ← @true;
};
Selection.Free[@value];
};
GenericProc: Containee.GenericProc = {
val: LONG UNSPECIFIED;
SELECT atom FROM
open => val ← OpenCTool[data].sws;
canYouTakeSelection => val ← IF Selection.CanYouConvert[target: file] THEN @true ELSE @false;
takeSelection, takeSelectionCopy => val ← TakeSelection[data];
ENDCASE => RETURN old.genericProc[atom, data, changeProc, changeProcData];
IF changeProc # NIL THEN
changeProc[changeProcData: changeProcData, data: data, noChanges: TRUE];
RETURN [val];
};
PictureProc: Containee.PictureProc = {
<<[data: Containee.DataHandle, window: Window.Handle, box: Window.Box,
old, new: Containee.PictureState]>>
normalPic: Picture ← [
17777B, 177777B, 177777B, 177770B, 37777B, 177777B, 177777B, 177774B, 70000B, 17B, 177000B, 16B, 160000B, 377B, 177740B, 7B, 140000B, 1777B, 177770B, 3B, 140000B, 7777B, 177776B, 3B, 140000B, 37777B, 177777B, 100003B, 140000B, 77777B, 177777B, 140003B, 140001B, 177777B, 177777B, 170003B, 140003B, 177777B, 177777B, 174003B, 140007B, 177777B, 177777B, 176003B, 140017B, 177777B, 177777B, 177003B, 140037B, 177777B, 177777B, 177403B, 140077B, 177777B, 177777B, 177603B, 140177B, 177760B, 777B, 177703B, 140177B, 177700B, 177B, 177703B, 140377B, 177400B, 37B, 177743B, 140777B, 176000B, 7B, 177763B, 140777B, 174000B, 3B, 177763B, 141777B, 170000B, 1B, 177773B, 141777B, 160000B, 0B, 3B, 143777B, 140000B, 0B, 3B, 143777B, 140000B, 0B, 3B, 147777B, 100000B, 0B, 3B, 147777B, 100000B, 0B, 3B, 147777B, 0B, 0B, 3B, 147777B, 0B, 0B, 3B, 157776B, 0B, 0B, 3B, 157776B, 0B, 0B, 3B, 157776B, 0B, 0B, 3B, 157776B, 0B, 0B, 3B, 157776B, 0B, 0B, 3B, 157776B, 0B, 0B, 3B, 157776B, 0B, 0B, 3B, 157776B, 0B, 0B, 3B, 157776B, 0B, 0B, 3B, 157776B, 0B, 0B, 3B, 147777B, 0B, 0B, 3B, 147777B, 0B, 0B, 3B, 147777B, 100000B, 0B, 3B, 147777B, 100000B, 0B, 3B, 143777B, 140000B, 0B, 3B, 143777B, 140000B, 0B, 3B, 141777B, 160000B, 0B, 3B, 141777B, 170000B, 1B, 177773B, 140777B, 174000B, 3B, 177763B, 140777B, 176000B, 7B, 177763B, 140377B, 177400B, 37B, 177743B, 140177B, 177700B, 177B, 177703B, 140177B, 177760B, 777B, 177703B, 140077B, 177777B, 177777B, 177603B, 140037B, 177777B, 177777B, 177403B, 140017B, 177777B, 177777B, 177003B, 140007B, 177777B, 177777B, 176003B, 140003B, 177777B, 177777B, 174003B, 140001B, 177777B, 177777B, 170003B, 140000B, 77777B, 177777B, 140003B, 140000B, 37777B, 177777B, 100003B, 140000B, 7777B, 177776B, 3B, 140000B, 1777B, 177770B, 3B, 160000B, 377B, 177740B, 7B, 70000B, 17B, 177000B, 16B, 37777B, 177777B, 177777B, 177774B, 17777B, 177777B, 177777B, 177770B
];
ghostPic: Picture ← [
17777B, 177777B, 177777B, 177770B, 37777B, 177777B, 177777B, 177774B, 70000B, 25B, 52400B, 16B, 160000B, 252B, 125240B, 7B, 140000B, 2525B, 52520B, 3B, 140000B, 5252B, 125252B, 3B, 140000B, 12525B, 52525B, 3B, 140000B, 25252B, 125252B, 100003B, 140001B, 52525B, 52525B, 50003B, 140002B, 125252B, 125252B, 124003B, 140005B, 52525B, 52525B, 52003B, 140012B, 125252B, 125252B, 125003B, 140025B, 52525B, 52525B, 52403B, 140052B, 125252B, 125252B, 125203B, 140125B, 52520B, 525B, 52403B, 140052B, 125200B, 52B, 125203B, 140125B, 52400B, 25B, 52503B, 140252B, 124000B, 2B, 125243B, 140525B, 50000B, 1B, 52523B, 141252B, 120000B, 0B, 125253B, 140525B, 40000B, 0B, 3B, 141252B, 100000B, 0B, 3B, 142525B, 40000B, 0B, 3B, 145252B, 100000B, 0B, 3B, 142525B, 0B, 0B, 3B, 145252B, 0B, 0B, 3B, 152525B, 0B, 0B, 3B, 145252B, 0B, 0B, 3B, 152524B, 0B, 0B, 3B, 145252B, 0B, 0B, 3B, 152524B, 0B, 0B, 3B, 145252B, 0B, 0B, 3B, 152524B, 0B, 0B, 3B, 145252B, 0B, 0B, 3B, 152524B, 0B, 0B, 3B, 145252B, 0B, 0B, 3B, 152524B, 0B, 0B, 3B, 145252B, 0B, 0B, 3B, 152525B, 0B, 0B, 3B, 145252B, 100000B, 0B, 3B, 142525B, 0B, 0B, 3B, 141252B, 100000B, 0B, 3B, 142525B, 40000B, 0B, 3B, 141252B, 120000B, 0B, 3B, 140525B, 50000B, 1B, 52523B, 140252B, 124000B, 2B, 125243B, 140525B, 52000B, 5B, 52523B, 140252B, 125000B, 12B, 125243B, 140125B, 52500B, 125B, 52503B, 140052B, 125240B, 252B, 125203B, 140025B, 52525B, 52525B, 52403B, 140012B, 125252B, 125252B, 125003B, 140005B, 52525B, 52525B, 52003B, 140002B, 125252B, 125252B, 124003B, 140001B, 52525B, 52525B, 50003B, 140000B, 125252B, 125252B, 120003B, 140000B, 52525B, 52525B, 40003B, 140000B, 25252B, 125252B, 100003B, 140000B, 2525B, 52524B, 3B, 140000B, 1252B, 125250B, 3B, 160000B, 125B, 52500B, 7B, 70000B, 12B, 125000B, 16B, 37777B, 177777B, 177777B, 177774B, 17777B, 177777B, 177777B, 177770B
];
invertFlags: Display.BitBltFlags = [
direction: forward,
disjoint: TRUE,
disjointItems: FALSE,
gray: FALSE,
srcFunc: complement,
dstFunc: null,
reserved: 0];
replaceFlags: Display.BitBltFlags = [
direction: forward,
disjoint: TRUE,
disjointItems: FALSE,
gray: FALSE,
srcFunc: null,
dstFunc: null,
reserved: 0];
IF new = garbage THEN RETURN;
box.dims ← [w: 64, h: 64];
box.place ← [box.place.x + 4, box.place.y + 4];
Display.Bitmap[
window: window,
box: box,
address: [word: IF new = ghost THEN @ghostPic ELSE @normalPic, bit: 0],
bitmapBitWidth: 64,
flags: IF new = highlighted THEN invertFlags ELSE replaceFlags];
};
InitSmallPicture: PROCEDURE = {
bits: ARRAY [0..16) OF WORD ← [
0B, 0B, 3760B, 7770B, 17074B, 16034B, 34000B, 34000B,
34000B, 34000B, 16034B, 17074B, 7770B, 3760B, 0B, 0B];
ch ← SimpleTextFont.AddClientDefinedCharacter [
width: 16, height: 16, bitsPerLine: 16, bits: @bits];
};
SmallPictureProc: Containee.SmallPictureProc = {RETURN[ch]};
SetOutputMode: PUBLIC PROCEDURE [h: Handle, iomode: INTEGER] = {
h.iomode ← iomode;
};
Init: PROC = {
contextType ← Context.UniqueType[];
MakeGenericProcAtoms[];
FindOrCreateIconFile[];
SetImplementation[];
};
-- mainline code
Init[];
}.