浏览代码

From CHAR8 to CHAR16, module Files finally places .tmp.. files in /tmp

Arthur Yefimov 3 年之前
父节点
当前提交
e446b5b98d
共有 9 个文件被更改,包括 218 次插入244 次删除
  1. 1 1
      src/Editor.Mod
  2. 11 39
      src/EditorText.Mod
  3. 149 102
      src/Files.Mod
  4. 23 46
      src/FreeOberon.Mod
  5. 20 22
      src/Graph.Mod
  6. 1 2
      src/In.Mod
  7. 2 19
      src/OV.Mod
  8. 4 11
      src/Terminal.Mod
  9. 7 2
      src/Utf8.Mod

+ 1 - 1
src/Editor.Mod

@@ -962,7 +962,7 @@ END EditorMouseMove;
 
 
 PROCEDURE EditorTextInput(c: OV.Control; ch: CHAR);
 PROCEDURE EditorTextInput(c: OV.Control; ch: CHAR);
 BEGIN
 BEGIN
-  IF ch # 0X THEN c(Editor).text.InsertChar(OV.ToCP866(ch)); T.ResetCursorBlink;
+  IF ch # 0X THEN c(Editor).text.InsertChar(ch); T.ResetCursorBlink;
     c(Editor).text.selected := FALSE; PrintText(c(Editor))
     c(Editor).text.selected := FALSE; PrintText(c(Editor))
   END
   END
 END EditorTextInput;
 END EditorTextInput;

+ 11 - 39
src/EditorText.Mod

@@ -321,29 +321,15 @@ BEGIN
   buf[i] := 0X
   buf[i] := 0X
 END CopySelection;
 END CopySelection;
 
 
-PROCEDURE WriteString(VAR r: Files.Rider; s: ARRAY OF CHAR);
-VAR i: INTEGER; ch: CHAR;
-BEGIN
-  i := 0; s[LEN(s) - 1] := 0X;
-  WHILE s[i] # 0X DO
-    ch := s[i];
-    IF ORD(ch) < 128 THEN Files.WriteChar(r, SHORT(ch)) (* ASCII *)
-    ELSIF ORD(ch) = 240 THEN (* Big cyrillic Yo *)
-      Files.WriteChar(r, 0D0X); Files.WriteChar(r, 81X)
-    ELSIF ORD(ch) < 224 THEN (* Before small cyrillic R *)
-      Files.WriteChar(r, 0D0X);
-      Files.WriteChar(r, SHORT(CHR(ORD(ch) - 128 + 090H)))
-    ELSE
-      Files.WriteChar(r, 0D1X);
-      Files.WriteChar(r, SHORT(CHR(ORD(ch) - 224 + 080H)))
-    END;
-    INC(i)
-  END
+PROCEDURE WriteString(VAR r: Files.Rider; IN s: ARRAY OF CHAR);
+VAR i: INTEGER;
+BEGIN i := 0;
+  WHILE (i # LEN(s)) & (s[i] # 0X) DO Files.WriteChar(r, s[i]); INC(i) END
 END WriteString;
 END WriteString;
 
 
 PROCEDURE WriteLn(VAR r: Files.Rider);
 PROCEDURE WriteLn(VAR r: Files.Rider);
 BEGIN
 BEGIN
-  IF Config.isWindows THEN Files.WriteChar(r, 0DX) END;
+  IF Config.isWindows THEN Files.WriteChar(r, 0DX) END;(*!TODO crossplatform*)
   Files.WriteChar(r, 0AX)
   Files.WriteChar(r, 0AX)
 END WriteLn;
 END WriteLn;
 
 
@@ -362,11 +348,9 @@ PROCEDURE (t: Text) SaveToFile*(fname: ARRAY OF CHAR): BOOLEAN, NEW;
 VAR f: Files.File; r: Files.Rider;
 VAR f: Files.File; r: Files.Rider;
   success: BOOLEAN;
   success: BOOLEAN;
   L: Line;
   L: Line;
-  s: ARRAY 2048 OF SHORTCHAR;
 BEGIN success := FALSE;
 BEGIN success := FALSE;
   FixFname(fname);
   FixFname(fname);
-  Utf8.Encode(fname, s);
-  f := Files.New(s);
+  f := Files.New(fname);
   IF f # NIL THEN (*!FIXME error checking is wrong *)
   IF f # NIL THEN (*!FIXME error checking is wrong *)
     Files.Set(r, f, 0);
     Files.Set(r, f, 0);
     L := t.first;
     L := t.first;
@@ -388,26 +372,16 @@ BEGIN success := FALSE;
 RETURN success END SaveToFile;
 RETURN success END SaveToFile;
 
 
 PROCEDURE ReadLine(VAR r: Files.Rider; L: Line);
 PROCEDURE ReadLine(VAR r: Files.Rider; L: Line);
-VAR x: SHORTCHAR; ch: CHAR; i: INTEGER;
+VAR ch: CHAR; i: INTEGER;
 BEGIN i := 0;
 BEGIN i := 0;
-  Files.ReadChar(r, x); ch := LONG(x);
+  Files.ReadChar(r, ch);
   WHILE ~r.eof & (i < LEN(L.s) - 1) & (ch # 0AX) & (ch # 0DX) DO
   WHILE ~r.eof & (i < LEN(L.s) - 1) & (ch # 0AX) & (ch # 0DX) DO
-    IF ORD(ch) < 128 THEN L.s[i] := ch
-    ELSIF ch = 0D0X THEN
-      Files.ReadChar(r, x); ch := LONG(x);
-      IF ch = 081X THEN L.s[i] := CHR(240) (* Big Yo *)
-      ELSE L.s[i] := CHR(ORD(ch) - 16)
-      END
-    ELSIF ch = 0D1X THEN
-      Files.ReadChar(r, x); ch := LONG(x); L.s[i] := CHR(ORD(ch) + 96)
-    END;
-    Files.ReadChar(r, x); ch := LONG(x);
-    INC(i)
+    L.s[i] := ch; Files.ReadChar(r, ch); INC(i)
   END;
   END;
   L.s[i] := 0X;
   L.s[i] := 0X;
   IF ch = 0DX THEN
   IF ch = 0DX THEN
     L.lineEndLen := 2; (* Assume CRLF (DOS) *)
     L.lineEndLen := 2; (* Assume CRLF (DOS) *)
-    Files.ReadChar(r, x) (* Skip LF *)
+    Files.ReadChar(r, ch) (* Skip LF *)
   ELSE L.lineEndLen := 1 (* Assume LF (UNIX) *)
   ELSE L.lineEndLen := 1 (* Assume LF (UNIX) *)
   END
   END
 END ReadLine;
 END ReadLine;
@@ -416,12 +390,10 @@ PROCEDURE (t: Text) LoadFromFile*(fname: ARRAY OF CHAR): BOOLEAN, NEW;
 VAR f: Files.File; r: Files.Rider;
 VAR f: Files.File; r: Files.Rider;
   success: BOOLEAN;
   success: BOOLEAN;
   L: Line;
   L: Line;
-  s: ARRAY 2048 OF SHORTCHAR;
 BEGIN success := FALSE;
 BEGIN success := FALSE;
   IF fname[0] # 0X THEN
   IF fname[0] # 0X THEN
     FixFname(fname);
     FixFname(fname);
-    Utf8.Encode(fname, s);
-    f := Files.Old(s);
+    f := Files.Old(fname);
     IF f # NIL THEN
     IF f # NIL THEN
       Files.Set(r, f, 0);
       Files.Set(r, f, 0);
       L := NewLine();
       L := NewLine();

+ 149 - 102
src/Files.Mod

@@ -28,7 +28,10 @@ CONST
                  just write directly to final register name *)
                  just write directly to final register name *)
 
 
 TYPE
 TYPE
-  FileName = ARRAY 256 OF SHORTCHAR;
+  SBYTE* = BYTE;
+  BYTE* = UBYTE;
+
+  FileName = ARRAY 256 OF CHAR;
   File* = POINTER TO FileDesc;
   File* = POINTER TO FileDesc;
   Buffer = POINTER TO BufDesc;
   Buffer = POINTER TO BufDesc;
 
 
@@ -48,7 +51,7 @@ TYPE
     chg: BOOLEAN;
     chg: BOOLEAN;
     org: LONGINT;
     org: LONGINT;
     size: INTEGER;
     size: INTEGER;
-    data: ARRAY BufSize OF BYTE
+    data: ARRAY BufSize OF SBYTE
   END;
   END;
 
 
   Rider* = RECORD
   Rider* = RECORD
@@ -64,8 +67,8 @@ VAR
   files: POINTER [notag] TO FileDesc;
   files: POINTER [notag] TO FileDesc;
 
 
   tempno: INTEGER;
   tempno: INTEGER;
-  home: ARRAY 1024 OF SHORTCHAR;
-  SearchPath: ARRAY 4096 OF SHORTCHAR;
+  home: ARRAY 1024 OF CHAR;
+  SearchPath: ARRAY 4096 OF CHAR;
 
 
 PROCEDURE -IdxTrap(pos: INTEGER) '__HALT(-1, "Files.Mod", pos)';
 PROCEDURE -IdxTrap(pos: INTEGER) '__HALT(-1, "Files.Mod", pos)';
 
 
@@ -75,8 +78,8 @@ PROCEDURE Err(IN s: ARRAY OF CHAR; f: File; errcode: Platform.ErrorCode);
 BEGIN
 BEGIN
   Out.Ln; Out.String('-- '); Out.String(s); Out.String(': ');
   Out.Ln; Out.String('-- '); Out.String(s); Out.String(': ');
   IF f # NIL THEN
   IF f # NIL THEN
-    IF f.registerName # '' THEN Out.Utf8(f.registerName)
-    ELSE Out.Utf8(f.workName)
+    IF f.registerName # '' THEN Out.String(f.registerName)
+    ELSE Out.String(f.workName)
     END;
     END;
     IF f.fd # 0 THEN Out.String(' f.fd = '); Out.Int(f.fd, 1) END
     IF f.fd # 0 THEN Out.String(' f.fd = '); Out.Int(f.fd, 1) END
   END;
   END;
@@ -85,8 +88,7 @@ BEGIN
   HALT(99)
   HALT(99)
 END Err;
 END Err;
 
 
-PROCEDURE MakeFileName(IN dir, name: ARRAY OF SHORTCHAR;
-    VAR dest: ARRAY OF SHORTCHAR);
+PROCEDURE MakeFileName(IN dir, name: ARRAY OF CHAR; VAR dest: ARRAY OF CHAR);
 VAR i, j: INTEGER;
 VAR i, j: INTEGER;
 BEGIN i := 0; j := 0;
 BEGIN i := 0; j := 0;
   WHILE dir[i] # 0X DO dest[i] := dir[i]; INC(i) END;
   WHILE dir[i] # 0X DO dest[i] := dir[i]; INC(i) END;
@@ -95,30 +97,19 @@ BEGIN i := 0; j := 0;
   dest[i] := 0X
   dest[i] := 0X
 END MakeFileName;
 END MakeFileName;
 
 
-PROCEDURE GetTempName(IN finalName: ARRAY OF SHORTCHAR;
-    VAR name: ARRAY OF SHORTCHAR);
-VAR n, i, j: INTEGER;
-BEGIN
-  INC(tempno); n := tempno; i := 0;
-  IF finalName[0] # PathDelimiter THEN  (* relative pathname *)
-    WHILE Platform.CWD[i] # 0X DO name[i] := Platform.CWD[i]; INC(i) END;
-    IF Platform.CWD[i-1] # PathDelimiter THEN
-      name[i] := PathDelimiter; INC(i)
-    END
-  END;
-  j := 0;
-  WHILE finalName[j] # 0X DO name[i] := finalName[j]; INC(i); INC(j) END;
-  DEC(i);
-  WHILE name[i] # PathDelimiter DO DEC(i) END;
-  name[i + 1] := '.'; name[i + 2] := 't'; name[i + 3] := 'm';
-  name[i + 4] := 'p'; name[i + 5] := '.'; INC(i, 6);
-  WHILE n > 0 DO
-    name[i] := SHORT(CHR(n MOD 10 + ORD('0'))); n := n DIV 10; INC(i)
-  END;
+PROCEDURE GetTempName(IN finalName: ARRAY OF CHAR; VAR name: ARRAY OF CHAR);
+VAR n, i: INTEGER;
+  q: ARRAY 256 OF SHORTCHAR;
+BEGIN INC(tempno); Platform.GetTempPath(q); Utf8.Decode(q, name);
+  i := 0; WHILE name[i] # 0X DO INC(i) END;
+
+  name[i] := 'o'; INC(i); name[i] := 'b'; INC(i); name[i] := 'e'; INC(i);
+  name[i] := 'r'; INC(i); name[i] := 'o'; INC(i); name[i] := 'n'; INC(i);
+  name[i] := '.'; INC(i); n := tempno;
+  REPEAT name[i] := CHR(n MOD 10 + 30H); n := n DIV 10; INC(i) UNTIL n = 0;
+
   name[i] := '.'; INC(i); n := Platform.PID;
   name[i] := '.'; INC(i); n := Platform.PID;
-  WHILE n > 0 DO
-    name[i] := SHORT(CHR(n MOD 10 + ORD('0'))); n := n DIV 10; INC(i)
-  END;
+  REPEAT name[i] := CHR(n MOD 10 + 30H); n := n DIV 10; INC(i) UNTIL n = 0;
   name[i] := 0X
   name[i] := 0X
 END GetTempName;
 END GetTempName;
 
 
@@ -131,12 +122,14 @@ END GetTempName;
    a real Oberon system, where registering the new file has the effect of
    a real Oberon system, where registering the new file has the effect of
    unregistering the old file. To simulate this we need to change the old
    unregistering the old file. To simulate this we need to change the old
    Files.File back to a temp file. *)
    Files.File back to a temp file. *)
-PROCEDURE Deregister(IN name: ARRAY OF SHORTCHAR);
+PROCEDURE Deregister(IN name: ARRAY OF CHAR);
 VAR identity: Platform.FileIdentity;
 VAR identity: Platform.FileIdentity;
   osfile: File;
   osfile: File;
   error: Platform.ErrorCode;
   error: Platform.ErrorCode;
+  q, s: ARRAY 2048 OF SHORTCHAR;
 BEGIN
 BEGIN
-  IF Platform.IdentifyByName(name, identity) = 0 THEN
+  Utf8.Encode(name, q);
+  IF Platform.IdentifyByName(q, identity) = 0 THEN
     (* The name we are registering is an already existing file. *)
     (* The name we are registering is an already existing file. *)
     osfile := files;
     osfile := files;
     WHILE (osfile # NIL) & ~Platform.SameFile(osfile.identity, identity) DO
     WHILE (osfile # NIL) & ~Platform.SameFile(osfile.identity, identity) DO
@@ -151,7 +144,9 @@ BEGIN
       osfile.tempFile := TRUE;
       osfile.tempFile := TRUE;
       error := Platform.CloseFile(osfile.fd);
       error := Platform.CloseFile(osfile.fd);
       osfile.state := close;
       osfile.state := close;
-      error := Platform.RenameFile(osfile.registerName, osfile.workName);
+      Utf8.Encode(osfile.registerName, q);
+      Utf8.Encode(osfile.workName, s);
+      error := Platform.RenameFile(q, s);
       IF error # 0 THEN
       IF error # 0 THEN
         Err('Could not rename previous version of file being registered',
         Err('Could not rename previous version of file being registered',
           osfile, error)
           osfile, error)
@@ -160,14 +155,15 @@ BEGIN
   END
   END
 END Deregister;
 END Deregister;
 
 
+(** Makes sure there is an OS file backing this Oberon file.
+    Used when more data has been written to an unregistered new file than
+    buffers can hold, or when registering a new file whose data is all in
+    buffers. *)
 PROCEDURE Create(f: File);
 PROCEDURE Create(f: File);
-(* Makes sure there is an OS file backing this Oberon file.
-   Used when more data has been written to an unregistered new file than
-   buffers can hold, or when registering a new file whose data is all in
-   buffers. *)
 VAR done: BOOLEAN;
 VAR done: BOOLEAN;
   error: Platform.ErrorCode;
   error: Platform.ErrorCode;
   err: ARRAY 32 OF CHAR;
   err: ARRAY 32 OF CHAR;
+  q: ARRAY 2048 OF SHORTCHAR;
 BEGIN
 BEGIN
   IF f.fd = Platform.InvalidHandleValue() THEN
   IF f.fd = Platform.InvalidHandleValue() THEN
     IF f.state = create THEN
     IF f.state = create THEN
@@ -182,9 +178,10 @@ BEGIN
       f.workName := f.registerName; f.registerName := ''; f.tempFile := FALSE
       f.workName := f.registerName; f.registerName := ''; f.tempFile := FALSE
     END;
     END;
     (* Unlink first to avoid stale NFS handles and to avoid reuse of inodes *)
     (* Unlink first to avoid stale NFS handles and to avoid reuse of inodes *)
-    error := Platform.DeleteFile(f.workName);
+    Utf8.Encode(f.workName, q);
+    error := Platform.DeleteFile(q);
 
 
-    error := Platform.NewFile(f.workName, f.fd);
+    error := Platform.NewFile(q, f.fd);
     done := error = 0;
     done := error = 0;
     IF done THEN
     IF done THEN
       (* Link this file into the list of OS backed files. *)
       (* Link this file into the list of OS backed files. *)
@@ -247,7 +244,7 @@ END Close;
 PROCEDURE Length*(f: File): LONGINT;
 PROCEDURE Length*(f: File): LONGINT;
 BEGIN RETURN f.len END Length;
 BEGIN RETURN f.len END Length;
 
 
-PROCEDURE New*(IN name: ARRAY OF SHORTCHAR): File;
+PROCEDURE New*(IN name: ARRAY OF CHAR): File;
 VAR f: File;
 VAR f: File;
 BEGIN
 BEGIN
   NEW(f); f.workName := ''; f.registerName := name$;
   NEW(f); f.workName := ''; f.registerName := name$;
@@ -255,11 +252,11 @@ BEGIN
   f.len := 0; f.pos := 0; f.swapper := -1 ;
   f.len := 0; f.pos := 0; f.swapper := -1 ;
 RETURN f END New;
 RETURN f END New;
 
 
-PROCEDURE ScanPath(VAR pos: INTEGER; VAR dir: ARRAY OF SHORTCHAR);
+PROCEDURE ScanPath(VAR pos: INTEGER; VAR dir: ARRAY OF CHAR);
 (* Extract next individual directory from searchpath starting at pos,
 (* Extract next individual directory from searchpath starting at pos,
    updating pos and returning dir.
    updating pos and returning dir.
    Supports ~, ~user and blanks inside path *)
    Supports ~, ~user and blanks inside path *)
-VAR i: INTEGER; ch: SHORTCHAR;
+VAR i: INTEGER; ch: CHAR;
 BEGIN
 BEGIN
   i := 0;
   i := 0;
   IF SearchPath = '' THEN (* Default search path is the current directory *)
   IF SearchPath = '' THEN (* Default search path is the current directory *)
@@ -284,8 +281,8 @@ BEGIN
   dir[i] := 0X
   dir[i] := 0X
 END ScanPath;
 END ScanPath;
 
 
-PROCEDURE HasDir(IN name: ARRAY OF SHORTCHAR): BOOLEAN;
-VAR i: INTEGER; ch: SHORTCHAR;
+PROCEDURE HasDir(IN name: ARRAY OF CHAR): BOOLEAN;
+VAR i: INTEGER; ch: CHAR;
 BEGIN i := 0; ch := name[0];
 BEGIN i := 0; ch := name[0];
   WHILE (ch # 0X) & (ch # PathDelimiter) DO INC(i); ch := name[i] END ;
   WHILE (ch # 0X) & (ch # PathDelimiter) DO INC(i); ch := name[i] END ;
 RETURN ch = PathDelimiter END HasDir;
 RETURN ch = PathDelimiter END HasDir;
@@ -310,35 +307,34 @@ BEGIN f := files;
   RETURN NIL
   RETURN NIL
 END CacheEntry;
 END CacheEntry;
 
 
-PROCEDURE Old*(IN name: ARRAY OF SHORTCHAR): File;
+PROCEDURE Old*(IN name: ARRAY OF CHAR): File;
 VAR f: File;
 VAR f: File;
   fd: Platform.FileHandle;
   fd: Platform.FileHandle;
   pos: INTEGER;
   pos: INTEGER;
   done: BOOLEAN;
   done: BOOLEAN;
-  dir, path: ARRAY 256 OF SHORTCHAR;
+  dir, path: ARRAY 256 OF CHAR;
   error: Platform.ErrorCode;
   error: Platform.ErrorCode;
   identity: Platform.FileIdentity;
   identity: Platform.FileIdentity;
+  q: ARRAY 4096 OF SHORTCHAR;
 BEGIN
 BEGIN
-  (* Out.String('Files.Old '); Out.String(name); Out.Ln; *)
   IF name # '' THEN
   IF name # '' THEN
     IF HasDir(name) THEN dir := ''; path := name$
     IF HasDir(name) THEN dir := ''; path := name$
     ELSE pos := 0; ScanPath(pos, dir);
     ELSE pos := 0; ScanPath(pos, dir);
       MakeFileName(dir, name, path); ScanPath(pos, dir)
       MakeFileName(dir, name, path); ScanPath(pos, dir)
     END;
     END;
-    LOOP
-      error := Platform.OldRW(path, fd); done := error = 0;
+    LOOP Utf8.Encode(path, q);
+      error := Platform.OldRW(q, fd); done := error = 0;
       IF ~done & Platform.TooManyFiles(error) THEN
       IF ~done & Platform.TooManyFiles(error) THEN
         Err('too many files open', f, error)
         Err('too many files open', f, error)
       END;
       END;
       IF ~done & Platform.Inaccessible(error) THEN
       IF ~done & Platform.Inaccessible(error) THEN
-        error := Platform.OldRO(path, fd); done := error = 0
+        error := Platform.OldRO(q, fd); done := error = 0
       END;
       END;
       IF ~done & ~Platform.Absent(error) THEN
       IF ~done & ~Platform.Absent(error) THEN
-        Out.String('Warning: Files.Old '); Out.Utf8(name);
-        Out.String(' error = '); Out.Int(error, 0); Out.Ln;
+        Out.String('Warning: Files.Old '); Out.String(name);
+        Out.String(' error = '); Out.Int(error, 0); Out.Ln
       END;
       END;
       IF done THEN
       IF done THEN
-        (* Out.String('  fd = '); Out.Int(fd,1); Out.Ln; *)
         error := Platform.Identify(fd, identity);
         error := Platform.Identify(fd, identity);
         f := CacheEntry(identity);
         f := CacheEntry(identity);
         IF f # NIL THEN
         IF f # NIL THEN
@@ -428,7 +424,7 @@ BEGIN
   r.buf := buf; r.org := org; r.offset := offset; r.eof := FALSE; r.res := 0
   r.buf := buf; r.org := org; r.offset := offset; r.eof := FALSE; r.res := 0
 END Set;
 END Set;
 
 
-PROCEDURE ReadByte*(VAR r: Rider; VAR x: BYTE);
+PROCEDURE Read*(VAR r: Rider; VAR x: BYTE);
 VAR offset: INTEGER; buf: Buffer;
 VAR offset: INTEGER; buf: Buffer;
 BEGIN
 BEGIN
   buf := r.buf; offset := r.offset;
   buf := r.buf; offset := r.offset;
@@ -436,13 +432,13 @@ BEGIN
     Set(r, buf.f, r.org + offset); buf := r.buf; offset := r.offset
     Set(r, buf.f, r.org + offset); buf := r.buf; offset := r.offset
   END;
   END;
   IF (offset < buf.size) THEN
   IF (offset < buf.size) THEN
-    x := buf.data[offset]; r.offset := offset + 1
+    x := SYSTEM.VAL(BYTE, buf.data[offset]); r.offset := offset + 1
   ELSIF r.org + offset < buf.f.len THEN
   ELSIF r.org + offset < buf.f.len THEN
     Set(r, r.buf.f, r.org + offset);
     Set(r, r.buf.f, r.org + offset);
-    x := r.buf.data[0]; r.offset := 1
+    x := SYSTEM.VAL(BYTE, r.buf.data[0]); r.offset := 1
   ELSE x := 0; r.eof := TRUE
   ELSE x := 0; r.eof := TRUE
   END
   END
-END ReadByte;
+END Read;
 
 
 PROCEDURE ReadBytes*(VAR r: Rider; VAR x: ARRAY OF BYTE; n: INTEGER);
 PROCEDURE ReadBytes*(VAR r: Rider; VAR x: ARRAY OF BYTE; n: INTEGER);
 VAR xpos, min, restInBuf, offset: INTEGER; buf: Buffer;
 VAR xpos, min, restInBuf, offset: INTEGER; buf: Buffer;
@@ -463,15 +459,34 @@ BEGIN
   r.res := 0; r.eof := FALSE
   r.res := 0; r.eof := FALSE
 END ReadBytes;
 END ReadBytes;
 
 
-PROCEDURE ReadChar*(VAR r: Rider; VAR x: SHORTCHAR);
-BEGIN ReadByte(r, SYSTEM.VAL(BYTE, x))
+PROCEDURE ReadShortChar*(VAR r: Rider; VAR x: SHORTCHAR);
+BEGIN Read(r, SYSTEM.VAL(BYTE, x))
+END ReadShortChar;
+
+PROCEDURE ReadChar*(VAR r: Rider; VAR x: CHAR);
+VAR b: BYTE; y: INTEGER;
+BEGIN Read(r, b); y := b;
+  IF y > 80H THEN Read(r, b); b := SYSTEM.VAL(BYTE, b MOD 64); (* Not 1 byte *)
+    IF y DIV 32 = 6 THEN (* 2 bytes *)
+      y := y MOD 32 * 64 + b
+    ELSIF y DIV 16 = 14 THEN (* 3 bytes *)
+      y := (y MOD 16 * 64 + b) * 64;
+      Read(r, b); INC(y, b MOD 64)
+    ELSIF y DIV 8 = 30 THEN (* 4 bytes *)
+      y := (y MOD 8 * 64 + b) * 64;
+      Read(r, b); y := (y + b MOD 64) * 64;
+      Read(r, b); INC(y, b MOD 64) (*!FIXME UTF-16 surrogate pairs *)
+    ELSE y := 0
+    END
+  END;
+  x := CHR(y)
 END ReadChar;
 END ReadChar;
 
 
 PROCEDURE Base*(VAR r: Rider): File;
 PROCEDURE Base*(VAR r: Rider): File;
 BEGIN RETURN r.buf.f
 BEGIN RETURN r.buf.f
 END Base;
 END Base;
 
 
-PROCEDURE WriteByte*(VAR r: Rider; x: BYTE);
+PROCEDURE Write*(VAR r: Rider; x: BYTE);
 VAR buf: Buffer; offset: INTEGER;
 VAR buf: Buffer; offset: INTEGER;
 BEGIN
 BEGIN
   buf := r.buf; offset := r.offset;
   buf := r.buf; offset := r.offset;
@@ -485,7 +500,7 @@ BEGIN
     INC(buf.size); INC(buf.f.len)
     INC(buf.size); INC(buf.f.len)
   END;
   END;
   r.offset := offset + 1; r.res := 0
   r.offset := offset + 1; r.res := 0
-END WriteByte;
+END Write;
 
 
 PROCEDURE WriteBytes*(VAR r: Rider; IN x: ARRAY OF BYTE; n: INTEGER);
 PROCEDURE WriteBytes*(VAR r: Rider; IN x: ARRAY OF BYTE; n: INTEGER);
 VAR xpos, min, restInBuf, offset: INTEGER; buf: Buffer;
 VAR xpos, min, restInBuf, offset: INTEGER; buf: Buffer;
@@ -507,9 +522,10 @@ BEGIN
   r.res := 0
   r.res := 0
 END WriteBytes;
 END WriteBytes;
 
 
-PROCEDURE Delete*(IN name: ARRAY OF SHORTCHAR; VAR res: INTEGER);
+PROCEDURE Delete*(IN name: ARRAY OF CHAR; VAR res: INTEGER);
 VAR pos: INTEGER;
 VAR pos: INTEGER;
-  dir, path: ARRAY 256 OF SHORTCHAR;
+  dir, path: ARRAY 2048 OF CHAR;
+  q: ARRAY 2048 OF SHORTCHAR;
 BEGIN
 BEGIN
   IF name # '' THEN
   IF name # '' THEN
     IF HasDir(name) THEN dir := ''; path := name$
     IF HasDir(name) THEN dir := ''; path := name$
@@ -518,7 +534,8 @@ BEGIN
     END;
     END;
     LOOP
     LOOP
       Deregister(path);
       Deregister(path);
-      res := Platform.DeleteFile(path);
+      Utf8.Encode(path, q);
+      res := Platform.DeleteFile(q);
       IF (res = 0) OR (dir = '') THEN RETURN
       IF (res = 0) OR (dir = '') THEN RETURN
       ELSE MakeFileName(dir, name, path); ScanPath(pos, dir)
       ELSE MakeFileName(dir, name, path); ScanPath(pos, dir)
       END
       END
@@ -527,21 +544,21 @@ BEGIN
   END
   END
 END Delete;
 END Delete;
 
 
-PROCEDURE Rename*(IN old, new: ARRAY OF SHORTCHAR; VAR res: INTEGER);
+PROCEDURE Rename*(IN old, new: ARRAY OF CHAR; VAR res: INTEGER);
 VAR n: INTEGER;
 VAR n: INTEGER;
   fdold, fdnew: Platform.FileHandle;
   fdold, fdnew: Platform.FileHandle;
   error, ignore: Platform.ErrorCode;
   error, ignore: Platform.ErrorCode;
   oldidentity, newidentity: Platform.FileIdentity;
   oldidentity, newidentity: Platform.FileIdentity;
-  buf: ARRAY 4096 OF SHORTCHAR;
+  buf, old2, new2: ARRAY 4096 OF SHORTCHAR;
 BEGIN
 BEGIN
-  error := Platform.IdentifyByName(old, oldidentity);
+  Utf8.Encode(old, old2); Utf8.Encode(new, new2);
+  error := Platform.IdentifyByName(old2, oldidentity);
   IF error = 0 THEN
   IF error = 0 THEN
-    error := Platform.IdentifyByName(new, newidentity);
+    error := Platform.IdentifyByName(new2, newidentity);
     IF (error # 0) & ~Platform.SameFile(oldidentity, newidentity) THEN
     IF (error # 0) & ~Platform.SameFile(oldidentity, newidentity) THEN
       Delete(new, error) (* work around stale nfs handles *)
       Delete(new, error) (* work around stale nfs handles *)
     END;
     END;
-    error := Platform.RenameFile(old, new);
-    (* Out.String('Platform.Rename error code '); Out.Int(error,1); Out.Ln; *)
+    error := Platform.RenameFile(old2, new2);
     (* TODO, if we already have a FileDesc for old, it ought to be updated
     (* TODO, if we already have a FileDesc for old, it ought to be updated
        with the new workname. *)
        with the new workname. *)
     IF ~Platform.DifferentFilesystems(error) THEN
     IF ~Platform.DifferentFilesystems(error) THEN
@@ -549,12 +566,12 @@ BEGIN
       RETURN
       RETURN
     ELSE
     ELSE
       (* cross device link, move the file *)
       (* cross device link, move the file *)
-      error := Platform.OldRO(old, fdold);
+      error := Platform.OldRO(old2, fdold);
       IF error # 0 THEN
       IF error # 0 THEN
         res := 2;
         res := 2;
         RETURN
         RETURN
       END;
       END;
-      error := Platform.NewFile(new, fdnew);
+      error := Platform.NewFile(new2, fdnew);
       IF error # 0 THEN
       IF error # 0 THEN
         error := Platform.CloseFile(fdold); res := 3;
         error := Platform.CloseFile(fdold); res := 3;
         RETURN
         RETURN
@@ -571,17 +588,17 @@ BEGIN
       END;
       END;
       ignore := Platform.CloseFile(fdold);
       ignore := Platform.CloseFile(fdold);
       ignore := Platform.CloseFile(fdnew);
       ignore := Platform.CloseFile(fdnew);
-      IF n = 0 THEN error := Platform.DeleteFile(old); res := 0
+      IF n = 0 THEN error := Platform.DeleteFile(old2); res := 0
       ELSE Err('cannot move file', NIL, error)
       ELSE Err('cannot move file', NIL, error)
       END
       END
     END
     END
-  ELSE
-    res := 2 (* old file not found *)
+  ELSE res := 2 (* old file not found *)
   END
   END
 END Rename;
 END Rename;
 
 
 PROCEDURE Register*(f: File);
 PROCEDURE Register*(f: File);
 VAR errcode: INTEGER;
 VAR errcode: INTEGER;
+  q: ARRAY 2048 OF SHORTCHAR;
 BEGIN
 BEGIN
   IF (f.state = create) & (f.registerName # '') THEN f.state := close END;
   IF (f.state = create) & (f.registerName # '') THEN f.state := close END;
   Close(f);
   Close(f);
@@ -590,8 +607,8 @@ BEGIN
     errcode := Platform.CloseFile(f.fd);
     errcode := Platform.CloseFile(f.fd);
     IF errcode = 0 THEN (* Platform.RenameFile requires a closed file *)
     IF errcode = 0 THEN (* Platform.RenameFile requires a closed file *)
       Rename(f.workName, f.registerName, errcode);
       Rename(f.workName, f.registerName, errcode);
-      IF errcode = 0 THEN
-        errcode := Platform.OldRW(f.registerName, f.fd);
+      IF errcode = 0 THEN Utf8.Encode(f.registerName, q);
+        errcode := Platform.OldRW(q, f.fd);
         IF errcode = 0 THEN f.workName := f.registerName;
         IF errcode = 0 THEN f.workName := f.registerName;
           f.registerName := ''; f.tempFile := FALSE;
           f.registerName := ''; f.tempFile := FALSE;
           RETURN
           RETURN
@@ -602,9 +619,9 @@ BEGIN
   END
   END
 END Register;
 END Register;
 
 
-PROCEDURE ChangeDirectory*(IN path: ARRAY OF SHORTCHAR; VAR res: INTEGER);
-BEGIN
-  res := Platform.ChDir(path)
+PROCEDURE ChangeDirectory*(IN path: ARRAY OF CHAR; VAR res: INTEGER);
+VAR q: ARRAY 2048 OF SHORTCHAR;
+BEGIN Utf8.Encode(path, q); res := Platform.ChDir(q)
 END ChangeDirectory;
 END ChangeDirectory;
 
 
 PROCEDURE FlipBytes(VAR src, dest: ARRAY OF BYTE);
 PROCEDURE FlipBytes(VAR src, dest: ARRAY OF BYTE);
@@ -617,7 +634,7 @@ BEGIN
 END FlipBytes;
 END FlipBytes;
 
 
 PROCEDURE ReadBool*(VAR R: Rider; VAR x: BOOLEAN);
 PROCEDURE ReadBool*(VAR R: Rider; VAR x: BOOLEAN);
-BEGIN ReadByte(R, SYSTEM.VAL(BYTE, x))
+BEGIN Read(R, SYSTEM.VAL(BYTE, x))
 END ReadBool;
 END ReadBool;
 
 
 PROCEDURE ReadSInt*(VAR R: Rider; VAR x: SHORTINT);
 PROCEDURE ReadSInt*(VAR R: Rider; VAR x: SHORTINT);
@@ -659,9 +676,15 @@ BEGIN ReadBytes(R, b, 8);
   FlipBytes(b, SYSTEM.THISARR(SYSTEM.ADR(x), 8))
   FlipBytes(b, SYSTEM.THISARR(SYSTEM.ADR(x), 8))
 END ReadLReal;
 END ReadLReal;
 
 
-PROCEDURE ReadString*(VAR R: Rider; VAR x: ARRAY OF SHORTCHAR);
+PROCEDURE ReadShortString*(VAR R: Rider; VAR x: ARRAY OF SHORTCHAR);
 VAR i: INTEGER; ch: SHORTCHAR;
 VAR i: INTEGER; ch: SHORTCHAR;
-BEGIN i := 0;
+BEGIN i := 0; (*!FIXME code from scratch*)
+  REPEAT ReadShortChar(R, ch); x[i] := ch; INC(i) UNTIL ch = 0X
+END ReadShortString;
+
+PROCEDURE ReadString*(VAR R: Rider; VAR x: ARRAY OF CHAR);
+VAR i: INTEGER; ch: CHAR;
+BEGIN i := 0; (*!FIXME code from scratch*)
   REPEAT ReadChar(R, ch); x[i] := ch; INC(i) UNTIL ch = 0X
   REPEAT ReadChar(R, ch); x[i] := ch; INC(i) UNTIL ch = 0X
 END ReadString;
 END ReadString;
 
 
@@ -669,7 +692,7 @@ PROCEDURE ReadLine*(VAR R: Rider; VAR x: ARRAY OF SHORTCHAR);
 VAR i: INTEGER; ch: SHORTCHAR; b: BOOLEAN;
 VAR i: INTEGER; ch: SHORTCHAR; b: BOOLEAN;
 BEGIN i := 0; b := FALSE;
 BEGIN i := 0; b := FALSE;
   REPEAT
   REPEAT
-    ReadChar(R, ch);
+    ReadShortChar(R, ch);
     IF ((ch = 0X) OR (ch = 0AX) OR (ch = 0DX)) THEN b := TRUE
     IF ((ch = 0X) OR (ch = 0AX) OR (ch = 0DX)) THEN b := TRUE
     ELSE x[i] := ch; INC(i)
     ELSE x[i] := ch; INC(i)
     END
     END
@@ -677,20 +700,28 @@ BEGIN i := 0; b := FALSE;
 END ReadLine;
 END ReadLine;
 
 
 PROCEDURE ReadNum*(VAR R: Rider; VAR x: LONGINT);
 PROCEDURE ReadNum*(VAR R: Rider; VAR x: LONGINT);
-VAR s: INTEGER; ch: SHORTCHAR;
-BEGIN s := 0; x := 0; ReadChar(R, ch);
-  WHILE ORD(ch) >= 128 DO
-    INC(x, ASH(LONG(ORD(ch) - 128), s)); INC(s, 7); ReadChar(R, ch)
+VAR n: INTEGER; b: BYTE;
+BEGIN n := 0; x := 0; Read(R, b);
+  WHILE b >= 128 DO
+    INC(x, ASH(LONG(b) - 128, n)); INC(n, 7); Read(R, b)
   END;
   END;
-  INC(x, ASH(LONG(ORD(ch) MOD 64 - ORD(ch) DIV 64 * 64), s))
+  INC(x, ASH(LONG(b) MOD 64 - LONG(b) DIV 64 * 64, n))
 END ReadNum;
 END ReadNum;
 
 
 PROCEDURE WriteBool*(VAR R: Rider; x: BOOLEAN);
 PROCEDURE WriteBool*(VAR R: Rider; x: BOOLEAN);
-BEGIN WriteByte(R, SYSTEM.VAL(BYTE, x))
+BEGIN Write(R, SYSTEM.VAL(BYTE, x))
 END WriteBool;
 END WriteBool;
 
 
-PROCEDURE WriteChar*(VAR R: Rider; x: SHORTCHAR);
-BEGIN WriteByte(R, SYSTEM.VAL(BYTE, x))
+PROCEDURE WriteShortChar*(VAR R: Rider; x: SHORTCHAR);
+BEGIN Write(R, SYSTEM.VAL(BYTE, x))
+END WriteShortChar;
+
+PROCEDURE WriteChar*(VAR R: Rider; c: CHAR);
+VAR i, L: INTEGER;
+  q: ARRAY 5 OF SHORTCHAR;
+BEGIN
+  Utf8.EncodeChar(c, q, L); i := 0;
+  WHILE i # L DO Write(R, SYSTEM.VAL(BYTE, q[i])); INC(i) END
 END WriteChar;
 END WriteChar;
 
 
 PROCEDURE WriteSInt*(VAR R: Rider; x: SHORTINT);
 PROCEDURE WriteSInt*(VAR R: Rider; x: SHORTINT);
@@ -733,37 +764,53 @@ BEGIN FlipBytes(SYSTEM.THISARR(SYSTEM.ADR(x), 8), b);
   WriteBytes(R, b, 8)
   WriteBytes(R, b, 8)
 END WriteLReal;
 END WriteLReal;
 
 
-PROCEDURE WriteString*(VAR R: Rider; IN x: ARRAY OF SHORTCHAR);
+PROCEDURE WriteShortString*(VAR R: Rider; IN s: ARRAY OF SHORTCHAR);
+VAR i: INTEGER;
+BEGIN i := 0; WHILE s[i] # 0X DO INC(i) END;
+  WriteBytes(R, SYSTEM.THISARR(SYSTEM.ADR(s), LEN(s)), i + 1)
+END WriteShortString;
+
+PROCEDURE WriteString*(VAR R: Rider; IN s: ARRAY OF CHAR);
 VAR i: INTEGER;
 VAR i: INTEGER;
-BEGIN i := 0; WHILE x[i] # 0X DO INC(i) END;
-  WriteBytes(R, SYSTEM.THISARR(SYSTEM.ADR(x), LEN(x)), i+1)
+BEGIN i := -1;
+  REPEAT INC(i); WriteChar(R, s[i]) UNTIL (i = LEN(s)) OR (s[i] = 0X)
 END WriteString;
 END WriteString;
 
 
 PROCEDURE WriteNum*(VAR R: Rider; x: LONGINT);
 PROCEDURE WriteNum*(VAR R: Rider; x: LONGINT);
 BEGIN
 BEGIN
   WHILE (x < - 64) OR (x > 63) DO
   WHILE (x < - 64) OR (x > 63) DO
-    WriteChar(R, SHORT(CHR(SHORT(x) MOD 128 + 128))); x := x DIV 128
+    Write(R, SYSTEM.VAL(BYTE, x MOD 128 + 128)); x := x DIV 128
   END;
   END;
-  WriteChar(R, SHORT(CHR(SHORT(x) MOD 128)))
+  Write(R, SYSTEM.VAL(BYTE, x MOD 128))
 END WriteNum;
 END WriteNum;
 
 
-PROCEDURE GetName*(f: File; VAR name: ARRAY OF SHORTCHAR);
+PROCEDURE GetName*(f: File; VAR name: ARRAY OF CHAR);
 BEGIN name := f.workName$
 BEGIN name := f.workName$
 END GetName;
 END GetName;
 
 
 PROCEDURE Finalize(o: SYSTEM.PTR);
 PROCEDURE Finalize(o: SYSTEM.PTR);
 VAR f: File; res: INTEGER;
 VAR f: File; res: INTEGER;
+  q: ARRAY 2048 OF SHORTCHAR;
 BEGIN f := SYSTEM.VAL(File, o);
 BEGIN f := SYSTEM.VAL(File, o);
   IF f.fd # Platform.InvalidHandleValue() THEN
   IF f.fd # Platform.InvalidHandleValue() THEN
     CloseOSFile(f);
     CloseOSFile(f);
-    IF f.tempFile THEN res := Platform.DeleteFile(f.workName) END
+    IF f.tempFile THEN
+      Utf8.Encode(f.workName, q);
+      res := Platform.DeleteFile(q)
+    END
   END
   END
 END Finalize;
 END Finalize;
 
 
 PROCEDURE SetSearchPath*(IN path: ARRAY OF CHAR);
 PROCEDURE SetSearchPath*(IN path: ARRAY OF CHAR);
-BEGIN Utf8.Encode(path, SearchPath)
+BEGIN SearchPath := path$
 END SetSearchPath;
 END SetSearchPath;
 
 
+PROCEDURE Init;
+VAR q: ARRAY 2048 OF SHORTCHAR;
 BEGIN tempno := -1; Heap.FileCount := 0; SearchPath := '';
 BEGIN tempno := -1; Heap.FileCount := 0; SearchPath := '';
-  home := ''; Platform.GetEnv('HOME', home)
+  Platform.GetEnv('HOME', q); Utf8.Decode(q, home);
+END Init;
+
+BEGIN
+  Init
 END Files.
 END Files.

+ 23 - 46
src/FreeOberon.Mod

@@ -57,7 +57,7 @@ TYPE
 
 
 VAR
 VAR
   progBuf: ARRAY 16300 OF SHORTCHAR; (* For interacting with a launched program *)
   progBuf: ARRAY 16300 OF SHORTCHAR; (* For interacting with a launched program *)
-  inputBuf: ARRAY 16300 OF SHORTCHAR; (* Saves entered chars before Enter pressed *)
+  inputBuf: ARRAY 16300 OF CHAR; (* Saves entered chars before Enter pressed *)
   inputBufLen: INTEGER;
   inputBufLen: INTEGER;
   programFinished: BOOLEAN;
   programFinished: BOOLEAN;
   tempWindowed: BOOLEAN; (* TRUE if editor windowed while program is running *)
   tempWindowed: BOOLEAN; (* TRUE if editor windowed while program is running *)
@@ -300,26 +300,14 @@ BEGIN
   END
   END
 END PollProgram;
 END PollProgram;
 
 
-PROCEDURE WriteToProcess(s: ARRAY OF SHORTCHAR; len: INTEGER);
-VAR buf: ARRAY 2048 OF SHORTCHAR; i, bufLen: INTEGER; ch: SHORTCHAR;
-BEGIN
-  bufLen := 0; i := 0;
+PROCEDURE WriteToProcess(s: ARRAY OF CHAR; len: INTEGER);
+VAR buf: ARRAY 2048 OF SHORTCHAR;
+  q: ARRAY 5 OF SHORTCHAR;
+  i, j, L, bufLen: INTEGER;
+BEGIN bufLen := 0; i := 0;
   WHILE i < len DO
   WHILE i < len DO
-    ch := s[i];
-    IF ch < 80X THEN
-      buf[bufLen] := ch; INC(bufLen)
-    ELSIF ORD(ch) = 240 THEN (* Big cyrillic Yo *)
-      buf[bufLen] := 0D0X; buf[bufLen + 1] := 81X;
-      INC(bufLen, 2)
-    ELSIF ORD(ch) < 224 THEN (* Before small cyrillic R *)
-      buf[bufLen] := 0D0X;
-      buf[bufLen + 1] := SHORT(CHR(ORD(ch) - 128 + 090H));
-      INC(bufLen, 2)
-    ELSE
-      buf[bufLen] := 0D1X;
-      buf[bufLen + 1] := SHORT(CHR(ORD(ch) - 224 + 080H));
-      INC(bufLen, 2)
-    END;
+    Utf8.EncodeChar(s[i], q, L); j := 0;
+    WHILE j # L DO buf[bufLen] := q[j]; INC(bufLen); INC(j) END;
     INC(i)
     INC(i)
   END;
   END;
   Term.WriteToProcess(buf, bufLen)
   Term.WriteToProcess(buf, bufLen)
@@ -359,8 +347,7 @@ END HandleTerminalKeyDown;
 PROCEDURE HandleTerminalTextInput(s: ARRAY OF CHAR; ch: CHAR);
 PROCEDURE HandleTerminalTextInput(s: ARRAY OF CHAR; ch: CHAR);
 BEGIN
 BEGIN
   IF (ch # 0X) & (inputBufLen < LEN(inputBuf)) THEN
   IF (ch # 0X) & (inputBufLen < LEN(inputBuf)) THEN
-    inputBuf[inputBufLen] := SHORT(OV.ToCP866(ch)); INC(inputBufLen);
-    T.Write(OV.ToCP866(ch))
+    inputBuf[inputBufLen] := ch; INC(inputBufLen); T.Write(ch)
   END
   END
 END HandleTerminalTextInput;
 END HandleTerminalTextInput;
 
 
@@ -393,9 +380,7 @@ RETURN p # NIL END IsSysModule;
 PROCEDURE ModuleExists(IN fname: ARRAY OF CHAR): BOOLEAN;
 PROCEDURE ModuleExists(IN fname: ARRAY OF CHAR): BOOLEAN;
 VAR F: Files.File;
 VAR F: Files.File;
   exists: BOOLEAN;
   exists: BOOLEAN;
-  s: ARRAY 2048 OF SHORTCHAR;
-BEGIN Utf8.Encode(fname, s);
-  F := Files.Old(s); exists := F # NIL;
+BEGIN F := Files.Old(fname); exists := F # NIL;
   IF F # NIL THEN Files.Close(F) END ;
   IF F # NIL THEN Files.Close(F) END ;
 RETURN exists END ModuleExists;
 RETURN exists END ModuleExists;
 
 
@@ -517,7 +502,6 @@ PROCEDURE Link(IN fname, mod: ARRAY OF CHAR;
     graph: BOOLEAN; list: StrList; VAR exename: ARRAY OF CHAR): BOOLEAN;
     graph: BOOLEAN; list: StrList; VAR exename: ARRAY OF CHAR): BOOLEAN;
 VAR ok: BOOLEAN;
 VAR ok: BOOLEAN;
   s: ARRAY 2048 OF CHAR;
   s: ARRAY 2048 OF CHAR;
-  e2, s2: ARRAY 2048 OF SHORTCHAR;
   res: INTEGER;
   res: INTEGER;
 BEGIN ok := RunCommand(fname, mod, TRUE, graph, FALSE, list);
 BEGIN ok := RunCommand(fname, mod, TRUE, graph, FALSE, list);
   IF ok THEN (* Move executable file if workDir is non-standard *)
   IF ok THEN (* Move executable file if workDir is non-standard *)
@@ -525,10 +509,7 @@ BEGIN ok := RunCommand(fname, mod, TRUE, graph, FALSE, list);
     exename := 'bin/'; Strings.Append(s, exename);
     exename := 'bin/'; Strings.Append(s, exename);
     IF workDir # Editor.stdPath THEN
     IF workDir # Editor.stdPath THEN
       Strings.Insert(workDir, 0, s);
       Strings.Insert(workDir, 0, s);
-
-      Utf8.Encode(exename, e2);
-      Utf8.Encode(s, s2);
-      Files.Rename(e2, s2, res);
+      Files.Rename(exename, s, res);
       IF res = 0 THEN exename := s$ END
       IF res = 0 THEN exename := s$ END
     END
     END
   END ;
   END ;
@@ -653,25 +634,24 @@ END FileSave;
 
 
 PROCEDURE SkipComment(VAR R: Files.Rider; VAR ch: CHAR; VAR s: ARRAY OF CHAR);
 PROCEDURE SkipComment(VAR R: Files.Rider; VAR ch: CHAR; VAR s: ARRAY OF CHAR);
 VAR last: CHAR;
 VAR last: CHAR;
-  x: SHORTCHAR;
-BEGIN last := ch; Files.ReadChar(R, x); ch := LONG(x);
+BEGIN last := ch; Files.ReadChar(R, ch);
   WHILE ~R.eof & ((last # '*') OR (ch # ')')) DO
   WHILE ~R.eof & ((last # '*') OR (ch # ')')) DO
     IF (last = '(') & (ch = '*') THEN SkipComment(R, ch, s) END;
     IF (last = '(') & (ch = '*') THEN SkipComment(R, ch, s) END;
-    last := ch; Files.ReadChar(R, x); ch := LONG(x)
+    last := ch; Files.ReadChar(R, ch)
   END;
   END;
-  IF ~R.eof THEN Files.ReadChar(R, x); ch := LONG(x) END;
-  WHILE ~R.eof & (ch <= ' ') DO Files.ReadChar(R, x); ch := LONG(x) END
+  IF ~R.eof THEN Files.ReadChar(R, ch) END;
+  WHILE ~R.eof & (ch <= ' ') DO Files.ReadChar(R, ch) END
 END SkipComment;
 END SkipComment;
 
 
 PROCEDURE GetSym(VAR R: Files.Rider; VAR ch: CHAR; VAR s: ARRAY OF CHAR);
 PROCEDURE GetSym(VAR R: Files.Rider; VAR ch: CHAR; VAR s: ARRAY OF CHAR);
-VAR i: INTEGER; x: SHORTCHAR;
+VAR i: INTEGER;
 BEGIN
 BEGIN
-  WHILE ~R.eof & (ch <= ' ') DO Files.ReadChar(R, x); ch := LONG(x) END;
+  WHILE ~R.eof & (ch <= ' ') DO Files.ReadChar(R, ch) END;
   i := 0;
   i := 0;
   IF ~R.eof THEN
   IF ~R.eof THEN
     IF ch = '(' THEN
     IF ch = '(' THEN
-      Files.ReadChar(R, x); ch := LONG(x);
-      IF ch = '*' THEN Files.ReadChar(R, x); ch := LONG(x); SkipComment(R, ch, s)
+      Files.ReadChar(R, ch);
+      IF ch = '*' THEN Files.ReadChar(R, ch); SkipComment(R, ch, s)
       ELSE s[i] := ch; INC(i)
       ELSE s[i] := ch; INC(i)
       END
       END
     END;
     END;
@@ -680,14 +660,14 @@ BEGIN
             (('A' <= CAP(ch)) & (CAP(ch) <= 'Z') OR
             (('A' <= CAP(ch)) & (CAP(ch) <= 'Z') OR
              ('0' <= ch) & (ch <= '9')) DO
              ('0' <= ch) & (ch <= '9')) DO
         IF i < LEN(s) - 1 THEN s[i] := ch; INC(i) END;
         IF i < LEN(s) - 1 THEN s[i] := ch; INC(i) END;
-        Files.ReadChar(R, x); ch := LONG(x)
+        Files.ReadChar(R, ch)
       END
       END
     ELSE
     ELSE
       WHILE ~R.eof & (ch > ' ') &
       WHILE ~R.eof & (ch > ' ') &
             ~(('A' <= CAP(ch)) & (CAP(ch) <= 'Z') OR
             ~(('A' <= CAP(ch)) & (CAP(ch) <= 'Z') OR
               ('0' <= ch) & (ch <= '9')) DO
               ('0' <= ch) & (ch <= '9')) DO
         IF i < LEN(s) - 1 THEN s[i] := ch; INC(i) END;
         IF i < LEN(s) - 1 THEN s[i] := ch; INC(i) END;
-        Files.ReadChar(R, x); ch := LONG(x)
+        Files.ReadChar(R, ch)
       END
       END
     END
     END
   END;
   END;
@@ -701,14 +681,11 @@ VAR F: Files.File;
   top, p: StrList;
   top, p: StrList;
   ch: CHAR;
   ch: CHAR;
   mod, s, fname2: ARRAY 256 OF CHAR;
   mod, s, fname2: ARRAY 256 OF CHAR;
-  q: ARRAY 2048 OF SHORTCHAR;
-  x: SHORTCHAR;
   exit: BOOLEAN;
   exit: BOOLEAN;
 BEGIN NEW(top); top.next := NIL; p := top;
 BEGIN NEW(top); top.next := NIL; p := top;
-  Utf8.Encode(fname, q);
-  F := Files.Old(q);
+  F := Files.Old(fname);
   IF F # NIL THEN
   IF F # NIL THEN
-    Files.Set(R, F, 0); Files.ReadChar(R, x); ch := LONG(x); GetSym(R, ch, s);
+    Files.Set(R, F, 0); Files.ReadChar(R, ch); GetSym(R, ch, s);
     ok := s = 'MODULE'; GetSym(R, ch, s); GetSym(R, ch, s); (*!FIXME check module name*)
     ok := s = 'MODULE'; GetSym(R, ch, s); GetSym(R, ch, s); (*!FIXME check module name*)
     IF ok THEN
     IF ok THEN
       ok := s = ';'; GetSym(R, ch, s);
       ok := s = ';'; GetSym(R, ch, s);

+ 20 - 22
src/Graph.Mod

@@ -660,16 +660,31 @@ BEGIN bmp := LoadBitmap(filename);
   END ;
   END ;
 RETURN font END LoadFont;
 RETURN font END LoadFont;
 
 
+PROCEDURE FindFontChar(c: CHAR; OUT n: INTEGER);
+BEGIN
+  IF c <= 0FFX THEN n := ORD(c)
+  ELSIF (410X(*A*) <= c) & (c <= 43FX(*p*)) THEN n := ORD(c) - (410H - 80H)
+  ELSIF (440X(*r*) <= c) & (c <= 44FX(*ja*)) THEN n := ORD(c) - (440H - 0E0H)
+  ELSIF c = 401X(*JO*) THEN n := 0F0H
+  ELSIF c = 451X(*jo*) THEN n := 0F1H
+  ELSE n := -1
+  END
+END FindFontChar;
+
 PROCEDURE DrawCharacter*(dest: Bitmap; font: Font;
 PROCEDURE DrawCharacter*(dest: Bitmap; font: Font;
   x, y: INTEGER; ch: CHAR; fg: INTEGER);
   x, y: INTEGER; ch: CHAR; fg: INTEGER);
-VAR fx, fy, r, g, b: INTEGER; dstRect: SDL.Rect;
+VAR n, fx, fy, r, g, b: INTEGER; dstRect: SDL.Rect;
 BEGIN dstRect.x := x; dstRect.y := y;
 BEGIN dstRect.x := x; dstRect.y := y;
-  fx := ORD(ch) MOD font.charsInRow;
-  fy := ORD(ch) DIV font.charsInRow;
+  FindFontChar(ch, n);
+  IF n < 0 THEN n := 1 (* "Bad" character *) END;
+  fx := n MOD font.charsInRow;
+  fy := n DIV font.charsInRow;
   ColorToRGB(fg, r, g, b);
   ColorToRGB(fg, r, g, b);
   SDL.SetSurfaceColorMod(font.bmp.surface, r, g, b);
   SDL.SetSurfaceColorMod(font.bmp.surface, r, g, b);
-  SDL.BlitSurface(font.bmp.surface, font.sprites[fy, fx],
-    screen.surface, dstRect)
+  IF (fy < LEN(font.sprites)) & (fx < LEN(font.sprites[0])) THEN
+    SDL.BlitSurface(font.bmp.surface, font.sprites[fy, fx],
+      screen.surface, dstRect)
+  END
 END DrawCharacter;
 END DrawCharacter;
 
 
 PROCEDURE DrawString*(dest: Bitmap; font: Font;
 PROCEDURE DrawString*(dest: Bitmap; font: Font;
@@ -718,23 +733,6 @@ VAR sym: INTEGER;
 BEGIN
 BEGIN
   IF events.len < LEN(events.buf) THEN
   IF events.len < LEN(events.buf) THEN
     e := SYSTEM.VAL(SDL.TextInputEvent, SYSTEM.ADR(event));
     e := SYSTEM.VAL(SDL.TextInputEvent, SYSTEM.ADR(event));
-    IF e.text[1] = 0X THEN (* ASCII character *)
-      sym := ORD(e.text[0])
-    ELSE (* Unicode character. Assuming 2 bytes *)
-      sym := ORD(e.text[1]);
-      (* UTF-8 cyrillic *)
-      IF (e.text[0] = 0D0X) OR (e.text[0] = 0D1X) THEN
-        IF e.text[0] = 0D0X THEN DEC(sym, 090H)
-        ELSE DEC(sym, 060H - 16)
-        END;
-        (* Convert to CP866 *)
-        IF sym = 65 THEN sym := 0F1H (* jo *)
-        ELSIF sym = -15 THEN sym := 0F0H (* JO *)
-        ELSIF sym < 48 THEN INC(sym, 80H) (* A..JA, a..p *)
-        ELSE INC(sym, 0E0H - 48) (* r..ja *)
-        END
-      END
-    END;
     QueueEvent;
     QueueEvent;
     events.buf[events.last].type := textInput;
     events.buf[events.last].type := textInput;
     Utf8.Decode(e.text, events.buf[events.last].s);
     Utf8.Decode(e.text, events.buf[events.last].s);

+ 1 - 2
src/In.Mod

@@ -52,8 +52,7 @@ END Byte;
 
 
 PROCEDURE ReadChar;
 PROCEDURE ReadChar;
 VAR x, y: INTEGER;
 VAR x, y: INTEGER;
-BEGIN
-  x := GetByte();
+BEGIN x := GetByte();
   IF readstate = ready THEN
   IF readstate = ready THEN
     IF cp = utf8 THEN
     IF cp = utf8 THEN
       IF x > 80H THEN y := GetByte() MOD 64; (* Not 1 byte *)
       IF x > 80H THEN y := GetByte() MOD 64; (* Not 1 byte *)

+ 2 - 19
src/OV.Mod

@@ -796,23 +796,6 @@ BEGIN
   IF ('a' <= ch) & (ch <= 'z') THEN ch := CAP(ch) END ;
   IF ('a' <= ch) & (ch <= 'z') THEN ch := CAP(ch) END ;
 RETURN ch END Cap;
 RETURN ch END Cap;
 
 
-PROCEDURE ToCP866*(ch: CHAR): CHAR;
-VAR n: INTEGER;
-BEGIN n := ORD(ch);
-  IF n >= 80H THEN
-    IF (410H(*A*) <= n) & (n <= 42FH(*YA*)) THEN n := n - 410H + 80H
-    ELSIF (430H(*a*) <= n) & (n <= 44FH(*ya*)) THEN
-      IF n <= 43FH(*p*) THEN n := n - 430H + 0A0H (*a..p*)
-      ELSE n := n - 440H + 0E0H (*r..ya*)
-      END
-    ELSIF n = 401H(*YO*) THEN n := 0F0H
-    ELSIF n = 451H(*yo*) THEN n := 0F1H
-    ELSIF n = 2116H(*No*) THEN n := 0FCH
-    ELSE n := 0
-    END
-  END ;
-RETURN CHR(n) END ToCP866;
-
 PROCEDURE Refresh*(c: Control);
 PROCEDURE Refresh*(c: Control);
 BEGIN
 BEGIN
   IF c.do.refresh # NIL THEN c.do.refresh(c) END
   IF c.do.refresh # NIL THEN c.do.refresh(c) END
@@ -1769,7 +1752,7 @@ PROCEDURE EditTextInput*(c: Control; ch: CHAR);
 VAR e: Edit;
 VAR e: Edit;
 BEGIN
 BEGIN
   IF ch # 0X THEN e := c(Edit);
   IF ch # 0X THEN e := c(Edit);
-    InsertChar(ToCP866(ch), e.pos, e.caption, e.len);
+    InsertChar(ch, e.pos, e.caption, e.len);
     IF e.pos < e.len THEN INC(e.pos) END;
     IF e.pos < e.len THEN INC(e.pos) END;
     NeedRedraw(c.app); T.ResetCursorBlink
     NeedRedraw(c.app); T.ResetCursorBlink
   END
   END
@@ -1971,7 +1954,7 @@ PROCEDURE ColumnListTextInput*(c: Control; ch: CHAR);
 VAR C: ColumnList; n: INTEGER;
 VAR C: ColumnList; n: INTEGER;
 BEGIN C := c(ColumnList);
 BEGIN C := c(ColumnList);
   IF ch # 0X THEN
   IF ch # 0X THEN
-    n := FindFirstLetterInList(C.items, Cap(ToCP866(ch)));
+    n := FindFirstLetterInList(C.items, CAP(ch));
     IF n # -1 THEN ColumnListSetCur(C, n) END
     IF n # -1 THEN ColumnListSetCur(C, n) END
   END
   END
 END ColumnListTextInput;
 END ColumnListTextInput;

+ 4 - 11
src/Terminal.Mod

@@ -95,20 +95,14 @@ BEGIN
 RETURN color END InvertColor;
 RETURN color END InvertColor;
 
 
 PROCEDURE DrawChar*(ch: CHAR; x, y, fg, bg: INTEGER);
 PROCEDURE DrawChar*(ch: CHAR; x, y, fg, bg: INTEGER);
-VAR color: INTEGER;
-BEGIN
-  G.RectFill(screen, x, y, x + charW - 1,
-    y + charH - 1, ExpandColor(bg));
-  IF ch # ' ' THEN
-    G.DrawCharacter(screen, font, x, y, ch, ExpandColor(fg))
-  END
+BEGIN G.RectFill(screen, x, y, x + charW - 1, y + charH - 1, ExpandColor(bg));
+  IF ch # ' ' THEN G.DrawCharacter(screen, font, x, y, ch, ExpandColor(fg)) END
 END DrawChar;
 END DrawChar;
 
 
 PROCEDURE DrawMouse;
 PROCEDURE DrawMouse;
 VAR x, y, bg, fg: INTEGER; ch: CHAR;
 VAR x, y, bg, fg: INTEGER; ch: CHAR;
 BEGIN
 BEGIN
-  IF (mouseX >= 0) & (mouseX < charsX) &
-     (mouseY >= 0) & (mouseY < charsY) THEN
+  IF (mouseX >= 0) & (mouseX < charsX) & (mouseY >= 0) & (mouseY < charsY) THEN
     bg := InvertColor(chars[mouseY, mouseX].bg);
     bg := InvertColor(chars[mouseY, mouseX].bg);
     fg := InvertColor(chars[mouseY, mouseX].fg);
     fg := InvertColor(chars[mouseY, mouseX].fg);
     ch := chars[mouseY, mouseX].ch
     ch := chars[mouseY, mouseX].ch
@@ -122,8 +116,7 @@ END DrawMouse;
 PROCEDURE Draw*(): BOOLEAN;
 PROCEDURE Draw*(): BOOLEAN;
 VAR x, y, color: INTEGER;
 VAR x, y, color: INTEGER;
   drawn: BOOLEAN;
   drawn: BOOLEAN;
-BEGIN
-  drawn := needRedraw;
+BEGIN drawn := needRedraw;
   IF needRedraw THEN
   IF needRedraw THEN
     needRedraw := FALSE;
     needRedraw := FALSE;
     (* Chars *)
     (* Chars *)

+ 7 - 2
src/Utf8.Mod

@@ -32,7 +32,7 @@ PROCEDURE EncodeEx*(IN in: ARRAY OF CHAR; inLen: INTEGER;
 VAR i, j, val, lim: INTEGER;
 VAR i, j, val, lim: INTEGER;
 BEGIN Done := TRUE; i := 0; j := 0; lim := LEN(out) - 1;
 BEGIN Done := TRUE; i := 0; j := 0; lim := LEN(out) - 1;
   IF inLen < 0 THEN inLen := LEN(in) END;
   IF inLen < 0 THEN inLen := LEN(in) END;
-  WHILE Done & (i < inLen) & (in[i] # 0X) & (j < lim) DO
+  WHILE Done & (i # inLen) & (in[i] # 0X) & (j < lim) DO
     val := ORD(in[i]); INC(i);
     val := ORD(in[i]); INC(i);
     IF val < 128 THEN
     IF val < 128 THEN
       out[j] := SHORT(CHR(val)); INC(j)
       out[j] := SHORT(CHR(val)); INC(j)
@@ -47,7 +47,7 @@ BEGIN Done := TRUE; i := 0; j := 0; lim := LEN(out) - 1;
     END
     END
   END;
   END;
   out[j] := 0X; outLen := j;
   out[j] := 0X; outLen := j;
-  IF in[i] # 0X THEN Done := FALSE END
+  IF (i # inLen) & (in[i] # 0X) THEN Done := FALSE END
 END EncodeEx;
 END EncodeEx;
 
 
 PROCEDURE Encode*(IN in: ARRAY OF CHAR; OUT out: ARRAY OF SHORTCHAR);
 PROCEDURE Encode*(IN in: ARRAY OF CHAR; OUT out: ARRAY OF SHORTCHAR);
@@ -70,4 +70,9 @@ BEGIN c := ORD(s[0]);
   END ;
   END ;
 RETURN CHR(c) END DecodeChar;
 RETURN CHR(c) END DecodeChar;
 
 
+PROCEDURE EncodeChar*(c: CHAR; OUT s: ARRAY OF SHORTCHAR; OUT len: INTEGER);
+VAR q: ARRAY 1 OF CHAR;
+BEGIN q[0] := c; EncodeEx(q, 1, s, len)
+END EncodeChar;
+
 END Utf8.
 END Utf8.