#!/bin/sh
exec ${GUILE-guile} -e '(guile-baux as-C-byte-array)' -s $0 "$@" # -*- scheme -*-
!#
;;; as-C-byte-array --- embed file contents in C code

;; Copyright (C) 2011, 2017 Thien-Thi Nguyen
;;
;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation; either version 3, or
;; (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;; General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program.  If not, see <http://www.gnu.org/licenses/>.

;;; Commentary:

;; Usage: as-C-byte-array [options] [file...]
;;
;; Write concatenated contents of FILE... as one C ‘uint8_t’ array.
;; The array length is one more than the combined file sizes;
;; its last element is always ‘\0’ (i.e., ‘#\nul’).
;;
;; Options (defaults in square braces):
;;  -g, --global       -- omit ‘static’ qualifier
;;  -t, --type NAME    -- use type NAME [uint8_t]
;;  -v, --var NAME     -- use variable NAME [bytes]

;;; Code:

(define-module (guile-baux as-C-byte-array)
  #:export (main)
  #:use-module ((guile-baux common) #:select (fso check-hv qop<-args)))

(define (read-byte port)
  (modulo (char->integer (read-char port)) 256))

(define (redisplay port size)
  (do ((i 0 (1+ i)))
      ((= size i))
    (let ((n (read-byte port)))
      (cond ((= #x0A n)                 ; #\newline
             (fso " '\\n',~% "))
            ((memq n '(#x27 #x5c))      ; (#\' #\\)
             (fso " '\\~A'," (integer->char n)))
            ((<= 32 n 126)
             (fso " '~A'," (integer->char n)))
            (else
             (fso " 0x~A," (number->string n 16))))))
  (close-port port))

(define (main/qop qop)
  (let* ((ports (map open-input-file (qop '())))
         (sizes (map stat:size (map stat ports))))

    (fso "~Aconst ~A ~A[~A] = {~% "
         (if (qop 'global)
             ""
             "static ")
         (or (qop 'type) "uint8_t")
         (or (qop 'var) "bytes")
         (apply + 1 sizes))
    (for-each redisplay ports sizes)
    (fso " '\\0'~%};~%"))
  #t)

(define (main args)
  (check-hv args '((package . "Guile-BAUX")
                   (version . "0.0")
                   (help . commentary)))
  (main/qop (qop<-args
             args '((global (single-char #\g))
                    (type   (single-char #\t) (value #t))
                    (var    (single-char #\v) (value #t))))))

;;; as-C-byte-array ends here
