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"))