3 IMPORT S
:= SYSTEM
, Kernel
, stdlib
:= PosixCstdlib
, locale
:= PosixClocale
,
4 iconv
:= PosixCiconv
, errno
:= PosixCerrno
, macro
:= PosixCmacro
;
12 replace
* = 0; pep383x
* = 1; pep383
* = 2;
15 lang
-, country
-, encoding
-: ARRAY maxLen
OF CHAR;
16 c2sc
, sc2c
, invalid
: iconv
.iconv_t
;
18 PROCEDURE StringToHost
* (IN in
: ARRAY OF CHAR; OUT out
: ARRAY OF SHORTCHAR
; mode
: INTEGER; OUT res
: INTEGER);
19 VAR i
, j
, err
: INTEGER; maxlen
, len
, count
: iconv
.size_t
; inadr
, outadr
: Kernel
.ADDRESS
; sch
: SHORTCHAR
;
21 ASSERT(mode
IN {replace
..pep383
}, 20);
22 ASSERT(c2sc
# invalid
, 100);
24 outadr
:= S
.ADR(out
[0]);
25 maxlen
:= LEN(out
) - 1;
26 WHILE (err
= 0) & (in
[i
] # 0X
) DO
28 WHILE (in
[i
] # 0X
) & ((in
[i
] < 0D800X
) OR (in
[i
] > 0D8FFX
)) DO INC(i
) END;
30 WHILE (err
= 0) & (len
> 0) & (maxlen
> 0) DO
31 inadr
:= S
.ADR(in
[j
]);
32 count
:= iconv
.iconv(c2sc
, inadr
, len
, outadr
, maxlen
);
36 IF mode
= replace
THEN
41 S
.PUT(outadr
, sch
); INC(outadr
); DEC(maxlen
);
47 | errno
.E2BIG
: err
:= 1 (* unexpected end of out *)
48 | errno
.EINVAL
: HALT(101) (* unexpected end of input *)
49 | errno
.EBADF
: HALT(102) (* invalid iconv descriptor *)
50 ELSE HALT(103) (* unknown error *)
54 WHILE (err
= 0) & (in
[i
] >= 0D800X
) & (in
[i
] <= 0D8FFX
) DO
58 sch
:= SHORT(CHR(ORD(in
[i
]) MOD 256));
59 IF (mode
IN {replace
, pep383x
}) OR (sch
> 7FX
) THEN
60 S
.PUT(outadr
, sch
); INC(outadr
); DEC(maxlen
);
73 PROCEDURE HostToString
* (IN in
: ARRAY OF SHORTCHAR
; OUT out
: ARRAY OF CHAR; mode
: INTEGER; OUT res
: INTEGER);
74 VAR err
: INTEGER; maxin
, maxout
, count
: iconv
.size_t
; inadr
, outadr
: Kernel
.ADDRESS
; sch
: SHORTCHAR
; ch
: CHAR;
76 ASSERT(mode
IN {replace
..pep383
}, 20);
77 ASSERT(sc2c
# invalid
, 100);
79 inadr
:= S
.ADR(in
[0]);
80 outadr
:= S
.ADR(out
[0]);
81 maxin
:= LEN(in$
); maxout
:= LEN(out
) * 2 - 2;
82 WHILE (err
= 0) & (maxout
> 1) & (maxin
> 0) DO
83 count
:= iconv
.iconv(sc2c
, inadr
, maxin
, outadr
, maxout
);
86 | errno
.EILSEQ
, errno
.EINVAL
, errno
.E2BIG
:
88 err
:= 1 (* unexpected end of output buffer *)
90 err
:= 2 (* unexpected end of input buffer *)
92 IF mode
= replace
THEN
93 sch
:= "?"; ch
:= "?"; INC(inadr
); DEC(maxin
);
95 S
.GET(inadr
, sch
); INC(inadr
); DEC(maxin
);
96 ch
:= CHR(0D800H
+ ORD(sch
));
98 IF (mode
IN {replace
, pep383x
}) OR (sch
> 7FX
) THEN
99 S
.PUT(outadr
, ch
); INC(outadr
, 2); DEC(maxout
, 2)
101 err
:= 3 (* invalid char *)
104 | errno
.EBADF
: HALT(101)
115 VAR p
: POINTER TO ARRAY [untagged
] OF SHORTCHAR
; i
, j
: INTEGER; enc
: ARRAY maxLen
OF SHORTCHAR
;
117 invalid
:= S
.VAL(iconv
.iconv_t
, -1);
118 p
:= locale
.setlocale(locale
.LC_ALL
, "");
120 p
:= stdlib
.getenv("LANG");
126 IF (p$
= "") OR (p$
= "C") OR (p$
= "POSIX") THEN
127 lang
:= ""; country
:= ""; enc
:= ""
131 WHILE (j
< maxLen
- 1) & (p
[i
] # 0X
) & (p
[i
] # "_") & (p
[i
] # ".") DO
136 IF j
>= maxLen
- 1 THEN
137 WHILE (p
[i
] # 0X
) & (p
[i
] # "_") & (p
[i
] # ".") DO INC(i
) END;
143 WHILE (j
< maxLen
- 1) & (p
[i
] # 0X
) & (p
[i
] # ".") DO
148 IF j
>= maxLen
- 1 THEN
149 WHILE (p
[i
] # 0X
) & (p
[i
] # ".") DO INC(i
) END;
156 WHILE (j
< maxLen
- 1) & (p
[i
] # 0X
) DO
161 IF j
>= maxLen
- 1 THEN
167 sc2c
:= invalid
; c2sc
:= invalid
;
168 IF Kernel
.littleEndian
THEN sc2c
:= iconv
.iconv_open("UCS-2LE", enc
)
169 ELSE sc2c
:= iconv
.iconv_open("UCS-2BE", enc
)
171 IF sc2c
= invalid
THEN
173 IF Kernel
.littleEndian
THEN sc2c
:= iconv
.iconv_open("UCS-2LE", enc
)
174 ELSE sc2c
:= iconv
.iconv_open("UCS-2BE", enc
)
176 ASSERT(sc2c
# invalid
, 100) (* ascii to ucs2 not supported? *)
178 IF Kernel
.littleEndian
THEN c2sc
:= iconv
.iconv_open(enc
, "UCS-2LE")
179 ELSE c2sc
:= iconv
.iconv_open(enc
, "UCS-2BE");
181 ASSERT(c2sc
# invalid
, 101); (* ucs2 to ascii not supported? *)
186 Do not close iconv descriptors!
187 It can lead to quiet traps on program termination and bugs like
188 not removed temp files.