-- LedgerOptions.mesa Edited by Sweet, 30-Mar-81 22:28:43 DIRECTORY IODefs: FROM "iodefs", LedgerDefs: FROM "ledgerdefs", SegmentDefs: FROM "segmentdefs", StreamDefs: FROM "streamdefs", StringDefs: FROM "stringdefs", SystemDefs: FROM "systemdefs"; LedgerOptions: PROGRAM IMPORTS IODefs, LedgerDefs, SegmentDefs, StreamDefs, StringDefs, SystemDefs EXPORTS LedgerDefs = BEGIN OPEN IODefs, LedgerDefs; leftX, leftY, rightX, rightY: PUBLIC INTEGER ← 0; PrinterParam: TYPE = {leftX, leftY, rightX, rightY}; -- ************************************************************** -- Set up category keywords and names -- ************************************************************** categoryName: PUBLIC ARRAY Column OF STRING ← ALL[NIL]; categoryKey: PUBLIC ARRAY Column OF STRING ← ALL[NIL]; categoryNeg: PUBLIC ARRAY Column OF BOOLEAN ← ALL[FALSE]; totalInfo: PUBLIC ARRAY Column OF TotalRec ← ALL[[FALSE, FALSE, 0]]; extendedCats: PUBLIC BOOLEAN; budgetGiven: PUBLIC BOOLEAN ← FALSE; budget: PUBLIC ARRAY Column OF ARRAY [1..12] OF Money ← ALL[ALL[0]]; CopyString: PROCEDURE [old: STRING] RETURNS [new: STRING] = BEGIN new ← SystemDefs.AllocateHeapString[old.length]; StringDefs.AppendString[new, old]; END; TokenCol: PROCEDURE RETURNS [col: Column] = BEGIN FOR col IN Column DO IF StringDefs.EquivalentString[categoryKey[col], token] THEN EXIT; REPEAT FINISHED => WarnS["Invalid budget category",token]; ENDLOOP; RETURN END; us: StreamDefs.StreamHandle ← NIL; token: STRING; terminator: CHARACTER; ReadUserCm: PUBLIC PROCEDURE = BEGIN us ← StreamDefs.NewByteStream["Ledger.profile",StreamDefs.Read ! SegmentDefs.FileNameError => CONTINUE]; IF us = NIL THEN us ← StreamDefs.NewByteStream["User.cm",StreamDefs.Read ! SegmentDefs.FileNameError => CONTINUE]; IF us=NIL THEN WarnS["NO","Ledger.profile or User.cm"]; token ← SystemDefs.AllocateResidentPages[1]; token↑ ← [length: 0, maxlength: (256-2)*2, text: NULL]; BEGIN ENABLE UNWIND => BEGIN OPEN IODefs; ind: StreamDefs.StreamIndex = StreamDefs.GetIndex[us]; WriteString[" User.cm at index "]; WriteOctal[ind.page*256+ind.byte]; WriteChar[CR]; us.destroy[us]; us ← NIL; END; ReadCategories[]; ReadBudget[]; ReadTotals[]; ReadPrinterAdj[]; ReadControl[]; END; -- of enable FinishScanning[]; END; ReadCategories: PROCEDURE = BEGIN col: Column ← 0; IF ~StartScanning["[Ledger]"] THEN WarnS["NO","category names"]; DO IF NOT GetNextToken[] THEN EXIT; IF token[0]='[ THEN EXIT; IF terminator = ': THEN BEGIN IF token.length # 0 THEN categoryKey[col] ← CopyString[token]; IF ~GetNextToken[] OR (terminator # CR AND terminator # '") THEN WarnS["Multi-token category name not quoted", categoryKey[col]]; IF token.length # 0 THEN BEGIN IF token[0] = '- THEN BEGIN i: CARDINAL; categoryNeg[col] ← TRUE; FOR i IN [1..token.length) DO token[i-1] ← token[i]; ENDLOOP; token.length ← token.length-1; END; categoryName[col] ← CopyString[token]; END; col ← col+1; END; ENDLOOP; extendedCats ← col > BreakColumn; END; PParam: PROC RETURNS [PrinterParam] = BEGIN SELECT TRUE FROM StringDefs.EquivalentString[token, "leftX"L] => RETURN[leftX]; StringDefs.EquivalentString[token, "leftY"L] => RETURN[leftY]; StringDefs.EquivalentString[token, "rightX"L] => RETURN[rightX]; StringDefs.EquivalentString[token, "rightY"L] => RETURN[rightY]; ENDCASE => WarnS["funny printer param", token]; ERROR; END; ReadPrinterAdj: PROCEDURE = BEGIN desc: StringDefs.SubStringDescriptor; ss: StringDefs.SubString = @desc; IF ~StartScanning["[LedgerPrinter]"] THEN RETURN; DO IF NOT GetNextToken[] THEN EXIT; IF token[0]='[ THEN EXIT; IF terminator = ': THEN BEGIN pp: PrinterParam ← PParam[]; delta: INTEGER; [] ← GetNextToken[]; desc ← [base: token, offset: 0, length: 1]; delta ← GetNumber[ss]; SELECT pp FROM leftX => leftX ← delta; leftY => leftY ← delta; rightX => rightX ← delta; rightY => rightY ← delta; ENDCASE; END; ENDLOOP; END; ReadControl: PROCEDURE = BEGIN desc: StringDefs.SubStringDescriptor; ss: StringDefs.SubString = @desc; IF ~StartScanning["[LedgerControl]"] THEN RETURN; DO IF NOT GetNextToken[] THEN EXIT; IF token[0]='[ THEN EXIT; IF terminator = ': THEN BEGIN IF StringDefs.EquivalentString[token, "maxBSize"L] THEN BEGIN [] ← GetNextToken[]; desc ← [base: token, offset: 0, length: 1]; maxBSize ← GetNumber[ss]; END; END; ENDLOOP; END; ReadBudget: PROCEDURE = BEGIN OPEN StringDefs; col: Column; desc: SubStringDescriptor; ss: SubString = @desc; IF ~StartScanning["[Budget]"] THEN RETURN; DO IF NOT GetNextToken[] THEN EXIT; IF token[0]='[ THEN EXIT; IF terminator = ': THEN BEGIN val: Money; month: CARDINAL; col ← TokenCol[]; IF ~GetNextToken[] THEN WarnS["funny budget def", categoryKey[col]]; desc ← [base: token, offset: 0, length: 1]; val ← GetMoney[ss].val; SkipBlanks[ss]; IF categoryNeg[col] THEN val ← - val; FOR month IN [1..12] DO budget[col][month] ← val; ENDLOOP; UNTIL Exhausted[ss] DO IF CurrentChar[ss] # '/ THEN WarnSS["expected /", ss]; Bump[ss]; month ← GetNumber[ss]; IF month ~IN [1..12] THEN WarnSS["invalid month",ss]; IF CurrentChar[ss] # ': THEN WarnSS["missing :", ss]; Bump[ss]; val ← GetMoney[ss].val; IF categoryNeg[col] THEN val ← - val; budget[col][month] ← val; SkipBlanks[ss]; ENDLOOP; END; ENDLOOP; budgetGiven ← TRUE; END; ReadTotals: PROCEDURE = BEGIN desc: StringDefs.SubStringDescriptor; ss: StringDefs.SubString = @desc; IF ~StartScanning["[TotalColumns]"] THEN RETURN; DO IF NOT GetNextToken[] THEN EXIT; IF token[0]='[ THEN EXIT; IF terminator = ': THEN BEGIN col: Column = TokenCol[]; m: CARDINAL; addend: Column; IF ~GetNextToken[] THEN WarnS["funny total def", categoryKey[col]]; desc ← [base: token, offset: 0, length: 1]; totalInfo[col].isTotal ← TRUE; DO addend ← GetCategory[ss].col; totalInfo[addend].hasTotal ← TRUE; totalInfo[addend].myTotal ← col; FOR m IN [1..12] DO budget[col][m] ← budget[col][m] + budget[addend][m]; ENDLOOP; SkipBlanks[ss]; IF Exhausted[ss] THEN EXIT; IF CurrentChar[ss] # '+ THEN WarnS["Expected +", token]; Bump[ss]; ENDLOOP; END; ENDLOOP; END; StartScanning: PROCEDURE [section: STRING] RETURNS [BOOLEAN] = BEGIN us.reset[us]; WHILE GetNextToken[] DO IF StringDefs.EquivalentString[token,section] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; END; FinishScanning: PROCEDURE = BEGIN SystemDefs.FreePages[token]; token ← NIL; us.destroy[us]; us ← NIL; END; GetNextToken: PROCEDURE RETURNS [BOOLEAN] = BEGIN token.length ← 0; UNTIL us.endof[us] DO terminator ← us.get[us]; SELECT terminator FROM SP => IF (token.length#0) THEN RETURN[TRUE]; -- flush leading blanks ':, CR => RETURN[TRUE]; -- allow null tokens '" => BEGIN -- gobble things up until matching close quote UNTIL us.endof[us] DO terminator ← us.get[us]; IF terminator='" THEN EXIT; StringDefs.AppendChar[token,terminator]; ENDLOOP; END; ENDCASE => StringDefs.AppendChar[token,terminator]; ENDLOOP; RETURN[token.length#0]; END; END.