-- MDScanImpl.Mesa -- last edit 17-Dec-81 12:59:49 -- last edit May 22, 1983 4:48 pm, Russ Atkinson -- Pilot 6.0/ Mesa 7.0 -- scanning and parsing subroutines for the system modeller DIRECTORY Ascii: TYPE USING [CR, FF, TAB], CWF: TYPE USING [SWF1, WF0, WF1, WF2, WF3], File: TYPE USING [Capability], LongString: TYPE USING [EqualString, EquivalentString], MDSubr: TYPE USING [AddToDep, AddToDepends, AddToMod, ADepRecord, DepSeq, EntrySeq, GetAnEntry, InsertOtherSym, IsAlpha, IsDigit, Look, lookNil, LookRecord, LookSeq, ModInfo, ModType, StringSeq, Token, versionUnknown], Space: TYPE USING [Create, Delete, Handle, Map, virtualMemory], Stream: TYPE USING [Handle], String: TYPE USING [CompareStrings, StringToDecimal], Subr: TYPE USING [AllocateString, Any, CopyString, EndsIn, EnumerateDirectory, FreeString, GetChar, GetCreateDateWithSpace, GetLine, GetString, LongZone, PackedTime, strcpy, StripLeadingBlanks, SubStrCopy], SystemInternal: TYPE USING [UniversalID], Time: TYPE USING [Current]; MDScanImpl: PROGRAM IMPORTS CWF, LongString, MDSubr, Space, String, Subr, Time EXPORTS MDSubr = { AliasSeqRecord: TYPE = RECORD[ size: CARDINAL _ 0, body: SEQUENCE maxsize: CARDINAL OF AliasRecord ]; AliasRecord: TYPE = RECORD[ str: LONG STRING _ NIL, val: LONG STRING _ NIL ]; -- MDS USAGE !!! peektok: PUBLIC MDSubr.Token; peekvalue: PUBLIC LONG UNSPECIFIED; nextchar: CHAR; tokstring: LONG POINTER TO ARRAY MDSubr.Token OF LONG STRING _ NIL; aliasseq: LONG POINTER TO AliasSeqRecord _ NIL; savestr: LONG STRING _ NIL; toksave: LONG STRING _ NIL; -- endof MDS USAGE NALIASES: CARDINAL = 50; MaxLineLength: CARDINAL = 600; -- parse the stream handle, add that parent depends -- on everything in the streamhandle -- it turns out we ignore IMPORTS and EXPORTS since those entries must appear -- in the DIRECTORY clause -- if pmod = NIL then use depseq ParseObject: PUBLIC PROC[sh: Stream.Handle, parent: CARDINAL, entryseq: MDSubr.EntrySeq, pmod: MDSubr.ModInfo, depseq: MDSubr.DepSeq, stringseq: MDSubr.StringSeq, sfn: LONG STRING] = { tok: MDSubr.Token _ tokBAD; tokvalue: LONG UNSPECIFIED; str: LONG STRING; child: CARDINAL; stemp: STRING _ [100]; imp, isconfig, isdefns: BOOL _ FALSE; savename: STRING _ [100]; ScanInit[sh]; IF pmod ~= NIL THEN { pmod.isconfig _ pmod.isdefn _ FALSE; pmod.impinx _ pmod.expinx _ pmod.dirinx _ 0; }; WHILE tok ~= tokBEGIN AND tok ~= tokEOF DO SELECT tok FROM tokDIR => tok _ Direct[sh, parent, entryseq, pmod, depseq, sfn]; tokCONFIG => { IF savename.length > 0 AND depseq ~= NIL THEN depseq.modulename _ Subr.CopyString[savename, entryseq.entryzone]; isconfig _ TRUE; [tok,tokvalue] _ NextTok[sh]; }; tokPROGRAM => { IF savename.length > 0 AND depseq ~= NIL THEN depseq.modulename _ Subr.CopyString[savename, entryseq.entryzone]; isconfig _ FALSE; [tok,tokvalue] _ NextTok[sh]; }; tokMONITOR => { IF savename.length > 0 AND depseq ~= NIL THEN depseq.modulename _ Subr.CopyString[savename, entryseq.entryzone]; isconfig _ FALSE; [tok,tokvalue] _ NextTok[sh]; }; tokDEFINITIONS => { IF savename.length > 0 AND depseq ~= NIL THEN depseq.modulename _ Subr.CopyString[savename, entryseq.entryzone]; isdefns _ TRUE; [tok,tokvalue] _ NextTok[sh]; }; tokIMPORTS, tokEXPORTS => { imp _ tok = tokIMPORTS; [tok, tokvalue] _ NextTok[sh]; WHILE tok = tokID OR tok = tokCOLON OR tok = tokCOMMA DO IF tok = tokID AND peektok ~= tokCOLON THEN { str _ tokvalue; str _ GetAlias[str]; CWF.SWF1[stemp,"%s.bcd"L, str]; IF pmod ~= NIL THEN { [child,] _ MDSubr.GetAnEntry[stemp, entryseq]; MDSubr.AddToMod[pmod, child, IF imp THEN imports ELSE exports]; } ELSE { adeprecord: MDSubr.ADepRecord _ []; adeprecord.bcdfilename _ Subr.CopyString[stemp, entryseq.entryzone]; adeprecord.relation _ IF imp THEN imports ELSE exports; adeprecord.modulename _ Subr.CopyString[tokvalue, entryseq.entryzone]; AddToDep[depseq, @adeprecord]; }; }; [tok, tokvalue] _ NextTok[sh]; ENDLOOP; }; ENDCASE => { -- this may be the module name IF tok = tokID THEN Subr.strcpy[savename, tokvalue]; [tok,tokvalue] _ NextTok[sh]; }; ENDLOOP; IF pmod ~= NIL THEN { pmod.isconfig _ isconfig; pmod.isdefn _ isdefns; } ELSE{ depseq.isconfig _ isconfig; depseq.isdefns _ isdefns; }; IF NOT isconfig THEN RETURN; tok _ ConfigBody[sh, parent, entryseq, sfn, depseq]; IF tok = tokEND AND stringseq ~= NIL THEN ParseStrings[sh, stringseq]; RETURN; }; -- parses the configuration AFTER the { ConfigBody: PROC[sh: Stream.Handle, parent: CARDINAL, entryseq: MDSubr.EntrySeq, sfn: LONG STRING, depseq: MDSubr.DepSeq] RETURNS[tok: MDSubr.Token] = { tokvalue: LONG UNSPECIFIED; str: LONG STRING; child: CARDINAL; stemp: STRING _ [40]; save: STRING _ [40]; -- [itemlist] _ id : id [idlist] LINKS : {CODE, FRAME} {PLUS, THEN} ...; -- id : id _ ...; DO { [tok,tokvalue] _ NextTok[sh]; save.length _ 0; IF tok = tokID THEN Subr.strcpy[save, tokvalue]; -- used if _ or : IF tok = tokEND THEN EXIT; IF tok = tokLB THEN { WHILE tok ~= tokRB AND tok ~= tokSEMI AND tok ~= tokEND AND tok ~= tokEOF DO [tok, tokvalue] _ NextTok[sh]; IF tok = tokID THEN AddAlias[tokvalue, NIL]; ENDLOOP; CheckTok[tok,tokRB,sfn]; } -- ELSE IF peektok = tokCOLON THEN { -- [tok,] _ NextTok[sh]; -- IF peektok = tokID AND save.length > 0 THEN -- AddAlias[save, NIL]; -- [tok,tokvalue] _ NextTok[sh]; -- } ; IF peektok = tokARROW THEN { [tok,] _ NextTok[sh]; IF peektok = tokID AND save.length > 0 THEN AddAlias[save, NIL]; [tok,tokvalue] _ NextTok[sh]; }; DO CheckTok[tok, tokID,sfn]; IF peektok = tokCOLON THEN { -- id1: id2 -- id1: CONFIGURATION str _ tokvalue; Subr.strcpy[save, str]; [] _ NextTok[sh]; [tok, tokvalue] _ NextTok[sh]; IF tok = tokCONFIG THEN { WHILE tok ~= tokEOF AND tok ~= tokBEGIN DO [tok, tokvalue] _ NextTok[sh]; ENDLOOP; IF tok = tokEOF THEN RETURN[tok]; AddAlias[save, NIL]; tok _ ConfigBody[sh, parent, entryseq, sfn, depseq]; CheckTok[tok, tokEND,sfn]; [tok,] _ NextTok[sh]; CheckTok[tok, tokSEMI,sfn]; GOTO outer; }; CheckTok[tok, tokID,sfn]; AddAlias[save, NIL]; -- ignore id1 }; str _ tokvalue; str _ GetAlias[str]; IF str ~= NIL THEN { CWF.SWF1[stemp, "%s.bcd"L, str]; IF entryseq ~= NIL THEN { [child,] _ MDSubr.GetAnEntry[stemp, entryseq]; MDSubr.AddToDepends[parent, child, entryseq]; } ELSE { adeprecord: MDSubr.ADepRecord _ []; adeprecord.bcdfilename _ Subr.CopyString[stemp, entryseq.entryzone]; MDSubr.AddToDep[depseq, @adeprecord]; }; }; [tok,] _ NextTok[sh]; WHILE tok ~= tokSEMI AND tok ~= tokPLUS AND tok ~= tokTHEN AND tok ~= tokEND AND tok ~= tokEOF DO [tok, tokvalue] _ NextTok[sh]; ENDLOOP; IF tok = tokPLUS OR tok = tokTHEN THEN { [tok, tokvalue] _ NextTok[sh]; LOOP; }; EXIT; ENDLOOP; IF tok = tokSEMI THEN LOOP ELSE { CheckTok[tok, tokEND, sfn]; RETURN[tok]; }; EXITS outer => NULL; }; ENDLOOP; }; -- Interface: FROM "FileName": TYPE USING [a,b,c],; -- Interface: TYPE USING [a,b,c],; -- Interface ,; -- FileName: TYPE Interface -- FileName: TYPE Direct: PROC[sh: Stream.Handle, parent: CARDINAL, entryseq: MDSubr.EntrySeq, pmod: MDSubr.ModInfo, depseq: MDSubr.DepSeq, sfn: LONG STRING] RETURNS[MDSubr.Token] = { tok: MDSubr.Token; tokvalue: LONG UNSPECIFIED; filename: LONG STRING; stemp: STRING _ [40]; child: CARDINAL; interface: STRING _ [100]; i: CARDINAL; isfrom: BOOL; [tok,tokvalue] _ NextTok[sh]; WHILE tok ~= tokPROGRAM AND tok ~= tokEOF AND tok ~= tokDEFINITIONS AND tok ~= tokSEMI AND tok~= tokCONFIG DO IF tok = tokID THEN { filename _ tokvalue; Subr.strcpy[interface, filename]; [tok, tokvalue] _ NextTok[sh]; IF tok = tokCOLON THEN { [tok, tokvalue] _ NextTok[sh]; IF tok = tokFROM THEN isfrom _ TRUE ELSE IF tok = tokTYPE THEN isfrom _ FALSE ELSE CheckTok[tok, tokFROM, sfn]; IF peektok = tokSTRLIT OR peektok = tokID THEN { [tok, tokvalue] _ NextTok[sh]; filename _ tokvalue; IF NOT isfrom THEN { Subr.strcpy[stemp, filename]; Subr.strcpy[filename, interface]; Subr.strcpy[interface, stemp]; }; IF Subr.EndsIn[filename, ".bcd"L] THEN filename.length _ filename.length - 4; IF NOT LongString.EquivalentString[interface, filename] THEN { IF Subr.Any[filename, '>] THEN { i _ filename.length - 1; DO IF filename[i] = '> THEN { Subr.SubStrCopy[filename, filename, i+1]; EXIT; }; IF i = 0 THEN EXIT; i _ i - 1; ENDLOOP; }; AddAlias[interface, filename]; Subr.strcpy[interface, filename]; }; }; }; CWF.SWF1[stemp,"%s.bcd"L,interface]; IF pmod ~= NIL THEN { [child,] _ MDSubr.GetAnEntry[stemp, entryseq]; MDSubr.AddToDepends[parent, child, entryseq]; MDSubr.AddToMod[pmod, child, directory]; } ELSE { adeprecord: MDSubr.ADepRecord _ []; adeprecord.bcdfilename _ Subr.CopyString[stemp, entryseq.entryzone]; adeprecord.relation _ directory; adeprecord.modulename _ Subr.CopyString[interface, entryseq.entryzone]; AddToDep[depseq, @adeprecord]; }; WHILE tok ~= tokCOMMA AND tok ~= tokSEMI AND tok ~= tokEOF AND tok ~= tokPROGRAM AND tok ~= tokDEFINITIONS AND tok ~= tokCONFIG DO IF tok = tokLB THEN { WHILE tok ~= tokEOF AND tok ~= tokRB DO [tok,tokvalue] _ NextTok[sh]; ENDLOOP; CheckTok[tok, tokRB, sfn]; }; [tok,tokvalue] _ NextTok[sh]; ENDLOOP; } ELSE [tok,tokvalue] _ NextTok[sh]; ENDLOOP; RETURN[tok]; }; ParseStrings: PROC[sh: Stream.Handle, stringseq: MDSubr.StringSeq] = { line: STRING _ [MaxLineLength]; linx: CARDINAL; str: STRING _ [MaxLineLength]; val: STRING _ [MaxLineLength]; WHILE Subr.GetLine[sh,line] DO linx _ 0; linx _ Subr.GetString[line, str, linx]; IF str.length = 0 OR NOT MDSubr.IsAlpha[str[0]] THEN LOOP; linx _ Subr.GetString[line, val, linx]; IF val.length ~= 1 OR val[0] ~= '= THEN LOOP; Subr.SubStrCopy[val, line, linx]; Subr.StripLeadingBlanks[str]; Subr.StripLeadingBlanks[val]; MDSubr.InsertOtherSym[str, val, stringseq]; ENDLOOP; }; -- initiallizes the various data structures ScanInit: PUBLIC PROC [st: Stream.Handle] = { IF aliasseq = NIL THEN Init[]; FreeAliases[]; -- clear out any aliases here previously peektok _ tokBAD; peekvalue _ 0; nextchar _ Ascii.CR; [] _ NextTok[st]; }; -- to free this memory, simply call StopScanner Init: PROC = { longzone: UNCOUNTED ZONE _ Subr.LongZone[]; tokstring _ longzone.NEW[ARRAY MDSubr.Token OF LONG STRING]; InitTokString[]; aliasseq _ longzone.NEW[AliasSeqRecord[NALIASES]]; savestr _ Subr.AllocateString[200]; toksave _ Subr.AllocateString[200]; }; -- frees memory as needed, call only once StopScanner: PUBLIC PROC = { longzone: UNCOUNTED ZONE _ Subr.LongZone[]; IF tokstring = NIL THEN RETURN; -- Init never called FOR t: MDSubr.Token IN MDSubr.Token DO Subr.FreeString[tokstring[t]]; ENDLOOP; longzone.FREE[@tokstring]; FreeAliases[]; longzone.FREE[@aliasseq]; Subr.FreeString[toksave]; Subr.FreeString[savestr]; savestr _ toksave _ NIL; }; -- frees memory for aliases, call many times FreeAliases: PROC = { FOR i: CARDINAL IN [0 .. aliasseq.size) DO Subr.FreeString[aliasseq[i].str]; Subr.FreeString[aliasseq[i].val]; ENDLOOP; aliasseq.size _ 0; }; -- NOTE: this checks the type of MDSubr.Token in case the string literal must -- be saved NextTok: PUBLIC PROC [st: Stream.Handle] RETURNS[MDSubr.Token,LONG UNSPECIFIED] ={ tok: MDSubr.Token; tokvalue: LONG UNSPECIFIED; tok _ peektok; IF tok = tokID OR tok = tokSTRLIT THEN { Subr.strcpy[toksave,peekvalue]; tokvalue _ toksave; } ELSE tokvalue _ peekvalue; [peektok,peekvalue] _ ReadTok[st]; -- IF Subr.debugflg THEN { -- CWF.WF1["tok %s"L,GetTokString[tok]]; -- IF tok = tokID THEN CWF.WF1[" = '%s'\n"L,tokvalue]; -- CWF.WF0["\n"L]; -- }; RETURN[tok,tokvalue]; }; -- if tok = tokID, tokvalue is a STRING ReadTok: PROC [st: Stream.Handle] RETURNS[toktype: MDSubr.Token,tokval: LONG UNSPECIFIED] ={ i: CARDINAL; lastchar: CHAR; DO IF nextchar = 0C THEN RETURN[tokEOF,0]; WHILE nextchar = ' OR nextchar = Ascii.CR OR nextchar = Ascii.TAB DO nextchar _ Subr.GetChar[st] ENDLOOP; IF MDSubr.IsAlpha[nextchar] THEN { i _ 0; WHILE (MDSubr.IsAlpha[nextchar] OR MDSubr.IsDigit[nextchar]) AND i <= savestr.maxlength DO savestr[i] _ nextchar; i _ i + 1; nextchar _ Subr.GetChar[st]; ENDLOOP; savestr.length _ i; toktype _ KeywordLookup[savestr]; IF toktype ~= tokBAD THEN RETURN[toktype,0]; -- not keyword, must be identifier RETURN[tokID,savestr] } ELSE IF MDSubr.IsDigit[nextchar] THEN { stemp: STRING _ [40]; i _ 0; WHILE MDSubr.IsDigit[nextchar] AND i <= stemp.maxlength DO stemp[i] _ nextchar; i _ i+1; nextchar _ Subr.GetChar[st]; ENDLOOP; stemp.length _ i; RETURN[tokNUM,String.StringToDecimal[stemp]] } ELSE { lastchar _ nextchar; nextchar _ Subr.GetChar[st]; SELECT lastchar FROM '( => toktype _ tokLP; ') => toktype _ tokRP; '[ => toktype _ tokLB; '] => toktype _ tokRB; '{ => toktype _ tokBEGIN; '} => toktype _ tokEND; '. => toktype _ tokDOT; ': => toktype _ tokCOLON; ', => toktype _ tokCOMMA; '@ => toktype _ tokAT; '! => toktype _ tokBANG; '; => toktype _ tokSEMI; '> => toktype _ tokGT; '< => toktype _ tokLT; '^ => toktype _ tokUP; '_ => toktype _ tokARROW; Ascii.FF => LOOP; 0C => toktype _ tokEOF; '= => { toktype _ tokEQ; IF nextchar = '> THEN { nextchar _ Subr.GetChar[st]; toktype _ tokIMPLIES; }; }; '- => { { IF nextchar ~= '- THEN CWF.WF0["bad comment\n"L]; nextchar _ Subr.GetChar[st]; WHILE nextchar ~= Ascii.CR AND nextchar ~= 0C DO IF nextchar = '- THEN { nextchar _ Subr.GetChar[st]; IF nextchar = '- THEN { nextchar _ Subr.GetChar[st]; GOTO goon; }; }; nextchar _ Subr.GetChar[st]; ENDLOOP; nextchar _ Subr.GetChar[st]; EXITS goon => NULL; }; LOOP; }; '" => { i _ 0; WHILE i < savestr.maxlength DO savestr[i] _ nextchar; nextchar _ Subr.GetChar[st]; i _ i + 1; IF nextchar = '" THEN { nextchar _ Subr.GetChar[st]; IF nextchar = '" THEN LOOP; EXIT; }; REPEAT FINISHED => CWF.WF0["String literal too long\n"L]; ENDLOOP; savestr.length _ i; RETURN[tokSTRLIT, savestr]; }; ENDCASE => { i: INTEGER _ LOOPHOLE[lastchar]; CWF.WF1["unknown char %c\n"L,@i]; toktype _ tokEOF; }; RETURN[toktype,0]; }; ENDLOOP; }; -- return the tok if found, return tokBAD if error KeywordLookup: PROC[str: LONG STRING] RETURNS[tok: MDSubr.Token] = { OPEN LongString; IF EquivalentString[str,"BEGIN"L] THEN RETURN[tokBEGIN]; -- deviation due to use of Defs modules "Code" IF EqualString[str,"CODE"L] THEN RETURN[tokCODE]; IF EquivalentString[str,"CONFIGURATION"L] THEN RETURN[tokCONFIG]; IF EquivalentString[str,"CONTROL"L] THEN RETURN[tokCONTROL]; IF EquivalentString[str,"DEFINITIONS"L] THEN RETURN[tokDEFINITIONS]; -- deviation due to use of Defs modules "Directory" IF EqualString[str,"DIRECTORY"L] THEN RETURN[tokDIR]; IF EquivalentString[str,"END"L] THEN RETURN[tokEND]; IF EquivalentString[str,"EXPORTS"L] THEN RETURN[tokEXPORTS]; IF EquivalentString[str,"FRAME"L] THEN RETURN[tokFRAME]; IF EquivalentString[str,"FROM"L] THEN RETURN[tokFROM]; IF EquivalentString[str,"IMPORTS"L] THEN RETURN[tokIMPORTS]; IF EquivalentString[str,"LET"L] THEN RETURN[tokLINKS]; IF EquivalentString[str,"LINKS"L] THEN RETURN[tokLINKS]; IF EquivalentString[str,"MONITOR"L] THEN RETURN[tokMONITOR]; IF EquivalentString[str,"OPEN"L] THEN RETURN[tokLINKS]; IF EquivalentString[str,"OTHERS"L] THEN RETURN[tokOTHERS]; IF EquivalentString[str,"PACK"L] THEN RETURN[tokPACK]; IF EquivalentString[str,"PLUS"L] THEN RETURN[tokPLUS]; IF EquivalentString[str,"PROC"L] THEN RETURN[tokPROC]; IF EquivalentString[str,"PROGRAM"L] THEN RETURN[tokPROGRAM]; IF EquivalentString[str,"RETURNS"L] THEN RETURN[tokRETURNS]; IF EquivalentString[str,"SELECT"L] THEN RETURN[tokSELECT]; IF EquivalentString[str,"SHARES"L] THEN RETURN[tokSHARES]; -- deviation due to use of Defs modules "String" IF EqualString[str,"STRING"L] THEN RETURN[tokSTRING]; IF EquivalentString[str,"THEN"L] THEN RETURN[tokTHEN]; IF EquivalentString[str,"TYPE"L] THEN RETURN[tokTYPE]; IF EquivalentString[str,"USING"L] THEN RETURN[tokUSING]; RETURN[tokBAD]; }; GetTokString: PUBLIC PROC[tok: MDSubr.Token] RETURNS[LONG STRING] = { RETURN[tokstring[tok]]; }; CheckTok: PUBLIC PROC[tokis, tokshouldbe: MDSubr.Token, sfn: LONG STRING] = { IF tokis ~= tokshouldbe THEN CWF.WF3["MDSubr.Token is %s, should be %s, in file %s\n"L, GetTokString[tokis],GetTokString[tokshouldbe],sfn]; }; AddAlias: PROC[str, val: LONG STRING] = { IF aliasseq.size >= aliasseq.maxsize THEN CWF.WF0["Error - too many aliases\n"L] ELSE { aliasseq[aliasseq.size].str _ Subr.CopyString[str]; aliasseq[aliasseq.size].val _ IF val ~= NIL THEN Subr.CopyString[val] ELSE NIL; aliasseq.size _ aliasseq.size + 1; }; }; -- aliases must be correctly capitalized GetAlias: PROC[str: LONG STRING] RETURNS[LONG STRING] = { FOR i: CARDINAL IN [0 .. aliasseq.size) DO IF LongString.EqualString[str, aliasseq[i].str] THEN RETURN[aliasseq[i].val]; ENDLOOP; RETURN[str]; }; AddToMod: PUBLIC PROC[pmod: MDSubr.ModInfo, child: CARDINAL, type: MDSubr.ModType] = { SELECT type FROM imports => { IF pmod.impinx >= LENGTH[pmod.imports] THEN CWF.WF0["pmod - too many imports\n"L] ELSE { pmod.imports[pmod.impinx] _ child; pmod.impinx _ pmod.impinx + 1; }; }; exports => { IF pmod.expinx >= LENGTH[pmod.exports] THEN CWF.WF0["pmod - too many exports\n"L] ELSE { pmod.exports[pmod.expinx] _ child; pmod.expinx _ pmod.expinx + 1; }; }; directory => { IF pmod.dirinx >= LENGTH[pmod.dirname] THEN CWF.WF0["pmod - too many directory entries\n"L] ELSE { pmod.dirname[pmod.dirinx] _ child; pmod.dirinx _ pmod.dirinx + 1; }; }; ENDCASE; }; AddToDep: PUBLIC PROC[depseq: MDSubr.DepSeq, padeprecord: POINTER TO MDSubr.ADepRecord] = { IF padeprecord^.relation = errortype THEN ERROR; IF depseq.size + 1 >= depseq.maxsize THEN CWF.WF0["Error - too many dependencies.\n"L] ELSE { depseq[depseq.size] _ padeprecord^; depseq.size _ depseq.size + 1; }; }; -- fills in FP if file in in lookseq ReadLocalDirectory: PUBLIC PROC[lookseq: MDSubr.LookSeq] ={ fcount: CARDINAL _ 0; MyDirProc: PROC[cap: File.Capability, sfn: LONG STRING] RETURNS [BOOL] = { look: MDSubr.Look; fcount _ fcount + 1; [look,] _ LookLook[sfn, lookseq]; IF look ~= NIL THEN { look.cap _ cap; look.presentonlocaldisk _ TRUE; RETURN[FALSE]; }; RETURN[FALSE]; }; -- CWF.WF0["Reading local directory.\n"L]; Subr.EnumerateDirectory[MyDirProc]; CWF.WF1["%u files in local directory\n"L, @fcount]; }; -- fills in lookseq with all files in directory -- except if ThrowAwayThisFile[] ReadInLocalDirectoryAll: PUBLIC PROC[lookseq: MDSubr.LookSeq, ThrowAwayThisFile: PROC[name: LONG STRING] RETURNS[BOOL]] = { fcount: CARDINAL _ 0; AddDirName: PROC[cap: File.Capability, sfn: LONG STRING] RETURNS[BOOL] = { look: MDSubr.Look; fcount _ fcount + 1; IF ThrowAwayThisFile[sfn] THEN RETURN[FALSE]; look _ AddToLook[sfn,lookseq]; look.cap _ cap; look.presentonlocaldisk _ TRUE; IF lookseq.size >= lookseq.maxsize THEN { m: CARDINAL _ lookseq.maxsize; CWF.WF1[ "Error - More than %d files, will do only that many files.\n"L, @m]; RETURN[TRUE]; }; RETURN[FALSE]; }; -- CWF.WF0["Begin reading local directory.\n"L]; Subr.EnumerateDirectory[AddDirName]; CWF.WF1["%u files in local directory\n"L, @fcount]; }; AnalyzeLocalFiles: PUBLIC PROC[oktosort: BOOL, lookseq: MDSubr.LookSeq, getcreatedate: BOOL] = { -- fill in mod time for all local files we need time: Subr.PackedTime; -- mtc, mtr: LONG CARDINAL; count: CARDINAL _ 0; look: MDSubr.Look; filename: STRING _ [100]; space: Space.Handle; IF oktosort THEN SortByFileCap[lookseq]; space _ Space.Create[size: 1, parent: Space.virtualMemory]; Space.Map[space]; -- map in for CopyIn -- CWF.WF0["Begin reading local file times.\n"]; time _ Time.Current[]; FOR i: CARDINAL IN [0 .. lookseq.size) DO look _ @lookseq[i]; IF look.name = NIL OR NOT look.need OR NOT look.presentonlocaldisk OR look.localversion ~= MDSubr.versionUnknown THEN LOOP; -- [create: mtc, read: mtr, length: look.locallength] _ -- Subr.GetCreateDate[look.cap]; -- [createDate: mtc, readDate: mtr, byteLength: look.locallength] _ -- Directory.GetProps[look.cap, filename -- ! Directory.Error => { -- CWF.WF0["Directory.Error.\n"L]; -- mtc _ mtr _ 0; -- CONTINUE -- }]; -- look.localversion _ IF getcreatedate THEN mtc ELSE mtr; look.localversion _ Subr.GetCreateDateWithSpace[look.cap, space]; count _ count + 1; ENDLOOP; time _ Time.Current[] - time; Space.Delete[space: space]; IF count > 0 THEN CWF.WF2["Took %lu secs to read properties of %u files.\n"L, @time, @count]; }; PrintLook: PUBLIC PROC[lookseq: MDSubr.LookSeq] = { look: MDSubr.Look; len: LONG CARDINAL; CWF.WF0["Look Summary:\n"L]; FOR i: CARDINAL IN [0 .. lookseq.size) DO look _ @lookseq[i]; IF look.name ~= NIL AND look.need THEN { CWF.WF1["File %s:\n"L,look.name]; IF look.presentonlocaldisk THEN { CWF.WF0[" Local Disk"L]; IF look.localversion ~= MDSubr.versionUnknown THEN { len _ look.localversion; CWF.WF1[", Time %lt"L, @len]; }; CWF.WF0["\n"L]; }; }; ENDLOOP; }; SortByFileCap: PROC[lookseq: MDSubr.LookSeq]={ FileTimeLessThan: PROC[left, right:MDSubr.Look]RETURNS[BOOL] = { l,r: LONG POINTER TO SystemInternal.UniversalID; l _ LOOPHOLE[@left.cap]; r _ LOOPHOLE[@right.cap]; RETURN[l.sequence < r.sequence]; }; TreeSort[lookseq, FileTimeLessThan]; }; SortByFileTime: PUBLIC PROC[lookseq: MDSubr.LookSeq, descending: BOOL _ FALSE]={ FileTimeLessThan: PROC[left, right:MDSubr.Look]RETURNS[BOOL] = { RETURN[IF descending THEN(left.localversion > right.localversion) ELSE(left.localversion < right.localversion)]; }; TreeSort[lookseq, FileTimeLessThan]; }; SortByFileName: PUBLIC PROC[lookseq: MDSubr.LookSeq, descending: BOOL _ FALSE]={ FileNameLessThan: PROC[left, right: MDSubr.Look] RETURNS [BOOL] = { s1: STRING _ [100]; s2: STRING _ [100]; IF left.name = NIL OR right.name = NIL THEN RETURN[FALSE]; Subr.strcpy[s1, left.name]; Subr.strcpy[s2, right.name]; -- IF String.CompareStrings[s1, s2, TRUE] > 0 THEN -- CWF.WF2["%s is greater than than %s\n"L, s1,s2]; RETURN[IF descending THEN(String.CompareStrings[s1, s2, TRUE] > 0) ELSE(String.CompareStrings[s1, s2, TRUE] < 0)]; }; TreeSort[lookseq, FileNameLessThan]; }; TreeSort: PROC[lookseq: MDSubr.LookSeq,LessThan: PROC[MDSubr.Look, MDSubr.Look] RETURNS[BOOL]] = { left, right: MDSubr.Look; siftUp: PROC[low, high: INTEGER] ={ k, son: INTEGER; left, right: MDSubr.Look; k _ low; DO IF 2*k>high THEN EXIT; left _ @lookseq[2*k+1-1]; right _ @lookseq[2*k-1]; IF 2*k+1>high OR LessThan[left, right] THEN son _ 2*k ELSE son _ 2*k+1; left _ @lookseq[son-1]; right _ @lookseq[k-1]; IF LessThan[left, right] THEN { EXIT; }; LookExch[left, right]; k _ son; ENDLOOP; }; FOR i:CARDINAL DECREASING IN [1..lookseq.size/2] DO siftUp[i,lookseq.size] ENDLOOP; FOR i:CARDINAL DECREASING IN [1..lookseq.size) DO left _ @lookseq[0]; right _ @lookseq[i]; LookExch[left, right]; siftUp[1,i] ENDLOOP; }; LookExch: PROC[left, right: MDSubr.Look] = { t: MDSubr.LookRecord; t _ left^; left^ _ right^; right^ _ t; }; -- returns NIL if not found LookLook: PUBLIC PROC[name: LONG STRING, lookseq: MDSubr.LookSeq] RETURNS[look: MDSubr.Look, lookinx: CARDINAL] = { FOR i: CARDINAL IN [0..lookseq.size) DO look _ @lookseq[i]; IF look.need AND look.name ~= NIL AND look.name.length = name.length AND LongString.EquivalentString[name, look.name] THEN RETURN[look, i]; ENDLOOP; RETURN[NIL, MDSubr.lookNil]; }; FreeLookSeq: PUBLIC PROC[plookseq: LONG POINTER TO MDSubr.LookSeq] = { IF plookseq^ = NIL THEN RETURN; IF FALSE THEN -- no frees allowed FOR i: CARDINAL IN [0.. plookseq^.size) DO Subr.FreeString[plookseq^[i].name]; ENDLOOP; -- longzone.FREE[plookseq]; plookseq^ _ NIL; }; AddToLook: PUBLIC PROC[name: LONG STRING, lookseq: MDSubr.LookSeq] RETURNS[look: MDSubr.Look] = { IF lookseq.size >= lookseq.maxsize THEN { m: CARDINAL _ lookseq.maxsize; CWF.WF1["Error - more than %d files to look for."L, @m]; RETURN[NIL]; }; look _ @lookseq[lookseq.size]; -- other fields are defaulted look^ _ [need: TRUE, name: Subr.CopyString[name, lookseq.lookzone]]; lookseq.size _ lookseq.size + 1; RETURN[look]; }; InitTokString: PROC = { TokString: ARRAY MDSubr.Token OF STRING = ["ErrorMDSubr.Token"L, "EndOfFile"L, "("L, ")"L, "["L, "]"L, "."L, ":"L, "L,"L, "="L, "@"L, "!"L, ";"L, ">"L,"<"L, "^"L, "=>"L, "_"L, "Identifier"L, "Number"L, "TYPE"L, "PLUS"L, "THEN"L, "PROC"L, "RETURNS"L, "StringLiteral"L, "STRING"L, "SELECT"L, "FROM"L, "DIRECTORY"L,"IMPORTS"L, "EXPORTS"L,"PROGRAM"L,"{"L, "DEFINITIONS"L, "OTHERS"L, "CONTROL"L, "CONFIGURATION"L, "LINKS"L, "CODE"L, "FRAME"L, "PACK"L, "END"L, "USING"L, "SHARES"L, "LET"L, "OPEN"L, "MONITOR"L]; FOR t: MDSubr.Token IN MDSubr.Token DO tokstring[t] _ Subr.CopyString[TokString[t]]; ENDLOOP; }; }. Κ{˜Jš€Οc·œΟk œ žœžœžœžœžœžœžœžœ%žœžœžœžœ,žœžœΨžœžœ9žœžœžœžœ,žœžœΧžœžœžœžœžœžœžœ0žœžœžœ žœ žœ žœžœžœžœžœžœžœžœžœžœœ žœžœžœž œ žœ žœžœžœžœžœžœžœžœ žœžœžœžœ žœžœžœ žœžœžœœžœžœžœ δΟn œžœžœžœož œ,žœž œžœžœ žœ žœ"žœžœ žœžœ žœžœ"žœ4žœžœžœžœžœVžœžœ žœžœUžœ:žœžœ žœžœUžœ:žœžœ žœžœUžœ>žœžœ žœžœTžœžœ žœžœžœžœ žœžœ4žœ!žœ žœžœ_žœžœžœžœ—žœžœžœ΄žœžœœžœ žœHžœžœ žœžœ9žœ>žœžœ žœžœ7žœžœžœžœžœ(Ÿ œžœžœ#ž œžœ"žœž œžœžœ žœ žœžœ [žœ7žœ žœœžœžœžœžœ žœžœžœžœžœžœ'žœ žœžœžœ$%œœ/œœ!œœžœžœžœžœžœžœ,žœ!žœžœ œœjžœžœžœžœžœ*žœžœžœžœžœžžœ?žœœ3žœžœžœžœ"žœ žœžœržœΛžœžœžœžœžœžœ(žœžœžœžœ*žœ žœžœžœžœžœžœ#žœ žœ žœžœ•ŸœžœžœQž œžœ0žœž œ žœžœ žœžœ žœ žœ žœ!žœžœžœžœžœžœžœ žœažœžœ(žœžœ žœžœžœžœ žœžœ!žœžœžœCžœžœžœ}žœ žœ1žœžœ7žœžœžœ(žœ žœžœKžœžœžœžœžœmžœ$žœ žœžœ™žœŒžœžœžœžœžœžœžœžœ žœžœžœžœ)žœLžœžœ žœžœ Ÿ œžœ;žœžœžœžœžœžœ6žœžœžœžœžœ,žœžœžœžœ‘žœ,Ÿœžœžœžœ žœžœ)œ2žœ0Ÿœžœž œžœ)žœžœžœžœžœ(žœžœP*Ÿ œžœžœž œžœžœ žœžœžœžœžœžœ"žœ žœ&žœUžœ-Ÿ œžœžœžœžœžœHžœ[Ÿœžœžœžœžœž œ"žœž œžœ žœžœ<žœ:œ)œ7œœžœ(Ÿœžœžœžœž œžœ žœžœžœžœžœ žœžœžœžœžœžœ!žœžœžœžœžœžœžœLžœ>žœžœžœ#œžœžœžœžœ žœžœžœžœHžœžœ,žœ;žœ žœ»žœžœ?žœžœ^žœžœžœ;žœžœžœžœžœžœ*žœžœ,žœ=žœ%žœ žœ žœžœžœPžœžœ*žœžœžœžœžœžœ žœ(žœžœžœ žœžœžœ<žœžœ3Ÿ œžœžœžœžœžœ žœ žœžœ /žœžœžœ žœ(žœžœ žœ"žœžœžœ&žœžœ4žœžœžœ žœžœžœ žœ"žœžœžœ žœžœ žœžœžœ žœ"žœžœžœžœžœ žœ žœžœ žœ"žœžœžœžœžœ žœ!žœžœ žœžœžœ žœžœžœ žœžœžœ žœ"žœžœžœ"žœžœžœ!žœžœ žœ!žœžœ 1žœžœžœ žœžœžœ žœžœžœ žœ žœžœ žœŸ œžœžœžœžœžœžœŸœžœžœ(ž œžœžœžœrŸœžœ žœžœžœ#žœžœ$žœWžœžœžœžœžœ.)Ÿœžœžœžœžœžœžœžœžœžœžœžœ.žœžœžœžœ Ÿœžœžœžœžœžœžœžœžœžœ$žœ`žœžœžœžœ$žœbžœžœžœžœ.žœRžœŸœžœžœ'žœžœžœ#žœžœžœ#žœžœ*žœP%Ÿœžœžœ%žœŸ œžœžœžœžœžœTžœ žœžœ1žœžœžœ žœžœ+œ$žœ5QŸœžœžœŸœžœž œžœžœžœŸ œžœž œžœžœ1žœžœžœžœOžœžœ!žœžœžœRžœžœ žœžœ1œ%žœ5Ÿœžœžœ žœ,žœ0œœžœ#žœ žœ žœgFœžœžœžœžœžœ žœžœžœ žœžœžœ,žœžœ8œ!œDœ)œœ#œœ œœ;œXžœ<žœ žœžœOŸ œžœžœ6žœžœžœžœžœžœžœžœžœžœ žœžœ!žœžœžœžœ,žœ%žœ%žœžœŸ œžœŸœžœžœžœ žœžœžœ"žœžœžœIŸœžœžœ'žœžœŸœžœžœžœžœžœžœ+žœYŸœžœžœ(žœžœŸœžœžœžœ žœžœ žœ žœžœžœžœžœžœ?3œ4œžœžœžœžœ žœžœ7ŸœžœŸœžœžœžœ+žœ žœžœ(žœžœ žœžœ;žœ žœžœžœFžœžœžœ.žœžœžœž œžœžœžœžœžœž œžœžœRžœŸœžœ`Ÿœžœžœžœžœžœžœžœžœžœžœžœ žœžœžœ!žœ0žœžœ žœžœžœŸ œžœžœ žœžœžœžœ žœžœžœžœžœžœœžœžœžœžœ'žœœ žœŸ œžœžœžœžœžœžœ!žœžœžœ7žœžœ&œžœSžœ Ÿ œžœžœžœžœΤžœžœžœ1žœ ˜ΓΗ—…—cΖrG