Potentially can convert to/from any encoding that libc's "iconv()" does.
Tested only on Linux... and I'm looking for comments about coding.
Code: Select all
; iconv interface. See man 3 iconv. (C) Dmi
(context 'ICONV)
(set 'funcs '("iconv_open" "iconv" "iconv_close"))
(dolist (l funcs) (import "libc.so.6" l))
; iconv library function wrapper
; inbuf - string to recode
; with no-force does one iconv call,
; returns list with iconv result, in-buffer/restsize, out-buffer/restsize.
; without no-force, if iconv call return error, drops broken symbol and
; repeats iconv for the rest. Returns recodeed string.
(define (recode str no-force)
(letn (strlen (length str)
buflen (+ (* 2 strlen) 4)
buf (dup "\000" buflen)
plen (pack "lu" buflen)
pbuf (pack "ld" buf)
rsize 0 bufrest 0)
(do-until (or no-force (>= rsize 0) (<= strlen 0))
(set 'pstrlen (pack "lu" strlen)
'pstr (pack "ld" str))
(set 'rsize (iconv cds pstr pstrlen pbuf plen))
(set 'strlen ((unpack "lu" pstrlen) 0))
(set 'str (get-string ((unpack "ld" pstr) 0)))
(unless no-force
(set 'str (1 strlen str)
'strlen (- strlen 1))))
(set 'buf (slice buf 0 (find "\000" buf))
'bufrest ((unpack "lu" plen) 0))
(if no-force
(list rsize str strlen buf bufrest)
buf)))
; recode at once. do iconv_init, iconv and iconv_close together.
; also shows proposed usage for "recode"
(define (recode-once cfrom cto str no-force)
(let (cds (iconv_open cto cfrom) res nil)
(if (= -1 cds) -1
(begin
(set 'res (recode str no-force))
(iconv_close cds)
res))))
(context MAIN)
; example
;(println (ICONV:recode-once "KOI8R" "UTF-8" "abc провdefерка юникодаgh"))