[net.micro.mac] MacModula-2 bug fixes

stuart@gargoyle.UChicago.UUCP (Stuart A. Kurtz) (03/18/85)

Modula Corporation recently released bug fixes for their MacModula-2
product.  Performing the fix requires either typing in a 5 page Modula
program and running it, or sending your Master disk (together with $3.00
and various customer information) to Modula Corp.  In the interests
of saving everyone some time and/or money, I'm posting the program
(and the m-code .LOD file) to net.sources.mac.

Modula Corporation recommends running this program on the work disk, and
*NOT MODIFYING* your distributions disks.  The program modifies both
interpreter files (Modula-2 and Modula 2).

Stuart Kurtz				ihnp4!gargoyle!stuart
Dept. of Computer Science		stuart@uchicago.csnet
University of Chicago

P.S.  This posting has the official blessing of Modula Corporation.

stuart@gargoyle.UChicago.UUCP (Stuart A. Kurtz) (03/18/85)

Here's the listing of the bug fix program for MacModula-2's interpreters.
The compiled (m-code) version is also being posted in BinHex4.0 form.
(It's difficult but possible to compile on a 128K Mac.)

Stuart Kurtz				ihnp4!gargoyle!stuart
Dept. of Computer Science		stuart@uchicago.csnet
University of Chicago

------------------------------[cut here]------------------------------

(*  This program patches a number of potential problems in MacModula-2...
      1- Fixes a problem of the interpreter crashing at
         exit on some systems on a 128K Mac.
      2- Fixes SystemEvent trap.
      3- Fisex GetNamedResource trap.
      4- Fixes local variable problem in NewProcess
*)

MODULE Patch;
  FROM InOut            IMPORT  ClearScreen, WriteString, ReadString, WriteLn,
                                WriteCard, Read, WriteInt, Write;
  FROM ResourceManager  IMPORT  SizeResource, OpenResFile, GetResource,
                                ChangedResource, CloseResFile, ResError;
  FROM Strings          IMPORT  StrModToMac;
  FROM MacSystemTypes    IMPORT  Str255, Handle;
  FROM MemoryManager    IMPORT  HNoPurge, HPurge;
  
  CONST
    Same      =  11;    (* Number of similiar patch bytes for both *)
    bigCnt    =   5;    (* Number of patch bytes for Modula-2 *)
    smallCnt  =  6;    (* Number of patch bytes for Modula 2 *)
    Max        =  Same + bigCnt + smallCnt;
    GrandSum  =  8587;  (* Total vertical checksum *)
    
  TYPE
    patchRec =  RECORD
                  where : CARDINAL;    (* Byte location of byte to be
					* changed *)
                  bad    : CARDINAL;    (* Original value *)
                  good  :  CARDINAL;    (* New value to replace original
					 * value *)
                  chksum:  CARDINAL;
                END;
    buffer  =  POINTER TO ARRAY [0..32767] OF CHAR;
    bufhdl  =  POINTER TO buffer;
    
  VAR
    Data  :  ARRAY [1..Max] OF patchRec;
    RsrcHdl1, RsrcHdl2 : bufhdl;
    res1, res2  : INTEGER;
    ch  :  CHAR;
    
  PROCEDURE ChangeByte(Hdl : bufhdl; i : CARDINAL);
    VAR where : CARDINAL;
  BEGIN
    WITH Data[i] DO
      IF CHAR(bad) # Hdl^^[where] THEN  (* Verify old byte is bad *)
        IF CHAR(good) = Hdl^^[where] THEN (* Byte must be already changed *)
          WriteString('Patch #'); WriteCard(i,0);
          WriteString(' has already been patched!'); WriteLn;
        ELSE
          WriteString('Patch #'); WriteCard(i,0);
          WriteString(' has wrong byte! File must be corrupt!');
          WriteLn;
          Error;
        END;
      END;
      Hdl^^[where] := CHAR(good);    (* Change byte in resource *)
    END;
  END ChangeByte;
  
  PROCEDURE OpenResourceFiles;
    VAR macstr : Str255;
  BEGIN
    StrModToMac(macstr,'Modula-2');
    res1 := OpenResFile(macstr);        (* Open resource fork of Modula-2 *)
    IF res1 = -1 THEN
      WriteString('Could not open resource: Modula-2');
      WriteLn;
      Error;
    END;
    CheckError;
    RsrcHdl1 := GetResource('CODE',1);  (* Get the machine code *)
    IF RsrcHdl1 = NIL THEN
      WriteString('Cannot read code resource for Modula-2');
      WriteLn;
      Error;
    END;
    CheckError;
    HNoPurge(Handle(RsrcHdl1));            (* Lock our resource into memory *)
    
    StrModToMac(macstr,'Modula 2');
    res2 := OpenResFile(macstr);        (* Open resource fork of Modula 2 *)
    IF res2 = -1 THEN
      WriteString('Could not open resource: Modula 2');
      WriteLn;
      Error;
    END;
    CheckError;
    RsrcHdl2 := GetResource('CODE',1);  (* Get the machine code *)
    IF RsrcHdl2 = NIL THEN
      WriteString('Cannot read code resource for Modula 2');
      WriteLn;
      Error;
    END;
    CheckError;
    HNoPurge(Handle(RsrcHdl2));            (* Lock our resource into memory *)
  END OpenResourceFiles;
  
  PROCEDURE FixBigInterp;
    VAR i : CARDINAL;
  BEGIN
    FOR i := 1 TO Same DO                (* Change the similiar bytes *)
      ChangeByte(RsrcHdl1,i);
    END;
    FOR i := Same TO Same + bigCnt DO    (* Change the unique bytes *)
      ChangeByte(RsrcHdl1,i);
    END;
    WriteString('Changing resource'); WriteLn;
    ChangedResource(Handle(RsrcHdl1));  (* Flag the resource as changed *)
    CheckError;
    HPurge(Handle(RsrcHdl1));            (* Let the resource be purged *)
  END FixBigInterp;

  PROCEDURE CheckError;
    VAR err: INTEGER;
  BEGIN
    err := ResError();
    IF err # 0 THEN
      WriteString('error = ');
      WriteInt(err,0); WriteLn;
      Error;
    END;
  END CheckError;
  
  PROCEDURE FixSmallInterp;
    VAR i : CARDINAL;
  BEGIN
    FOR i := 1 TO Same DO                (* Change the similiar bytes *)
      ChangeByte(RsrcHdl2,i);
    END;
    FOR i := Same + bigCnt + 1 TO Same + bigCnt + smallCnt DO
      ChangeByte(RsrcHdl2,i);
    END;
    WriteString('Changing resource'); WriteLn;
    ChangedResource(Handle(RsrcHdl2));  (* Flag the resource as changed *)
    CheckError;
    HPurge(Handle(RsrcHdl2));            (* Let the resource be purged *)
  END FixSmallInterp;

  PROCEDURE Error;
    VAR ch : CHAR;
  BEGIN
    WriteString('Hit any key to Halt...(Files will probably not be updated)');
    Read(ch);
    HALT;
  END Error;
  
  PROCEDURE CheckData;   (* Verify that the data has been entered correctly *)
    VAR i, calcSum : CARDINAL;
  BEGIN
    WriteString('Checking data...'); WriteLn;
    calcSum := 0;
    FOR i := 1 TO Max DO
      WITH Data[i] DO
        IF where + bad + good # chksum THEN
          WriteString('Inconsistant data in array element: ');
          WriteCard(i,0); WriteLn;
          WriteString('Check the data initialization section carefully!');
          WriteLn;
          Error;
        END;
        (* Perform an XOR checksum *)
        calcSum := CARDINAL(BITSET(calcSum) / BITSET(chksum));
      END;
    END;
    IF calcSum # GrandSum THEN
      WriteString('Total checksum (');
      WriteCard(calcSum,0);
      WriteString(') does not equal correct amount(');
      WriteCard(GrandSum,0);
      WriteString(').');
      WriteLn;
      Error;
    ELSE
      WriteString('Data is OK -- Patching can proceed.'); WriteLn;
    END;
  END CheckData;
  
BEGIN
  ClearScreen;
  
  (* Data Initialization Section *)
  
  Data[1].where    := 3358;    Data[1].bad        := 32;
  Data[1].good    := 103;      Data[1].chksum  := 3493;
  
  Data[2].where    := 3359;    Data[2].bad        := 68;
  Data[2].good    := 26;      Data[2].chksum  := 3453;
  
  Data[3].where    := 3361;    Data[3].bad        := 104;
  Data[3].good    := 68;      Data[3].chksum  := 3533;
  
  Data[4].where    := 3362;    Data[4].bad        := 0;
  Data[4].good    := 32;      Data[4].chksum  := 3394;
  
  Data[5].where    := 3363;    Data[5].bad        := 118;
  Data[5].good    := 104;      Data[5].chksum  := 3585;
  
  Data[6].where    := 3364;    Data[6].bad        := 50;
  Data[6].good    := 0;        Data[6].chksum  := 3414;
  
  Data[7].where    := 3365;    Data[7].bad        := 40;
  Data[7].good    := 118;      Data[7].chksum  := 3523;
  
  Data[8].where    := 3366;    Data[8].bad        := 0;
  Data[8].good    := 50;      Data[8].chksum  := 3416;
  
  Data[9].where    := 3367;    Data[9].bad        := 8;
  Data[9].good    := 40;      Data[9].chksum  := 3415;
  
  Data[10].where  := 3368;    Data[10].bad        := 66;
  Data[10].good    := 0;        Data[10].chksum  := 3434;
  
  Data[11].where  := 3369;    Data[11].bad        := 130;
  Data[11].good    := 8;        Data[11].chksum  := 3507;
  
  Data[12].where  := 8608;    Data[12].bad        := 32;
  Data[12].good    := 34;      Data[12].chksum  := 8674;
  
  Data[13].where  := 8613;    Data[13].bad        := 16;
  Data[13].good    := 17;      Data[13].chksum  := 8646;
  
  Data[14].where  := 10611;    Data[14].bad        := 194;
  Data[14].good    := 178;      Data[14].chksum  := 10983;
  
  Data[15].where  := 15881;    Data[15].bad        := 2;
  Data[15].good    := 3;        Data[15].chksum  := 15886;
  
  Data[16].where  := 4279;    Data[16].bad        := 38;
  Data[16].good    := 40;      Data[16].chksum  := 4357;
  
  Data[17].where  := 3370;    Data[17].bad        := 52;
  Data[17].good    := 36;      Data[17].chksum  := 3458;
  
  Data[18].where  := 4558;    Data[18].bad        := 34;
  Data[18].good    := 50;      Data[18].chksum  := 4642;
  
  Data[19].where  := 4602;    Data[19].bad        := 34;
  Data[19].good    := 50;      Data[19].chksum  := 4686;
  
  Data[20].where  := 4646;    Data[20].bad        := 34;
  Data[20].good    := 50;      Data[20].chksum  := 4730;
  
  Data[21].where  := 7426;    Data[21].bad        := 49;
  Data[21].good    := 33;      Data[21].chksum  := 7508;
  
  Data[22].where  := 10385;    Data[22].bad        := 2;
  Data[22].good    := 3;        Data[22].chksum  := 10390;
  
  CheckData;
  OpenResourceFiles;
  
  WriteString('Patch Modula-2? ');
  Read(ch); Write(ch); WriteLn;
  IF CAP(ch) = 'Y' THEN
    FixBigInterp;
  END;
  
  WriteString('Patch Modula 2? ');
  Read(ch); Write(ch); WriteLn;
  IF CAP(ch) = 'Y' THEN
    FixSmallInterp;
  END;
  
  WriteString('Patching has been completed successfully!');
  WriteLn;
  WriteString('Hit any key to halt...');
  Read(ch);
  HALT;      (* Note: Program is intended to terminate with HALT *)
END Patch.