#include <perms.h>
void Initialiseiosystem(void);
static const int Integersize = 4;
static const int Realsize = 4;
static const int Bytesize = 1;
static const int Longrealsize = 8;
static const int Integertype = 1;
static const int Realtype = 2;
static const int Stringtype = 3;
static const int Recordtype = 4;
static const int Bytetype = 5;
static const int Shortintegertype = 6;
static const int Longintegertype = 7;
static const int Longrealtype = 8;
static const int Stdnullhandle = 0;
static const int Stderrhandle = 1;
static const int Stdinhandle = 2;
static const int Stdouthandle = 3;
static const int Maxinputstream = 4;
static const int Maxoutputstream = 4;
static const int Isinput = 0 << 0;
static const int Isoutput = 1 << 0;
static const int Istext = 0 << 1;
static const int Isbinary = 1 << 1;
static const int Uninitialised = 0;
static const int Initialised = 1;
typedef struct Impstream {
  int Lookahead;
  int Flags;
  _imp_string Filename;
  int Handle;
} Impstream;
typedef struct Impinput {
  int Currentstream;
  Impstream Streams[5 /*0:4*/];
} Impinput;
typedef struct Impoutput {
  int Currentstream;
  Impstream Streams[5 /*0:4*/];
} Impoutput;
static Impinput In;
static Impoutput Out;
static Impstream Nullstream;
static Impstream Errorstream;
static int Initialisedstate = Uninitialised;
int Fileerror;
static void Imptocstring(_imp_string *Impstring) {
  int Len;
  int I;
  unsigned char *Src;
  if (Addr(*Impstring)) {
    Len = *Length(*Impstring);
    for (I = 0; I <= Len - 1; I++) {
      Src = Byteinteger(Addr(*Impstring) + I + 1);
      *Charno(*Impstring, I) = *Src;
    }
    *Charno(*Impstring, Len) = 0;
  }
}
int /* boolean */ Needtoinitialise(void) {
  if (Initialisedstate == Uninitialised) return (1);
  return (0);
}
static void Initialisestream(Impstream *S) {
  S.Handle = 0;
  *Length(S.Filename) = 0;
  S.Flags = 0;
  S.Lookahead = -1;
}
static void Finalisestream(Impstream *S) {
  if (S.Handle != 0) Close;
  Initialisestream(*S);
}
static int /* boolean */ Acceptabletype(int Type) {
  if (Type == Integertype) return (1);
  if (Type == Realtype) return (1);
  if (Type == Stringtype) return (1);
  if (Type == Recordtype) return (1);
  if (Type == Bytetype) return (1);
  if (Type == Longrealtype) return (1);
  return (0);
}
static _imp_string Inputprompt = _imp_str_literal("prompt ->");
static int Ttyneedsaprompt = 1;
void Prompt(_imp_string S) { Inputprompt = S; }
static void Initialiseinputsystem(void) {
  Impstream *Streamx;
  int I;
  In.Currentstream = 0;
  for (I = 0; I <= Maxinputstream; I++) {
    Streamx = &In.Streams;
    Initialisestream(*Streamx);
  }
  In.Streams = Getstdinhandle;
  In.Streams = _imp_str_literal("stdin");
}
static void Terminateinputsystem(void) {
  Impstream *Streamx;
  int I;
  In.Currentstream = -1;
  for (I = 1; I <= Maxinputstream; I++) {
    Streamx = &In.Streams;
    Finalisestream(*Streamx);
  }
}
int Readbuffer(_imp_name Ptr, int Count) {
  Impstream *Streamx;
  int I;
  int Actualcount;
  int Len;
  int Adr;
  int Type;
  int Itemsz;
  Len = Sizeof(Ptr);
  Adr = Addr(Ptr);
  Type = Typeof(Ptr);
  if ((Debugmode & Dbgio) != 0) {
    Debugstring;
    Debugnewline;
    Debugstring;
    Debugnewline;
    Debugstring;
    Debugnewline;
    Debugstring;
    Debugnewline;
  }
  if (!Acceptabletype(Type)) _imp_signal(5, 5, Type, _imp_str_literal(""));
  Itemsz = -1;
  if (Type == Integertype) Itemsz = Integersize;
  if (Type == Realtype) Itemsz = Realsize;
  if (Type == Stringtype) Itemsz = Len;
  if (Type == Bytetype) Itemsz = Bytesize;
  if (Type == Longrealtype) Itemsz = Longrealsize;
  if (Type == Recordtype) Itemsz = Len;
  if (Needtoinitialise()) Initialiseiosystem();
  if ((0 >= In.Currentstream || In.Currentstream > Maxinputstream))
    _imp_signal(9, 9, 0, _imp_str_literal(""));
  Streamx = &In.Streams;
  if ((Streamx->Handle == 0))
    _imp_signal(9, 4, In.Currentstream, _imp_str_literal(""));
  Actualcount = Readbytes;
  if ((0 <= Len && Len <= 255) && (Typeof(Ptr) == Stringtype)) {
    for (I = Actualcount - 1; I >= 0; I--)
      *Charno(*String(Addr(Ptr)), I + 1) = *Charno(*String(Addr(Ptr)), I);
    *Charno(*String(Addr(Ptr)), 0) = Actualcount;
  }
  return (Actualcount);
}
int Inputstream(void) {
  if (Needtoinitialise()) Initialiseiosystem();
  return (In.Currentstream);
}
void Resetinput(void) {
  Impstream *Streamx;
  if (Needtoinitialise()) Initialiseiosystem();
  if ((0 >= In.Currentstream || In.Currentstream > Maxinputstream))
    _imp_signal(9, 9, 0, _imp_str_literal(""));
  Streamx = &In.Streams;
  if ((Streamx->Handle == 0))
    _imp_signal(9, 4, In.Currentstream, _imp_str_literal(""));
  Filerewind;
}
void Seekinput(int Displacement, int Pos) {
  Impstream *Streamx;
  if (Needtoinitialise()) Initialiseiosystem();
  if ((0 >= In.Currentstream || In.Currentstream > Maxinputstream))
    _imp_signal(9, 9, 0, _imp_str_literal(""));
  Streamx = &In.Streams;
  if ((Streamx->Handle == 0))
    _imp_signal(9, 4, In.Currentstream, _imp_str_literal(""));
  if (0 <= Pos && Pos <= 2) Fileseek;
}
int Tellinput(void) {
  Impstream *Streamx;
  if (Needtoinitialise()) Initialiseiosystem();
  if ((0 >= In.Currentstream || In.Currentstream > Maxinputstream))
    _imp_signal(9, 9, 0, _imp_str_literal(""));
  Streamx = &In.Streams;
  if ((Streamx->Handle == 0))
    _imp_signal(9, 4, In.Currentstream, _imp_str_literal(""));
  return (Tell);
}
_imp_string Inputname(void) {
  Impstream *Streamx;
  _imp_string Name;
  if (Needtoinitialise()) Initialiseiosystem();
  if ((0 > In.Currentstream || In.Currentstream > Maxinputstream))
    _imp_signal(9, 9, 0, _imp_str_literal(""));
  Streamx = &In.Streams;
  if ((Streamx->Handle == 0))
    _imp_signal(9, 4, In.Currentstream, _imp_str_literal(""));
  Name = Streamx->Filename;
  return (Name);
}
void Selectinput(int Streamid) {
  Impstream *Streamx;
  if (Needtoinitialise()) Initialiseiosystem();
  if ((0 > Streamid || Streamid > Maxinputstream))
    _imp_signal(9, 9, 0, _imp_str_literal(""));
  Streamx = &In.Streams;
  if ((Streamx->Handle == 0)) _imp_signal(9, 4, Streamid, _imp_str_literal(""));
  In.Currentstream = Streamid;
}
void Closeinput(void) {
  Impstream *Streamx;
  if (Needtoinitialise()) Initialiseiosystem();
  if (0 < In.Currentstream && In.Currentstream <= Maxinputstream) {
    Streamx = &In.Streams;
    if (Streamx->Handle != 0) {
      Close;
      Initialisestream(*Streamx);
    }
  }
}
void Openinput(int Streamid, _imp_string Filename) {
  Impstream *Streamx;
  int Handle;
  int Flags = Isinput | Istext;
  _imp_string Mode = _imp_str_literal("r");
  _imp_string Xxx;
  _imp_string Yyy;
  if (Needtoinitialise()) Initialiseiosystem();
  if ((0 >= Streamid || Streamid > Maxinputstream))
    _imp_signal(9, 9, Streamid, _imp_str_literal(""));
  Streamx = &In.Streams;
  if (Streamx->Handle == 0) {
    Xxx = Filename;
    Yyy = Mode;
    Imptocstring(Xxx);
    Imptocstring(Yyy);
    Handle = Openfile;
    if (Handle == 0) {
      if ((Debugmode & Dbgio) != 0) {
        Debugstring;
        Debugnewline;
      }
      _imp_signal(9, 2, Geterror, _imp_str_literal(""));
    } else {
      if ((Debugmode & Dbgio) != 0) {
        Debugstring;
        Debugnewline;
      }
      Streamx = &In.Streams;
      Streamx->Handle = Handle;
      Streamx->Filename = Filename;
      Streamx->Flags = Flags;
    }
  }
}
void Openbinaryinput(int Streamid, _imp_string Filename) {
  Impstream *Streamx;
  int Handle;
  int Flags = Isinput | Isbinary;
  _imp_string Mode = _imp_str_literal("rb");
  _imp_string Xxx;
  _imp_string Yyy;
  if (Needtoinitialise()) Initialiseiosystem();
  if ((0 >= Streamid || Streamid > Maxinputstream))
    _imp_signal(9, 9, Streamid, _imp_str_literal(""));
  Streamx = &In.Streams;
  if (Streamx->Handle == 0) {
    Xxx = Filename;
    Yyy = Mode;
    Imptocstring(Xxx);
    Imptocstring(Yyy);
    Handle = Openfile;
    if (Handle == 0) {
      if ((Debugmode & Dbgio) != 0) {
        Debugstring;
        Debugnewline;
      }
      _imp_signal(9, 2, Geterror, _imp_str_literal(""));
    } else {
      if ((Debugmode & Dbgio) != 0) {
        Debugstring;
        Debugnewline;
      }
      Streamx = &In.Streams;
      Streamx->Handle = Handle;
      Streamx->Filename = Filename;
      Streamx->Flags = Flags;
    }
  }
}
int Nextsymbol(void) {
  Impstream *Streamx;
  int Ch;
  int I;
  if (Needtoinitialise()) Initialiseiosystem();
  if ((0 > In.Currentstream || In.Currentstream > Maxinputstream))
    _imp_signal(9, 9, In.Currentstream, _imp_str_literal(""));
  Streamx = &In.Streams;
  if ((Streamx->Handle == 0))
    _imp_signal(9, 4, In.Currentstream, _imp_str_literal(""));
  if (Streamx->Lookahead < 0) {
    if (In.Currentstream == 0)
      if (Ttyneedsaprompt != 0) {
        Ttyneedsaprompt = 0;
        for (I = 1; I <= *Length(Inputprompt); I++) Putchar;
      }
    Ch = Getchar;
    Streamx->Lookahead = Ch;
    if ((In.Currentstream == 0) && (Ch == Nl)) Ttyneedsaprompt = 1;
    if (Ch < 0) _imp_signal(9, 0, In.Currentstream, _imp_str_literal(""));
  }
  return (Streamx->Lookahead);
}
void Readsymbol(int *Ch) {
  Impstream *Streamx;
  if (Needtoinitialise()) Initialiseiosystem();
  *Ch = Nextsymbol();
  Streamx = &In.Streams;
  Streamx->Lookahead = -1;
  if (*Ch < 0) _imp_signal(9, 1, In.Currentstream, _imp_str_literal(""));
}
static void Initialiseoutputsystem(void) {
  Impstream *Streamx;
  int I;
  Out.Currentstream = 0;
  for (I = 0; I <= Maxoutputstream; I++) {
    Streamx = &Out.Streams;
    Initialisestream(*Streamx);
  }
  Streamx = &Out.Streams;
  Streamx->Handle = Getstdouthandle;
  Streamx->Filename = _imp_str_literal("stdout");
  Streamx->Flags = Isoutput | Istext;
  Streamx = &Errorstream;
  Initialisestream(*Streamx);
  Streamx->Handle = Getstderrhandle;
  Streamx->Filename = _imp_str_literal("stderr");
  Streamx->Flags = Isoutput | Istext;
}
static void Terminateoutputsystem(void) {
  Impstream *Streamx;
  int I;
  Out.Currentstream = -1;
  for (I = 1; I <= Maxoutputstream; I++) {
    Streamx = &Out.Streams;
    Finalisestream(*Streamx);
  }
}
void Debugsymbol(int C) {
  if (Needtoinitialise()) Initialiseiosystem();
  if (Errorstream.Handle != 0) Putchar;
}
void Debugreal(double D) {
  if (Needtoinitialise()) Initialiseiosystem();
  if (Errorstream.Handle != 0) Putdouble;
}
int Writebuffer(_imp_name Ptr, int Count) {
  Impstream *Streamx;
  int Len;
  int Adr;
  int Type;
  int Itemsz;
  int I;
  int Res;
  Len = Sizeof(Ptr);
  Adr = Addr(Ptr);
  Type = Typeof(Ptr);
  if ((Debugmode & Dbgio) != 0) {
    Debugstring;
    Debugnewline;
    Debugstring;
    Debugnewline;
    Debugstring;
    Debugnewline;
    Debugstring;
    Debugnewline;
  }
  if (!(Acceptabletype(Type) && (Len == Count)))
    _imp_signal(5, 5, Type, _imp_str_literal(""));
  Itemsz = -1;
  if (Type == Integertype) Itemsz = Integersize;
  if (Type == Realtype) Itemsz = Realsize;
  if (Type == Stringtype) Itemsz = Len;
  if (Type == Bytetype) Itemsz = Bytesize;
  if (Type == Longrealtype) Itemsz = Longrealsize;
  if (Type == Recordtype) Itemsz = Len;
  if (Needtoinitialise()) Initialiseiosystem();
  if ((0 >= Out.Currentstream || Out.Currentstream > Maxoutputstream))
    _imp_signal(9, 9, 0, _imp_str_literal(""));
  Streamx = &Out.Streams;
  if ((Streamx->Handle == 0))
    _imp_signal(9, 5, Out.Currentstream, _imp_str_literal(""));
  return (Writebytes);
}
int Outputstream(void) {
  if (Needtoinitialise()) Initialiseiosystem();
  return (Out.Currentstream);
}
void Resetoutput(void) {
  Impstream *Streamx;
  if (Needtoinitialise()) Initialiseiosystem();
  if ((0 >= Out.Currentstream || Out.Currentstream > Maxoutputstream))
    _imp_signal(9, 9, 0, _imp_str_literal(""));
  Streamx = &Out.Streams;
  if ((Streamx->Handle == 0))
    _imp_signal(9, 5, Out.Currentstream, _imp_str_literal(""));
  Filerewind;
}
void Seekoutput(int Displacement, int Pos) {
  Impstream *Streamx;
  if (Needtoinitialise()) Initialiseiosystem();
  if ((0 >= Out.Currentstream || Out.Currentstream > Maxoutputstream))
    _imp_signal(9, 9, 0, _imp_str_literal(""));
  Streamx = &Out.Streams;
  if ((Streamx->Handle == 0))
    _imp_signal(9, 5, Out.Currentstream, _imp_str_literal(""));
  if (0 <= Pos && Pos <= 2) Fileseek;
}
int Telloutput(void) {
  Impstream *Streamx;
  if (Needtoinitialise()) Initialiseiosystem();
  if ((0 >= Out.Currentstream || Out.Currentstream > Maxoutputstream))
    _imp_signal(9, 9, 0, _imp_str_literal(""));
  Streamx = &Out.Streams;
  if ((Streamx->Handle == 0))
    _imp_signal(9, 5, Out.Currentstream, _imp_str_literal(""));
  return (Tell);
}
_imp_string Outputname(void) {
  Impstream *Streamx;
  if (Needtoinitialise()) Initialiseiosystem();
  if ((0 > Out.Currentstream || Out.Currentstream > Maxoutputstream))
    _imp_signal(9, 9, 0, _imp_str_literal(""));
  Streamx = &Out.Streams;
  if ((Streamx->Handle == 0))
    _imp_signal(9, 5, Out.Currentstream, _imp_str_literal(""));
  return (Streamx->Filename);
}
void Selectoutput(int Streamid) {
  Impstream *Streamx;
  if (Needtoinitialise()) Initialiseiosystem();
  if ((0 > Streamid || Streamid > Maxoutputstream))
    _imp_signal(9, 9, 0, _imp_str_literal(""));
  Streamx = &Out.Streams;
  if ((Streamx->Handle == 0)) _imp_signal(9, 5, Streamid, _imp_str_literal(""));
  Out.Currentstream = Streamid;
}
void Closeoutput(void) {
  Impstream *Streamx;
  if (Needtoinitialise()) Initialiseiosystem();
  if (0 < Out.Currentstream && Out.Currentstream <= Maxoutputstream) {
    Streamx = &Out.Streams;
    if (Streamx->Handle != 0) {
      Close;
      Initialisestream(*Streamx);
    }
  }
}
void Openoutput(int Streamid, _imp_string Filename) {
  Impstream *Streamx;
  int Handle;
  int Flags = Isoutput | Istext;
  _imp_string Mode = _imp_str_literal("w");
  _imp_string Xxx;
  _imp_string Yyy;
  if (Needtoinitialise()) Initialiseiosystem();
  if ((0 >= Streamid || Streamid > Maxoutputstream))
    _imp_signal(9, 9, Streamid, _imp_str_literal(""));
  Streamx = &Out.Streams;
  if (Streamx->Handle == 0) {
    Xxx = Filename;
    Yyy = Mode;
    Imptocstring(Xxx);
    Imptocstring(Yyy);
    Handle = Openfile;
    if (Handle == 0) {
      if ((Debugmode & Dbgio) != 0) {
        Debugstring;
        Debugnewline;
      }
      _imp_signal(9, 2, Geterror, _imp_str_literal(""));
    } else {
      if ((Debugmode & Dbgio) != 0) {
        Debugstring;
        Debugnewline;
      }
      Streamx->Handle = Handle;
      Streamx->Filename = Filename;
      Streamx->Flags = Flags;
    }
  }
}
void Openbinaryoutput(int Streamid, _imp_string Filename) {
  Impstream *Streamx;
  int Handle;
  int Flags = Isoutput | Isbinary;
  _imp_string Mode = _imp_str_literal("wb");
  _imp_string Xxx;
  _imp_string Yyy;
  if (Needtoinitialise()) Initialiseiosystem();
  if ((0 >= Streamid || Streamid > Maxoutputstream))
    _imp_signal(9, 9, Streamid, _imp_str_literal(""));
  Streamx = &Out.Streams;
  if (Streamx->Handle == 0) {
    Xxx = Filename;
    Yyy = Mode;
    Imptocstring(Xxx);
    Imptocstring(Yyy);
    Handle = Openfile;
    if (Handle == 0) {
      if ((Debugmode & Dbgio) != 0) {
        Debugstring;
        Debugnewline;
      }
      _imp_signal(9, 2, Geterror, _imp_str_literal(""));
    } else {
      if ((Debugmode & Dbgio) != 0) {
        Debugstring;
        Debugnewline;
      }
      Streamx->Handle = Handle;
      Streamx->Filename = Filename;
      Streamx->Flags = Flags;
    }
  }
}
void Flushoutput(void) {
  Impstream *Streamx;
  if (Needtoinitialise()) Initialiseiosystem();
  if ((0 > Out.Currentstream || Out.Currentstream > Maxoutputstream))
    _imp_signal(9, 9, Out.Currentstream, _imp_str_literal(""));
  Streamx = &Out.Streams;
  if ((Streamx->Handle == 0))
    _imp_signal(9, 5, Out.Currentstream, _imp_str_literal(""));
  Flush;
}
void Printsymbol(int C) {
  Impstream *Streamx;
  if (Needtoinitialise()) Initialiseiosystem();
  if ((0 > Out.Currentstream || Out.Currentstream > Maxoutputstream))
    _imp_signal(9, 9, Out.Currentstream, _imp_str_literal(""));
  Streamx = &Out.Streams;
  if ((Streamx->Handle == 0))
    _imp_signal(9, 5, Out.Currentstream, _imp_str_literal(""));
  if (Streamx->Handle != 0) {
    Putchar;
    if (C == Nl) Flushoutput();
  }
}
void Printreal(double D) {
  Impstream *Streamx;
  if (Needtoinitialise()) Initialiseiosystem();
  if ((0 > Out.Currentstream || Out.Currentstream > Maxoutputstream))
    _imp_signal(9, 9, Out.Currentstream, _imp_str_literal(""));
  Streamx = &Out.Streams;
  if ((Streamx->Handle == 0))
    _imp_signal(9, 5, Out.Currentstream, _imp_str_literal(""));
  if (Streamx->Handle != 0) Putdouble;
}
void Initialiseiosystem(void) {
  int I;
  Nullstream.Handle = 0;
  Nullstream.Filename = _imp_str_literal("null");
  Initialiseinputsystem();
  Initialiseoutputsystem();
  Initialisedstate = Initialised;
}
void Terminateiosystem(void) {
  Terminateinputsystem();
  Terminateoutputsystem();
  Initialisedstate = Uninitialised;
}
static void Parseinputlist(_imp_string List) {
  _imp_string X;
  _imp_string A;
  _imp_string C;
  _imp_string Mode;
  _imp_string File;
  int Streamid;
  X = List;
  Streamid = 1;
  while (*Length(X) > 0) {
    if ((1 > Streamid || Streamid > Maxinputstream)) break;
    *Length(A) = 0;
    *Length(C) = 0;
    if (!_imp_resolve(X, A, _imp_str_literal(","), C)) _imp_signal(7, 0, 0);
    if (*Length(A) <= 0) break;
    File = A;
    *Length(Mode) = 0;
    if ((*Charno(A, *Length(A)) == 'b') &&
        (*Charno(A, *Length(A) - 1) == ':')) {
      *Length(File) = *Length(File) - 2;
      Mode = _imp_str_literal(":b");
    }
    if (*Length(File) <= 0) break;
    if (!*Length(Mode))
      Openinput(Streamid, File);
    else
      Openbinaryinput(Streamid, File);
    X = C;
    Streamid++;
  }
}
static void Parseoutputlist(_imp_string List) {
  _imp_string X;
  _imp_string A;
  _imp_string C;
  _imp_string Mode;
  _imp_string File;
  int Streamid;
  X = List;
  Streamid = 1;
  while (*Length(X) > 0) {
    if ((1 > Streamid || Streamid > Maxoutputstream)) break;
    *Length(A) = 0;
    *Length(C) = 0;
    if (!_imp_resolve(X, A, _imp_str_literal(","), C)) _imp_signal(7, 0, 0);
    if (*Length(A) <= 0) break;
    File = A;
    *Length(Mode) = 0;
    if ((*Charno(A, *Length(A)) == 'b') &&
        (*Charno(A, *Length(A) - 1) == ':')) {
      *Length(File) = *Length(File) - 2;
      Mode = _imp_str_literal(":b");
    }
    if (*Length(File) <= 0) break;
    if (!*Length(Mode))
      Openoutput(Streamid, File);
    else
      Openbinaryoutput(Streamid, File);
    X = C;
    Streamid++;
  }
}
int Splitiolist(_imp_string Iolist) {
  _imp_string S;
  _imp_string A;
  _imp_string B;
  _imp_string C;
  S = Iolist;
  *Length(A) = 0;
  B = Tostring(Filesep);
  *Length(C) = 0;
  if (!_imp_resolve(S, A, B, C)) _imp_signal(7, 0, 0);
  if (*Length(A) > 0) Parseinputlist(A);
  if (*Length(C) > 0) Parseoutputlist(C);
  return (0);
}
