-- MungeStats.mesa
--   Edited by Sweet, February 3, 1981  11:06 AM

DIRECTORY
  AltoFileDefs,
  InlineDefs,
  IODefs,
  ImageDefs,
  MiscDefs,
  SegmentDefs,
  StreamDefs,
  StringDefs;

Munge: PROGRAM IMPORTS  ImageDefs, InlineDefs, IODefs, MiscDefs, SegmentDefs, StreamDefs, StringDefs =
  BEGIN OPEN IODefs, StringDefs, StreamDefs;
  in1, in2: StreamHandle;
  line1: STRING ← [200];
  line2: STRING ← [200];
  token1: STRING ← [40];
  token2: STRING ← [40];
  beforeFile: STRING ← [40];
  afterFile: STRING ← [40];
  n1, n2: CARDINAL;

  commandStream: StreamHandle;

  SetUpCommands: PROCEDURE =
    BEGIN
    cfa: POINTER TO AltoFileDefs.CFA ← MiscDefs.CommandLineCFA[];
    cfile: SegmentDefs.FileHandle ← SegmentDefs.InsertFile[@cfa.fp,Read];
    commandStream ← NIL;
    commandStream ← CreateByteStream[cfile,Read
      ! SegmentDefs.InvalidFP => CONTINUE];
    IF commandStream # NIL THEN
      BEGIN
      JumpToFA[commandStream,@cfa.fa];
      WHILE commandStream.get[commandStream
              ! StreamError => GOTO nocommands] <= SP DO
        NULL ENDLOOP;
      SetIndex[commandStream,ModifyIndex[GetIndex[commandStream],-1]];
      EXITS nocommands =>
        BEGIN commandStream.destroy[commandStream]; commandStream ← NIL END;
      END;
    END;

  ReadName: PROCEDURE [s: STRING] =
    BEGIN
    c: CHARACTER;
    IF commandStream = NIL THEN ReadID[s]
    ELSE
      BEGIN
      s.length ← 0;
      DO
        IF (c←commandStream.get[commandStream
              ! StreamError => GOTO endoffile]) <= SP THEN
          BEGIN IF s.length # 0 THEN RETURN END
  	ELSE BEGIN StringDefs.AppendChar[s,c]; WriteChar[c] END;
        REPEAT endoffile =>
          BEGIN commandStream.destroy[commandStream]; commandStream ← NIL END;
        ENDLOOP;
      END;
    END;

  ReadLines: PROC RETURNS [BOOLEAN] =
    BEGIN
    line1.length ← n1 ← 0;
    line2.length ← n2 ← 0;
    DO
      line1[n1] ← in1.get[in1 ! StreamError => EXIT];
      IF line1[n1] = CR THEN IF n1 = 0 THEN LOOP ELSE EXIT;
      n1 ← n1 + 1;
      ENDLOOP;
    line1.length ← n1;
    DO
      line2[n2] ← in2.get[in2 ! StreamError => EXIT];
      IF line2[n2] = CR THEN IF n2 = 0 THEN LOOP ELSE EXIT;
      n2 ← n2 + 1;
      ENDLOOP;
    line2.length ← n2;
    RETURN [n1*n2 # 0];
    END;

  Scan: PROC =
    BEGIN
    token1.length ← 0;
    WHILE n1 < line1.length AND (line1[n1] = SP OR line1[n1] = TAB) DO
      n1 ← n1 + 1;
      ENDLOOP;
    WHILE n1 < line1.length AND ~(line1[n1] = SP OR line1[n1] = TAB) DO
      AppendChar[token1, line1[n1]];
      n1 ← n1 + 1;
      ENDLOOP;
    token2.length ← 0;
    WHILE n2 < line2.length AND (line2[n2] = SP OR line2[n2] = TAB) DO
      n2 ← n2 + 1;
      ENDLOOP;
    WHILE n2 < line2.length AND ~(line2[n2] = SP OR line2[n2] = TAB) DO
      AppendChar[token2, line2[n2]];
      n2 ← n2 + 1;
      ENDLOOP;
    END;

  sourceChars, obj1, obj2: LONG INTEGER;

  tSource, tObj1, tObj2, dSource, dObj1, dObj2: LONG INTEGER ← 0;


  Decimal7: NumberFormat =
    [base: 10, unsigned: FALSE, zerofill: FALSE, columns: 7];
  Decimal8: NumberFormat =
    [base: 10, unsigned: FALSE, zerofill: FALSE, columns: 8];
  Decimal5: NumberFormat =
    [base: 10, unsigned: FALSE, zerofill: FALSE, columns: 5];
  Decimal2Z: NumberFormat =
    [base: 10, unsigned: TRUE, zerofill: TRUE, columns: 2];

  RJ: PROC [s: STRING, cols: CARDINAL] =
    BEGIN
    THROUGH (s.length..cols] DO WriteChar[SP] ENDLOOP;
    WriteString[s];
    END;

  LJ: PROC [s: STRING, cols: CARDINAL] =
    BEGIN
    WriteString[s];
    THROUGH (s.length..cols] DO WriteChar[SP] ENDLOOP;
    END;

  WriteLongNumber: PROC [n: LONG INTEGER, fmt: NumberFormat] =
    BEGIN
    s: STRING = [20];
    c: CARDINAL;
    f: CHARACTER = IF fmt.zerofill THEN '0 ELSE SP;
    AppendLongNumber[s, (IF fmt.unsigned THEN n ELSE ABS[n]), fmt.base];
    c ← s.length;
    IF ~fmt.unsigned AND n < 0  THEN 
      BEGIN
      c ← c + 1; 
      IF fmt.zerofill THEN WriteChar['-];
      END;
    THROUGH (c..fmt.columns] DO WriteChar[SP] ENDLOOP;
    IF ~fmt.unsigned AND n < 0 AND ~fmt.zerofill THEN WriteChar['-];
    WriteString[s];
    END;

  Results: PROC [sou, c1, c2: LONG INTEGER] =
    BEGIN
    delta, t: LONG INTEGER;
    it: INTEGER;
    WriteLongNumber[sou, Decimal8];
    WriteLongNumber[c1, Decimal8];
    WriteLongNumber[c2, Decimal8];
    delta ← c2 - c1;
    WriteLongNumber[delta, Decimal7];
    t ← (delta * 10000) / c1;
    it ← InlineDefs.LowHalf[t];
    IF it = 0 THEN RJ["0", 5]
    ELSE 
      BEGIN
      IF it IN (-100..0) THEN RJ["-", 5]
      ELSE WriteNumber[it / 100, Decimal5];
      WriteChar['.];
      WriteNumber[ABS[it] MOD 100, Decimal2Z];
      END;
    IF c1 / 512 # c2 / 512 THEN WriteChar['*];
    WriteChar[CR];
    END;

  Dashes: PROC [s: STRING] RETURNS [BOOLEAN] =
    BEGIN
    d: CARDINAL ← 0;
    FOR i: CARDINAL IN [0..s.length) DO
      IF s[i] = '- THEN d ← d + 1 ELSE d ← 0;
      IF d = 3 THEN RETURN[TRUE];
      ENDLOOP;
    RETURN[FALSE];
    END;

  DoIt: PROC =
    BEGIN
    DO
      BEGIN
      tSource ← 0;
      tObj1 ← 0;
      tObj2 ← 0;
      dSource ← 0;
      dObj1 ← 0;
      dObj2 ← 0;
      WriteChar[CR];
      WriteChar[CR];
      WriteChar[CR];
      WriteString["file 1: "L];
      ReadName[beforeFile];
      IF beforeFile.length = 0 THEN ImageDefs.StopMesa[];
      in1 ← NewByteStream[beforeFile, Read ! SegmentDefs.FileNameError => 
        GO TO cantFind];
      WriteChar[CR];
      WriteString["file 2: "L];
      ReadName[afterFile];
      in2 ← NewByteStream[afterFile, Read ! SegmentDefs.FileNameError => {
        in1.destroy[in1];
        GO TO cantFind}];
      WriteChar[CR];
      WriteChar[CR];
      LJ["MODULE", 35]; RJ["source", 8];
      RJ["obj/1", 8]; RJ["obj/2", 8];
      RJ["diff", 7]; RJ["%", 5];
      WriteChar[CR]; WriteChar[CR];
      DO
        IF ~ReadLines[] THEN GO TO badFormat;
        IF Dashes[line1] THEN EXIT;
        ENDLOOP;
      WHILE ReadLines[] DO
        IF Dashes[line1] OR Dashes[line2] THEN EXIT;
        n1 ← n2 ← 0;
        Scan[];
        IF ~EqualStrings[token1, token2] THEN GO TO unequalNames;
        LJ[token1, 35];
        Scan[];
        sourceChars ← StringToLongNumber[token1, 10];
        Scan[];
        Scan[];
        obj1 ← StringToLongNumber[token1, 10];
        obj2 ← StringToLongNumber[token2, 10];
        Results[sourceChars, obj1, obj2];
        tSource ← tSource + sourceChars;
        tObj1 ← tObj1 + obj1;
        tObj2 ← tObj2 + obj2;
        IF obj1 # obj2 THEN
          BEGIN
          dSource ← dSource + sourceChars;
          dObj1 ← dObj1 + obj1;
          dObj2 ← dObj2 + obj2;
          END;
        REPEAT
          unequalNames => {
            WriteChar[CR];
            WriteString[token1]; WriteString[" (from 1) and "];
            WriteString[token2]; WriteLine[" (from 2) should be equal"]};
        ENDLOOP;
      in1.destroy[in1]; in2.destroy[in2];
      LJ["<total modules>", 35]; Results[tSource, tObj1, tObj2];
      LJ["<modules with change>", 35]; Results[dSource, dObj1, dObj2];
      beforeFile.length ← 0; StringDefs.AppendString[beforeFile, afterFile];
      EXITS
        badFormat => WriteLine[" can't find start of stats"];
        cantFind => WriteLine[" file not found"];
      END;
      ENDLOOP;
    END;

  SetUpCommands[];
  DoIt[];
  END.