-- DataInput.mesa Edited by Sweet, 15-Jan-81 16:11:51 DIRECTORY IODefs: FROM "iodefs" USING [ControlZ, CR, SP, WriteString, TAB], LedgerDefs: FROM "ledgerdefs", StreamDefs: FROM "streamdefs", StringDefs: FROM "stringdefs", SystemDefs: FROM "systemdefs"; DataInput: PROGRAM IMPORTS IODefs, LedgerDefs, StreamDefs, StringDefs, SystemDefs EXPORTS LedgerDefs = BEGIN OPEN IODefs, StringDefs, LedgerDefs; SkipBlanks: PUBLIC PROCEDURE [ss: SubString, notTab: BOOLEAN _ FALSE] = BEGIN DO IF Exhausted[ss] THEN RETURN; SELECT CurrentChar[ss] FROM TAB => IF notTab THEN RETURN ELSE Bump[ss]; SP => Bump[ss]; CR => WarnSS["Unexpected end of line", ss]; ENDCASE => RETURN; ENDLOOP; END; GetNumber: PUBLIC PROCEDURE [ss: SubString, defaultOK: BOOLEAN _ FALSE, default: INTEGER _ 0] RETURNS [val: INTEGER] = BEGIN neg: BOOLEAN _ FALSE; c: CHARACTER; SkipBlanks[ss]; DO IF Exhausted[ss] THEN GO TO noNum; SELECT (c _ CurrentChar[ss]) FROM '- => neg _ TRUE; IN ['0..'9] => EXIT; ENDCASE => GO TO noNum; Bump[ss]; REPEAT noNum => BEGIN IF ~defaultOK THEN WarnSS["Missing number", ss]; RETURN [default]; END; ENDLOOP; val _ 0; WHILE c IN ['0..'9] DO val _ 10*val+(c-'0); Bump[ss]; IF Exhausted[ss] THEN EXIT; c _ CurrentChar[ss]; ENDLOOP; IF neg THEN val _ -val; RETURN END; GetLongNumber: PROCEDURE [ss: SubString, defaultOK: BOOLEAN _ FALSE, default: LONG INTEGER _ 0] RETURNS [val: LONG INTEGER] = BEGIN neg: BOOLEAN _ FALSE; c: CHARACTER; SkipBlanks[ss]; DO IF Exhausted[ss] THEN GO TO noNum; SELECT (c _ CurrentChar[ss]) FROM '- => neg _ TRUE; IN ['0..'9] => EXIT; ENDCASE => GO TO noNum; Bump[ss]; REPEAT noNum => BEGIN IF ~defaultOK THEN WarnSS["Missing number", ss]; RETURN [default]; END; ENDLOOP; val _ 0; WHILE c IN ['0..'9] DO val _ 10*val+(c-'0); Bump[ss]; IF Exhausted[ss] THEN EXIT; c _ CurrentChar[ss]; ENDLOOP; IF neg THEN val _ -val; RETURN END; GetMoney: PUBLIC PROCEDURE [ss: SubString] RETURNS [val: Money, deductable: BOOLEAN] = BEGIN neg, brkt: BOOLEAN _ FALSE; SkipBlanks[ss]; IF CurrentChar[ss] = '< THEN BEGIN neg _ brkt _ TRUE; Bump[ss] END; IF CurrentChar[ss] = '- THEN BEGIN neg _ TRUE; Bump[ss]; END; val _ IF CurrentChar[ss] = '. THEN 0 ELSE GetLongNumber[ss]*100; IF CurrentChar[ss] = '. THEN BEGIN Bump[ss]; val _ val + GetLongNumber[ss, TRUE, 0]; END; IF brkt THEN IF CurrentChar[ss] # '> THEN WarnSS["Missing <",ss] ELSE Bump[ss]; IF neg THEN val _ -val; SELECT CurrentChar[ss] FROM 'T, 't => BEGIN Bump[ss]; deductable _ TRUE; END; ENDCASE => deductable _ FALSE; RETURN END; defaultYear: [60..99] _ 60; yearDefaultable: BOOLEAN _ FALSE; lastDate: PUBLIC SmallDate _ NullDate; GetDate: PROCEDURE [ss: SubString] RETURNS [dd: SmallDate] = BEGIN m: CARDINAL; SkipBlanks[ss, TRUE]; IF CurrentChar[ss] = TAB THEN IF lastDate = NullDate THEN WarnSS["Invalid date",ss] ELSE RETURN [lastDate]; dd.cv _ 0; m _ GetNumber[ss]; IF CurrentChar[ss] # '/ THEN IF lastDate = NullDate THEN WarnSS["Invalid date",ss] ELSE {lastDate.day _ m; dd _ lastDate; RETURN}; dd.month _ m; Bump[ss]; dd.day _ GetNumber[ss]; IF CurrentChar[ss] = '/ THEN BEGIN Bump[ss]; dd.year _ GetNumber[ss, yearDefaultable, defaultYear]; END ELSE IF yearDefaultable THEN dd.year _ defaultYear ELSE WarnSS["Invalid date",ss]; lastDate _ dd; RETURN END; lastCheck: PUBLIC CARDINAL _ NullCheck; GetCheck: PROC [ss: SubString] RETURNS [CARDINAL] = BEGIN SkipBlanks[ss, TRUE]; IF CurrentChar[ss] = TAB THEN IF lastCheck = NullCheck THEN WarnSS["Missing Check number",ss] ELSE RETURN [lastCheck _ lastCheck + 1]; RETURN[lastCheck _ GetNumber[ss]]; END; GetUpTo: PUBLIC PROCEDURE [ss: SubString, stop: CHARACTER] RETURNS [ans: STRING] = BEGIN adesc: SubStringDescriptor _ ss^; DO IF Exhausted[ss] THEN BEGIN ws: STRING _ [15]; AppendString[ws, "Missing "]; IF stop = IODefs.TAB THEN AppendString[ws, ""] ELSE AppendChar[ws, stop]; WarnSS[ws, ss]; END; IF CurrentChar[ss] = stop THEN EXIT; Bump[ss]; ENDLOOP; adesc.length _ ss.offset - adesc.offset; ans _ SystemDefs.AllocateHeapString[adesc.length]; AppendSubString[ans, @adesc]; END; GetCategory: PUBLIC PROCEDURE [ss: SubString] RETURNS [col: Column, note: STRING] = BEGIN key: STRING _ [10]; c: CHARACTER; SkipBlanks[ss]; IF Exhausted[ss] THEN WarnSS["Missing Category", ss]; DO IF Exhausted[ss] THEN EXIT; SELECT (c _ CurrentChar[ss]) FROM IN ['a..'z], IN ['A..'Z] => StringDefs.AppendChar[key, c]; ENDCASE => EXIT; Bump[ss]; ENDLOOP; FOR col IN Column DO IF StringDefs.EquivalentString[categoryKey[col], key] THEN EXIT; REPEAT FINISHED => WarnSS["Invalid category", ss]; ENDLOOP; SkipBlanks[ss]; IF ~Exhausted[ss] AND CurrentChar[ss] = '( THEN BEGIN Bump[ss]; note _ GetUpTo[ss, ')]; Bump[ss]; END ELSE note _ NIL; END; dateFirst: PUBLIC BOOLEAN; instring: STRING; InputLine: PUBLIC PROCEDURE [p: POINTER] RETURNS [CARDINAL] = BEGIN sip: POINTER TO SortItem = p; adesc: StringDefs.SubStringDescriptor _ [base: instring, offset: NULL, length: 1]; ss: StringDefs.SubString = @adesc; DO ENABLE BadData => LOOP; GetLine[instring]; IF EndOfFile AND instring.length = 0 THEN BEGIN IODefs.WriteString["Sorting..."]; RETURN[0]; END; ss.offset _ 0; SkipBlanks[ss, TRUE]; IF Exhausted[ss] THEN LOOP; SELECT CurrentChar[ss] FROM TAB, IN ['0..'9] => BEGIN IF dateFirst THEN BEGIN sip.date _ GetDate[ss]; SkipBlanks[ss, TRUE]; IF CurrentChar[ss] # TAB THEN WarnSS["missing TAB", ss]; Bump[ss]; sip.check _ GetCheck[ss]; END ELSE BEGIN sip.check _ GetCheck[ss]; SkipBlanks[ss, TRUE]; IF CurrentChar[ss] # TAB THEN WarnSS["missing TAB", ss]; Bump[ss]; sip.date _ GetDate[ss]; END; SkipBlanks[ss]; ss.length _ instring.length - ss.offset; sip.string _ [length: 0, maxlength: ss.length, text:]; StringDefs.AppendSubString[@sip.string, ss]; RETURN [SIZE[SortItem]+(ss.length+1)/2] END; 'y, 'Y => BEGIN SkipToken[ss]; yearDefaultable _ TRUE; defaultYear _ GetNumber[ss]; END; 'd, 'D => dateFirst _ TRUE; 'c, 'C => dateFirst _ FALSE; 't, 'T => BEGIN col: Column; val: Money; SkipToken[ss]; DO val _ GetMoney[ss].val; col _ GetCategory[ss].col; ytdTotal[col] _ val; SkipBlanks[ss]; IF Exhausted[ss] THEN EXIT; IF CurrentChar[ss] # '/ THEN WarnSS["Expected /", ss]; Bump[ss]; ENDLOOP; END; IODefs.ControlZ => NULL; -- ignore lines that start with ^Z ENDCASE => WarnSS["Bad input data",ss]; ENDLOOP; END; SkipToken: PROCEDURE [ss: StringDefs.SubString] = BEGIN DO Bump[ss]; SELECT CurrentChar[ss] FROM SP, TAB => EXIT; CR => WarnSS["Unexpected end of line",ss]; ENDCASE => NULL; ENDLOOP; END; EndOfFile: PUBLIC BOOLEAN; instream: PUBLIC StreamDefs.StreamHandle _ NIL; GetLine: PROCEDURE [instring: STRING] = BEGIN ch: CHARACTER; instring.length _ 0; IF EndOfFile THEN RETURN; DO ch _ instream.get[instream !StreamDefs.StreamError => IF error = StreamAccess THEN BEGIN EndOfFile _ TRUE; EXIT END]; IF ch = CR THEN EXIT; AppendChar[instring, ch]; ENDLOOP; RETURN END; instring _ SystemDefs.AllocateResidentPages[2]; instring^ _ [length: 0, maxlength: (512-2)*2, text: NULL]; END.