DIRECTORY BasicTime, Booting, Commander, CommandTool, FS, IO, List, Process, PutGet, Random, Rope, RopeFile, TextNode, UserProfile; Cookie: CEDAR MONITOR IMPORTS BasicTime, Booting, Commander, CommandTool, FS, IO, List, Process, PutGet, Random, Rope, RopeFile, TextNode, UserProfile = BEGIN ROPE: TYPE = Rope.ROPE; RopeList: TYPE = LIST OF ROPE; WeightedIndexSet: TYPE = REF WeightedIndexSetRep; WeightedIndexSetRep: TYPE = RECORD [ length: CARDINAL, totalWeight: REAL, indices: SEQUENCE size: CARDINAL OF Index]; Index: TYPE = REF IndexRep; IndexRep: TYPE = RECORD [ incrWeight, sumWeight: REAL, alles: ROPE, entries: SEQUENCE size: CARDINAL OF IndexEntry]; IndexEntry: TYPE = RECORD [pos: INT]; rs: Random.RandomStream _ NIL; cookies: WeightedIndexSet _ NewWeightedIndexSet[10]; files: RopeList _ NIL; hold: RopeList _ NIL; installedDirectory: ROPE _ CommandTool.CurrentWorkingDirectory[]; defaultProbability: REAL _ 0.1; defaultInitial: INT _ 1; enabled: BOOL _ FALSE; AddFile: PROC [to: WeightedIndexSet, weight: REAL, fileName: ROPE] RETURNS [new: WeightedIndexSet, count: INT] = BEGIN indexStream: IO.STREAM _ NIL; ok: BOOLEAN _ TRUE; alles, dataName, indexName: ROPE _ NIL; dWeight: REAL; count _ 0; IF to.length = to.size THEN { new _ NEW [WeightedIndexSetRep[to.size*2]]; new.length _ to.length; new.totalWeight _ to.totalWeight; FOR i: CARDINAL IN [0 .. to.length) DO new[i] _ to[i]; ENDLOOP; } ELSE new _ to; dataName _ FS.ExpandName[fileName, installedDirectory].fullFName; indexName _ FS.ExpandName[fileName.Concat[".Index"], installedDirectory].fullFName; indexStream _ FS.StreamOpen[indexName !FS.Error => CONTINUE]; IF indexStream # NIL THEN { indexTime: BasicTime.GMT _ indexStream.GetTime[]; dataTime: BasicTime.GMT _ BasicTime.nullGMT; dataTime _ FS.FileInfo[dataName !FS.Error => CONTINUE].created; IF dataTime = BasicTime.nullGMT THEN RETURN; ok _ dataTime = indexTime; } ELSE ok _ FALSE; IF NOT ok THEN { messages _ messages.Cat["Had to remake index for ", fileName, " --- tell maintainer\n"]; MakeIndex[fileName, installedDirectory]; indexStream _ NIL; indexStream _ FS.StreamOpen[indexName !FS.Error => CONTINUE]; IF indexStream = NIL THEN RETURN; }; indexStream.SetIndex[indexStream.GetLength[] - 10]; count _ indexStream.GetCard[]; alles _ RopeFile.Create[name: dataName, raw: FALSE !FS.Error => CONTINUE]; IF alles = NIL THEN RETURN; hold _ CONS[alles, hold]; indexStream.SetIndex[0]; [] _ indexStream.GetTime[]; dWeight _ weight * count; new[new.length] _ NEW [IndexRep[count]]; new[new.length].incrWeight _ dWeight; new.totalWeight _ new[new.length].sumWeight _ dWeight + (IF new.length > 0 THEN new[new.length-1].sumWeight ELSE 0); new[new.length].alles _ alles; FOR i: INT IN [0 .. count) DO new[new.length][i].pos _ indexStream.GetInt[]; ENDLOOP; indexStream.Close[]; new.length _ new.length + 1; END; NewWeightedIndexSet: PROC [size: CARDINAL] RETURNS [new: WeightedIndexSet] = {new _ NEW [WeightedIndexSetRep[size]]; new.totalWeight _ new.length _ 0}; Allocate: ENTRY PROC = {workers _ workers + 1}; Release: ENTRY PROC = {workers _ workers - 1; BROADCAST done}; workers: INTEGER _ 0; done: CONDITION; NoticeChanges: UserProfile.ProfileChangedProc --PROC [reason: ProfileChangeReason]-- = BEGIN newFiles: RopeList _ UserProfile.ListOfTokens[ key: "Cookie.Sources", default: LIST [ "Almond.Cookies", "Legal.Cookies", "Doit.LOTS", "Snippets", "Dans.Cookies"]]; temp1, temp2: RopeList; defaultProbability _ IO.RIS[UserProfile.Token[key: "Cookie.Probability", default: "0.1"]].GetReal[! IO.Error => CONTINUE]; defaultInitial _ UserProfile.Number[key: "Cookie.Initial", default: 1]; enabled _ UserProfile.Boolean[key: "Cookie.Enabled", default: FALSE]; IF NOT enabled THEN RETURN; Allocate[]; BEGIN ENABLE UNWIND => Release[]; IF workers > 1 THEN ERROR; temp1 _ files; temp2 _ newFiles; WHILE (temp1 # NIL) AND (temp2 # NIL) DO IF NOT temp1.first.Equal[temp2.first] THEN EXIT; temp1 _ temp1.rest; temp2 _ temp2.rest; ENDLOOP; IF (temp1 # NIL) OR (temp2 # NIL) THEN BEGIN weight: REAL _ 1.0; files _ newFiles; fileSizes _ NIL; cookies.totalWeight _ cookies.length _ 0; FOR newFiles _ newFiles, newFiles.rest WHILE newFiles # NIL DO r: ROPE _ newFiles.first; IF r.Length[] = 0 THEN LOOP; IF r.Fetch[0] IN ['0 .. '9] THEN BEGIN in: IO.STREAM _ IO.RIS[r]; weight _ in.GetReal[!IO.Error => CONTINUE]; END ELSE BEGIN count: INT; [cookies, count] _ AddFile[cookies, weight, r]; fileSizes _ CONS[[r, count], fileSizes]; END ENDLOOP; END; END; Release[]; END; MakeIndex: PROC [rootName, wdir: ROPE] = BEGIN in, index: IO.STREAM _ NIL; created: BasicTime.GMT; count: CARDINAL _ 0; inName: ROPE _ FS.ExpandName[rootName, wdir].fullFName; outName: ROPE _ FS.ExpandName[rootName.Concat[".Index"], wdir].fullFName; in _ FS.StreamOpen[inName !FS.Error => CONTINUE]; index _ FS.StreamOpen[outName, create !FS.Error => CONTINUE]; IF in = NIL OR index = NIL THEN RETURN; [created: created] _ FS.FileInfo[inName]; index.PutF["%g\n", IO.time[created]]; DO where: INT _ in.GetIndex[]; [] _ in.SkipWhitespace[]; IF in.EndOf[] THEN EXIT; index.PutF[" %g", IO.card[where]]; [] _ in.GetRopeLiteral[]; count _ count + 1; ENDLOOP; index.PutF["\n %8g\n", IO.card[count]]; index.Close[]; END; FileSize: TYPE = RECORD [ name: ROPE, count: INT]; fileSizes: LIST OF FileSize _ NIL; ConvertVanilla: PROC [fromName, toName: ROPE] = BEGIN from, to: IO.STREAM; from _ FS.StreamOpen[fromName]; to _ FS.StreamOpen[toName, create]; WHILE NOT from.EndOf[] DO fortune: ROPE; fortune _ from.GetLineRope[]; to.PutF["\"%q\"\n", IO.rope[fortune]]; ENDLOOP; from.Close[]; to.Close[]; END; ConvertHacker: PROC [fromName, toName: ROPE] = BEGIN from, to: IO.STREAM; author, msg: ROPE _ NIL; tabs: INT _ 0; from _ FS.StreamOpen[fromName]; to _ FS.StreamOpen[toName, create]; WHILE NOT from.EndOf[] DO toke: ROPE _ from.GetTokenRope[CreditBreak].token; IF toke.Equal["\n"] THEN BEGIN IF msg.Length[] > 0 THEN {IF author.Length[] > 0 THEN to.PutF["\"%q -- %g\"\n", IO.rope[msg], IO.rope[author]] ELSE to.PutF["\"%q\"\n", IO.rope[msg]]}; author _ msg _ NIL; tabs _ 0; END ELSE IF toke.Equal["\t"] THEN {IF (tabs _ tabs+1) > 2 THEN ERROR} ELSE SELECT tabs FROM 0 => IF toke.Length[] # 1 THEN ERROR; 1 => author _ toke; 2 => msg _ toke; ENDCASE => ERROR; ENDLOOP; from.Close[]; to.Close[]; END; CreditBreak: IO.BreakProc --PROC [char: CHAR] RETURNS [CharClass]-- = {RETURN [SELECT char FROM '\n, '\t => break, ENDCASE => other]}; ConvertParagraphs: PROC [fromName, toName: ROPE] = BEGIN from, to: IO.STREAM; msg: ROPE _ NIL; from _ FS.StreamOpen[fromName]; to _ FS.StreamOpen[toName, create]; WHILE NOT from.EndOf[] DO toke: ROPE _ from.GetLineRope[]; IF toke.Length[] = 0 THEN BEGIN to.PutF["\"%q\"\n", IO.rope[msg]]; msg _ NIL; END ELSE BEGIN IF msg = NIL THEN BEGIN first: CHAR _ toke.Fetch[0]; IF first IN [0C .. IO.SP] THEN ERROR; msg _ toke; END ELSE msg _ msg.Cat["\n", toke]; END; ENDLOOP; from.Close[]; to.Close[]; END; ConvertStringy: PROC [fromName, toName, sep: ROPE] = BEGIN from: ROPE _ RopeFile.Create[name: fromName]; fromLength: INT = from.Length[]; to: IO.STREAM = FS.StreamOpen[toName, create]; sepLen: INT = sep.Length[]; start: INT _ 0; WHILE start < fromLength DO sepStart: INT _ Rope.Index[s1: from, s2: sep, case: TRUE, pos1: start]; to.PutF["\"%q\"\n", IO.rope[from.Substr[start: start, len: sepStart - start]]]; start _ sepStart + sepLen; ENDLOOP; to.Close[]; END; ConvertNodes: PROC [fromName, toName: ROPE] = BEGIN fromRoot: TextNode.Ref _ PutGet.FromFile[fromName]; cur: TextNode.Ref _ fromRoot; to: IO.STREAM _ FS.StreamOpen[toName, create]; WHILE (cur _ TextNode.StepForward[cur]) # NIL DO tn: TextNode.RefTextNode _ TextNode.NarrowToTextNode[cur]; r: ROPE _ NIL; IF tn # NIL THEN r _ TextNode.NodeRope[tn]; IF r.Length[] > 0 THEN to.PutF["\"%q\"\n", IO.rope[r]]; ENDLOOP; to.Close[]; END; CookieControl: TYPE = REF CookieControlRep; CookieControlRep: TYPE = RECORD [ probability: REAL _ 0.1, ferSure: INT _ 1 --because I can italicize in an After proc, but not a directly invoked one! ]; giveCookieHandle: Commander.CommandProcHandle _ NEW [Commander.CommandProcObject _ [proc: GiveCookie]]; NumArgs: INT = 2; names: ARRAY [0 .. NumArgs) OF ROPE = ["Probability", "Initial"]; Cookit: PROC [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL] --Commander.CommandProc-- = BEGIN cmdLine: IO.STREAM _ IO.RIS[cmd.commandLine]; index: CARDINAL _ 0; cc: CookieControl; cc _ NARROW[List.Assoc[aList: cmd.propertyList, key: $CookieControl]]; IF cc = NIL THEN BEGIN cmd.propertyList _ List.PutAssoc[ aList: cmd.propertyList, key: $CookieControl, val: cc _ NEW [CookieControlRep _ []]]; cmd.propertyList _ CommandTool.AddProcToList[aList: cmd.propertyList, listKey: $After, proc: giveCookieHandle]; END; cc^ _ [defaultProbability, defaultInitial]; [] _ cmdLine.SkipWhitespace[]; WHILE NOT cmdLine.EndOf[] DO name, value, temp: ROPE _ NIL; kind: IO.TokenKind; [kind, value, ] _ cmdLine.GetCedarTokenRope[]; SELECT kind FROM tokenDECIMAL, tokenREAL => IF index < NumArgs THEN name _ names[index] ELSE {result _ $Failure; msg _ syntaxErrMsg}; tokenID => BEGIN name _ value; [kind, value, ] _ cmdLine.GetCedarTokenRope[!IO.Error, IO.EndOfStream => {result _ $Failure; msg _ syntaxErrMsg; CONTINUE}]; IF result = $Failure THEN RETURN; IF value.Equal["="] OR value.Equal["_"] OR value.Equal["~"] OR value.Equal[":"] THEN [kind, value, ] _ cmdLine.GetCedarTokenRope[!IO.Error, IO.EndOfStream => {result _ $Failure; msg _ syntaxErrMsg; CONTINUE}]; END; ENDCASE => {result _ $Failure; msg _ syntaxErrMsg}; IF result = $Failure THEN RETURN; IF name.Equal["probability", FALSE] THEN cc.probability _ IO.RIS[value].GetReal[!IO.Error, IO.EndOfStream => {result _ $Failure; msg _ syntaxErrMsg; CONTINUE}] ELSE IF name.Equal["initial", FALSE] THEN cc.ferSure _ IO.RIS[value].GetInt[!IO.Error, IO.EndOfStream => {result _ $Failure; msg _ syntaxErrMsg; CONTINUE}] ELSE {result _ $Failure; msg _ IO.PutFR["No such keyword as \"%q\"", IO.rope[name]]}; IF result = $Failure THEN RETURN; [] _ cmdLine.SkipWhitespace[]; index _ index + 1; ENDLOOP; IF (NOT enabled) AND (cc.probability > 0 OR cc.ferSure > 0) THEN messages _ messages.Cat["You won't get your cookies because your profile doesn't enable Cookie.\n"]; END; syntaxErrMsg: ROPE = "Syntax Error. Correct Usage: Cookie [[Probability [=|_|~|:]] [[Initial [=|_|~|:]] ]]"; messages: ROPE _ NIL; GiveCookie: PROC [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL] --Commander.CommandProc-- = BEGIN toDo: INT _ rs.ChooseInt[min: 0, max: 999999999]; cc: CookieControl _ NARROW[List.Assoc[key: $CookieControl, aList: cmd.propertyList]]; IF messages # NIL THEN { cmd.out.PutF["%l%g%l", IO.rope["bi"], IO.rope[messages], IO.rope["BI"]]; messages _ NIL}; IF enabled THEN { WHILE cc.ferSure > 0 DO cc.ferSure _ cc.ferSure - 1; [] _ ReallyGiveCookie[cmd]; ENDLOOP; IF cc.probability*1E9 > toDo THEN [] _ ReallyGiveCookie[cmd]; }; END; ReallyGiveCookie: PROC [cmd: Commander.Handle] = BEGIN Enter: ENTRY PROC = {WHILE workers > 0 DO WAIT done ENDLOOP}; Enter[]; IF cookies.length = 0 THEN cmd.out.PutF["%lNo cookies to give! (your UserProfile entry \"Cookie.Sources\" lists only bad files%l\n", IO.rope["bi"], IO.rope["BI"]] ELSE BEGIN spot: REAL _ cookies.totalWeight*rs.ChooseInt[min: 0, max: 1000000000]/1000000000.0; file, entry: CARDINAL; is: IO.STREAM; rope: ROPE; FOR file _ 0, file+1 DO IF cookies[file].sumWeight >= spot THEN EXIT; ENDLOOP; entry _ rs.ChooseInt[min: 0, max: cookies[file].size-1]; is _ IO.RIS[cookies[file].alles.Substr[start: cookies[file][entry].pos]]; rope _ is.GetRopeLiteral[]; cmd.out.PutF["%l%s%l\n", IO.rope["i"], IO.rope[rope], IO.rope["I"]]; is.Close[]; END; END; Randomize: Booting.RollbackProc --PROC[clientData: REF ANY]-- = {rs _ Random.Create[seed: -1]}; TRUSTED {Process.InitializeCondition[@done, Process.SecondsToTicks[1]]}; Randomize[NIL]; Booting.RegisterProcs[r: Randomize]; UserProfile.CallWhenProfileChanges[NoticeChanges]; Commander.Register[key: "Cookie", proc: Cookit, doc: "sets up fortune cookery"]; END. XCookie.Mesa last fiddled by Spreitzer May 6, 1985 9:37:51 pm PDT ? weight _ 1.0; Κδ– "cedar" style˜Icode™ K™4K˜KšΟk œ-œœG˜ƒK˜šΠbxœœ˜Kšœ-œœH˜‚—K˜Kš˜K˜Kšœœœ˜Kš œ œœœœ˜K˜Kšœœœ˜1šœœœ˜$Kšœœ˜Kšœ œ˜Kšœ œœœ˜+—K˜Kšœœœ ˜šœ œœ˜Kšœœ˜Kšœœ˜ Kšœ œœœ ˜0—K˜Kšœ œœœ˜%K˜Kšœœ˜Kšœ4˜4Kšœœ˜Kšœœ˜Kšœœ)˜AK˜Kšœœ˜Kšœœ˜Kšœ œœ˜K˜š Οnœœ œ œœ œ˜pKš˜Kšœ œœœ˜Kšœœœ˜Kšœœœ˜'Kšœ œ˜K˜ šœœ˜Kšœœ"˜+K˜K˜!šœœœ˜&K˜Kšœ˜—K˜—Kšœ ˜Kšœ œ4˜AKšœ œE˜SKšœœœ œ˜=šœœœ˜Kšœœ˜1Kšœœ˜,Kšœ œœ œ ˜?Kšœœœ˜,Kšœ˜Kšœ˜—Kšœœ˜šœœœ˜K˜XKšœ(˜(Kšœœ˜Kšœœœ œ˜=Kšœœœœ˜!Kšœ˜—K˜3Kšœ˜Kšœ-œœ œ˜JKšœ œœœ˜Kšœœ˜K˜Kšœ˜Kšœ˜Kšœœ˜(Kšœ%˜%šœ-˜-Kšœ œœœ˜F—Kšœ˜šœœœ˜K˜.Kšœ˜—K˜Kšœ˜Kšœ˜—K˜šŸœœœœ˜LKšœœ˜'Kšœ"˜"—K˜KšŸœœœ˜/KšŸœœœ œ˜>Kšœ œ˜Kšœ œ˜K˜šŸ œ!Οc&œ˜VKš˜šœ.˜.Kšœ˜šœ œ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ˜——K˜Kš œœœIœ œ˜zKšœG˜GKšœ>œ˜EKšœœ œœ˜˜ Kšœœœ˜!Kšœ œœ˜K˜K˜š œ œœ œ˜(Kšœœ œœ˜0K˜K˜Kšœ˜—šœ œœ œ˜!šœ˜ Kšœœ˜Kšœœ˜"Kšœ)˜)šœ$œ œ˜>Kšœœ˜Kšœœœ˜šœ œ ˜ Kš˜Kš œœœœœ˜Kšœœ œ˜+Kš˜—šœ˜ Kšœœ˜ K˜/K™Kšœ œ˜(Kš˜—Kšœ˜—Kšœ˜——Kšœ˜—K˜ Kšœ˜—K˜šŸ œœœ˜(Kš˜Kšœ œœœ˜Kšœœ˜Kšœœ˜Kšœœœ&˜7Kšœ œœ7˜IKšœœœ œ˜1Kšœœœ œ˜=Kš œœœ œœœ˜'Kšœœ˜)Kšœœ˜%š˜Kšœœ˜K˜Kšœ œœ˜Kšœœ˜"K˜K˜Kšœ˜—Kšœœ˜'K˜Kšœ˜—K˜šœ œœ˜Kšœœ˜ Kšœœ˜ —K˜Kšœ œœ œ˜"K˜šŸœœœ˜/Kš˜Kšœ œœ˜Kšœœ˜Kšœœ˜#šœœ˜Kšœ œ˜K˜Kšœœ˜&Kšœ˜—K˜ K˜ Kšœ˜—K˜šŸ œœœ˜.Kš˜Kšœ œœ˜Kšœ œœ˜Kšœœ˜Kšœœ˜Kšœœ˜#šœœ˜Kšœœ(˜2šœ˜Kš˜šœ˜šœœ˜Kšœœ œ˜=Kšœœ ˜(——Kšœœ˜K˜ Kš˜—šœœ˜Kšœœœœ˜#—šœœ˜Kšœœœœ˜%K˜K˜Kšœœ˜—Kšœ˜—K˜ K˜ Kšœ˜—K˜šŸ œœ  )œ˜Ešœœœ˜K˜Kšœ ˜——K˜šŸœœœ˜2Kš˜Kšœ œœ˜Kšœœœ˜Kšœœ˜Kšœœ˜#šœœ˜Kšœœ˜ šœ˜Kš˜Kšœœ ˜"Kšœœ˜ Kš˜—šœ˜ šœœ˜Kš˜Kšœœ˜Kš œœœœœœ˜%K˜ Kš˜—Kšœ˜Kšœ˜—Kšœ˜—K˜ K˜ Kšœ˜—K˜šŸœœœ˜4Kš˜Kšœœ#˜-Kšœ œ˜ Kšœœœœ˜.Kšœœ˜Kšœœ˜šœ˜Kšœ œ'œ˜GKšœœ9˜OKšœ˜Kšœ˜—K˜ Kšœ˜—K˜šŸ œœœ˜-Kš˜K˜3K˜Kšœœœœ˜.šœ%œ˜0Kšœ:˜:Kšœœœ˜Kšœœœ˜+Kšœœœ ˜7Kšœ˜—K˜ Kšœ˜—K˜Kšœœœ˜+šœœœ˜!Kšœ œ˜Kšœ œ K˜\Kšœ˜—K˜šœ/˜/Kšœ4˜7—K˜Kšœ œ˜Kšœœœœ˜AK˜šŸœœœ œœœœœ œ˜qKš˜Kš œ œœœœ˜-Kšœœ˜Kšœ˜Kšœœ;˜Fšœ˜ šœ˜ šœ!˜!Kšœ˜Kšœ˜Kšœ œ˜'—Kšœo˜oKšœ˜——Kšœ+˜+K˜šœœ˜Kšœœœ˜Kšœœ ˜K˜.šœ˜šœœ˜-Kšœ˜Kšœ)˜-—šœ ˜K˜ Kšœ-œœ8œ˜|Kšœœœ˜!šœœœœ˜OKšœ.œœ8œ˜—Kšœ˜—Kšœ,˜3—Kšœœœ˜!šœœ˜#Kš œœœœœ8œ˜{—šœœœ˜$Kš œœœœœ8œ˜v—Kšœœ$œ˜UKšœœœ˜!K˜K˜Kšœ˜—Kš œœ œœœe˜₯Kšœ˜—K˜šœœ ˜2K˜I—K˜Kšœ œœ˜K˜šŸ œœœ œœœœœ œ˜uKš˜Kšœœ)˜2Kšœœ;˜Ušœ œœ˜Kšœœ œœ ˜HKšœ œ˜—šœ œ˜šœ˜Kšœ˜Kšœ˜Kšœ˜—Kšœœ˜=K˜—Kšœ˜—K˜šŸœœ˜0Kš˜KšŸœœœœ œœœ˜=K˜šœ˜Kšœkœ œ ˜Œšœ˜ KšœœJ˜TKšœ œ˜Kšœœœ˜Kšœœ˜ šœ˜Kšœ!œœ˜-Kšœ˜—Kšœ8˜8Kšœœœ>˜IK˜Kšœœ œ œ ˜DK˜ Kšœ˜——Kšœ˜—K˜šŸ œ œ˜?Kšœ˜—K˜KšœA˜HKšœ œ˜K˜$K˜2K˜PK˜Kšœ˜—…—/&@b