-- 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.