rdelim.scm 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. ;;; installed-scm-file
  2. ;;;; Copyright (C) 1997, 1999, 2000, 2001, 2006, 2010 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 3 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
  22. read-line!
  23. read-delimited
  24. read-delimited!
  25. %read-delimited!
  26. %read-line
  27. write-line))
  28. (%init-rdelim-builtins)
  29. (define* (read-line! string #:optional (port current-input-port))
  30. ;; corresponds to SCM_LINE_INCREMENTORS in libguile.
  31. (define scm-line-incrementors "\n")
  32. (let* ((rv (%read-delimited! scm-line-incrementors
  33. string
  34. #t
  35. port))
  36. (terminator (car rv))
  37. (nchars (cdr rv)))
  38. (cond ((and (= nchars 0)
  39. (eof-object? terminator))
  40. terminator)
  41. ((not terminator) #f)
  42. (else nchars))))
  43. (define* (read-delimited! delims buf #:optional
  44. (port (current-input-port)) (handle-delim 'trim)
  45. (start 0) (end (string-length buf)))
  46. (let* ((rv (%read-delimited! delims
  47. buf
  48. (not (eq? handle-delim 'peek))
  49. port
  50. start
  51. end))
  52. (terminator (car rv))
  53. (nchars (cdr rv)))
  54. (cond ((or (not terminator) ; buffer filled
  55. (eof-object? terminator))
  56. (if (zero? nchars)
  57. (if (eq? handle-delim 'split)
  58. (cons terminator terminator)
  59. terminator)
  60. (if (eq? handle-delim 'split)
  61. (cons nchars terminator)
  62. nchars)))
  63. (else
  64. (case handle-delim
  65. ((trim peek) nchars)
  66. ((concat) (string-set! buf (+ nchars start) terminator)
  67. (+ nchars 1))
  68. ((split) (cons nchars terminator))
  69. (else (error "unexpected handle-delim value: "
  70. handle-delim)))))))
  71. (define* (read-delimited delims #:optional (port (current-input-port))
  72. (handle-delim 'trim))
  73. (let loop ((substrings '())
  74. (total-chars 0)
  75. (buf-size 100)) ; doubled each time through.
  76. (let* ((buf (make-string buf-size))
  77. (rv (%read-delimited! delims
  78. buf
  79. (not (eq? handle-delim 'peek))
  80. port))
  81. (terminator (car rv))
  82. (nchars (cdr rv))
  83. (new-total (+ total-chars nchars)))
  84. (cond
  85. ((not terminator)
  86. ;; buffer filled.
  87. (loop (cons (substring buf 0 nchars) substrings)
  88. new-total
  89. (* buf-size 2)))
  90. ((and (eof-object? terminator) (zero? new-total))
  91. (if (eq? handle-delim 'split)
  92. (cons terminator terminator)
  93. terminator))
  94. (else
  95. (let ((joined
  96. (string-concatenate-reverse
  97. (cons (substring buf 0 nchars) substrings))))
  98. (case handle-delim
  99. ((concat)
  100. (if (eof-object? terminator)
  101. joined
  102. (string-append joined (string terminator))))
  103. ((trim peek) joined)
  104. ((split) (cons joined terminator))
  105. (else (error "unexpected handle-delim value: "
  106. handle-delim)))))))))
  107. ;;; read-line [PORT [HANDLE-DELIM]] reads a newline-terminated string
  108. ;;; from PORT. The return value depends on the value of HANDLE-DELIM,
  109. ;;; which may be one of the symbols `trim', `concat', `peek' and
  110. ;;; `split'. If it is `trim' (the default), the trailing newline is
  111. ;;; removed and the string is returned. If `concat', the string is
  112. ;;; returned with the trailing newline intact. If `peek', the newline
  113. ;;; is left in the input port buffer and the string is returned. If
  114. ;;; `split', the newline is split from the string and read-line
  115. ;;; returns a pair consisting of the truncated string and the newline.
  116. (define* (read-line #:optional (port (current-input-port))
  117. (handle-delim 'trim))
  118. (let* ((line/delim (%read-line port))
  119. (line (car line/delim))
  120. (delim (cdr line/delim)))
  121. (case handle-delim
  122. ((trim) line)
  123. ((split) line/delim)
  124. ((concat) (if (and (string? line) (char? delim))
  125. (string-append line (string delim))
  126. line))
  127. ((peek) (if (char? delim)
  128. (unread-char delim port))
  129. line)
  130. (else
  131. (error "unexpected handle-delim value: " handle-delim)))))