MODULE ulmSysErrors;

   IMPORT Errors := ulmErrors, Events := ulmEvents, Priorities := ulmPriorities, RelatedEvents := ulmRelatedEvents, Streams := ulmStreams, Strings := ulmStrings, Sys := ulmSys;

   CONST
      perm*		= 1;
      noent*		= 2;
      srch*		= 3;
      intr*		= 4;
      io*		= 5;
      nxio*		= 6;
      toobig*		= 7;
      noexec*		= 8;
      badf*		= 9;
      child*		= 10;
      again*		= 11;
      nomem*		= 12;
      acces*		= 13;
      fault*		= 14;
      notblk*		= 15;
      busy*		= 16;
      exist*		= 17;
      xdev*		= 18;
      nodev*		= 19;
      notdir*		= 20;
      isdir*		= 21;
      inval*		= 22;
      nfile*		= 23;
      mfile*		= 24;
      notty*		= 25;
      txtbsy*		= 26;
      fbig*		= 27;
      nospc*		= 28;
      spipe*		= 29;
      rofs*		= 30;
      mlink*		= 31;
      pipe*		= 32;
      dom*		= 33;
      range*		= 34;
      deadlk*		= 35;
      nametoolong*	= 36;
      nolck*		= 37;
      nosys*		= 38;
      notempty*		= 39;
      loop*		= 40;
      wouldblock*	= again;
      nomsg*		= 42;
      idrm*		= 43;
      chrng*		= 44;
      l2nsync*		= 45;
      l3hlt*		= 46;
      l3rst*		= 47;
      lnrng*		= 48;
      unatch*		= 49;
      nocsi*		= 50;
      l2hlt*		= 51;
      bade*		= 52;
      badr*		= 53;
      xfull*		= 54;
      noano*		= 55;
      badrqc*		= 56;
      badslt*		= 57;
      deadlock*		= deadlk;
      bfont*		= 59;
      nostr*		= 60;
      nodata*		= 61;
      time*		= 62;
      nosr*		= 63;
      nonet*		= 64;
      nopkg*		= 65;
      remote*		= 66;
      nolink*		= 67;
      adv*		= 68;
      srmnt*		= 69;
      comm*		= 70;
      proto*		= 71;
      multihop*		= 72;
      dotdot*		= 73;
      badmsg*		= 74;
      overflow*		= 75;
      notuniq*		= 76;
      badfd*		= 77;
      remchg*		= 78;
      libacc*		= 79;
      libbad*		= 80;
      libscn*		= 81;
      libmax*		= 82;
      libexec*		= 83;
      ilseq*		= 84;
      restart*		= 85;
      strpipe*		= 86;
      users*		= 87;
      notsock*		= 88;
      destaddrreq*	= 89;
      msgsize*		= 90;
      prototype*		= 91;
      noprotoopt*	= 92;
      protonosupport*	= 93;
      socktnosupport*	= 94;
      opnotsupp*		= 95;
      pfnosupport*	= 96;
      afnosupport*	= 97;
      addrinuse*		= 98;
      addrnotavail*	= 99;
      netdown*		= 100;
      netunreach*	= 101;
      netreset*		= 102;
      connaborted*	= 103;
      connreset*		= 104;
      nobufs*		= 105;
      isconn*		= 106;
      notconn*		= 107;
      shutdown*		= 108;
      toomanyrefs*	= 109;
      timedout*		= 110;
      connrefused*	= 111;
      hostdown*		= 112;
      hostunreach*	= 113;
      already*		= 114;
      inprogress*	= 115;
      stale*		= 116;
      uclean*		= 117;
      notnam*		= 118;
      navail*		= 119;
      isnam*		= 120;
      remoteio*		= 121;
      dquot*		= 122;
      nomedium*		= 123;
      mediumtype*	= 124;

      ncodes*         = 126;   (* number of error codes *)
      
      textlen* = 512;

   TYPE
      Name* = ARRAY 20 OF CHAR;
      Event* = POINTER TO EventRec;
      EventRec* =
	 RECORD
	    (Events.EventRec)
	    errno*: (*INTEGER*)LONGINT;
	    syscall*: (*INTEGER*)LONGINT; (* number of system call *)
	    text*: ARRAY textlen OF CHAR;
	 END;

   VAR
      message*: ARRAY ncodes OF Events.Message;
      name*: ARRAY ncodes OF Name;
      syserrors*: Events.EventType;
      syserror*: ARRAY ncodes OF Events.EventType;

   PROCEDURE Raise*(errors: RelatedEvents.Object;
		   errno, syscall: (*INTEGER*)LONGINT; text: ARRAY OF CHAR); (* in ulm's system INTEGER and LONGINT have the same size *)
      (* raises the events syserrors and syserrors[syscall];
	 `text' contains additional information (e.g. filenames);
	 further, the syserrors[syscall] event is passed to
	 RelatedEvents if object # NIL
      *)
      VAR
	 event: Event;

      PROCEDURE InitEvent(VAR event: Event; type: Events.EventType);
      BEGIN
	 NEW(event);
	 event.type := type;
	 event.message := message[errno];
	 event.errno := errno;
	 event.syscall := syscall;
	 COPY(text, event.text);
      END InitEvent;

   BEGIN
      IF (errno > 0) & (errno < ncodes) THEN
	 InitEvent(event, syserrors); Events.Raise(event);
	 InitEvent(event, syserror[errno]); Events.Raise(event);
	 IF errors # NIL THEN
	    InitEvent(event, syserrors);
	    RelatedEvents.Raise(errors, event);
	 END;
      END;
   END Raise;

   PROCEDURE Write(s: Streams.Stream; event: Events.Event);

      PROCEDURE WriteString(txt: ARRAY OF CHAR);
      BEGIN
	 IF ~Streams.WritePart(s, txt, 0, Strings.Len(txt)) THEN END;
      END WriteString;

      PROCEDURE Write(ch: CHAR);
      BEGIN
	 IF ~Streams.WriteByte(s, ch) THEN END;
      END Write;

      PROCEDURE WriteInt(intval: LONGINT);
	 VAR
	    rest: LONGINT;
      BEGIN
	 rest := intval DIV 10;
	 IF rest > 0 THEN
	    WriteInt(rest);
	 END;
	 Write(CHR(ORD("0") + intval MOD 10));
      END WriteInt;

   BEGIN
      IF event IS Event THEN
	 WITH event: Event DO
	    IF event.text[0] # 0X THEN
	       WriteString(event.text);
	       WriteString(": ");
	    END;
	    IF event.errno = 0 THEN
	       WriteString("no error (");
	       WriteString(Sys.name[event.syscall]); Write(")");
	    ELSIF (event.errno >= ncodes) OR (message[event.errno][0] = 0X) THEN
	       WriteString("unknown error (");
	       WriteString(Sys.name[event.syscall]);
	       WriteString(": "); WriteInt(event.errno); Write(")");
	    ELSE
	       WriteString(message[event.errno]);
	       WriteString(" (");
	       WriteString(Sys.name[event.syscall]); WriteString(": ");
	       WriteString(name[event.errno]); Write(")");
	    END;
	 END;
      ELSE
	 WriteString(event.message);
      END;
   END Write;

   PROCEDURE InitEvents;
      VAR
	 errno: INTEGER;
   BEGIN
      syserror[0] := NIL;
      errno := 1;
      WHILE errno < ncodes DO
	 Events.Define(syserror[errno]);
	 Events.Ignore(syserror[errno]);
	 Events.SetPriority(syserror[errno], Priorities.syserrors);
	 INC(errno);
      END;
      Events.Define(syserrors);
      Events.Ignore(syserrors);
      Events.SetPriority(syserrors, Priorities.syserrors);
      Errors.AssignWriteProcedure(syserrors, Write);
   END InitEvents;

BEGIN
   InitEvents;
   name[perm] := "EPERM";
   message[perm] := "Operation not permitted";
   name[noent] := "ENOENT";
   message[noent] := "No such file or directory";
   name[srch] := "ESRCH";
   message[srch] := "No such process";
   name[intr] := "EINTR";
   message[intr] := "Interrupted system call";
   name[io] := "EIO";
   message[io] := "I/O error";
   name[nxio] := "ENXIO";
   message[nxio] := "No such device or address";
   name[toobig] := "E2BIG";
   message[toobig] := "Arg list too long";
   name[noexec] := "ENOEXEC";
   message[noexec] := "Exec format error";
   name[badf] := "EBADF";
   message[badf] := "Bad file number";
   name[child] := "ECHILD";
   message[child] := "No child processes";
   name[again] := "EAGAIN";
   message[again] := "Try again";
   name[nomem] := "ENOMEM";
   message[nomem] := "Out of memory";
   name[acces] := "EACCES";
   message[acces] := "Permission denied";
   name[fault] := "EFAULT";
   message[fault] := "Bad address";
   name[notblk] := "ENOTBLK";
   message[notblk] := "Block device required";
   name[busy] := "EBUSY";
   message[busy] := "Device or resource busy";
   name[exist] := "EEXIST";
   message[exist] := "File exists";
   name[xdev] := "EXDEV";
   message[xdev] := "Cross-device link";
   name[nodev] := "ENODEV";
   message[nodev] := "No such device";
   name[notdir] := "ENOTDIR";
   message[notdir] := "Not a directory";
   name[isdir] := "EISDIR";
   message[isdir] := "Is a directory";
   name[inval] := "EINVAL";
   message[inval] := "Invalid argument";
   name[nfile] := "ENFILE";
   message[nfile] := "File table overflow";
   name[mfile] := "EMFILE";
   message[mfile] := "Too many open files";
   name[notty] := "ENOTTY";
   message[notty] := "Not a typewriter";
   name[txtbsy] := "ETXTBSY";
   message[txtbsy] := "Text file busy";
   name[fbig] := "EFBIG";
   message[fbig] := "File too large";
   name[nospc] := "ENOSPC";
   message[nospc] := "No space left on device";
   name[spipe] := "ESPIPE";
   message[spipe] := "Illegal seek";
   name[rofs] := "EROFS";
   message[rofs] := "Read-only file system";
   name[mlink] := "EMLINK";
   message[mlink] := "Too many links";
   name[pipe] := "EPIPE";
   message[pipe] := "Broken pipe";
   name[dom] := "EDOM";
   message[dom] := "Math argument out of domain of func";
   name[range] := "ERANGE";
   message[range] := "Math result not representable";
   name[deadlk] := "EDEADLK";
   message[deadlk] := "Resource deadlock would occur";
   name[nametoolong] := "ENAMETOOLONG";
   message[nametoolong] := "File name too long";
   name[nolck] := "ENOLCK";
   message[nolck] := "No record locks available";
   name[nosys] := "ENOSYS";
   message[nosys] := "Function not implemented";
   name[notempty] := "ENOTEMPTY";
   message[notempty] := "Directory not empty";
   name[loop] := "ELOOP";
   message[loop] := "Too many symbolic links encountered";
   name[nomsg] := "ENOMSG";
   message[nomsg] := "No message of desired type";
   name[idrm] := "EIDRM";
   message[idrm] := "Identifier removed";
   name[chrng] := "ECHRNG";
   message[chrng] := "Channel number out of range";
   name[l2nsync] := "EL2NSYNC";
   message[l2nsync] := "Level 2 not synchronized";
   name[l3hlt] := "EL3HLT";
   message[l3hlt] := "Level 3 halted";
   name[l3rst] := "EL3RST";
   message[l3rst] := "Level 3 reset";
   name[lnrng] := "ELNRNG";
   message[lnrng] := "Link number out of range";
   name[unatch] := "EUNATCH";
   message[unatch] := "Protocol driver not attached";
   name[nocsi] := "ENOCSI";
   message[nocsi] := "No CSI structure available";
   name[l2hlt] := "EL2HLT";
   message[l2hlt] := "Level 2 halted";
   name[bade] := "EBADE";
   message[bade] := "Invalid exchange";
   name[badr] := "EBADR";
   message[badr] := "Invalid request descriptor";
   name[xfull] := "EXFULL";
   message[xfull] := "Exchange full";
   name[noano] := "ENOANO";
   message[noano] := "No anode";
   name[badrqc] := "EBADRQC";
   message[badrqc] := "Invalid request code";
   name[badslt] := "EBADSLT";
   message[badslt] := "Invalid slot";
   name[bfont] := "EBFONT";
   message[bfont] := "Bad font file format";
   name[nostr] := "ENOSTR";
   message[nostr] := "Device not a stream";
   name[nodata] := "ENODATA";
   message[nodata] := "No data available";
   name[time] := "ETIME";
   message[time] := "Timer expired";
   name[nosr] := "ENOSR";
   message[nosr] := "Out of streams resources";
   name[nonet] := "ENONET";
   message[nonet] := "Machine is not on the network";
   name[nopkg] := "ENOPKG";
   message[nopkg] := "Package not installed";
   name[remote] := "EREMOTE";
   message[remote] := "Object is remote";
   name[nolink] := "ENOLINK";
   message[nolink] := "Link has been severed";
   name[adv] := "EADV";
   message[adv] := "Advertise error";
   name[srmnt] := "ESRMNT";
   message[srmnt] := "Srmount error";
   name[comm] := "ECOMM";
   message[comm] := "Communication error on send";
   name[proto] := "EPROTO";
   message[proto] := "Protocol error";
   name[multihop] := "EMULTIHOP";
   message[multihop] := "Multihop attempted";
   name[dotdot] := "EDOTDOT";
   message[dotdot] := "RFS specific error";
   name[badmsg] := "EBADMSG";
   message[badmsg] := "Not a data message";
   name[overflow] := "EOVERFLOW";
   message[overflow] := "Value too large for defined data type";
   name[notuniq] := "ENOTUNIQ";
   message[notuniq] := "Name not unique on network";
   name[badfd] := "EBADFD";
   message[badfd] := "File descriptor in bad state";
   name[remchg] := "EREMCHG";
   message[remchg] := "Remote address changed";
   name[libacc] := "ELIBACC";
   message[libacc] := "Can not access a needed shared library";
   name[libbad] := "ELIBBAD";
   message[libbad] := "Accessing a corrupted shared library";
   name[libscn] := "ELIBSCN";
   message[libscn] := ".lib section in a.out corrupted";
   name[libmax] := "ELIBMAX";
   message[libmax] := "Attempting to link in too many shared libraries";
   name[libexec] := "ELIBEXEC";
   message[libexec] := "Cannot exec a shared library directly";
   name[ilseq] := "EILSEQ";
   message[ilseq] := "Illegal byte sequence";
   name[restart] := "ERESTART";
   message[restart] := "Interrupted system call should be restarted";
   name[strpipe] := "ESTRPIPE";
   message[strpipe] := "Streams pipe error";
   name[users] := "EUSERS";
   message[users] := "Too many users";
   name[notsock] := "ENOTSOCK";
   message[notsock] := "Socket operation on non-socket";
   name[destaddrreq] := "EDESTADDRREQ";
   message[destaddrreq] := "Destination address required";
   name[msgsize] := "EMSGSIZE";
   message[msgsize] := "Message too long";
   name[prototype] := "EPROTOTYPE";
   message[prototype] := "Protocol wrong type for socket";
   name[noprotoopt] := "ENOPROTOOPT";
   message[noprotoopt] := "Protocol not available";
   name[protonosupport] := "EPROTONOSUPPORT";
   message[protonosupport] := "Protocol not supported";
   name[socktnosupport] := "ESOCKTNOSUPPORT";
   message[socktnosupport] := "Socket type not supported";
   name[opnotsupp] := "EOPNOTSUPP";
   message[opnotsupp] := "Operation not supported on transport endpoint";
   name[pfnosupport] := "EPFNOSUPPORT";
   message[pfnosupport] := "Protocol family not supported";
   name[afnosupport] := "EAFNOSUPPORT";
   message[afnosupport] := "Address family not supported by protocol";
   name[addrinuse] := "EADDRINUSE";
   message[addrinuse] := "Address already in use";
   name[addrnotavail] := "EADDRNOTAVAIL";
   message[addrnotavail] := "Cannot assign requested address";
   name[netdown] := "ENETDOWN";
   message[netdown] := "Network is down";
   name[netunreach] := "ENETUNREACH";
   message[netunreach] := "Network is unreachable";
   name[netreset] := "ENETRESET";
   message[netreset] := "Network dropped connection because of reset";
   name[connaborted] := "ECONNABORTED";
   message[connaborted] := "Software caused connection abort";
   name[connreset] := "ECONNRESET";
   message[connreset] := "Connection reset by peer";
   name[nobufs] := "ENOBUFS";
   message[nobufs] := "No buffer space available";
   name[isconn] := "EISCONN";
   message[isconn] := "Transport endpoint is already connected";
   name[notconn] := "ENOTCONN";
   message[notconn] := "Transport endpoint is not connected";
   name[shutdown] := "ESHUTDOWN";
   message[shutdown] := "Cannot send after transport endpoint shutdown";
   name[toomanyrefs] := "ETOOMANYREFS";
   message[toomanyrefs] := "Too many references: cannot splice";
   name[timedout] := "ETIMEDOUT";
   message[timedout] := "Connection timed out";
   name[connrefused] := "ECONNREFUSED";
   message[connrefused] := "Connection refused";
   name[hostdown] := "EHOSTDOWN";
   message[hostdown] := "Host is down";
   name[hostunreach] := "EHOSTUNREACH";
   message[hostunreach] := "No route to host";
   name[already] := "EALREADY";
   message[already] := "Operation already in progress";
   name[inprogress] := "EINPROGRESS";
   message[inprogress] := "Operation now in progress";
   name[stale] := "ESTALE";
   message[stale] := "Stale NFS file handle";
   name[uclean] := "EUCLEAN";
   message[uclean] := "Structure needs cleaning";
   name[notnam] := "ENOTNAM";
   message[notnam] := "Not a XENIX named type file";
   name[navail] := "ENAVAIL";
   message[navail] := "No XENIX semaphores available";
   name[isnam] := "EISNAM";
   message[isnam] := "Is a named type file";
   name[remoteio] := "EREMOTEIO";
   message[remoteio] := "Remote I/O error";
   name[dquot] := "EDQUOT";
   message[dquot] := "Quota exceeded";
   name[nomedium] := "ENOMEDIUM";
   message[nomedium] := "No medium found";
   name[mediumtype] := "EMEDIUMTYPE";
   message[mediumtype] := "Wrong medium type";
END ulmSysErrors.
