<<>> <> <> <> <> <> <> <> <> << Bugs: >> <> 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 ¬ 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]; <> ImportInterface[GetHash[tb[NARROW[t, MobTree.Link.subtree].index].son[1]], 0, 0]}; ExpItem: MobTree.Map = { [v, , ] ¬ ProcessItem[t]; <> 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 = { <> 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_ExportInterface" 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_ForgetName"]; 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_AddControl"]; 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_FirstControl();"]}; 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 { <> <<#include >> <> <> <> <> <> <> <> <> <> <> <> <<*argv_ptr = defaultArgv;>> <<*argc_ptr = defaultArgc;>> <> <> <> <> <> <> <> <> <> <<*argv_ptr = defaultArgv;>> <<*argc_ptr = defaultArgc;}>> <> <> <();>> <> <();>> <<}>> Put: PROC [r: Rope.ROPE] = {IO.PutRope[stream, r]}; Line[2]; Put["#include \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_CommitInstallation();\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, "/* formerly from : */"]; Line[]; <> 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_ExportInterface ();"]; Line[]; IO.PutRope[stream, "extern void XR_ExportProc ();"]; 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_ForgetName ();"]; Line[]; IO.PutRope[stream, "extern void XR_ProhibitDuplicateExports ();"]; Line[]; IO.PutRope[stream, "extern void XR_PermitDuplicateExports ();"]; Line[]; IO.PutRope[stream, "extern void XR_AddControl ();"]; Line[]; IO.PutRope[stream, "extern XR_GlobalFramePtr XR_FirstControl();"]; 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_configBuildTime_%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}; }.