DEADSOFTWARE

fix possible traps while HostLang initialization
[cpc.git] / src / posix / generic / Host / Mod / Lang.cp
index 00a7935d943d72e04a795f1e86d35f537638d2cb..4a2b3f79f0dbc7e03bfb9eb853cda1a040461355 100644 (file)
@@ -6,15 +6,19 @@ MODULE HostLang;
   CONST
     maxLen = 32;
 
+    default = "ASCII";
+
+    (* modes *)
+    replace* = 0; pep383x* = 1; pep383* = 2;
+
   VAR
     lang-, country-, encoding-: ARRAY maxLen OF CHAR;
     c2sc, sc2c, invalid: iconv.iconv_t;
 
-  (* PEP 383 *)
-
-  PROCEDURE StringToHost* (IN in: ARRAY OF CHAR; OUT out: ARRAY OF SHORTCHAR; low: BOOLEAN; OUT res: INTEGER);
-    VAR i, j, err: INTEGER; maxlen, len, count: iconv.size_t; inadr, outadr: Kernel.ADDRESS; ch: SHORTCHAR;
+  PROCEDURE StringToHost* (IN in: ARRAY OF CHAR; OUT out: ARRAY OF SHORTCHAR; mode: INTEGER; OUT res: INTEGER);
+    VAR i, j, err: INTEGER; maxlen, len, count: iconv.size_t; inadr, outadr: Kernel.ADDRESS; sch: SHORTCHAR;
   BEGIN
+    ASSERT(mode IN {replace..pep383}, 20);
     ASSERT(c2sc # invalid, 100);
     i := 0; err := 0;
     outadr := S.ADR(out[0]);
@@ -29,18 +33,21 @@ MODULE HostLang;
         IF count # 0 THEN
           CASE macro.errno() OF
           | errno.EILSEQ:
-               (* !!! HALT(101)*) (* invalid input char *)
-               IF maxlen < 1 THEN
-                 err := 1
+               IF mode = replace THEN
+                 IF maxlen < 1 THEN
+                   err := 1
+                 ELSE
+                   sch := "?";
+                   S.PUT(outadr, sch); INC(outadr); DEC(maxlen);
+                   INC(j); DEC(len, 2)
+                 END
                ELSE
-                 ch := "?";
-                 S.PUT(outadr, ch); INC(outadr); DEC(maxlen);
-                 INC(j); DEC(len, 2)
-               END
+                 err := 3
+               END;
           | errno.E2BIG: err := 1 (* unexpected end of out *)
-          | errno.EINVAL: HALT(102) (* unexpected end of input *)
-          | errno.EBADF: HALT(103) (* invalid iconv descriptor *)
-          ELSE HALT(104) (* unknown error *)
+          | errno.EINVAL: HALT(101) (* unexpected end of input *)
+          | errno.EBADF: HALT(102) (* invalid iconv descriptor *)
+          ELSE HALT(103) (* unknown error *)
           END
         END
       END;
@@ -48,24 +55,25 @@ MODULE HostLang;
         IF maxlen < 1 THEN
           err := 1
         ELSE
-          ch := SHORT(CHR(ORD(in[i]) MOD 256));
-          IF low OR (ch > 7FX) THEN
-            S.PUT(outadr, ch); INC(outadr); DEC(maxlen);
+          sch := SHORT(CHR(ORD(in[i]) MOD 256));
+          IF (mode IN {replace, pep383x}) OR (sch > 7FX) THEN
+            S.PUT(outadr, sch); INC(outadr); DEC(maxlen);
             INC(i)
           ELSE
-            err := 3 (* invalid char *)
+            err := 3
           END
         END
       END
     END;
-    ch := 0X;
-    S.PUT(outadr, ch);
+    sch := 0X;
+    S.PUT(outadr, sch);
     res := err
   END StringToHost;
 
-  PROCEDURE HostToString* (IN in: ARRAY OF SHORTCHAR; OUT out: ARRAY OF CHAR; low: BOOLEAN; OUT res: INTEGER);
+  PROCEDURE HostToString* (IN in: ARRAY OF SHORTCHAR; OUT out: ARRAY OF CHAR; mode: INTEGER; OUT res: INTEGER);
     VAR err: INTEGER; maxin, maxout, count: iconv.size_t; inadr, outadr: Kernel.ADDRESS; sch: SHORTCHAR; ch: CHAR;
   BEGIN
+    ASSERT(mode IN {replace..pep383}, 20);
     ASSERT(sc2c # invalid, 100);
     err := 0;
     inadr := S.ADR(in[0]);
@@ -81,9 +89,13 @@ MODULE HostLang;
             ELSIF maxin < 1 THEN
               err := 2 (* unexpected end of input buffer *)
             ELSE
-              S.GET(inadr, sch); INC(inadr); DEC(maxin);
-              ch := CHR(0D800H + ORD(sch));
-              IF low OR (ch > 7FX) THEN
+              IF mode = replace THEN
+                sch := "?"; ch := "?"; INC(inadr); DEC(maxin);
+              ELSE
+                S.GET(inadr, sch); INC(inadr); DEC(maxin);
+                ch := CHR(0D800H + ORD(sch));
+              END;
+              IF (mode IN {replace, pep383x}) OR (sch > 7FX) THEN
                 S.PUT(outadr, ch); INC(outadr, 2); DEC(maxout, 2)
               ELSE
                 err := 3 (* invalid char *)
@@ -100,7 +112,7 @@ MODULE HostLang;
   END HostToString;
 
   PROCEDURE Init;
-    VAR p: POINTER TO ARRAY [untagged] OF SHORTCHAR; i, j: INTEGER; enc: ARRAY 32 OF SHORTCHAR;
+    VAR p: POINTER TO ARRAY [untagged] OF SHORTCHAR; i, j: INTEGER; enc: ARRAY maxLen OF SHORTCHAR;
   BEGIN
     invalid := S.VAL(iconv.iconv_t, -1);
     p := locale.setlocale(locale.LC_ALL, "");
@@ -110,41 +122,58 @@ MODULE HostLang;
         p := ""
       END
     END;
-    i := 0; j := 0;
-    WHILE (p[i] # 0X) & (p[i] # "_") & (p[i] # ".") DO
-      lang[j] := p[i];
-      INC(i); INC(j)
-    END;
-    lang[j] := 0X;
-    IF p[i] = "_" THEN
-      INC(i); j := 0;
-      WHILE (p[i] # 0X) & (p[i] # ".") DO
-        country[j] := p[i];
+
+    IF (p$ = "") OR (p$ = "C") OR (p$ = "POSIX") THEN
+      lang := ""; country := ""; enc := ""
+    ELSE
+      (* parse lang *)
+      i := 0; j := 0;
+      WHILE (j < maxLen - 1) & (p[i] # 0X) & (p[i] # "_") & (p[i] # ".") DO
+        lang[j] := p[i];
         INC(i); INC(j)
       END;
-      country[j] := 0X
-    END;
-    enc := "ASCII";
-    IF p[i] = "." THEN
-      INC(i); j := 0;
-      WHILE p[i] # 0X DO
-        enc[j] := p[i];
-        INC(i); INC(j)
+      lang[j] := 0X;
+      IF j >= maxLen - 1 THEN
+        WHILE (p[i] # 0X) & (p[i] # "_") & (p[i] # ".") DO INC(i) END;
+        lang := ""
       END;
-      enc[j] := 0X
-    END;
-    IF (lang = "C") OR (lang = "POSIX") THEN
-      lang := ""
+      (* parse country *)
+      IF p[i] = "_" THEN
+        INC(i); j := 0;
+        WHILE (j < maxLen - 1) & (p[i] # 0X) & (p[i] # ".") DO
+          country[j] := p[i];
+          INC(i); INC(j)
+        END;
+        country[j] := 0X;
+        IF j >= maxLen - 1 THEN
+          WHILE (p[i] # 0X) & (p[i] # ".") DO INC(i) END;
+          country := ""
+        END
+      END;
+      (* parse encoding *)
+      IF p[i] = "." THEN
+        INC(i); j := 0;
+        WHILE (j < maxLen - 1) & (p[i] # 0X) DO
+          enc[j] := p[i];
+          INC(i); INC(j)
+        END;
+        enc[j] := 0X;
+        IF j >= maxLen - 1 THEN
+          enc := ""
+        END
+      END
     END;
+
     sc2c := invalid; c2sc := invalid;
     IF Kernel.littleEndian THEN sc2c := iconv.iconv_open("UCS-2LE", enc)
     ELSE sc2c := iconv.iconv_open("UCS-2BE", enc)
     END;
-    IF sc2c = invalid THEN enc := "ASCII";
+    IF sc2c = invalid THEN
+      enc := default;
       IF Kernel.littleEndian THEN sc2c := iconv.iconv_open("UCS-2LE", enc)
       ELSE sc2c := iconv.iconv_open("UCS-2BE", enc)
       END;
-      ASSERT(c2sc # invalid, 100) (* ascii to ucs2 not supported? *)
+      ASSERT(sc2c # invalid, 100) (* ascii to ucs2 not supported? *)
     END;
     IF Kernel.littleEndian THEN c2sc := iconv.iconv_open(enc, "UCS-2LE")
     ELSE c2sc := iconv.iconv_open(enc, "UCS-2BE");