-- mdsubrimpl.Mesa, last edit January 4, 1983 1:30 pm -- Pilot 6.0/ Mesa 7.0 DIRECTORY CWF: TYPE USING [FWF0, FWF1, SWF1, SWF2, SWF3, WF0, WF1, WF2], LongString: TYPE USING [EquivalentString], IO: TYPE USING[PutChar], MDSubr: TYPE USING [AddToLook, entNil, Entry, EntrySeq, HUGEDEPLIST, Look, lookNil, LookSeq, LookupOtherSym, SMALLDEPLIST, StringSeq, WalkTheGraph], Stream: TYPE USING [Handle, PutChar], String: TYPE USING [AppendString], Subr: TYPE USING [CopyString, EndsIn, FreeString, PackedTime, strcpy, SubStrCopy, TTYProcs], Time: TYPE USING [Current]; MDSubrImpl: PROGRAM IMPORTS CWF, IO, LongString, MDSubr, Stream, String, Subr, Time EXPORTS MDSubr = { -- no MDS USAGE !!! -- utilities StripFirstWord: PUBLIC PROC[str, result: LONG STRING] = { i: CARDINAL ← 0; WHILE i < str.length AND i <result.maxlength DO IF str[i] = ' THEN EXIT; result[i] ← str[i]; i ← i + 1; ENDLOOP; result.length ← i; Subr.SubStrCopy[str,str,i]; }; -- having to do with EntrySeq's PrintEntries: PUBLIC PROC[entryseq: MDSubr.EntrySeq, sh: Stream.Handle, stringseq: MDSubr.StringSeq, ttyhandle: Subr.TTYProcs] = { i: CARDINAL; j: CARDINAL; ent, entchild: MDSubr.Entry; stemp: STRING ← [200]; str: LONG STRING; date: Subr.PackedTime ← Time.Current[]; WFsh: PROC[ch: CHAR] = { IF sh = NIL THEN ttyhandle.out.PutChar[ch] ELSE Stream.PutChar[sh, ch]; }; CWF.FWF1[WFsh, "-- created %lt\n"L, @date]; IF (str ← MDSubr.LookupOtherSym["PATH"L, stringseq]) ~= NIL THEN CWF.FWF1[WFsh, "PATH = %s\n"L, str]; IF (str ← MDSubr.LookupOtherSym["MESACOMP"L, stringseq]) ~= NIL THEN CWF.FWF1[WFsh, "MESACOMP = %s\n"L, str]; IF (str ← MDSubr.LookupOtherSym["MESABIND"L, stringseq]) ~= NIL THEN CWF.FWF1[WFsh, "MESABIND = %s\n"L, str]; FOR i IN [0.. stringseq.size) DO IF LongString.EquivalentString[stringseq[i].val, "local"L] THEN CWF.FWF1[WFsh, "%s = local\n"L, stringseq[i].str]; ENDLOOP; CWF.FWF0[WFsh,"\n"L]; FOR i IN [0..entryseq.size) DO ent ← @entryseq[i]; IF ent.rule = NIL AND ent.depends[0] = MDSubr.entNil THEN LOOP; -- CWF.WF3["Entry %d: '%s', Rule '%s'\n"L,@i,ent.name,ent.rule]; CWF.FWF1[WFsh,"%s:"L,ent.name]; j ← 0; DO IF ent.depends[j] = MDSubr.entNil THEN EXIT; -- WF.WF1[" Depends on %d\n"L,@ent.depends[j]]; entchild ← @entryseq[ent.depends[j]]; CWF.FWF1[WFsh," %s"L,entchild.name]; j ← j + 1; ENDLOOP; CWF.FWF0[WFsh,"\n"L]; IF ent.rule ~= NIL THEN CWF.FWF1[WFsh,"= %s\n"L,ent.rule]; CWF.FWF0[WFsh,"\n"L]; ENDLOOP; }; GetAnEntry: PUBLIC PROC[name: STRING, entryseq: MDSubr.EntrySeq] RETURNS[i: CARDINAL, new: BOOL] = { FOR i IN [0..entryseq.size) DO IF LongString.EquivalentString[name,entryseq[i].name] THEN RETURN[i,FALSE]; ENDLOOP; IF entryseq.size >= entryseq.maxsize THEN { m: CARDINAL ← entryseq.maxsize; CWF.WF1["Error - too many dependency entries > %d\n"L,@m] } ELSE { -- other fields are defaulted entryseq[entryseq.size] ← [name: Subr.CopyString[name, entryseq.entryzone], depends: DESCRIPTOR[NIL, 0]]; entryseq[entryseq.size].depends ← DESCRIPTOR[entryseq.entryzone.NEW[ ARRAY[0..MDSubr.SMALLDEPLIST) OF CARDINAL], MDSubr.SMALLDEPLIST]; entryseq[entryseq.size].depends[0] ← MDSubr.entNil; entryseq.size ← entryseq.size + 1; }; RETURN[entryseq.size-1,TRUE]; }; AddToDepends: PUBLIC PROC[parent, child: CARDINAL, entryseq: MDSubr.EntrySeq] = { i, max, len, inx: CARDINAL; saved: LONG DESCRIPTOR FOR ARRAY OF CARDINAL; entry: MDSubr.Entry; temp: CARDINAL; p: LONG POINTER; IF parent = MDSubr.entNil THEN RETURN; i ← 0; len ← LENGTH[entryseq[parent].depends]; max ← len - 1; entry ← @entryseq[parent]; WHILE i < max DO inx ← entry.depends[i]; IF inx = child THEN RETURN; -- already there IF inx = MDSubr.entNil THEN EXIT; i ← i + 1; REPEAT FINISHED => { -- CWF.WF1["Extending %s\n"L, entry.name]; IF len >= MDSubr.HUGEDEPLIST THEN { CWF.WF0["Error - too many depends\n"L]; RETURN; }; saved ← entry.depends; p ← entryseq.entryzone.NEW[ARRAY[0..MDSubr.HUGEDEPLIST) OF CARDINAL]; entry.depends ← DESCRIPTOR[p,MDSubr.HUGEDEPLIST]; FOR i IN [0..LENGTH[saved]) DO temp ← saved[i]; entry.depends[i] ← temp; ENDLOOP; i ← max; p ← BASE[saved]; -- no frees allowed -- longzone.FREE[@p]; }; ENDLOOP; entry.depends[i] ← child; entry.depends[i+1] ← MDSubr.entNil; }; FreeEntrySeq: PUBLIC PROC[pentryseq: LONG POINTER TO MDSubr.EntrySeq] = { entry: MDSubr.Entry; longp: LONG POINTER; IF pentryseq↑ = NIL THEN RETURN; IF FALSE THEN -- no frees allowed FOR i: CARDINAL IN [0..pentryseq↑.size) DO entry ← @(pentryseq↑)[i]; Subr.FreeString[entry.name]; Subr.FreeString[entry.rule]; longp ← BASE[entry.depends]; -- IF longp ~= NIL THEN longzone.FREE[@longp]; entry↑ ← [depends: DESCRIPTOR[NIL,0]]; ENDLOOP; -- longzone.FREE[pentryseq]; pentryseq↑ ← NIL; }; -- proc is only called once for each node that is connected to firstinx WalkTheGraph: PUBLIC PROC[firstinx: CARDINAL, entryseq:MDSubr.EntrySeq, proc: PROC[MDSubr.Entry]] = { RecurseThru: PROC[inx: CARDINAL, entryseq:MDSubr.EntrySeq, proc: PROC[MDSubr.Entry]] = { i: CARDINAL; entry: MDSubr.Entry ← @entryseq[inx]; IF entry.visited THEN RETURN; proc[entry]; -- call the users proc entry.visited ← TRUE; i ← 0; WHILE entry.depends[i] ~= MDSubr.entNil DO -- the recursive call RecurseThru[entry.depends[i], entryseq, proc]; i ← i + 1; ENDLOOP; }; FOR i: CARDINAL IN [0 .. entryseq.size) DO entryseq[i].visited ← FALSE; ENDLOOP; RecurseThru[firstinx, entryseq, proc]; }; -- look for a specific case of a .bcd depending on both a .config -- and .mesa file ThrowAwayLeaves: PUBLIC PROC[firstinx: CARDINAL, entryseq: MDSubr.EntrySeq, lookseq: MDSubr.LookSeq, ismodel: BOOL] = { RecurThrowAwayLeaves: PROC[entry: MDSubr.Entry] = { i, j1, j2: CARDINAL; lookj1, lookj2: MDSubr.Look; IF ismodel AND Subr.EndsIn[entry.name, ".bcd"L] THEN { i ← 0; lookj1 ← NIL; WHILE (j1 ← entry.depends[i]) ~= MDSubr.entNil DO IF (Subr.EndsIn[entryseq[j1].name,".config"L] OR Subr.EndsIn[entryseq[j1].name, ".mesa"L]) THEN { lookj1 ← @lookseq[entryseq[j1].lookinx]; IF lookj1.presentonlocaldisk THEN RETURN; }; i ← i + 1; ENDLOOP; -- if there was a .mesa or .config, and not on disk, then -- throw out IF lookj1 ~= NIL THEN { entry.depends[0] ← MDSubr.entNil; entry.rule ← NIL }; } ELSE { IF Subr.EndsIn[entry.name, ".bcd"L] AND (j1 ← entry.depends[0]) ~= MDSubr.entNil AND (j2 ← entry.depends[1]) ~= MDSubr.entNil AND entry.depends[2] = MDSubr.entNil AND Subr.EndsIn[entryseq[j1].name,".config"L] AND Subr.EndsIn[entryseq[j2].name, ".mesa"L] THEN { lookj1 ← @lookseq[entryseq[j1].lookinx]; lookj2 ← @lookseq[entryseq[j2].lookinx]; IF NOT lookj1.presentonlocaldisk AND NOT lookj2.presentonlocaldisk THEN entry.depends[0] ← MDSubr.entNil ELSE IF lookj1.presentonlocaldisk AND NOT lookj2.presentonlocaldisk THEN entry.depends[1] ← MDSubr.entNil ELSE IF NOT lookj1.presentonlocaldisk AND lookj2.presentonlocaldisk THEN { entry.depends[0] ← j2; entry.depends[1] ← MDSubr.entNil }; }; }; }; FOR i: CARDINAL IN [0.. entryseq.size) DO entryseq[i].visited ← FALSE; ENDLOOP; MDSubr.WalkTheGraph[firstinx, entryseq, RecurThrowAwayLeaves]; }; CheckNames: PUBLIC PROC[entryseq: MDSubr.EntrySeq, lookseq: MDSubr.LookSeq] = { look: MDSubr.Look; header: BOOL ← FALSE; FOR i: CARDINAL IN [0..entryseq.size) DO IF entryseq[i].lookinx ~= MDSubr.lookNil THEN { look ← @lookseq[entryseq[i].lookinx]; IF NOT LongString.EquivalentString[look.name, entryseq[i].name] THEN { IF NOT header THEN { CWF.WF0["Errors in look vs entry:\n"L]; header ← TRUE; }; CWF.WF2["Err - look %s entry %s\n"L, look.name, entryseq[i].name]; }; }; ENDLOOP; -- CWF.WF0["Looks ok to me\n"L]; }; ConvertToLook: PUBLIC PROC[entryseq: MDSubr.EntrySeq, lookseq: MDSubr.LookSeq] = { FOR i: CARDINAL IN [0..entryseq.size) DO IF entryseq[i].lookinx = MDSubr.lookNil THEN { entryseq[i].lookinx ← lookseq.size; [] ← MDSubr.AddToLook[entryseq[i].name, lookseq]; }; ENDLOOP; }; InsertOtherSym: PUBLIC PROC[str, val: STRING, stringseq: MDSubr.StringSeq] = { IF stringseq.size >= stringseq.maxsize THEN CWF.WF0["too many other syms\n"L] ELSE { stringseq[stringseq.size].str ← Subr.CopyString[str]; stringseq[stringseq.size].val ← Subr.CopyString[val]; stringseq.size ← stringseq.size + 1; }; RETURN; }; -- return the value corresponding to "str" -- searches backwards to allow users to redefine the strings LookupOtherSym: PUBLIC PROC[str: LONG STRING, stringseq: MDSubr.StringSeq] RETURNS[LONG STRING] = { FOR i: CARDINAL DECREASING IN [0..stringseq.size) DO IF LongString.EquivalentString[str,stringseq[i].str] THEN RETURN[stringseq[i].val]; ENDLOOP; RETURN[NIL]; }; GetCompilerRule: PUBLIC PROC[stringseq: MDSubr.StringSeq, name: LONG STRING, zone: UNCOUNTED ZONE] RETURNS[LONG STRING] = { comprule: STRING ← [100]; str: LONG STRING; pat: STRING ← [100]; count: CARDINAL ← 0; str ← MDSubr.LookupOtherSym["PILOTMESACOMP"L, stringseq]; IF str = NIL THEN str ← MDSubr.LookupOtherSym["MESACOMP"L, stringseq]; Subr.strcpy[pat, str]; FOR i: CARDINAL IN [0..pat.length) DO IF pat[i] = '% THEN count ← count + 1; ENDLOOP; IF count = 0 THEN String.AppendString[pat, " %s"L]; IF count > 3 THEN CWF.WF1["Too many %% in '%s'\n"L, pat] ELSE IF count = 3 THEN CWF.SWF3[comprule, pat, name, name, name] ELSE IF count = 2 THEN CWF.SWF2[comprule, pat, name, name] ELSE CWF.SWF1[comprule, pat, name]; RETURN[Subr.CopyString[comprule, zone]]; }; GetBinderRule: PUBLIC PROC[stringseq: MDSubr.StringSeq, name: LONG STRING, zone: UNCOUNTED ZONE] RETURNS[LONG STRING] = { comprule: STRING ← [100]; str: LONG STRING; pat: STRING ← [100]; count: CARDINAL ← 0; i: CARDINAL; str ← MDSubr.LookupOtherSym["PILOTMESABIND"L, stringseq]; IF str = NIL THEN str ← MDSubr.LookupOtherSym["MESABIND"L, stringseq]; Subr.strcpy[pat, str]; FOR i IN [0..pat.length) DO IF pat[i] = '% THEN count ← count + 1; ENDLOOP; IF count = 0 THEN String.AppendString[pat, " %s"L]; IF count > 3 THEN CWF.WF1["Too many %% in '%s'\n"L, pat] ELSE IF count = 3 THEN CWF.SWF3[comprule, pat, name, name, name] ELSE IF count = 2 THEN CWF.SWF2[comprule, pat, name, name] ELSE CWF.SWF1[comprule, pat, name]; RETURN[Subr.CopyString[comprule, zone]]; }; }. IDEAS 1. comments in line.cm for error messages