Login
7 branches 0 tags
Ben (X13/Arch) Rewrote [file/read][file/write] in Nujel e40da64 3 years ago 787 Commits
nujel / binlib / port.nuj
[defn slurp/buffer [pathname]
      "Read the entirety of PATHNAME and return it as a string if possible, otherwise return #nil."
      [def fh [file/open* pathname "r"]]
      [when-not fh [return #nil]]
      [try [fn []
               [file/close* fh]
               [return #nil]]
           [file/seek* fh 0 2]
           [def size [file/tell* fh]]
           [file/seek* fh 0 0]
           [def buf [buffer/allocate size]]
           [file/read* fh buf size]
           [file/close* fh]
           [return buf]]]
[def file/read/buffer slurp/buffer]

[defn slurp [pathname]
      "Read the entirety of PATHNAME and return it as a string if possible, otherwise return #nil."
      [buffer->string [slurp/buffer pathname]]]
[def file/read slurp]

[defn spit [pathname content]
      "Read the entirety of PATHNAME and return it as a string if possible, otherwise return #nil."
      [def fh [file/open* pathname "w"]]
      [when-not fh [return #f]]

      [try [fn []
               [file/close* fh]
               [return #f]]
           [file/write* fh content]
           [file/close* fh]]
      [return #t]]
[defn file/write [content pathname]
      "Writes CONTENT into PATHNAME"
      [spit pathname content]]


[def make-output-port #nil]
[def make-input-port #nil]
[def make-input/output-port #nil]

[let*
  [def output-port-method-table @[]]
  [def input-port-method-table @[]]
  [def temporary-buffer [buffer/allocate 1]]
  [def temporary-buffer-view [buffer/view/u8* temporary-buffer]]

  [tree/set! output-port-method-table :file-handle [fn [handle] handle]]
  [tree/set! output-port-method-table :write-char [fn [handle char]
                                                      [buffer/view/set! output-port-temporary-buffer-view 0 char]
                                                    [file/write* handle output-port-temporary-buffer-view]]]
  [tree/set! output-port-method-table :flush-output-port [fn [handle]
                                                             [file/flush* handle]]]
  [tree/set! output-port-method-table :block-write [fn [handle buffer size]
                                                       [file/write* handle buffer size]]]
  [tree/set! output-port-method-table :block-read [fn [handle buffer size]
                                                      [exception :type-error "Can't read from an output port" handle]]]
  [tree/set! output-port-method-table :read-char [tree/ref output-port-method-table :block-read]]
  [tree/set! output-port-method-table :close-port [fn [handle]
                                                      [file/close* handle]]]
  [tree/set! output-port-method-table :file-position [fn [handle]
                                                         [file/tell* handle]]]
  [tree/set! output-port-method-table :file-position! [fn [handle new-position]
                                                         [file/seek* handle new-position 0]]]



  [tree/set! input-port-method-table :read-char [fn [handle char]
                                                    [file/read* handle temporary-buffer-view 1]
                                                  [buffer/view/ref temporary-buffer-view 0 char]]]
  [tree/set! input-port-method-table :block-read [fn [handle buffer size]
                                                       [file/read* handle buffer size]]]
  [tree/set! input-port-method-table :block-write [fn [handle buffer size]
                                                      [exception :type-error "Can't write to an input port" handle]]]
  [tree/set! input-port-method-table :write-char [tree/ref output-port-method-table :block-write]]
  [tree/set! input-port-method-table :close-port [tree/ref output-port-method-table :close-port]]
  [tree/set! input-port-method-table :file-handle [tree/ref output-port-method-table :file-handle]]
  [tree/set! input-port-method-table :file-position [tree/ref output-port-method-table :file-position]]
  [tree/set! input-port-method-table :file-position! [tree/ref output-port-method-table :file-position!]]


  [set! make-output-port [fn [handle]
                             ""
                           [fn [method . args]
                               [apply [tree/ref output-port-method-table method] [cons handle args]]]]]

  [set! make-input-port [fn [handle]
                             ""
                           [fn [method . args]
                               [apply [tree/ref input-port-method-table method] [cons handle args]]]]]
]


[def stdin [make-input-port stdin*]]
[defn current-input-port [] stdin]
[defn current-input-port! [nport] [set! stdin nport]]

[def stdout [make-output-port stdout*]]
[defn current-output-port [] stdout]
[defn current-output-port! [nport] [set! stdout nport]]

[def stderr [make-output-port stderr*]]
[defn current-error-port [] stderr]
[defn current-error-port! [nport] [set! stderr nport]]

[defn print [v]
      "Display V on the standard output port"
      [stdout 'block-write [string v]]]

[defn error [v]
      "Prints v on the standard error port"
      [stderr 'block-write [string v]]]