-- LedgerDetail.mesa Edited by Sweet, March 30, 1981 10:34 PM DIRECTORY GPsortDefs: FROM "gpsortdefs", InlineDefs: FROM "inlinedefs", IODefs: FROM "iodefs", LedgerDefs: FROM "ledgerdefs", OutputDefs: FROM "outputdefs", StringDefs: FROM "stringdefs", SystemDefs: FROM "systemdefs"; LedgerDetail: PROGRAM IMPORTS GPsortDefs, InlineDefs, IODefs, LedgerDefs, OutputDefs, StringDefs, SystemDefs EXPORTS LedgerDefs = BEGIN OPEN LedgerDefs; NRJOut: PUBLIC PROCEDURE [s: STRING, l: CARDINAL] = BEGIN OPEN OutputDefs; THROUGH [s.length..l) DO PutChar[IF bravoOut THEN IODefs.ControlY ELSE IODefs.SP]; ENDLOOP; PutString[s]; END; OrderByDetail: PUBLIC PROCEDURE[p1, p2: POINTER] RETURNS [INTEGER] = BEGIN dip1: POINTER TO DetailItem = p1; dip2: POINTER TO DetailItem = p2; SELECT dip1.category FROM >dip2.category => RETURN[1]; <dip2.category => RETURN[-1]; ENDCASE; SELECT dip1.date.cv FROM >dip2.date.cv => RETURN[1]; <dip2.date.cv => RETURN[-1]; ENDCASE; SELECT dip1.check FROM >dip2.check => RETURN[1]; <dip2.check => RETURN[-1]; ENDCASE => RETURN [0]; END; dBuffer: POINTER TO SortItem; nDetail: CARDINAL ← 0; maxDetail: CARDINAL ← 30; detail: POINTER TO ARRAY [0..0) OF InternalDetailItem; currentDate: SmallDate; currentCheck: CARDINAL; currentPayee: STRING; InternalDetailItem: TYPE = RECORD [ category: Column, amount: Money, taxded: BOOLEAN, comment: STRING]; SetPayee: PROCEDURE [payee: STRING, total: Money] = BEGIN currentPayee ← payee; END; AddDetail: PROCEDURE [col: Column, amt: Money, note: STRING, ded: BOOLEAN] = BEGIN IF nDetail = maxDetail THEN BEGIN newDetail: POINTER TO ARRAY [0..0) OF InternalDetailItem; maxDetail ← maxDetail + 20; newDetail ← SystemDefs.AllocateHeapNode[maxDetail]; InlineDefs.COPY[ from: detail, to: newDetail, nwords: (nDetail-1)*SIZE[InternalDetailItem]]; SystemDefs.FreeHeapNode[detail]; detail ← newDetail; END; IF categoryNeg[col] THEN amt ← - amt; detail[nDetail] ← [ category: col, amount: amt, taxded: ded, comment: note]; nDetail ← nDetail + 1; END; DetailInput: PUBLIC PROCEDURE [p: POINTER] RETURNS [CARDINAL] = BEGIN dip: POINTER TO DetailItem = p; DO ENABLE BadData => BEGIN OPEN IODefs; i: CARDINAL; WriteString[" Aborting item "]; WriteDecimal[currentDate.month]; WriteChar['/]; WriteDecimal[currentDate.day]; WriteChar['/]; WriteDecimal[currentDate.year]; WriteChar[SP]; WriteDecimal[currentCheck]; WriteChar[CR]; FOR i IN [0..nDetail) DO SystemDefs.FreeHeapString[detail[i].comment]; ENDLOOP; nDetail ← 0; LOOP END; IF nDetail = 0 THEN BEGIN desc: StringDefs.SubStringDescriptor; IF currentPayee # NIL THEN SystemDefs.FreeHeapString[currentPayee]; currentPayee ← NIL; IF InputLine[dBuffer] = 0 THEN RETURN[0]; currentDate ← dBuffer.date; currentCheck ← dBuffer.check; desc ← [base: @dBuffer.string, offset: 0, length: 1]; BreakApart[@desc, SetPayee, AddDetail]; END; IF nDetail = 0 THEN RETURN[0]; nDetail ← nDetail - 1; dip↑ ← [date: currentDate, check: currentCheck, category: detail[nDetail].category, amount: detail[nDetail].amount, taxded: detail[nDetail].taxded, text: [length: 0, maxlength: (200-SIZE[DetailItem])*2, text: ]]; StringDefs.AppendString[@dip.text, currentPayee]; StringDefs.AppendChar[@dip.text, IODefs.TAB]; IF detail[nDetail].comment # NIL THEN BEGIN StringDefs.AppendString[@dip.text, detail[nDetail].comment]; SystemDefs.FreeHeapNode[detail[nDetail].comment]; END; RETURN [SIZE[DetailItem]+(dip.text.length+1)/2]; ENDLOOP; END; lastCat: Column ← LAST[Column]; prevDate: SmallDate ← NullDate; monthTotal, yearTotal: Money; monthCount, yearCount: CARDINAL; taxDedOnly: PUBLIC BOOLEAN ← FALSE; DetailOutput: PUBLIC PROCEDURE [p: POINTER, len: CARDINAL] = BEGIN OPEN OutputDefs; dip: POINTER TO DetailItem = p; str: STRING = [30]; payee, note: STRING; desc: StringDefs.SubStringDescriptor ← [ base: @dip.text, offset: 0, length: 1]; DoMonthTotal: PROCEDURE = BEGIN IF monthCount > 1 THEN BEGIN mName: STRING = MonthName[prevDate.month]; PutString[mName]; PutString[" total"]; PutChar[IODefs.TAB]; str.length ← 0; MoneyToString[str, monthTotal]; NRJOut[str, 10]; PutChar[IODefs.ControlZ]; PutString["e4\bg"]; PutDecimal[mName.length+6]; PutString["t3 1t0"]; PutCR[]; END; yearTotal ← yearTotal + monthTotal; yearCount ← yearCount + 1; monthTotal ← 0; monthCount ← 0; END; DoYearTotal: PROC = BEGIN IF yearCount > 1 THEN BEGIN PutString["Annual total"]; PutChar[IODefs.TAB]; str.length ← 0; MoneyToString[str, yearTotal]; NRJOut[str, 10]; PutChar[IODefs.ControlZ]; PutString["e6\gb12t3 1t0"]; PutCR[]; END; yearCount ← 0; yearTotal ← 0; END; IF p = NIL THEN {DoMonthTotal[]; DoYearTotal[]; RETURN}; IF firstOut THEN BEGIN IODefs.WriteString["Writing..."]; firstOut ← FALSE; PutChar[IODefs.ControlZ]; PutString[tabString ← "(0,4608)(1,5664)(2,10272)(3,12384)"]; PutCR[]; END; IF dip.category # lastCat THEN BEGIN DoMonthTotal[]; DoYearTotal[]; lastCat ← dip.category; BravoNewPage[]; PrintCategoryName[dip.category]; PutChar[IODefs.ControlZ]; PutString["c\f5b"L]; PutCR[]; prevDate ← NullDate; END; IF dip.date.month # prevDate.month THEN BEGIN DoMonthTotal[]; PutCR[]; END; monthTotal ← monthTotal + dip.amount; monthCount ← monthCount + 1; prevDate ← dip.date; ADateOut[dip.date, dip.check]; PutChar[IODefs.TAB]; payee ← GetUpTo[@desc, IODefs.TAB]; Bump[@desc]; PutString[payee]; SystemDefs.FreeHeapString[payee]; PutChar[IODefs.TAB]; str.length ← 0; MoneyToString[str, dip.amount]; IF dip.taxded THEN StringDefs.AppendChar[str, 'T]; NRJOut[str, IF dip.taxded THEN 11 ELSE 10]; note ← GetRestOf[@desc]; IF note # NIL THEN BEGIN PutChar[IODefs.TAB]; PutString[note]; SystemDefs.FreeHeapNode[note]; END; PutChar[IODefs.ControlZ]; PutString["\g"L]; PutChar[IODefs.CR]; END; PrintCategoryName: PUBLIC PROCEDURE [cat: Column] = BEGIN OPEN OutputDefs; cName: STRING ← categoryName[cat]; ch: CHARACTER; i: CARDINAL; FOR i ← 0, i+1 WHILE i < cName.length DO ch ← cName[i]; SELECT ch FROM '- => IF cName[i+1] = '/ THEN i ← i+1 ELSE PutChar[ch]; '/ => PutChar[IODefs.SP]; ENDCASE => PutChar[ch]; ENDLOOP; END; GetRestOf: PUBLIC PROCEDURE [ss: StringDefs.SubString] RETURNS [rest: STRING] = BEGIN IF Exhausted[ss] THEN RETURN[NIL]; rest ← SystemDefs.AllocateHeapString[ss.base.length - ss.offset]; UNTIL Exhausted[ss] DO StringDefs.AppendChar[rest, CurrentChar[ss]]; Bump[ss]; ENDLOOP; END; ProduceDetailReport: PUBLIC PROCEDURE = BEGIN lastCat ← LAST[Column]; currentPayee ← NIL; prevDate ← NullDate; monthCount ← yearCount ← 0; monthTotal ← yearTotal ← 0; GPsortDefs.Sort[ get: DetailInput, put: DetailOutput, compare: OrderByDetail, expectedItemSize: 25, maxItemSize: 200, reservedPages: 110]; DetailOutput[NIL,0]; END; dBuffer ← SystemDefs.AllocateResidentPages[2]; detail ← SystemDefs.AllocateHeapNode[maxDetail * SIZE [InternalDetailItem]]; END.