-- UnixSysCallsMXCode.mesa
DIRECTORY Atom, PFS, Rope, Scheme, SchemeSys, UnixSpawn, UnixSysCalls, UnixTypes;
UnixSysCallsMXCode: CEDAR PROGRAM
IMPORTS Atom, PFS, Scheme, SchemeSys, UnixSpawn, UnixSysCalls
= BEGIN OPEN Scheme;
  SymbolFromRope: PROC [rope: Rope.ROPE] RETURNS [Symbol] ~ {RETURN[Atom.MakeAtom[rope]]};
  RopeFromSymbol: PROC [Symbol] RETURNS [Rope.ROPE] ~ Atom.GetPName;
  UnixSysCallsPrim: PROC [SELF: Primitive, ARG1,ARG2,ARG3: Any, REST: ProperList] RETURNS [result: Any ← unspecified] = {
INNER: PROC = {
    POP: PROC RETURNS [a: Any ← undefined] = {
      IF REST#NIL THEN {a ← REST.car; REST ← NARROW[REST.cdr]}};
    DATA: Pair ~ NARROW[SELF.data];
    env: Environment ~ NARROW[DATA.cdr];
    SELECT NAT[NARROW[DATA.car, REF INT]↑] FROM
      5 => {
        pid: Any ← ARG1;
        signal: Any ← ARG2;
        res: UnixTypes.SysCallResult = UnixSysCalls.KillPG[KCheck[pid], VAL[KCheck[signal]]];
        result ← IF res=success THEN true ELSE false;
        };
      4 => {
        pid: Any ← ARG1;
        signal: Any ← ARG2;
        res: UnixTypes.SysCallResult = UnixSysCalls.Kill[KCheck[pid], VAL[KCheck[signal]]];
        result ← IF res=success THEN true ELSE false;
        };
      3 => {
        pid: Any ← ARG1;
        result ← MakeFixnum[UnixSysCalls.GetPGrp[KCheck[pid]]];
        };
      2 => {
        result ← MakeFixnum[UnixSysCalls.GetPPID[]];
        };
      1 => {
        result ← MakeFixnum[UnixSysCalls.GetPID[]];
        };
      0 => {
        cmdString: Any ← ARG1;
        stdin: Any ← ARG2;
        stdout: Any ← ARG3;
        stderr: Any ← POP[];
        stdin ← DeScheme[stdin, TRUE];
        stdout ← DeScheme[stdout, FALSE];
        stderr ← DeScheme[stderr, FALSE];
        result ← DeCedar[UnixSpawn.Spawn[command: RopeFromString[TheString[cmdString]], stdin: stdin, stdout: stdout, stderr: stderr, wd: PFS.RopeFromPath[PFS.GetWDir[]], exec: TRUE, tty: FALSE, debug: FALSE].details];
        };
      ENDCASE => ERROR
    }; INNER[!
        UnixSpawn.Error => {
        Complain[code, msg];
        };
    ];
    };
    
  UnixSysCallsInit: PROC [env: Environment] = {
    DefinePrimitive[name: "unix-killpg", nArgs: 2, proc: UnixSysCallsPrim, doc: "(pid signal) kill (signal) a unix process group", env: env, optional: 0, dotted: FALSE, data: Cons[MakeFixnum[5], env]];
    DefinePrimitive[name: "unix-kill", nArgs: 2, proc: UnixSysCallsPrim, doc: "(pid signal) kill (signal) a unix process", env: env, optional: 0, dotted: FALSE, data: Cons[MakeFixnum[4], env]];
    DefinePrimitive[name: "unix-getpgrp", nArgs: 1, proc: UnixSysCallsPrim, doc: "(pid) get unix process group", env: env, optional: 0, dotted: FALSE, data: Cons[MakeFixnum[3], env]];
    DefinePrimitive[name: "unix-getppid", nArgs: 0, proc: UnixSysCallsPrim, doc: "() get unix parent process id", env: env, optional: 0, dotted: FALSE, data: Cons[MakeFixnum[2], env]];
    DefinePrimitive[name: "unix-getpid", nArgs: 0, proc: UnixSysCallsPrim, doc: "() get unix process id", env: env, optional: 0, dotted: FALSE, data: Cons[MakeFixnum[1], env]];
    DefinePrimitive[name: "unix-spawn", nArgs: 4, proc: UnixSysCallsPrim, doc: "(cmd-string [ stdin ] [ stdout ] [ stderr ]) fork a (Unix) process to run cmd, attaching its standard input, output and error file descriptors to the files named by stdin, stdout, stderr", env: env, optional: 3, dotted: FALSE, data: Cons[MakeFixnum[0], env]];
    };
    
  ROPE: TYPE ~ Rope.ROPE;
  
  devNull: ROPE = "/dev/null";
  
  DeScheme: PROC [ref: REF, inP: BOOL] RETURNS [REF] = {
  SELECT ref FROM
  undefined, true => ref ← SchemeSys.GetPort[undefined, inP];
  false => ref ← devNull;
  ENDCASE => {
  WITH ref SELECT FROM
  string: Scheme.String => ref ← RopeFromString[string];
  ENDCASE => NULL;
  };
  RETURN [ref]
  };
  
  DeCedar: PROC [a: REF] RETURNS [REF] = {
  WITH a SELECT FROM
  lora: LIST OF REF => RETURN [Cons[lora.first, DeCedar[lora.rest]]];
  rope: ROPE => RETURN [StringFromRope[rope]];
  ENDCASE => RETURN [a];
  };
  
  RegisterInit[UnixSysCallsInit];
END.