c3b60a2b1a4b169740001bb83ac3f95d792f7bd0
3 IMPORT S
:= SYSTEM
, Kernel
, stdlib
:= C99stdlib
, locale
:= C99locale
,
4 iconv
:= C99iconv
, errno
:= C99errno
, macro
:= C99macro
;
10 replace
* = 0; pep383x
* = 1; pep383
* = 2;
13 lang
-, country
-, encoding
-: ARRAY maxLen
OF CHAR;
14 c2sc
, sc2c
, invalid
: iconv
.iconv_t
;
16 PROCEDURE StringToHost
* (IN in
: ARRAY OF CHAR; OUT out
: ARRAY OF SHORTCHAR
; mode
: INTEGER; OUT res
: INTEGER);
17 VAR i
, j
, err
: INTEGER; maxlen
, len
, count
: iconv
.size_t
; inadr
, outadr
: Kernel
.ADDRESS
; sch
: SHORTCHAR
;
19 ASSERT(mode
IN {replace
..pep383
}, 20);
20 ASSERT(c2sc
# invalid
, 100);
22 outadr
:= S
.ADR(out
[0]);
23 maxlen
:= LEN(out
) - 1;
24 WHILE (err
= 0) & (in
[i
] # 0X
) DO
26 WHILE (in
[i
] # 0X
) & ((in
[i
] < 0D800X
) OR (in
[i
] > 0D8FFX
)) DO INC(i
) END;
28 WHILE (err
= 0) & (len
> 0) & (maxlen
> 0) DO
29 inadr
:= S
.ADR(in
[j
]);
30 count
:= iconv
.iconv(c2sc
, inadr
, len
, outadr
, maxlen
);
34 IF mode
= replace
THEN
39 S
.PUT(outadr
, sch
); INC(outadr
); DEC(maxlen
);
45 | errno
.E2BIG
: err
:= 1 (* unexpected end of out *)
46 | errno
.EINVAL
: HALT(101) (* unexpected end of input *)
47 | errno
.EBADF
: HALT(102) (* invalid iconv descriptor *)
48 ELSE HALT(103) (* unknown error *)
52 WHILE (err
= 0) & (in
[i
] >= 0D800X
) & (in
[i
] <= 0D8FFX
) DO
56 sch
:= SHORT(CHR(ORD(in
[i
]) MOD 256));
57 IF (mode
IN {replace
, pep383x
}) OR (sch
> 7FX
) THEN
58 S
.PUT(outadr
, sch
); INC(outadr
); DEC(maxlen
);
71 PROCEDURE HostToString
* (IN in
: ARRAY OF SHORTCHAR
; OUT out
: ARRAY OF CHAR; mode
: INTEGER; OUT res
: INTEGER);
72 VAR err
: INTEGER; maxin
, maxout
, count
: iconv
.size_t
; inadr
, outadr
: Kernel
.ADDRESS
; sch
: SHORTCHAR
; ch
: CHAR;
74 ASSERT(mode
IN {replace
..pep383
}, 20);
75 ASSERT(sc2c
# invalid
, 100);
77 inadr
:= S
.ADR(in
[0]);
78 outadr
:= S
.ADR(out
[0]);
79 maxin
:= LEN(in$
); maxout
:= LEN(out
) * 2 - 2;
80 WHILE (err
= 0) & (maxout
> 1) & (maxin
> 0) DO
81 count
:= iconv
.iconv(sc2c
, inadr
, maxin
, outadr
, maxout
);
84 | errno
.EILSEQ
, errno
.EINVAL
, errno
.E2BIG
:
86 err
:= 1 (* unexpected end of output buffer *)
88 err
:= 2 (* unexpected end of input buffer *)
90 IF mode
= replace
THEN
91 sch
:= "?"; ch
:= "?"; INC(inadr
); DEC(maxin
);
93 S
.GET(inadr
, sch
); INC(inadr
); DEC(maxin
);
94 ch
:= CHR(0D800H
+ ORD(sch
));
96 IF (mode
IN {replace
, pep383x
}) OR (sch
> 7FX
) THEN
97 S
.PUT(outadr
, ch
); INC(outadr
, 2); DEC(maxout
, 2)
99 err
:= 3 (* invalid char *)
102 | errno
.EBADF
: HALT(101)
113 VAR p
: POINTER TO ARRAY [untagged
] OF SHORTCHAR
; i
, j
: INTEGER; enc
: ARRAY 32 OF SHORTCHAR
;
115 invalid
:= S
.VAL(iconv
.iconv_t
, -1);
116 p
:= locale
.setlocale(locale
.LC_ALL
, "");
118 p
:= stdlib
.getenv("LANG");
124 WHILE (p
[i
] # 0X
) & (p
[i
] # "_") & (p
[i
] # ".") DO
131 WHILE (p
[i
] # 0X
) & (p
[i
] # ".") DO
146 IF (lang
= "C") OR (lang
= "POSIX") THEN
149 sc2c
:= invalid
; c2sc
:= invalid
;
150 IF Kernel
.littleEndian
THEN sc2c
:= iconv
.iconv_open("UCS-2LE", enc
)
151 ELSE sc2c
:= iconv
.iconv_open("UCS-2BE", enc
)
153 IF sc2c
= invalid
THEN enc
:= "ASCII";
154 IF Kernel
.littleEndian
THEN sc2c
:= iconv
.iconv_open("UCS-2LE", enc
)
155 ELSE sc2c
:= iconv
.iconv_open("UCS-2BE", enc
)
157 ASSERT(c2sc
# invalid
, 100) (* ascii to ucs2 not supported? *)
159 IF Kernel
.littleEndian
THEN c2sc
:= iconv
.iconv_open(enc
, "UCS-2LE")
160 ELSE c2sc
:= iconv
.iconv_open(enc
, "UCS-2BE");
162 ASSERT(c2sc
# invalid
, 101); (* ucs2 to ascii not supported? *)
167 Do not close iconv descriptors!
168 It can lead to quiet traps on program termination and bugs like
169 not removed temp files.