m3cgcat/src/Main.m3


MODULE Main;

IMPORT IO, Params, Process, Stdio, Text, Rd, Wr, OSError;
IMPORT M3CG, M3CG_Rd, M3CG_Wr, M3CG_BinRd, M3CG_BinWr, MxConfig, Target, M3C;
IMPORT FileRd, FileWr, Word, RTIO, RTProcess;
FROM Thread IMPORT Alerted;

PROCEDURE TextFindEqual (a: TEXT; READONLY b: ARRAY OF TEXT): INTEGER =
BEGIN
  FOR i := FIRST (b) TO LAST (b) DO
    IF Text.Equal (a, b[i]) THEN
      RETURN i;
    END;
  END;
  RETURN -1;
END TextFindEqual;

PROCEDURE TextFindPrefix (a: TEXT; READONLY b: ARRAY OF TEXT): INTEGER =
VAR a_length := Text.Length (a);
BEGIN
  FOR i := FIRST (b) TO LAST (b) DO
    IF a_length >= Text.Length (b[i]) AND
        Text.Equal (Text.Sub (a, 0, Text.Length (b[i])), b[i]) THEN
      RETURN i;
    END;
  END;
  RETURN -1;
END TextFindPrefix;

PROCEDURE RdClose_DoNothing (a: Rd.T) RAISES {Rd.Failure, Alerted} <*NOWARN*>=
BEGIN END RdClose_DoNothing;

PROCEDURE WrClose_DoNothing (a: Wr.T) RAISES {Wr.Failure, Alerted} <*NOWARN*>=
BEGIN
END WrClose_DoNothing;

PROCEDURE DoIt () RAISES {Rd.Failure, Wr.Failure, Alerted, OSError.E} =
  TYPE Inhale_t = PROCEDURE (rd: Rd.T;  cg: M3CG.T);
       OutNew_t = PROCEDURE (wr: Wr.T): M3CG.T;
  CONST Inhale = ARRAY OF Inhale_t {M3CG_BinRd.Inhale, M3CG_Rd.Inhale};
  CONST OutNew = ARRAY OF OutNew_t {M3CG_BinWr.New, M3CG_Wr.New, M3C.New};
  CONST inout_text = ARRAY OF TEXT {"-in-", "-out-"};
  CONST types_text = ARRAY OF TEXT {"binary", "ascii", "c"};
  VAR arg : TEXT;
      inited := FALSE;
      rd_in := Stdio.stdin;
      wr_out := Stdio.stdout;
      arg_inout := 0;
      arg_type := 0;
      arg_length := 0;
      ch := '\000';
      inhale: Inhale_t := NIL;
      out_new: OutNew_t := NIL;
      rd_close := RdClose_DoNothing;
      wr_close := WrClose_DoNothing;
      any := FALSE;
  BEGIN
    TRY
      IF Params.Count < 2 THEN
        Usage ();
      END;
      IF Params.Count = 2 THEN
        arg := Params.Get (1);
        arg_type := TextFindEqual (arg, ARRAY OF TEXT { "-binary", "-ascii" });
        IF arg_type < 0 THEN
          Usage ();
          RETURN;
        END;
        Init ();
        Inhale[arg_type] (rd_in, OutNew[Word.Xor(arg_type, 1)] (wr_out));
        RETURN;
      END;
      FOR i := 1 TO Params.Count - 1 DO
        arg := Params.Get (i);
        arg_inout := TextFindPrefix (arg, inout_text);
        IF arg_inout < 0 THEN
          Usage ();
        END;
        arg := Text.Sub (arg, Text.Length (inout_text[arg_inout]));
        arg_type := TextFindPrefix (arg, types_text);
        IF arg_type < 0 THEN
          Usage ();
        END;
        IF arg_inout = 0 THEN
          inhale := Inhale[arg_type];
        ELSE
          out_new := OutNew[arg_type];
        END;
        arg := Text.Sub (arg, Text.Length (types_text[arg_type]));
        arg_length := Text.Length (arg);
        IF arg_length > 0 THEN
          ch := Text.GetChar (arg, 0);
          IF NOT (ch = ':' OR ch = '=') THEN
            Usage ();
          END;
          arg := Text.Sub (arg, 1);
          IF arg_inout = 0 THEN
            rd_close (rd_in);
            rd_in := FileRd.Open (arg);
            rd_close := Rd.Close;
          ELSE
            wr_close (wr_out);
            wr_out := FileWr.Open (arg);
            wr_close := Wr.Close;
          END;
        END;
        IF inhale # NIL AND out_new # NIL THEN
          IF NOT inited THEN
            Init ();
            inited := TRUE;
          END;
          inhale (rd_in, out_new (wr_out));
          any := TRUE;
          inhale := NIL;
          out_new := NIL;
          wr_close (wr_out);
          wr_close := WrClose_DoNothing;
          wr_out := NIL;
          rd_close (rd_in);
          rd_close := RdClose_DoNothing;
          rd_in := NIL;
        END;
      END;
      IF NOT any THEN
        Usage ();
      END;
    FINALLY
      wr_close (wr_out);
      rd_close (rd_in);
    END;
  END DoIt;

PROCEDURE Usage () =
  BEGIN
    IO.Put ("usage: " & Params.Get(0) & " -ascii  < in.asc > out.bin" & Wr.EOL);
    IO.Put ("       " & Params.Get(0) & " -binary < in.bin > out.asc" & Wr.EOL);
    IO.Put ("       " & Params.Get(0) & " -[in|out]-[binary|ascii|c] < in > out" & Wr.EOL);
    IO.Put ("       " & Params.Get(0) & " -[in|out]-[binary|ascii|c][:=file] < in > out" & Wr.EOL);
    IO.Put ("       example: " & Params.Get(0) & " -in-binary -out-c < in.bin > out.c" & Wr.EOL);
    IO.Put ("       example: " & Params.Get(0) & " -in-binary=in.bin -out-c:out.c" & Wr.EOL);
    Process.Exit (1);
  END Usage;

PROCEDURE Init () =
  VAR machine: TEXT;
  BEGIN
    machine := MxConfig.Get ("TARGET");
    IF machine = NIL THEN
      IO.Put ("unable to find TARGET definition in configuration file" & Wr.EOL);
      Process.Exit (1);
    ELSIF NOT Target.Init (machine) THEN
      IO.Put ("unable to initialize Target: " & machine & Wr.EOL);
      Process.Exit (1);
    END;
  END Init;

BEGIN
  DoIt ();
END Main.