-- LedgerControl.mesa Edited by Sweet, March 30, 1981 10:36 PM DIRECTORY AltoDefs: FROM "altodefs" USING [CharsPerPage], GPsortDefs: FROM "gpsortdefs" USING [CompareProcType, Sort], IODefs: FROM "iodefs" USING [ ControlZ, CR, DEL, FF, ReadChar, ReadID, Rubout, SP, TAB, WriteChar, WriteLine, WriteString], LedgerDefs: FROM "ledgerdefs" USING [ bravoLedger, categoryKey, Column, DataInput, dateFirst, Destination, EndOfFile, FormCreate, InputLine, instream, lastCheck, lastDate, LedgerOptions, LedgerOut, LedgerOutput, MoneyToString, NewItem, NullCheck, NullDate, pageGroup, PageGroup, ProduceDetailReport, ReadUserCm, SortItem, ytdTotal], MiscDefs: FROM "miscdefs" USING [CallDebugger], OutputDefs: FROM "outputdefs" USING [ CloseOutput, OpenOutput, outStream, PutChar, PutCR, PutDecimal, PutString, PutSubString], PressDefs, SegmentDefs: FROM "segmentdefs" USING [ DefaultVersion, FileHandle, FileNameError, LockFile, NewFile, Read, ReleaseFile, UnlockFile], StreamDefs: FROM "streamdefs" USING [ CreateByteStream, GetIndex, Read, StreamHandle, StreamIndex], StringDefs: FROM "stringdefs" USING [ AppendChar, AppendDecimal, AppendString, SubString, SubStringDescriptor]; LedgerControl: PROGRAM IMPORTS GPsortDefs, IODefs, LedgerDefs, MiscDefs, OutputDefs, PressDefs, SegmentDefs, StreamDefs, StringDefs EXPORTS LedgerDefs = BEGIN OPEN PressDefs, LedgerDefs; debugging: BOOLEAN _ FALSE; BadData: PUBLIC SIGNAL = CODE; BadState: PUBLIC SIGNAL = CODE; WarnS: PUBLIC PROCEDURE [s1, s2: STRING] = BEGIN OPEN IODefs; WriteChar[CR]; WriteString[s1]; WriteChar[' ]; WriteLine[IF s2 = NIL THEN "" ELSE s2]; IF debugging THEN MiscDefs.CallDebugger["from WarnS"]; SIGNAL BadState; END; WarnSS: PUBLIC PROCEDURE [s1: STRING, ss2: StringDefs.SubString] = BEGIN OPEN IODefs; i: CARDINAL; WriteChar[CR]; WriteLine[s1]; WriteLine[ss2.base]; FOR i IN (0..ss2.offset) DO WriteChar[IF ss2.base[i-1] = TAB THEN TAB ELSE SP]; ENDLOOP; WriteChar['^]; WriteChar[CR]; IF debugging THEN MiscDefs.CallDebugger["from WarnSS"]; SIGNAL BadData; END; pfdbody: PressDefs.PressFileDescriptor; pfd: PUBLIC POINTER TO PressDefs.PressFileDescriptor _ @pfdbody; dest: Destination; StartFile: PROCEDURE [name: STRING, where: Destination] = BEGIN dest _ where; InitPressFileDescriptor[pfd, name]; END; FinishFile: PROCEDURE = BEGIN PressDefs.ClosePressFile[pfd]; END; LC: PROCEDURE [c1: CHARACTER] RETURNS [CHARACTER] = INLINE BEGIN RETURN [IF c1 IN ['A..'Z] THEN c1-'A+'a ELSE c1]; END; ComparePayee: PROCEDURE [s1, s2: STRING] RETURNS [INTEGER] = BEGIN c1, c2: CHARACTER; i: CARDINAL; FOR i IN [0..MIN[s1.length, s2.length]) DO c1 _ LC[s1[i]]; c2 _ LC[s2[i]]; IF c1 = IODefs.TAB THEN RETURN [IF c2 = IODefs.TAB THEN 0 ELSE -1]; IF c2 = IODefs.TAB THEN RETURN[1]; SELECT c1 FROM >c2 => RETURN[1]; RETURN[-1]; ENDCASE; ENDLOOP; SELECT s1.length FROM >s2.length => RETURN[1]; RETURN[-1]; ENDCASE => RETURN[0]; END; OrderByCheck: PROCEDURE[p1, p2: POINTER] RETURNS [INTEGER] = BEGIN sip1: POINTER TO SortItem = p1; sip2: POINTER TO SortItem = p2; SELECT sip1.check FROM >sip2.check => RETURN[1]; RETURN[-1]; ENDCASE; SELECT sip1.date.cv FROM >sip2.date.cv => RETURN[1]; RETURN[-1]; ENDCASE; RETURN [ComparePayee[@sip1.string, @sip2.string]]; END; OrderByDate: PROCEDURE[p1, p2: POINTER] RETURNS [INTEGER] = BEGIN sip1: POINTER TO SortItem = p1; sip2: POINTER TO SortItem = p2; SELECT sip1.date.cv FROM >sip2.date.cv => RETURN[1]; RETURN[-1]; ENDCASE; SELECT sip1.check FROM >sip2.check => RETURN[1]; RETURN[-1]; ENDCASE; RETURN [ComparePayee[@sip1.string, @sip2.string]]; END; OrderByPayee: PROCEDURE[p1, p2: POINTER] RETURNS [INTEGER] = BEGIN sip1: POINTER TO SortItem = p1; sip2: POINTER TO SortItem = p2; SELECT ComparePayee[@sip1.string, @sip2.string] FROM >0 => RETURN[1]; <0 => RETURN[-1]; ENDCASE; SELECT sip1.date.cv FROM >sip2.date.cv => RETURN[1]; RETURN[-1]; ENDCASE; SELECT sip1.check FROM >sip2.check => RETURN[1]; RETURN[-1]; ENDCASE => RETURN[0]; END; prevCheck: CARDINAL _ 0; markGaps: BOOLEAN _ FALSE; bravoOut: PUBLIC BOOLEAN _ FALSE; firstOut: PUBLIC BOOLEAN _ TRUE; AsciiOut: PROCEDURE [p: POINTER, len: CARDINAL] = BEGIN OPEN OutputDefs; sip: POINTER TO SortItem = p; desc: StringDefs.SubStringDescriptor _ [base: @sip.string, offset: 0, length: NULL]; ss: StringDefs.SubString = @desc; PutDecimal[sip.date.month]; PutChar['/]; PutDecimal[sip.date.day]; PutChar['/]; PutDecimal[sip.date.year]; PutChar[IODefs.TAB]; IF firstOut THEN IODefs.WriteString["Writing..."] ELSE IF markGaps AND prevCheck # 0 AND sip.check # prevCheck+1 THEN PutChar['*]; PutDecimal[sip.check]; PutChar[IODefs.TAB]; FOR i IN [0..sip.string.length) DO IF sip.string.text[i] = IODefs.ControlZ THEN BEGIN ss.length _ i; EXIT; END; REPEAT FINISHED => ss.length _ sip.string.length; ENDLOOP; PutSubString[ss]; IF bravoOut THEN BEGIN PutChar[IODefs.ControlZ]; IF firstOut THEN PutString["(0,4928)(1,6080)(2,9878)"]; END; PutCR[]; prevCheck _ sip.check; firstOut _ FALSE; END; inFile: SegmentDefs.FileHandle _ NIL; GetInFile: PROCEDURE = BEGIN OPEN IODefs, SegmentDefs; infileName: STRING _ [40]; DO WriteString[" input file: "]; ReadID[infileName]; WriteChar[CR]; inFile _ NewFile[infileName, Read, DefaultVersion ! FileNameError => LOOP]; EXIT; ENDLOOP; LockFile[inFile]; EndOfFile _ FALSE; END; CloseInFile: PROCEDURE = BEGIN IF instream # NIL THEN BEGIN instream.destroy[instream]; instream _ NIL; END; IF inFile # NIL THEN BEGIN SegmentDefs.UnlockFile[inFile]; SegmentDefs.ReleaseFile[inFile]; inFile _ NIL; END; END; Confirm: PROCEDURE [prompt: STRING] RETURNS [BOOLEAN] = BEGIN OPEN IODefs; WriteString[prompt]; DO SELECT ReadChar[] FROM 'y, 'y, CR => BEGIN WriteLine[" Yes"]; RETURN [TRUE]; END; 'n, 'N, DEL => BEGIN WriteLine[" No"]; RETURN[FALSE]; END; ENDCASE; ENDLOOP; END; ProduceBravoLedger: PROCEDURE = BEGIN OPEN StringDefs; bravoLedger _ TRUE; firstOut _ TRUE; instream _ StreamDefs.CreateByteStream[inFile, StreamDefs.Read]; EndOfFile _ FALSE; ytdTotal _ ALL[0]; IODefs.WriteString["Reading..."]; GPsortDefs.Sort[ get: InputLine, put: LedgerOut, compare: OrderByDate, expectedItemSize: 25, maxItemSize: 500, reservedPages: 110]; instream.destroy[instream]; instream _ NIL; NewItem[NullDate, 0, NIL, 0]; -- to finish current month END; DoDetail: PROCEDURE = BEGIN OPEN StringDefs; bravoLedger _ TRUE; firstOut _ TRUE; instream _ StreamDefs.CreateByteStream[inFile, StreamDefs.Read]; EndOfFile _ FALSE; IODefs.WriteString["Reading..."]; ProduceDetailReport[]; instream.destroy[instream]; instream _ NIL; END; ProduceLedger: PROCEDURE [dest: Destination, grp: PageGroup, ext: STRING] = BEGIN OPEN StringDefs; fileName: STRING _ [40]; i: CARDINAL; bravoLedger _ FALSE; instream _ StreamDefs.CreateByteStream[inFile, StreamDefs.Read]; EndOfFile _ FALSE; FOR i IN [0..outName.length) WHILE outName[i] # '. DO AppendChar[fileName, outName[i]]; ENDLOOP; AppendString[fileName, ext]; pageGroup _ grp; StartFile[fileName, dest]; IF grp # left THEN PressDefs.WritePage[pfd]; ytdTotal _ ALL[0]; IODefs.WriteString["Reading..."]; GPsortDefs.Sort[ get: InputLine, put: LedgerOut, compare: OrderByDate, expectedItemSize: 25, maxItemSize: 500, reservedPages: 110]; instream.destroy[instream]; instream _ NIL; NewItem[NullDate, 0, NIL, 0]; -- to finish current month IF grp # right THEN PressDefs.WritePage[pfd]; FinishFile[]; END; i: CARDINAL; outName: STRING _ [40]; outFiles: CARDINAL _ 0; tabString: PUBLIC STRING _ NIL; maxBSize: PUBLIC CARDINAL _ 30000; BravoNewPage: PUBLIC PROCEDURE = BEGIN OPEN OutputDefs; index: StreamDefs.StreamIndex = StreamDefs.GetIndex[outStream]; pos: CARDINAL = index.page * AltoDefs.CharsPerPage + index.byte; IF pos > maxBSize THEN BEGIN CloseOutput[]; outFiles _ outFiles + 1; OpenOutputFile[]; PutChar[IODefs.FF]; PutChar[IODefs.ControlZ]; PutString[tabString]; PutCR[]; END ELSE BEGIN PutChar[IODefs.FF]; PutCR[]; END; END; OpenOutputFile: PROCEDURE = BEGIN outExt: STRING _ [20]; dotSeen: BOOLEAN _ FALSE; outExt.length _ 0; FOR i IN [0..outName.length) DO IF outName[i] = '. THEN dotSeen _ TRUE; IF dotSeen THEN StringDefs.AppendChar[outExt, outName[i]]; ENDLOOP; IF outFiles > 1 THEN StringDefs.AppendDecimal[outExt, outFiles]; OutputDefs.OpenOutput[outName, outExt]; END; -- ************************************************************* -- Main body -- ************************************************************* BEGIN -- to set up exits START LedgerOptions; START FormCreate; START DataInput; START LedgerOutput; ReadUserCm[ ! BadData, BadState =>GO TO fini]; DO OPEN IODefs, OutputDefs; ENABLE BEGIN Rubout => BEGIN CloseInFile[]; WriteString[" XXX"]; LOOP END; BadData, BadState => BEGIN CloseInFile[]; WriteString[" ABORTED"]; LOOP END; END; dateFirst _ TRUE; -- unless told otherwise lastDate _ NullDate; lastCheck _ NullCheck; WriteChar[IODefs.CR]; WriteChar['_]; SELECT ReadChar[] FROM 'r, 'R, 's, 'S => BEGIN compare: GPsortDefs.CompareProcType; markGaps _ FALSE; WriteString["Reorder"]; GetInFile[]; instream _ StreamDefs.CreateByteStream[inFile, StreamDefs.Read]; DO WriteString[" Sorted by "]; SELECT ReadChar[] FROM 'c, 'C, 'n, 'N => BEGIN WriteString["check number"]; compare _ OrderByCheck; markGaps _ Confirm[" Mark gaps and non-zero duplicates?"]; END; 'p, 'P => BEGIN WriteString["payee"]; compare _ OrderByPayee; END; DEL => SIGNAL Rubout; ENDCASE => BEGIN WriteString["date"]; compare _ OrderByDate; END; IF Confirm[" [Confirm]"] THEN EXIT; WriteChar[CR]; ENDLOOP; WriteString["Output to: "]; ReadID[outName]; outFiles _ 1; OpenOutputFile[]; WriteChar[CR]; bravoOut _ Confirm["Bravo format? "]; WriteString["Reading..."]; firstOut _ TRUE; prevCheck _ 0; GPsortDefs.Sort[ get: InputLine, put: AsciiOut, compare: compare, expectedItemSize: 25, maxItemSize: 500, reservedPages: 110]; CloseInFile[]; CloseOutput[]; END; 'b, 'B => BEGIN WriteString["Bravo format ledger "]; GetInFile[]; instream _ StreamDefs.CreateByteStream[inFile, StreamDefs.Read]; WriteString["Output to: "]; ReadID[outName]; outFiles _ 1; OpenOutputFile[]; WriteChar[CR]; ProduceBravoLedger[]; CloseOutput[]; END; 'd, 'D => BEGIN WriteString["Detail Report "]; GetInFile[]; instream _ StreamDefs.CreateByteStream[inFile, StreamDefs.Read]; WriteString["Output to: "]; ReadID[outName]; outFiles _ 1; OpenOutputFile[]; WriteChar[CR]; bravoOut _ Confirm["Figure spaces? "]; DoDetail[]; CloseOutput[]; END; 'p, 'P, 'l, 'L => BEGIN d: Destination; WriteString["Produce ledger from"]; GetInFile[]; WriteString["Output name: "]; ReadID[outName]; WriteChar[CR]; IF Confirm["Separate files for left and right pages? "] THEN BEGIN ProduceLedger[d, left, ".left"]; ProduceLedger[d, right, ".right"]; END ELSE ProduceLedger[d, both, ".press"]; CloseInFile[]; BEGIN col: Column; ms: STRING _ [20]; first: BOOLEAN _ TRUE; OpenOutput["YTDTotals",".ts"]; FOR col IN Column DO IF ytdTotal[col] # 0 THEN BEGIN PutString[IF first THEN "TOTALS "L ELSE " / "L]; first _ FALSE; MoneyToString[ms, ytdTotal[col]]; PutString[ms]; PutChar[IODefs.SP]; PutString[categoryKey[col]]; END; ENDLOOP; PutCR[]; CloseOutput[]; END; END; 'q, 'Q => BEGIN WriteString["Quit"]; IF Confirm[" [Confirm]"] THEN GO TO fini END; ENDCASE => WriteLine["?"]; ENDLOOP; EXITS fini => NULL; END; END.