ports.scm 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. ;;; Ports
  2. ;;; Copyright (C) 2016,2019,2021,2024 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 current-info-port
  31. current-load-port
  32. set-current-input-port set-current-output-port
  33. set-current-error-port set-current-info-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. current-info-port))
  141. (load-extension (string-append "libguile-" (effective-version))
  142. "scm_init_ice_9_ports")
  143. (load-extension (string-append "libguile-" (effective-version))
  144. "scm_init_ice_9_fports")
  145. (load-extension (string-append "libguile-" (effective-version))
  146. "scm_init_ice_9_ioext")
  147. (eval-when (load eval expand)
  148. (when (defined? 'SEEK_DATA)
  149. (module-export! (current-module) '(SEEK_DATA)))
  150. (when (defined? 'SEEK_HOLE)
  151. (module-export! (current-module) '(SEEK_HOLE))))
  152. (define (port-encoding port)
  153. "Return, as a string, the character encoding that @var{port} uses to
  154. interpret its input and output."
  155. (symbol->string (%port-encoding port)))
  156. (define-module (ice-9 ports internal)
  157. #:use-module (ice-9 ports)
  158. #:export (port-read-buffer
  159. port-write-buffer
  160. port-auxiliary-write-buffer
  161. port-line-buffered?
  162. expand-port-read-buffer!
  163. port-buffer-bytevector
  164. port-buffer-cur
  165. port-buffer-end
  166. port-buffer-has-eof?
  167. port-buffer-position
  168. set-port-buffer-cur!
  169. set-port-buffer-end!
  170. set-port-buffer-has-eof?!
  171. port-position-line
  172. port-position-column
  173. set-port-position-line!
  174. set-port-position-column!
  175. port-read
  176. port-write
  177. port-clear-stream-start-for-bom-read
  178. port-clear-stream-start-for-bom-write
  179. %port-encoding
  180. specialize-port-encoding!
  181. port-random-access?
  182. port-decode-char
  183. port-encode-char
  184. port-encode-chars
  185. port-read-buffering
  186. port-poll
  187. port-read-wait-fd
  188. port-write-wait-fd
  189. put-char
  190. put-string))
  191. (define-syntax-rule (port-buffer-bytevector buf) (vector-ref buf 0))
  192. (define-syntax-rule (port-buffer-cur buf) (vector-ref buf 1))
  193. (define-syntax-rule (port-buffer-end buf) (vector-ref buf 2))
  194. (define-syntax-rule (port-buffer-has-eof? buf) (vector-ref buf 3))
  195. (define-syntax-rule (port-buffer-position buf) (vector-ref buf 4))
  196. (define-syntax-rule (set-port-buffer-cur! buf cur)
  197. (vector-set! buf 1 cur))
  198. (define-syntax-rule (set-port-buffer-end! buf end)
  199. (vector-set! buf 2 end))
  200. (define-syntax-rule (set-port-buffer-has-eof?! buf has-eof?)
  201. (vector-set! buf 3 has-eof?))
  202. (define-syntax-rule (port-position-line position)
  203. (car position))
  204. (define-syntax-rule (port-position-column position)
  205. (cdr position))
  206. (define-syntax-rule (set-port-position-line! position line)
  207. (set-car! position line))
  208. (define-syntax-rule (set-port-position-column! position column)
  209. (set-cdr! position column))
  210. (eval-when (expand)
  211. (define-syntax-rule (private-port-bindings binding ...)
  212. (begin
  213. (define binding (@@ (ice-9 ports) binding))
  214. ...)))
  215. (private-port-bindings port-read-buffer
  216. port-write-buffer
  217. port-auxiliary-write-buffer
  218. port-line-buffered?
  219. expand-port-read-buffer!
  220. port-read
  221. port-write
  222. port-clear-stream-start-for-bom-read
  223. port-clear-stream-start-for-bom-write
  224. %port-encoding
  225. specialize-port-encoding!
  226. port-decode-char
  227. port-encode-char
  228. port-encode-chars
  229. port-random-access?
  230. port-read-buffering
  231. port-poll
  232. port-read-wait-fd
  233. port-write-wait-fd
  234. put-char
  235. put-string)
  236. ;; And we're back.
  237. (define-module (ice-9 ports))
  238. ;;; Current ports as parameters.
  239. ;;;
  240. (define current-input-port
  241. (fluid->parameter %current-input-port-fluid
  242. (lambda (x)
  243. (unless (input-port? x)
  244. (error "expected an input port" x))
  245. x)))
  246. (define current-output-port
  247. (fluid->parameter %current-output-port-fluid
  248. (lambda (x)
  249. (unless (output-port? x)
  250. (error "expected an output port" x))
  251. x)))
  252. (define current-error-port
  253. (fluid->parameter %current-error-port-fluid
  254. (lambda (x)
  255. (unless (output-port? x)
  256. (error "expected an output port" x))
  257. x)))
  258. (define current-warning-port
  259. (fluid->parameter %current-warning-port-fluid
  260. (lambda (x)
  261. (unless (output-port? x)
  262. (error "expected an output port" x))
  263. x)))
  264. (define current-info-port
  265. (fluid->parameter %current-info-port-fluid
  266. (lambda (x)
  267. (unless (output-port? x)
  268. (error "expected an output port" x))
  269. x)))
  270. ;;; {File Descriptors and Ports}
  271. ;;;
  272. (define file-position ftell)
  273. (define* (file-set-position port offset #:optional (whence SEEK_SET))
  274. (seek port offset whence))
  275. (define (move->fdes fd/port fd)
  276. (cond ((integer? fd/port)
  277. (dup->fdes fd/port fd)
  278. (close fd/port)
  279. fd)
  280. (else
  281. (primitive-move->fdes fd/port fd)
  282. (set-port-revealed! fd/port 1)
  283. fd/port)))
  284. (define (release-port-handle port)
  285. (let ((revealed (port-revealed port)))
  286. (if (> revealed 0)
  287. (set-port-revealed! port (- revealed 1)))))
  288. (define dup->port
  289. (case-lambda
  290. ((port/fd mode)
  291. (fdopen (dup->fdes port/fd) mode))
  292. ((port/fd mode new-fd)
  293. (let ((port (fdopen (dup->fdes port/fd new-fd) mode)))
  294. (set-port-revealed! port 1)
  295. port))))
  296. (define dup->inport
  297. (case-lambda
  298. ((port/fd)
  299. (dup->port port/fd "r"))
  300. ((port/fd new-fd)
  301. (dup->port port/fd "r" new-fd))))
  302. (define dup->outport
  303. (case-lambda
  304. ((port/fd)
  305. (dup->port port/fd "w"))
  306. ((port/fd new-fd)
  307. (dup->port port/fd "w" new-fd))))
  308. (define dup
  309. (case-lambda
  310. ((port/fd)
  311. (if (integer? port/fd)
  312. (dup->fdes port/fd)
  313. (dup->port port/fd (port-mode port/fd))))
  314. ((port/fd new-fd)
  315. (if (integer? port/fd)
  316. (dup->fdes port/fd new-fd)
  317. (dup->port port/fd (port-mode port/fd) new-fd)))))
  318. (define (duplicate-port port modes)
  319. (dup->port port modes))
  320. (define (fdes->inport fdes)
  321. (let loop ((rest-ports (fdes->ports fdes)))
  322. (cond ((null? rest-ports)
  323. (let ((result (fdopen fdes "r")))
  324. (set-port-revealed! result 1)
  325. result))
  326. ((input-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 (fdes->outport fdes)
  333. (let loop ((rest-ports (fdes->ports fdes)))
  334. (cond ((null? rest-ports)
  335. (let ((result (fdopen fdes "w")))
  336. (set-port-revealed! result 1)
  337. result))
  338. ((output-port? (car rest-ports))
  339. (set-port-revealed! (car rest-ports)
  340. (+ (port-revealed (car rest-ports)) 1))
  341. (car rest-ports))
  342. (else
  343. (loop (cdr rest-ports))))))
  344. (define (port->fdes port)
  345. (set-port-revealed! port (+ (port-revealed port) 1))
  346. (fileno port))
  347. ;; Legacy interfaces.
  348. (define (set-current-input-port port)
  349. "Set the current default input port to @var{port}."
  350. (current-input-port port))
  351. (define (set-current-output-port port)
  352. "Set the current default output port to @var{port}."
  353. (current-output-port port))
  354. (define (set-current-error-port port)
  355. "Set the current default error port to @var{port}."
  356. (current-error-port port))
  357. (define (set-current-info-port port)
  358. "Set the current default info port to @var{port}."
  359. (current-info-port port))
  360. ;;;; high level routines
  361. ;;; {High-Level Port Routines}
  362. ;;;
  363. ;; These are used to request the proper mode to open files in.
  364. ;;
  365. (define OPEN_READ "r")
  366. (define OPEN_WRITE "w")
  367. (define OPEN_BOTH "r+")
  368. (define *null-device* "/dev/null")
  369. (define* (open-input-file
  370. file #:key (binary #f) (encoding #f) (guess-encoding #f))
  371. "Takes a string naming an existing file and returns an input port
  372. capable of delivering characters from the file. If the file
  373. cannot be opened, an error is signaled."
  374. (open-file file (if binary "rb" "r")
  375. #:encoding encoding
  376. #:guess-encoding guess-encoding))
  377. (define* (open-output-file file #:key (binary #f) (encoding #f))
  378. "Takes a string naming an output file to be created and returns an
  379. output port capable of writing characters to a new file by that
  380. name. If the file cannot be opened, an error is signaled. If a
  381. file with the given name already exists, the effect is unspecified."
  382. (open-file file (if binary "wb" "w")
  383. #:encoding encoding))
  384. (define (open-io-file str)
  385. "Open file with name STR for both input and output."
  386. (open-file str OPEN_BOTH))
  387. (define (call-with-port port proc)
  388. "Call @var{proc}, passing it @var{port} and closing @var{port} upon exit of
  389. @var{proc}. Return the return values of @var{proc}."
  390. (call-with-values
  391. (lambda () (proc port))
  392. (lambda vals
  393. (close-port port)
  394. (apply values vals))))
  395. (define* (call-with-input-file
  396. file proc #:key (binary #f) (encoding #f) (guess-encoding #f))
  397. "PROC should be a procedure of one argument, and FILE should be a
  398. string naming a file. The file must
  399. already exist. These procedures call PROC
  400. with one argument: the port obtained by opening the named file for
  401. input or output. If the file cannot be opened, an error is
  402. signaled. If the procedure returns, then the port is closed
  403. automatically and the values yielded by the procedure are returned.
  404. If the procedure does not return, then the port will not be closed
  405. automatically unless it is possible to prove that the port will
  406. never again be used for a read or write operation."
  407. (let ((p (open-input-file file
  408. #:binary binary
  409. #:encoding encoding
  410. #:guess-encoding guess-encoding)))
  411. (call-with-port p proc)))
  412. (define* (call-with-output-file file proc #:key (binary #f) (encoding #f))
  413. "PROC should be a procedure of one argument, and FILE should be a
  414. string naming a file. The behavior is unspecified if the file
  415. already exists. These procedures call PROC
  416. with one argument: the port obtained by opening the named file for
  417. input or output. If the file cannot be opened, an error is
  418. signaled. If the procedure returns, then the port is closed
  419. automatically and the values yielded by the procedure are returned.
  420. If the procedure does not return, then the port will not be closed
  421. automatically unless it is possible to prove that the port will
  422. never again be used for a read or write operation."
  423. (let ((p (open-output-file file #:binary binary #:encoding encoding)))
  424. (call-with-port p proc)))
  425. (define (with-input-from-port port thunk)
  426. (parameterize ((current-input-port port))
  427. (thunk)))
  428. (define (with-output-to-port port thunk)
  429. (parameterize ((current-output-port port))
  430. (thunk)))
  431. (define (with-error-to-port port thunk)
  432. (parameterize ((current-error-port port))
  433. (thunk)))
  434. (define* (with-input-from-file
  435. file thunk #:key (binary #f) (encoding #f) (guess-encoding #f))
  436. "THUNK must be a procedure of no arguments, and FILE must be a
  437. string naming a file. The file must already exist. The file is opened for
  438. input, an input port connected to it is made
  439. the default value returned by `current-input-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-input-file file
  446. (lambda (p) (with-input-from-port p thunk))
  447. #:binary binary
  448. #:encoding encoding
  449. #:guess-encoding guess-encoding))
  450. (define* (with-output-to-file file thunk #:key (binary #f) (encoding #f))
  451. "THUNK must be a procedure of no arguments, and FILE must be a
  452. string naming a file. The effect is unspecified if the file already exists.
  453. The file is opened for output, an output port connected to it is made
  454. the default value returned by `current-output-port',
  455. and the THUNK is called with no arguments.
  456. When the THUNK returns, the port is closed and the previous
  457. default is restored. Returns the values yielded by THUNK. If an
  458. escape procedure is used to escape from the continuation of these
  459. procedures, their behavior is implementation dependent."
  460. (call-with-output-file file
  461. (lambda (p) (with-output-to-port p thunk))
  462. #:binary binary
  463. #:encoding encoding))
  464. (define* (with-error-to-file file thunk #:key (binary #f) (encoding #f))
  465. "THUNK must be a procedure of no arguments, and FILE must be a
  466. string naming a file. The effect is unspecified if the file already exists.
  467. The file is opened for output, an output port connected to it is made
  468. the default value returned by `current-error-port',
  469. and the THUNK is called with no arguments.
  470. When the THUNK returns, the port is closed and the previous
  471. default is restored. Returns the values yielded by THUNK. If an
  472. escape procedure is used to escape from the continuation of these
  473. procedures, their behavior is implementation dependent."
  474. (call-with-output-file file
  475. (lambda (p) (with-error-to-port p thunk))
  476. #:binary binary
  477. #:encoding encoding))
  478. (define (call-with-input-string string proc)
  479. "Call the one-argument procedure @var{proc} with a newly created input
  480. port from which @var{string}'s contents may be read. All values yielded
  481. by the @var{proc} are returned."
  482. (proc (open-input-string string)))
  483. (define (with-input-from-string string thunk)
  484. "THUNK must be a procedure of no arguments.
  485. The test of STRING is opened for
  486. input, an input port connected to it is made,
  487. and the THUNK is called with no arguments.
  488. When the THUNK returns, the port is closed.
  489. Returns the values yielded by THUNK. If an
  490. escape procedure is used to escape from the continuation of these
  491. procedures, their behavior is implementation dependent."
  492. (call-with-input-string string
  493. (lambda (p) (with-input-from-port p thunk))))
  494. (define (call-with-output-string proc)
  495. "Call the one-argument procedure @var{proc} with a newly created
  496. output port. When the function returns, port is closed and the string
  497. composed of the characters written into the port is returned."
  498. (let ((port (open-output-string)))
  499. (proc port)
  500. (let ((res (get-output-string port)))
  501. (close-port port)
  502. res)))
  503. (define (with-output-to-string thunk)
  504. "Calls THUNK and returns its output as a string."
  505. (call-with-output-string
  506. (lambda (p) (with-output-to-port p thunk))))
  507. (define (with-error-to-string thunk)
  508. "Calls THUNK and returns its error output as a string."
  509. (call-with-output-string
  510. (lambda (p) (with-error-to-port p thunk))))
  511. (define (inherit-print-state old-port new-port)
  512. (if (get-print-state old-port)
  513. (port-with-print-state new-port (get-print-state old-port))
  514. new-port))