rdelim.scm 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. ;;; installed-scm-file
  2. ;;;; Copyright (C) 1997, 1999, 2000, 2001, 2006 Free Software Foundation, Inc.
  3. ;;;;
  4. ;;;; This library is free software; you can redistribute it and/or
  5. ;;;; modify it under the terms of the GNU Lesser General Public
  6. ;;;; License as published by the Free Software Foundation; either
  7. ;;;; version 2.1 of the License, or (at your option) any later version.
  8. ;;;;
  9. ;;;; This library is distributed in the hope that it will be useful,
  10. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. ;;;; Lesser General Public License for more details.
  13. ;;;;
  14. ;;;; You should have received a copy of the GNU Lesser General Public
  15. ;;;; License along with this library; if not, write to the Free Software
  16. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. ;;;;
  18. ;;; This is the Scheme part of the module for delimited I/O. It's
  19. ;;; similar to (scsh rdelim) but somewhat incompatible.
  20. (define-module (ice-9 rdelim)
  21. :export (read-line read-line! read-delimited read-delimited!
  22. %read-delimited! %read-line write-line) ; C
  23. )
  24. (%init-rdelim-builtins)
  25. (define (read-line! string . maybe-port)
  26. ;; corresponds to SCM_LINE_INCREMENTORS in libguile.
  27. (define scm-line-incrementors "\n")
  28. (let* ((port (if (pair? maybe-port)
  29. (car maybe-port)
  30. (current-input-port))))
  31. (let* ((rv (%read-delimited! scm-line-incrementors
  32. string
  33. #t
  34. port))
  35. (terminator (car rv))
  36. (nchars (cdr rv)))
  37. (cond ((and (= nchars 0)
  38. (eof-object? terminator))
  39. terminator)
  40. ((not terminator) #f)
  41. (else nchars)))))
  42. (define (read-delimited! delims buf . args)
  43. (let* ((num-args (length args))
  44. (port (if (> num-args 0)
  45. (car args)
  46. (current-input-port)))
  47. (handle-delim (if (> num-args 1)
  48. (cadr args)
  49. 'trim))
  50. (start (if (> num-args 2)
  51. (caddr args)
  52. 0))
  53. (end (if (> num-args 3)
  54. (cadddr args)
  55. (string-length buf))))
  56. (let* ((rv (%read-delimited! delims
  57. buf
  58. (not (eq? handle-delim 'peek))
  59. port
  60. start
  61. end))
  62. (terminator (car rv))
  63. (nchars (cdr rv)))
  64. (cond ((or (not terminator) ; buffer filled
  65. (eof-object? terminator))
  66. (if (zero? nchars)
  67. (if (eq? handle-delim 'split)
  68. (cons terminator terminator)
  69. terminator)
  70. (if (eq? handle-delim 'split)
  71. (cons nchars terminator)
  72. nchars)))
  73. (else
  74. (case handle-delim
  75. ((trim peek) nchars)
  76. ((concat) (string-set! buf (+ nchars start) terminator)
  77. (+ nchars 1))
  78. ((split) (cons nchars terminator))
  79. (else (error "unexpected handle-delim value: "
  80. handle-delim))))))))
  81. (define (read-delimited delims . args)
  82. (let* ((port (if (pair? args)
  83. (let ((pt (car args)))
  84. (set! args (cdr args))
  85. pt)
  86. (current-input-port)))
  87. (handle-delim (if (pair? args)
  88. (car args)
  89. 'trim)))
  90. (let loop ((substrings '())
  91. (total-chars 0)
  92. (buf-size 100)) ; doubled each time through.
  93. (let* ((buf (make-string buf-size))
  94. (rv (%read-delimited! delims
  95. buf
  96. (not (eq? handle-delim 'peek))
  97. port))
  98. (terminator (car rv))
  99. (nchars (cdr rv))
  100. (join-substrings
  101. (lambda ()
  102. (apply string-append
  103. (reverse
  104. (cons (if (and (eq? handle-delim 'concat)
  105. (not (eof-object? terminator)))
  106. (string terminator)
  107. "")
  108. (cons (substring buf 0 nchars)
  109. substrings))))))
  110. (new-total (+ total-chars nchars)))
  111. (cond ((not terminator)
  112. ;; buffer filled.
  113. (loop (cons (substring buf 0 nchars) substrings)
  114. new-total
  115. (* buf-size 2)))
  116. ((eof-object? terminator)
  117. (if (zero? new-total)
  118. (if (eq? handle-delim 'split)
  119. (cons terminator terminator)
  120. terminator)
  121. (if (eq? handle-delim 'split)
  122. (cons (join-substrings) terminator)
  123. (join-substrings))))
  124. (else
  125. (case handle-delim
  126. ((trim peek concat) (join-substrings))
  127. ((split) (cons (join-substrings) terminator))
  128. (else (error "unexpected handle-delim value: "
  129. handle-delim)))))))))
  130. ;;; read-line [PORT [HANDLE-DELIM]] reads a newline-terminated string
  131. ;;; from PORT. The return value depends on the value of HANDLE-DELIM,
  132. ;;; which may be one of the symbols `trim', `concat', `peek' and
  133. ;;; `split'. If it is `trim' (the default), the trailing newline is
  134. ;;; removed and the string is returned. If `concat', the string is
  135. ;;; returned with the trailing newline intact. If `peek', the newline
  136. ;;; is left in the input port buffer and the string is returned. If
  137. ;;; `split', the newline is split from the string and read-line
  138. ;;; returns a pair consisting of the truncated string and the newline.
  139. (define (read-line . args)
  140. (let* ((port (if (null? args)
  141. (current-input-port)
  142. (car args)))
  143. (handle-delim (if (> (length args) 1)
  144. (cadr args)
  145. 'trim))
  146. (line/delim (%read-line port))
  147. (line (car line/delim))
  148. (delim (cdr line/delim)))
  149. (case handle-delim
  150. ((trim) line)
  151. ((split) line/delim)
  152. ((concat) (if (and (string? line) (char? delim))
  153. (string-append line (string delim))
  154. line))
  155. ((peek) (if (char? delim)
  156. (unread-char delim port))
  157. line)
  158. (else
  159. (error "unexpected handle-delim value: " handle-delim)))))