ports.scm 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. ;;; Ports
  2. ;;; Copyright (C) 2016,2019,2021 Free Software Foundation, Inc.
  3. ;;;
  4. ;;; This library is free software: you can redistribute it and/or modify
  5. ;;; it under the terms of the GNU Lesser General Public License as
  6. ;;; published by the Free Software Foundation, either version 3 of the
  7. ;;; License, or (at your option) any later version.
  8. ;;;
  9. ;;; This library is distributed in the hope that it will be useful, but
  10. ;;; 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 program. If not, see
  16. ;;; <http://www.gnu.org/licenses/>.
  17. ;;; Commentary:
  18. ;;;
  19. ;;; Implementation of input/output routines over ports.
  20. ;;;
  21. ;;; Note that loading this module overrides some core bindings; see the
  22. ;;; `replace-bootstrap-bindings' invocation below for details.
  23. ;;;
  24. ;;; Code:
  25. (define-module (ice-9 ports)
  26. #:export (;; Definitions from ports.c.
  27. %port-property
  28. %set-port-property!
  29. current-input-port current-output-port
  30. current-error-port current-warning-port
  31. current-load-port
  32. set-current-input-port set-current-output-port
  33. set-current-error-port
  34. port-mode
  35. port?
  36. input-port?
  37. output-port?
  38. port-closed?
  39. eof-object?
  40. close-port
  41. close-input-port
  42. close-output-port
  43. ;; These two are currently defined by scm_init_ports; fix?
  44. ;; %default-port-encoding
  45. ;; %default-port-conversion-strategy
  46. port-encoding
  47. set-port-encoding!
  48. port-conversion-strategy
  49. set-port-conversion-strategy!
  50. read-char
  51. peek-char
  52. unread-char
  53. unread-string
  54. setvbuf
  55. drain-input
  56. force-output
  57. char-ready?
  58. seek SEEK_SET SEEK_CUR SEEK_END
  59. truncate-file
  60. port-line
  61. set-port-line!
  62. port-column
  63. set-port-column!
  64. port-filename
  65. set-port-filename!
  66. port-for-each
  67. flush-all-ports
  68. %make-void-port
  69. ;; Definitions from fports.c.
  70. open-file
  71. file-port?
  72. port-revealed
  73. set-port-revealed!
  74. adjust-port-revealed!
  75. ;; note: %file-port-name-canonicalization is used in boot-9
  76. ;; Definitions from ioext.c.
  77. ftell
  78. redirect-port
  79. dup->fdes
  80. dup2
  81. fileno
  82. isatty?
  83. fdopen
  84. primitive-move->fdes
  85. fdes->ports
  86. ;; Definitions in Scheme
  87. file-position
  88. file-set-position
  89. move->fdes
  90. release-port-handle
  91. dup->port
  92. dup->inport
  93. dup->outport
  94. dup
  95. duplicate-port
  96. fdes->inport
  97. fdes->outport
  98. port->fdes
  99. OPEN_READ OPEN_WRITE OPEN_BOTH
  100. *null-device*
  101. open-input-file
  102. open-output-file
  103. open-io-file
  104. call-with-port
  105. call-with-input-file
  106. call-with-output-file
  107. with-input-from-port
  108. with-output-to-port
  109. with-error-to-port
  110. with-input-from-file
  111. with-output-to-file
  112. with-error-to-file
  113. call-with-input-string
  114. with-input-from-string
  115. call-with-output-string
  116. with-output-to-string
  117. with-error-to-string
  118. the-eof-object
  119. inherit-print-state))
  120. (define (replace-bootstrap-bindings syms)
  121. (for-each
  122. (lambda (sym)
  123. (let* ((var (module-variable the-scm-module sym))
  124. (mod (current-module))
  125. (iface (module-public-interface mod)))
  126. (unless var (error "unbound in root module" sym))
  127. (module-add! mod sym var)
  128. (when (module-local-variable iface sym)
  129. (module-add! iface sym var))))
  130. syms))
  131. (replace-bootstrap-bindings '(open-file
  132. open-input-file
  133. set-port-encoding!
  134. eof-object?
  135. force-output
  136. call-with-output-string
  137. close-port
  138. current-error-port
  139. current-warning-port))
  140. (load-extension (string-append "libguile-" (effective-version))
  141. "scm_init_ice_9_ports")
  142. (load-extension (string-append "libguile-" (effective-version))
  143. "scm_init_ice_9_fports")
  144. (load-extension (string-append "libguile-" (effective-version))
  145. "scm_init_ice_9_ioext")
  146. (define (port-encoding port)
  147. "Return, as a string, the character encoding that @var{port} uses to
  148. interpret its input and output."
  149. (symbol->string (%port-encoding port)))
  150. (define-module (ice-9 ports internal)
  151. #:use-module (ice-9 ports)
  152. #:export (port-read-buffer
  153. port-write-buffer
  154. port-auxiliary-write-buffer
  155. port-line-buffered?
  156. expand-port-read-buffer!
  157. port-buffer-bytevector
  158. port-buffer-cur
  159. port-buffer-end
  160. port-buffer-has-eof?
  161. port-buffer-position
  162. set-port-buffer-cur!
  163. set-port-buffer-end!
  164. set-port-buffer-has-eof?!
  165. port-position-line
  166. port-position-column
  167. set-port-position-line!
  168. set-port-position-column!
  169. port-read
  170. port-write
  171. port-clear-stream-start-for-bom-read
  172. port-clear-stream-start-for-bom-write
  173. %port-encoding
  174. specialize-port-encoding!
  175. port-random-access?
  176. port-decode-char
  177. port-encode-char
  178. port-encode-chars
  179. port-read-buffering
  180. port-poll
  181. port-read-wait-fd
  182. port-write-wait-fd
  183. put-char
  184. put-string))
  185. (define-syntax-rule (port-buffer-bytevector buf) (vector-ref buf 0))
  186. (define-syntax-rule (port-buffer-cur buf) (vector-ref buf 1))
  187. (define-syntax-rule (port-buffer-end buf) (vector-ref buf 2))
  188. (define-syntax-rule (port-buffer-has-eof? buf) (vector-ref buf 3))
  189. (define-syntax-rule (port-buffer-position buf) (vector-ref buf 4))
  190. (define-syntax-rule (set-port-buffer-cur! buf cur)
  191. (vector-set! buf 1 cur))
  192. (define-syntax-rule (set-port-buffer-end! buf end)
  193. (vector-set! buf 2 end))
  194. (define-syntax-rule (set-port-buffer-has-eof?! buf has-eof?)
  195. (vector-set! buf 3 has-eof?))
  196. (define-syntax-rule (port-position-line position)
  197. (car position))
  198. (define-syntax-rule (port-position-column position)
  199. (cdr position))
  200. (define-syntax-rule (set-port-position-line! position line)
  201. (set-car! position line))
  202. (define-syntax-rule (set-port-position-column! position column)
  203. (set-cdr! position column))
  204. (eval-when (expand)
  205. (define-syntax-rule (private-port-bindings binding ...)
  206. (begin
  207. (define binding (@@ (ice-9 ports) binding))
  208. ...)))
  209. (private-port-bindings port-read-buffer
  210. port-write-buffer
  211. port-auxiliary-write-buffer
  212. port-line-buffered?
  213. expand-port-read-buffer!
  214. port-read
  215. port-write
  216. port-clear-stream-start-for-bom-read
  217. port-clear-stream-start-for-bom-write
  218. %port-encoding
  219. specialize-port-encoding!
  220. port-decode-char
  221. port-encode-char
  222. port-encode-chars
  223. port-random-access?
  224. port-read-buffering
  225. port-poll
  226. port-read-wait-fd
  227. port-write-wait-fd
  228. put-char
  229. put-string)
  230. ;; And we're back.
  231. (define-module (ice-9 ports))
  232. ;;; Current ports as parameters.
  233. ;;;
  234. (define current-input-port
  235. (fluid->parameter %current-input-port-fluid
  236. (lambda (x)
  237. (unless (input-port? x)
  238. (error "expected an input port" x))
  239. x)))
  240. (define current-output-port
  241. (fluid->parameter %current-output-port-fluid
  242. (lambda (x)
  243. (unless (output-port? x)
  244. (error "expected an output port" x))
  245. x)))
  246. (define current-error-port
  247. (fluid->parameter %current-error-port-fluid
  248. (lambda (x)
  249. (unless (output-port? x)
  250. (error "expected an output port" x))
  251. x)))
  252. (define current-warning-port
  253. (fluid->parameter %current-warning-port-fluid
  254. (lambda (x)
  255. (unless (output-port? x)
  256. (error "expected an output port" x))
  257. x)))
  258. ;;; {File Descriptors and Ports}
  259. ;;;
  260. (define file-position ftell)
  261. (define* (file-set-position port offset #:optional (whence SEEK_SET))
  262. (seek port offset whence))
  263. (define (move->fdes fd/port fd)
  264. (cond ((integer? fd/port)
  265. (dup->fdes fd/port fd)
  266. (close fd/port)
  267. fd)
  268. (else
  269. (primitive-move->fdes fd/port fd)
  270. (set-port-revealed! fd/port 1)
  271. fd/port)))
  272. (define (release-port-handle port)
  273. (let ((revealed (port-revealed port)))
  274. (if (> revealed 0)
  275. (set-port-revealed! port (- revealed 1)))))
  276. (define dup->port
  277. (case-lambda
  278. ((port/fd mode)
  279. (fdopen (dup->fdes port/fd) mode))
  280. ((port/fd mode new-fd)
  281. (let ((port (fdopen (dup->fdes port/fd new-fd) mode)))
  282. (set-port-revealed! port 1)
  283. port))))
  284. (define dup->inport
  285. (case-lambda
  286. ((port/fd)
  287. (dup->port port/fd "r"))
  288. ((port/fd new-fd)
  289. (dup->port port/fd "r" new-fd))))
  290. (define dup->outport
  291. (case-lambda
  292. ((port/fd)
  293. (dup->port port/fd "w"))
  294. ((port/fd new-fd)
  295. (dup->port port/fd "w" new-fd))))
  296. (define dup
  297. (case-lambda
  298. ((port/fd)
  299. (if (integer? port/fd)
  300. (dup->fdes port/fd)
  301. (dup->port port/fd (port-mode port/fd))))
  302. ((port/fd new-fd)
  303. (if (integer? port/fd)
  304. (dup->fdes port/fd new-fd)
  305. (dup->port port/fd (port-mode port/fd) new-fd)))))
  306. (define (duplicate-port port modes)
  307. (dup->port port modes))
  308. (define (fdes->inport fdes)
  309. (let loop ((rest-ports (fdes->ports fdes)))
  310. (cond ((null? rest-ports)
  311. (let ((result (fdopen fdes "r")))
  312. (set-port-revealed! result 1)
  313. result))
  314. ((input-port? (car rest-ports))
  315. (set-port-revealed! (car rest-ports)
  316. (+ (port-revealed (car rest-ports)) 1))
  317. (car rest-ports))
  318. (else
  319. (loop (cdr rest-ports))))))
  320. (define (fdes->outport fdes)
  321. (let loop ((rest-ports (fdes->ports fdes)))
  322. (cond ((null? rest-ports)
  323. (let ((result (fdopen fdes "w")))
  324. (set-port-revealed! result 1)
  325. result))
  326. ((output-port? (car rest-ports))
  327. (set-port-revealed! (car rest-ports)
  328. (+ (port-revealed (car rest-ports)) 1))
  329. (car rest-ports))
  330. (else
  331. (loop (cdr rest-ports))))))
  332. (define (port->fdes port)
  333. (set-port-revealed! port (+ (port-revealed port) 1))
  334. (fileno port))
  335. ;; Legacy interfaces.
  336. (define (set-current-input-port port)
  337. "Set the current default input port to @var{port}."
  338. (current-input-port port))
  339. (define (set-current-output-port port)
  340. "Set the current default output port to @var{port}."
  341. (current-output-port port))
  342. (define (set-current-error-port port)
  343. "Set the current default error port to @var{port}."
  344. (current-error-port port))
  345. ;;;; high level routines
  346. ;;; {High-Level Port Routines}
  347. ;;;
  348. ;; These are used to request the proper mode to open files in.
  349. ;;
  350. (define OPEN_READ "r")
  351. (define OPEN_WRITE "w")
  352. (define OPEN_BOTH "r+")
  353. (define *null-device* "/dev/null")
  354. (define* (open-input-file
  355. file #:key (binary #f) (encoding #f) (guess-encoding #f))
  356. "Takes a string naming an existing file and returns an input port
  357. capable of delivering characters from the file. If the file
  358. cannot be opened, an error is signalled."
  359. (open-file file (if binary "rb" "r")
  360. #:encoding encoding
  361. #:guess-encoding guess-encoding))
  362. (define* (open-output-file file #:key (binary #f) (encoding #f))
  363. "Takes a string naming an output file to be created and returns an
  364. output port capable of writing characters to a new file by that
  365. name. If the file cannot be opened, an error is signalled. If a
  366. file with the given name already exists, the effect is unspecified."
  367. (open-file file (if binary "wb" "w")
  368. #:encoding encoding))
  369. (define (open-io-file str)
  370. "Open file with name STR for both input and output."
  371. (open-file str OPEN_BOTH))
  372. (define (call-with-port port proc)
  373. "Call @var{proc}, passing it @var{port} and closing @var{port} upon exit of
  374. @var{proc}. Return the return values of @var{proc}."
  375. (call-with-values
  376. (lambda () (proc port))
  377. (lambda vals
  378. (close-port port)
  379. (apply values vals))))
  380. (define* (call-with-input-file
  381. file proc #:key (binary #f) (encoding #f) (guess-encoding #f))
  382. "PROC should be a procedure of one argument, and FILE should be a
  383. string naming a file. The file must
  384. already exist. These procedures call PROC
  385. with one argument: the port obtained by opening the named file for
  386. input or output. If the file cannot be opened, an error is
  387. signalled. If the procedure returns, then the port is closed
  388. automatically and the values yielded by the procedure are returned.
  389. If the procedure does not return, then the port will not be closed
  390. automatically unless it is possible to prove that the port will
  391. never again be used for a read or write operation."
  392. (let ((p (open-input-file file
  393. #:binary binary
  394. #:encoding encoding
  395. #:guess-encoding guess-encoding)))
  396. (call-with-port p proc)))
  397. (define* (call-with-output-file file proc #:key (binary #f) (encoding #f))
  398. "PROC should be a procedure of one argument, and FILE should be a
  399. string naming a file. The behaviour is unspecified if the file
  400. already exists. These procedures call PROC
  401. with one argument: the port obtained by opening the named file for
  402. input or output. If the file cannot be opened, an error is
  403. signalled. If the procedure returns, then the port is closed
  404. automatically and the values yielded by the procedure are returned.
  405. If the procedure does not return, then the port will not be closed
  406. automatically unless it is possible to prove that the port will
  407. never again be used for a read or write operation."
  408. (let ((p (open-output-file file #:binary binary #:encoding encoding)))
  409. (call-with-port p proc)))
  410. (define (with-input-from-port port thunk)
  411. (parameterize ((current-input-port port))
  412. (thunk)))
  413. (define (with-output-to-port port thunk)
  414. (parameterize ((current-output-port port))
  415. (thunk)))
  416. (define (with-error-to-port port thunk)
  417. (parameterize ((current-error-port port))
  418. (thunk)))
  419. (define* (with-input-from-file
  420. file thunk #:key (binary #f) (encoding #f) (guess-encoding #f))
  421. "THUNK must be a procedure of no arguments, and FILE must be a
  422. string naming a file. The file must already exist. The file is opened for
  423. input, an input port connected to it is made
  424. the default value returned by `current-input-port',
  425. and the THUNK is called with no arguments.
  426. When the THUNK returns, the port is closed and the previous
  427. default is restored. Returns the values yielded by THUNK. If an
  428. escape procedure is used to escape from the continuation of these
  429. procedures, their behavior is implementation dependent."
  430. (call-with-input-file file
  431. (lambda (p) (with-input-from-port p thunk))
  432. #:binary binary
  433. #:encoding encoding
  434. #:guess-encoding guess-encoding))
  435. (define* (with-output-to-file file thunk #:key (binary #f) (encoding #f))
  436. "THUNK must be a procedure of no arguments, and FILE must be a
  437. string naming a file. The effect is unspecified if the file already exists.
  438. The file is opened for output, an output port connected to it is made
  439. the default value returned by `current-output-port',
  440. and the THUNK is called with no arguments.
  441. When the THUNK returns, the port is closed and the previous
  442. default is restored. Returns the values yielded by THUNK. If an
  443. escape procedure is used to escape from the continuation of these
  444. procedures, their behavior is implementation dependent."
  445. (call-with-output-file file
  446. (lambda (p) (with-output-to-port p thunk))
  447. #:binary binary
  448. #:encoding encoding))
  449. (define* (with-error-to-file file thunk #:key (binary #f) (encoding #f))
  450. "THUNK must be a procedure of no arguments, and FILE must be a
  451. string naming a file. The effect is unspecified if the file already exists.
  452. The file is opened for output, an output port connected to it is made
  453. the default value returned by `current-error-port',
  454. and the THUNK is called with no arguments.
  455. When the THUNK returns, the port is closed and the previous
  456. default is restored. Returns the values yielded by THUNK. If an
  457. escape procedure is used to escape from the continuation of these
  458. procedures, their behavior is implementation dependent."
  459. (call-with-output-file file
  460. (lambda (p) (with-error-to-port p thunk))
  461. #:binary binary
  462. #:encoding encoding))
  463. (define (call-with-input-string string proc)
  464. "Call the one-argument procedure @var{proc} with a newly created input
  465. port from which @var{string}'s contents may be read. All values yielded
  466. by the @var{proc} are returned."
  467. (proc (open-input-string string)))
  468. (define (with-input-from-string string thunk)
  469. "THUNK must be a procedure of no arguments.
  470. The test of STRING is opened for
  471. input, an input port connected to it is made,
  472. and the THUNK is called with no arguments.
  473. When the THUNK returns, the port is closed.
  474. Returns the values yielded by THUNK. If an
  475. escape procedure is used to escape from the continuation of these
  476. procedures, their behavior is implementation dependent."
  477. (call-with-input-string string
  478. (lambda (p) (with-input-from-port p thunk))))
  479. (define (call-with-output-string proc)
  480. "Call the one-argument procedure @var{proc} with a newly created
  481. output port. When the function returns, port is closed and the string
  482. composed of the characters written into the port is returned."
  483. (let ((port (open-output-string)))
  484. (proc port)
  485. (let ((res (get-output-string port)))
  486. (close-port port)
  487. res)))
  488. (define (with-output-to-string thunk)
  489. "Calls THUNK and returns its output as a string."
  490. (call-with-output-string
  491. (lambda (p) (with-output-to-port p thunk))))
  492. (define (with-error-to-string thunk)
  493. "Calls THUNK and returns its error output as a string."
  494. (call-with-output-string
  495. (lambda (p) (with-error-to-port p thunk))))
  496. (define (inherit-print-state old-port new-port)
  497. (if (get-print-state old-port)
  498. (port-with-print-state new-port (get-print-state old-port))
  499. new-port))