(library (nmosh win32 util)
         (export null-pointer
                 string->utf16-bv
                 mbcs->string
                 mbcs->string/cp
                 nmosh-executable-path)
         (import (rnrs)
                 (nmosh win32 misc)
                 (mosh ffi))

(define null-pointer (integer->pointer 0))

(define (byteswap! bv)
  (define len (bytevector-length bv))
  (define (itr idx)
    (if (>= idx len)
      bv
      (begin
        (let ((i (bytevector-u16-ref bv idx (endianness big))))
          (bytevector-u16-set! bv idx i (endianness little)))
        (itr (+ 2 idx)))))
  (itr 0))

(define (string->utf16-bv str) ;; N.B.: adds null char
  (define str-bv (string->bytevector str (make-transcoder (utf-16-codec))))
  (define len (bytevector-length str-bv))
  (define ret (make-bytevector (+ len 2) 0))
  (bytevector-copy! str-bv 0 ret 0 len)
  (byteswap! ret))

(define (utf16-bv->string bv) ;; N.B. : treats last null char
  (define (locate-null pos)
    (let ((i (bytevector-u16-ref bv pos (endianness little))))
      (if (= i 0)
        pos
        (locate-null (+ 2 pos)))))
  (let* ((nullpos (locate-null 0))
         (newbv (make-bytevector nullpos)))
    (bytevector-copy! bv 0 newbv 0 nullpos)
    (byteswap! newbv)
    (bytevector->string newbv (make-transcoder (utf-16-codec)))))

(define (mbcs->string/cp cp bv)
  (define (convert)
    (let* ((len (win32_measure_multibyte_to_widechar cp bv))
           (out-bv (make-bytevector len)))
      (let ((r (win32_multibyte_to_widechar cp bv out-bv)))
        (when (= r 0)
          (assertion-violation 'mbcs->string/cp
                               "something wrong"))
        (utf16->string out-bv (endianness little)))))
  (if (= 0 (bytevector-length bv))
    ""
    (convert)))

(define (mbcs->string bv)
  (mbcs->string/cp (win32_get_ansi_codepage) bv))

(define (nmosh-executable-path)
  (define BUFSIZE 4096)
  (define bv (make-bytevector BUFSIZE))
  (win32_mypath bv BUFSIZE)
  (utf16-bv->string bv))

)
