File: MobInstall.mesa - last edit:
Copyright Ó 1987, 1989, 1992 by Xerox Corporation. All rights reserved.
Andy Litman August 2, 1988 12:05:33 pm PDT
JKF May 24, 1990 4:40:14 pm PDT
LHowe, September 19, 1989 4:05:28 pm PDT
Foote, October 18, 1990 1:27 pm PDT
Mna, May 24, 1992 4:24 pm PDT
Willie-s, June 22, 1992 4:28 pm PDT

Bugs:
The .ld file is not quite right if configurations are nested and scoping matters.
DIRECTORY
Alloc USING [AddNotify, Base, DropNotify, Handle, InstanceData, Notifier],
BasicTime USING [Now, UnpackZ],
Convert USING [RopeFromTime, RopeFromUnpackedTime],
ConvertUnsafe USING [LS, SubString],
IO USING [card, int, Put1, PutChar, PutF, PutF1, PutRope, rope, STREAM, time, UnsafeBlock, UnsafePutBlock],
Loader USING [BCDBuildTime],
MobComData USING [Data, data],
MobControlDefs USING [],
MobDefs USING [cttype, cxtype, exptype, fttype, Selector, sttype, treetype, VersionStamp],
MobHashOps USING [HTIndex, SubStringForHash],
MobSymbols USING [Base, CXIndex, HTIndex, STIndex, STMap, stNull, STRecord],
MobTree USING [AttrId, Base, ConfigSons, Index, Link, Map, NodeName, null],
MobTreeOps USING [GetNode, UpdateList],
MobUtilDefs USING [ContextForTree],
OSMiscOps USING [Stamp, StampToTime],
Rope USING [ActionType, FetchType, MapType, MoveType, ROPE];
MobInstall: PROGRAM
IMPORTS Alloc, BasicTime, Convert, MobComData, MobUtilDefs, MobHashOps, IO, Loader, MobTreeOps, OSMiscOps
EXPORTS MobControlDefs = {
OPEN MobSymbols, MobComData;
Sons: TYPE = MobTree.ConfigSons;
XBuildSEError: ERROR = CODE;
stream, ldStream: IO.STREAM;
table: Alloc.Handle;
tb, stb, ctb, cxb, ftb, exb: Alloc.Base;
pass: {one, two};
main: BOOLEAN;
Notifier: Alloc.Notifier = {
tb ¬ base[MobDefs.treetype];
stb ¬ base[MobDefs.sttype];
cxb ¬ base[MobDefs.cxtype];
ctb ¬ base[MobDefs.cttype];
ftb ¬ base[MobDefs.fttype];
exb ¬ base[MobDefs.exptype]};
GetHash: PROC[link: MobTree.Link] RETURNS[hash: HTIndex] = {
WITH link SELECT FROM
hash => RETURN[index];
symbol => RETURN[stb[index].hti];
ENDCASE => ERROR};
MakeInstall: PUBLIC PROC[root: MobTree.Link] = {
stream ¬ data.installStream;
ldStream ¬ data.ldStream;
pass ¬ one;
XBuildSemanticEntries[root];
pass ¬ two;
XBuildSemanticEntries[root];
stream ¬ NIL;
ldStream ¬ NIL};
XBuildSemanticEntries: PROC [root: MobTree.Link] = {
node: MobTree.Index;
modName: Name;
main ← data.main;
main ¬ TRUE;
table ¬ data.table;
table.AddNotify[Notifier];
node ¬ MobTreeOps.GetNode[root];
IF tb[node].name # source THEN ERROR XBuildSEError;
modName ¬ GetHash[tb[NARROW[tb[node].son[3], MobTree.Link.subtree].index].son[Sons.name.ORD]];
LdHeader[modName];
IF pass = one THEN OuterHeader[modName];
tb[node].son[1] ¬ MobTreeOps.UpdateList[tb[node].son[1], DirItem];
tb[node].son[2] ¬ MobTreeOps.UpdateList[tb[node].son[2], PackId];
tb[node].son[3] ¬ ConfigStmt[tb[node].son[3]];
LdTrailer[];
IF pass = two THEN Line[];
table.DropNotify[Notifier];
table ¬ NIL};
DirItem: MobTree.Map = {
RETURN[t]};
PackId: MobTree.Map = {
RETURN[t]};
NullMap: MobTree.Map = {RETURN[t]};
ConfigStmt: MobTree.Map = {
WITH t SELECT FROM
hash, symbol => NULL;
subtree => {
node: MobTree.Index = index;
v ¬ SELECT tb[node].name FROM
list => MobTreeOps.UpdateList[t, ConfigStmt],
item => NullMap[t],
config => Config[node],
assign => NullMap[t],
plus, then => NullMap[t],
module => NullMap[t],
ENDCASE => ERROR XBuildSEError; };
ENDCASE => ERROR XBuildSEError;
RETURN};
OtherStmt: MobTree.Map = {
WITH t SELECT FROM
hash, symbol => v ¬ IF pass = two THEN Item[t] ELSE t;
subtree => {
node: MobTree.Index = index;
v ¬ SELECT tb[node].name FROM
list => MobTreeOps.UpdateList[t, OtherStmt],
item => IF pass = two THEN Item[t] ELSE t,
config => IF pass = two THEN NullMap[t] ELSE t,
assign => Assign[node],
plus, then => Expression[t],
module => Module[node],
ENDCASE => ERROR XBuildSEError; };
ENDCASE => ERROR XBuildSEError;
RETURN};
Item: MobTree.Map = {
[v, , ] ¬ ProcessItem[t]};
ProcessItem: PROC [t: MobTree.Link] RETURNS [tl: MobTree.Link, st1, st2: STIndex ¬ stNull] = {
WITH t SELECT FROM
hash, symbol =>
tl ¬ t;
subtree => {
tl ¬ t;
IF tb[index].son[2] # MobTree.null
THEN PushRename[GetHash[tb[index].son[2]], GetHash[tb[index].son[1]]]};
ENDCASE => ERROR XBuildSEError;
RETURN};
Config: PROC [node: MobTree.Index] RETURNS [MobTree.Link] = {
OPEN tb[node];
SeEntry: MobTree.Map = {
AddControl[GetHash[t]];
RETURN[t] };
IF pass = two THEN {
EnterConfig[node]; -- name
son[Sons.imports.ORD] ¬ MobTreeOps.UpdateList[son[Sons.imports.ORD], ImpItem];
son[Sons.exports.ORD] ¬ MobTreeOps.UpdateList[son[Sons.exports.ORD], ExpItem];
IF attrs[$exportsALL]
THEN ExportCx[MobUtilDefs.ContextForTree[son[Sons.name.ORD]]];
son[Sons.statics.ORD] ¬ MobTreeOps.UpdateList[son[Sons.statics.ORD], StaticItem];
son[Sons.dynamics.ORD] ¬ MobTreeOps.UpdateList[son[Sons.dynamics.ORD], DynamicItem];
HideNames[]; };
son[Sons.body.ORD] ¬ MobTreeOps.UpdateList[son[Sons.body.ORD], OtherStmt];
IF pass = two THEN {
son[Sons.control.ORD] ¬ MobTreeOps.UpdateList[son[Sons.control.ORD], SeEntry];
ConfigTrailer[GetHash[tb[node].son[Sons.name.ORD]]]};
son[Sons.body.ORD] ¬ MobTreeOps.UpdateList[son[Sons.body.ORD], ConfigStmt]; -- body
RETURN[[subtree[node]]]};
ExportCx: PROC[cx: MobSymbols.CXIndex] = {
FOR sti: STIndex ¬ cxb[cx].link, stb[sti].link UNTIL sti = stNull DO
IF ~stb[sti].filename THEN
WITH s: stb[sti] SELECT FROM
external =>
WITH s.map SELECT FROM
interface => ExportInterface[GetHash[[symbol[sti]]], 0, 0];
ENDCASE;
ENDCASE;
ENDLOOP};
EnterConfig: PROC [node: MobTree.Index] = {
ConfigHeader[GetHash[tb[node].son[Sons.name.ORD]]];
PushScope[GetHash[tb[node].son[Sons.name.ORD]]]};
ImpItem: MobTree.Map = {
[v, , ] ¬ ProcessItem[t];
The runtime knows how to interpret the following zeros.
ImportInterface[GetHash[tb[NARROW[t, MobTree.Link.subtree].index].son[1]], 0, 0]};
ExpItem: MobTree.Map = {
[v, , ] ¬ ProcessItem[t];
The runtime knows how to interpret the following zeros.
ExportInterface[GetHash[tb[NARROW[t, MobTree.Link.subtree].index].son[1]], 0, 0]};
DynamicItem: MobTree.Map = {
Dynamic[GetHash[t]];
RETURN[t]};
StaticItem: MobTree.Map = {
Static[GetHash[t]];
RETURN[t]};
AssignItem: MobTree.Map = {
[v, , ] ¬ ProcessItem[t];
ProhibitDuplicateExports[
GetHash[tb[NARROW[t, MobTree.Link.subtree].index].son[1]]];
mergeBase ¬
GetHash[tb[NARROW[t, MobTree.Link.subtree].index].son[1]]};
Assign: PROC [node: MobTree.Index] RETURNS [MobTree.Link] = {
IF pass = two THEN tb[node].son[1] ¬ MobTreeOps.UpdateList[tb[node].son[1], AssignItem];
tb[node].son[2] ¬ Expression[tb[node].son[2]];
RETURN[[subtree[node]]]};
mergeBase: HTIndex;
Expression: MobTree.Map = {
WITH t SELECT FROM
hash, symbol => v ¬ IF pass = two THEN ProcessItem[t].tl ELSE t;
subtree =>
SELECT tb[index].name FROM
item => v ¬ IF pass = two THEN ProcessItem[t].tl ELSE t;
module => v ¬ Module[index];
plus => {
IF pass = two THEN {
tb[index].son[1] ¬ Expression[tb[index].son[1]];
WITH tb[index].son[1] SELECT FROM
hash, symbol => MergeInterface[mergeBase, GetHash[tb[index].son[1]], TRUE];
ENDCASE;
tb[index].son[2] ¬ Expression[tb[index].son[2]];
MergeInterface[mergeBase, GetHash[tb[index].son[2]], TRUE]};
v ¬ t };
then => {
IF pass = two THEN {
tb[index].son[1] ¬ Expression[tb[index].son[1]];
WITH tb[index].son[1] SELECT FROM
hash, symbol => MergeInterface[mergeBase, GetHash[tb[index].son[1]], TRUE];
ENDCASE;
tb[index].son[2] ¬ Expression[tb[index].son[2]];
MergeInterface[mergeBase, GetHash[tb[index].son[2]], FALSE]};
v ¬ t };
ENDCASE => ERROR XBuildSEError;
ENDCASE => ERROR XBuildSEError;
RETURN};
ModItem: MobTree.Map = {
The syntax only allows positional notation for parameters to a module.
RETURN[t]};
Module: PROC [node: MobTree.Index] RETURNS [MobTree.Link] = {
IF pass = two THEN tb[node].son[1] ¬ Item[tb[node].son[1]];
BEGIN
son1: MobTree.Index = NARROW[tb[node].son[1], MobTree.Link.subtree].index;
modlink: MobTree.Link =
IF tb[son1].son[2] # MobTree.null THEN tb[son1].son[2] ELSE tb[son1].son[1];
ModuleInstall[GetHash[modlink], modlink];
END;
tb[node].son[2] ¬ MobTreeOps.UpdateList[tb[node].son[2], ModItem];
RETURN [[subtree[node]]]};
HashToBlock: PROC[hash: HTIndex] RETURNS[IO.UnsafeBlock] = {
ss: ConvertUnsafe.SubString;
ss ¬ MobHashOps.SubStringForHash[hash];
RETURN[[LOOPHOLE[@ss.base.text], ss.offset, ss.length]]};
Name: TYPE = HTIndex;
TypeIndex: TYPE = INT;
PutNumber: PROC[n: INT] = {
IO.Put1[stream, IO.int[n]]};
ImportInterface: PROC [name: Name, type: TypeIndex, size: INT] = {
DoInterface[name, type, size, FALSE]};
ExportInterface: PROC [name: Name, type: TypeIndex, size: INT] = {
DoInterface[name, type, size, TRUE]};
DoInterface: PROC [name: Name, type: TypeIndex, size: INT, export: BOOLEAN] = {
Line[];
IO.PutChar[stream, '\t];
IO.PutRope[stream,
IF export THEN "XR𡤎xportInterface" ELSE "XR←ImportInterface"];
Open[];
Quote[];
IO.UnsafePutBlock[stream, HashToBlock[name]];
Quote[];
Comma[];
PutNumber[type];
Comma[];
PutNumber[size];
Close[];
SemiColon[]};
Dynamic: PROC[name: Name] = {
Line[];
IO.PutRope[stream, "\tXR←request"];
Open[];
Quote[];
IO.UnsafePutBlock[stream, HashToBlock[name]];
Quote[];
Close[];
SemiColon[]};
Static: PROC[name: Name] = {
IO.UnsafePutBlock[ldStream, HashToBlock[name]];
IO.PutChar[ldStream, ' ]};
PushScope: PROC [name: Name] = {
Line[];
IO.PutRope[stream, "\tXR←PushScope"];
Open[];
Quote[];
IO.UnsafePutBlock[stream, HashToBlock[name]];
Quote[];
Close[];
SemiColon[]};
HideNames: PROC [] = {
Line[];
IO.PutRope[stream, "\tXR←HideNames"];
Open[];
Close[];
SemiColon[]};
PopScope: PROC [] = {
Line[];
IO.PutRope[stream, "\tXR←PopScope"];
Open[];
Close[];
SemiColon[]};
PushRename: PROC [alias: Name, name: Name] = {
Line[];
IO.PutRope[stream, "\tXR←PushRename"];
Open[];
Quote[];
IO.UnsafePutBlock[stream, HashToBlock[alias]];
Quote[];
Comma[];
Quote;
IO.UnsafePutBlock[stream, HashToBlock[name]];
Quote[];
Close[];
SemiColon[]};
PopRename: PROC [alias: Name] = {
Line[];
IO.PutRope[stream, "\tXR←PopRename"];
Open[];
Quote[];
IO.UnsafePutBlock[stream, HashToBlock[alias]];
Quote[];
Close[];
SemiColon[]};
ForgetName: PROC [name: Name] = {
Line[];
IO.PutRope[stream, "\tXR𡤏orgetName"];
Open[];
Quote[];
IO.UnsafePutBlock[stream, HashToBlock[name]];
Quote[];
Close[];
SemiColon[]};
ProhibitDuplicateExports: PROC [name: Name] = {
Line[];
IO.PutRope[stream, "\tXR←ProhibitDuplicateExports"];
Open[];
Quote[];
IO.UnsafePutBlock[stream, HashToBlock[name]];
Quote[];
Close[];
SemiColon[]};
PermitDuplicateExports: PROC [name: Name] = {
Line[];
IO.PutRope[stream, "\tXR←PermitDuplicateExports"];
Open[];
Quote[];
IO.UnsafePutBlock[stream, HashToBlock[name]];
Quote[];
Close[];
SemiColon[]};
MergeInterface: PROC [base: Name, aux: Name, unique: BOOL] = {
Line[];
IO.PutRope[stream, "\tXR←MergeInterface"];
Open[];
Quote[];
IO.UnsafePutBlock[stream, HashToBlock[base]];
Quote[];
Comma[];
Quote;
IO.UnsafePutBlock[stream, HashToBlock[aux]];
Quote[];
Comma[];
IO.PutRope[stream, IF unique THEN "1" ELSE "0"];
Close[];
SemiColon[]};
ModuleInstall: PROC [name: Name, modlink: MobTree.Link] = {
Line[];
IF pass = one
THEN IO.PutRope[stream, "extern void "]
ELSE IO.PutChar[stream, '\t];
IO.PutRope[stream, "XR←install←"];
IO.UnsafePutBlock[stream, HashToBlock[name]];
Open[];
Close[];
SemiColon[];
LdModuleInstall[name, modlink]};
LdModuleInstall: PROC[name: Name, modlink: MobTree.Link] = {
module: BOOL ¬ TRUE;
WITH modlink SELECT FROM
symbol =>
WITH stb[index] SELECT FROM
external =>
WITH map SELECT FROM
config => module ¬ FALSE;
ENDCASE;
ENDCASE;
ENDCASE;
SELECT pass FROM
one => {
IF module THEN { -- compile the module
IO.UnsafePutBlock[ldStream, HashToBlock[name]];
IF data.useC2CExtension THEN IO.PutRope[ldStream, ".c2c.c "]
ELSE IO.PutRope[ldStream, ".c "]}};
two => {
IO.UnsafePutBlock[ldStream, HashToBlock[name]];
IF module
THEN {
IF data.useC2CExtension THEN IO.PutRope[ldStream, ".c2c.o "] -- link in the .o file
ELSE IO.PutRope[ldStream, ".o "]}
ELSE IO.PutChar[ldStream, ' ]};
ENDCASE};
AddControl: PROC [name: Name] = {
Line[];
IO.PutRope[stream, "\tXR�ontrol"];
Open[];
Quote[];
IO.UnsafePutBlock[stream, HashToBlock[name]];
Quote[];
Close[];
SemiColon[]};
Open: PROC[] RETURNS[] = INLINE {
IO.PutChar[stream, '(]};
Close: PROC[] RETURNS[] = INLINE {
IO.PutChar[stream, ')]};
Quote: PROC[] RETURNS[] = INLINE {
IO.PutChar[stream, '"]};
SemiColon: PROC[] RETURNS[] = INLINE {
IO.PutChar[stream, ';]};
Comma: PROC[] RETURNS[] = INLINE {
IO.PutChar[stream, ',];
IO.PutChar[stream, ' ]};
ConfigHeader: PROC[name: Name] RETURNS[] = {
cedarCoreConfig: BOOLEAN ¬ data.cedarCoreConfig;
Line[2];
IF main
THEN {
IO.PutRope[stream, "static XR←GlobalFramePtr firstControl;"];Line[2];
IO.PutRope[stream, "extern void "];
IF cedarCoreConfig THEN IO.PutRope[stream, "XR←run←"]
ELSE IO.PutRope[stream, "XR←install←"];
IO.UnsafePutBlock[stream, HashToBlock[name]]; }
ELSE {
IO.PutRope[stream, "extern void "];
IF cedarCoreConfig THEN IO.PutRope[stream, "XR←run←"]
ELSE IO.PutRope[stream, "XR←install←"];
IO.UnsafePutBlock[stream, HashToBlock[name]]; };
SELECT pass FROM
one => IO.PutRope[stream, "();"];
two => {
IO.PutRope[stream, "() {"];
IF cedarCoreConfig THEN {
Line[];
IO.PutRope[stream, "\tstatic int firsttime = 1;"];
Line[];
IO.PutRope[stream, "\tif (firsttime == 1) {"];
Line[];
}
}
ENDCASE};
ConfigTrailer: PROC[name: Name] RETURNS[] = {
cedarCoreConfig: BOOLEAN ¬ data.cedarCoreConfig;
IF main THEN {
Line[];
IO.PutRope[stream, "\tfirstControl = XR𡤏irstControl();"]};
PopScope[];
IF cedarCoreConfig THEN {
Line[];
IO.PutRope[stream, "\tXR←StartCedarModule(firstControl);"];
Line[];
IO.PutRope[stream, "\t}"];
Line[];
IO.PutRope[stream, "\tfirsttime = 0;"];
};
Line[];
IO.PutRope[stream, "}"];
IF main THEN {
Line[2];
IO.PutRope[stream, IF data.extern THEN "extern" ELSE "static"];
IF cedarCoreConfig THEN IO.PutRope[stream, " void XR←install←"]
ELSE IO.PutRope[stream, " void XR←run←"];
IO.UnsafePutBlock[stream, HashToBlock[name]];
IF cedarCoreConfig THEN {
IO.PutRope[stream, "() { XR←run←"];
IO.UnsafePutBlock[stream, HashToBlock[name]];
IO.PutRope[stream, "(); }"]
}
ELSE IO.PutRope[stream, "() { XR←StartCedarModule(firstControl); }"];
};
IF main THEN {
Line[2];
IO.PutRope[stream, IF data.extern THEN "extern" ELSE "static"];
IO.PutRope[stream, " void XR←unload←"];
IO.UnsafePutBlock[stream, HashToBlock[name]];
IO.PutRope[stream, "() { XR←Unload(firstControl); }"]};
main ¬ FALSE;
IF data.buildPackagedWorld THEN {
generate the XR←InstallAndRunPackage boilerplate:
#include <string.h>
char XR←packageVersion[] = "<Today's Date>";
static char *argvec[25];
static char **defaultArgv = &argvec[0];
static int firstTime = 1;
static int defaultArgc = 0;
void XR←GetPackageDefaultArgs(argc←ptr, argv←ptr)
int *argc←ptr; char ***argv←ptr; {
extern char defaultArgs[];
char *nextArg;
if( (argc←ptr == 0) || (argv←ptr == 0) ) return;
if(!firstTime) {
*argv←ptr = defaultArgv;
*argc←ptr = defaultArgc;
return;}
for (;;) {
if (firstTime) {
nextArg = strtok(defaultArgs, " ");
firstTime = 0;}
else nextArg = strtok(0, " ");
if (nextArg == 0) break;
defaultArgv[defaultArgc] = nextArg;
defaultArgc++;};
*argv←ptr = defaultArgv;
*argc←ptr = defaultArgc;}
void XR←SetupPackage() { return;}
void XR←InstallAndRunPackage() {
XR←install←<packagename>();
XR𡤌ommitInstallation();
XR←run←<packagename>();
}
Put: PROC [r: Rope.ROPE] = {IO.PutRope[stream, r]};
Line[2];
Put["#include <string.h>\n"];
Put["char XR←packageVersion[] = \""];
Put[Convert.RopeFromTime[BasicTime.Now[]]]; Put["\";\n"];
Put["static char *argvec[25];\n"];
Put["static char **defaultArgv = &argvec[0];\n"];
Put["static int firstTime = 1;\n"];
Put["static int defaultArgc = 0;\n"];
Put["void XR←GetPackageDefaultArgs(argc←ptr, argv←ptr)\n"];
Put["\tint *argc←ptr; char ***argv←ptr; {\n"];
Put["\textern char defaultArgs[];\n"];
Put["\tchar *nextArg;\n"];
Put["\tif( (argc←ptr == 0) || (argv←ptr == 0) ) return;\n"];
Put["\tif(!firstTime) {\n"];
Put["\t\t*argv←ptr = defaultArgv;\n"];
Put["\t\t*argc←ptr = defaultArgc;\n"];
Put["\t\treturn;}\n"];
Put["\tfor (;;) {\n"];
Put["\t\tif (firstTime) {\n"];
Put["\t\t\tnextArg = strtok(defaultArgs, \" \");\n"];
Put["\t\t\tfirstTime = 0;}\n"];
Put["\t\telse nextArg = strtok(0, \" \");\n"];
Put["\t\tif (nextArg == 0) break;\n"];
Put["\t\tdefaultArgv[defaultArgc] = nextArg;\n"];
Put["\t\tdefaultArgc++;}\n"];
Put["\t*argv←ptr = defaultArgv;\n"];
Put["\t*argc←ptr = defaultArgc;\n}\n"];
Put["void XR←SetupPackage() { return;}\n"];
Put["void XR←InstallAndRunPackage() {\n"];
Put["\tXR←install←"]; IO.UnsafePutBlock[stream, HashToBlock[name]]; Put["();\n"];
Put["\tXR𡤌ommitInstallation();\n"];
Put["\tXR←run←"]; IO.UnsafePutBlock[stream, HashToBlock[name]]; Put["();\n}\n"];
};
};
OuterHeader: PROC[name: Name] RETURNS[] = {
IO.PutRope[stream, "/* "];
IO.UnsafePutBlock[stream, HashToBlock[name]];
IO.PutF1[stream, ".c produced by Cinder of %g", IO.time[Loader.BCDBuildTime[]]];
IO.PutRope[stream, " */"];
Line[2];
IO.PutRope[stream, "#include <cedar/InstallationSupport.h>"];
IO.PutRope[stream, "/* formerly from <cedar/InstallationSupport.h>: */"]; Line[];
These must match the definitions exported by InstallationSupport*.df
IO.PutRope[stream, "typedef unsigned XR←InterfacePtr;"]; Line[];
IO.PutRope[stream, "typedef unsigned XR←GlobalFramePtr;"]; Line[];
IO.PutRope[stream, "extern XR←InterfacePtr XR←ImportInterface ();"]; Line[];
IO.PutRope[stream, "extern XR←InterfacePtr XR𡤎xportInterface ();"]; Line[];
IO.PutRope[stream, "extern void XR𡤎xportProc ();"]; Line[];
IO.PutRope[stream, "extern void XR←PushScope ();"]; Line[];
IO.PutRope[stream, "extern void XR←HideNames ();"]; Line[];
IO.PutRope[stream, "extern void XR←PopScope ();"]; Line[];
IO.PutRope[stream, "extern void XR←PushRename ();"]; Line[];
IO.PutRope[stream, "extern void XR←PopRename ();"]; Line[];
IO.PutRope[stream, "extern void XR𡤏orgetName ();"]; Line[];
IO.PutRope[stream, "extern void XR←ProhibitDuplicateExports ();"]; Line[];
IO.PutRope[stream, "extern void XR←PermitDuplicateExports ();"]; Line[];
IO.PutRope[stream, "extern void XR�ontrol ();"]; Line[];
IO.PutRope[stream, "extern XR←GlobalFramePtr XR𡤏irstControl();"]; Line[];
IO.PutRope[stream, "void XR←Start ();"]; Line[];
IO.PutRope[stream, "static char versionStamp[] = \"@"];
IO.PutF[stream, "(#)mob←version [%g,%g] %g\";",
IO.card[OSMiscOps.StampToTime[data.objectStamp][0]],
IO.card[OSMiscOps.StampToTime[data.objectStamp][1]],
IO.rope[data.sourceName]];
Line[];
IO.PutRope[stream, "static char configBuildTime[] = \"@"];
IO.PutRope[stream, "(#)configBuildTime "];
IO.PutRope[stream, Convert.RopeFromTime[BasicTime.Now[]]];
IO.PutRope[stream, "\";"];
Line[];
IO.PutF1[stream, "char XR𡤌onfigBuildTime←%g[] = \"",
IO.rope[data.rootName]];
IO.PutRope[stream, Convert.RopeFromUnpackedTime[BasicTime.UnpackZ[BasicTime.Now[]]]];
IO.PutRope[stream, "\";"];
Line[];
};
LdHeader: PROC[name: Name] = {
SELECT pass FROM
one => {
IF data.PIC THEN IO.PutRope[ldStream, "cc -c -g -PIC "]
ELSE
IF data.pic THEN IO.PutRope[ldStream, "cc -c -g -pic "]
ELSE IO.PutRope[ldStream, "cc -c -g "];
IO.UnsafePutBlock[ldStream, HashToBlock[name]];
IF data.useC2CExtension THEN IO.PutRope[ldStream, ".c2c.c "]
ELSE IO.PutRope[ldStream, ".c "]};
two => {
IF data.relocate THEN IO.PutRope[ldStream, "ld -o "]
ELSE IO.PutRope[ldStream, "ld -r -o "];
IO.UnsafePutBlock[ldStream, HashToBlock[name]];
IO.PutChar[ldStream, ' ];
IO.UnsafePutBlock[ldStream, HashToBlock[name]];
IF data.useC2CExtension THEN IO.PutRope[ldStream, ".c2c.o "]
ELSE IO.PutRope[ldStream, ".o "]};
ENDCASE};
LdTrailer: PROC[] = {
SELECT pass FROM
one => LdLine[];
two => {
IF data.dynamicLibrarySearch = FALSE THEN IO.PutRope[ldStream, "-lxrc -lm "];
LdLine[];
};
ENDCASE};
LdLine: PROC[n: CARD ¬ 1] = {
FOR i: CARD IN [0..n) DO
IO.PutChar[ldStream, '\012];
ENDLOOP};
Line: PROC[n: CARD ¬ 1] = {
FOR i: CARD IN [0..n) DO
IO.PutChar[stream, '\012];
ENDLOOP};
}.