fports.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868
  1. /* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2006 Free Software Foundation, Inc.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation; either version 2, or (at your option)
  6. * any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this software; see the file COPYING. If not, write to
  15. * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  16. * Boston, MA 02110-1301 USA
  17. *
  18. * As a special exception, the Free Software Foundation gives permission
  19. * for additional uses of the text contained in its release of GUILE.
  20. *
  21. * The exception is that, if you link the GUILE library with other files
  22. * to produce an executable, this does not by itself cause the
  23. * resulting executable to be covered by the GNU General Public License.
  24. * Your use of that executable is in no way restricted on account of
  25. * linking the GUILE library code into it.
  26. *
  27. * This exception does not however invalidate any other reasons why
  28. * the executable file might be covered by the GNU General Public License.
  29. *
  30. * This exception applies only to the code released by the
  31. * Free Software Foundation under the name GUILE. If you copy
  32. * code from other Free Software Foundation releases into a copy of
  33. * GUILE, as the General Public License permits, the exception does
  34. * not apply to the code that you add in this way. To avoid misleading
  35. * anyone as to the status of such modified files, you must delete
  36. * this exception notice from them.
  37. *
  38. * If you write modifications of your own for GUILE, it is your choice
  39. * whether to permit this exception to apply to your modifications.
  40. * If you do not wish that, delete this exception notice. */
  41. #include <stdio.h>
  42. #include <fcntl.h>
  43. #include "libguile/_scm.h"
  44. #include "libguile/strings.h"
  45. #include "libguile/validate.h"
  46. #include "libguile/gc.h"
  47. #include "libguile/fports.h"
  48. #ifdef HAVE_STRING_H
  49. #include <string.h>
  50. #endif
  51. #ifdef HAVE_UNISTD_H
  52. #include <unistd.h>
  53. #else
  54. size_t fwrite ();
  55. #endif
  56. #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
  57. #include <sys/stat.h>
  58. #endif
  59. #include <errno.h>
  60. #include "libguile/iselect.h"
  61. /* Some defines for Windows. */
  62. #ifdef __MINGW32__
  63. # include <sys/stat.h>
  64. # include <winsock2.h>
  65. # define ftruncate(fd, size) chsize (fd, size)
  66. #endif /* __MINGW32__ */
  67. scm_t_bits scm_tc16_fport;
  68. /* default buffer size, used if the O/S won't supply a value. */
  69. static const size_t default_buffer_size = 1024;
  70. /* create FPORT buffer with specified sizes (or -1 to use default size or
  71. 0 for no buffer. */
  72. static void
  73. scm_fport_buffer_add (SCM port, long read_size, int write_size)
  74. #define FUNC_NAME "scm_fport_buffer_add"
  75. {
  76. scm_t_fport *fp = SCM_FSTREAM (port);
  77. scm_t_port *pt = SCM_PTAB_ENTRY (port);
  78. if (read_size == -1 || write_size == -1)
  79. {
  80. size_t default_size;
  81. #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
  82. struct stat st;
  83. default_size = (fstat (fp->fdes, &st) == -1) ? default_buffer_size
  84. : st.st_blksize;
  85. #else
  86. default_size = default_buffer_size;
  87. #endif
  88. if (read_size == -1)
  89. read_size = default_size;
  90. if (write_size == -1)
  91. write_size = default_size;
  92. }
  93. if (SCM_INPUT_PORT_P (port) && read_size > 0)
  94. {
  95. pt->read_buf = scm_must_malloc (read_size, FUNC_NAME);
  96. pt->read_pos = pt->read_end = pt->read_buf;
  97. pt->read_buf_size = read_size;
  98. }
  99. else
  100. {
  101. pt->read_pos = pt->read_buf = pt->read_end = &pt->shortbuf;
  102. pt->read_buf_size = 1;
  103. }
  104. if (SCM_OUTPUT_PORT_P (port) && write_size > 0)
  105. {
  106. pt->write_buf = scm_must_malloc (write_size, FUNC_NAME);
  107. pt->write_pos = pt->write_buf;
  108. pt->write_buf_size = write_size;
  109. }
  110. else
  111. {
  112. pt->write_buf = pt->write_pos = &pt->shortbuf;
  113. pt->write_buf_size = 1;
  114. }
  115. pt->write_end = pt->write_buf + pt->write_buf_size;
  116. if (read_size > 0 || write_size > 0)
  117. SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) & ~SCM_BUF0);
  118. else
  119. SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) | SCM_BUF0);
  120. }
  121. #undef FUNC_NAME
  122. SCM_DEFINE (scm_setvbuf, "setvbuf", 2, 1, 0,
  123. (SCM port, SCM mode, SCM size),
  124. "Set the buffering mode for @var{port}. @var{mode} can be:\n"
  125. "@table @code\n"
  126. "@item _IONBF\n"
  127. "non-buffered\n"
  128. "@item _IOLBF\n"
  129. "line buffered\n"
  130. "@item _IOFBF\n"
  131. "block buffered, using a newly allocated buffer of @var{size} bytes.\n"
  132. "If @var{size} is omitted, a default size will be used.\n"
  133. "@end table")
  134. #define FUNC_NAME s_scm_setvbuf
  135. {
  136. int cmode;
  137. long csize;
  138. scm_t_port *pt;
  139. port = SCM_COERCE_OUTPORT (port);
  140. SCM_VALIDATE_OPFPORT (1,port);
  141. SCM_VALIDATE_INUM_COPY (2,mode,cmode);
  142. if (cmode != _IONBF && cmode != _IOFBF && cmode != _IOLBF)
  143. scm_out_of_range (FUNC_NAME, mode);
  144. if (cmode == _IOLBF)
  145. {
  146. SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) | SCM_BUFLINE);
  147. cmode = _IOFBF;
  148. }
  149. else
  150. {
  151. SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) & ~(scm_t_bits)SCM_BUFLINE);
  152. }
  153. if (SCM_UNBNDP (size))
  154. {
  155. if (cmode == _IOFBF)
  156. csize = -1;
  157. else
  158. csize = 0;
  159. }
  160. else
  161. {
  162. SCM_VALIDATE_INUM_COPY (3,size,csize);
  163. if (csize < 0 || (cmode == _IONBF && csize > 0))
  164. scm_out_of_range (FUNC_NAME, size);
  165. }
  166. pt = SCM_PTAB_ENTRY (port);
  167. /* silently discards buffered chars. */
  168. if (pt->read_buf != &pt->shortbuf)
  169. scm_must_free (pt->read_buf);
  170. if (pt->write_buf != &pt->shortbuf)
  171. scm_must_free (pt->write_buf);
  172. scm_fport_buffer_add (port, csize, csize);
  173. return SCM_UNSPECIFIED;
  174. }
  175. #undef FUNC_NAME
  176. /* Move ports with the specified file descriptor to new descriptors,
  177. * reseting the revealed count to 0.
  178. */
  179. void
  180. scm_evict_ports (int fd)
  181. {
  182. long i;
  183. for (i = 0; i < scm_port_table_size; i++)
  184. {
  185. SCM port = scm_port_table[i]->port;
  186. if (SCM_FPORTP (port))
  187. {
  188. scm_t_fport *fp = SCM_FSTREAM (port);
  189. if (fp->fdes == fd)
  190. {
  191. fp->fdes = dup (fd);
  192. if (fp->fdes == -1)
  193. scm_syserror ("scm_evict_ports");
  194. scm_set_port_revealed_x (port, SCM_MAKINUM (0));
  195. }
  196. }
  197. }
  198. }
  199. SCM_DEFINE (scm_file_port_p, "file-port?", 1, 0, 0,
  200. (SCM obj),
  201. "Determine whether @var{obj} is a port that is related to a file.")
  202. #define FUNC_NAME s_scm_file_port_p
  203. {
  204. return SCM_BOOL (SCM_FPORTP (obj));
  205. }
  206. #undef FUNC_NAME
  207. /* scm_open_file
  208. * Return a new port open on a given file.
  209. *
  210. * The mode string must match the pattern: [rwa+]** which
  211. * is interpreted in the usual unix way.
  212. *
  213. * Return the new port.
  214. */
  215. SCM_DEFINE (scm_open_file, "open-file", 2, 0, 0,
  216. (SCM filename, SCM mode),
  217. "Open the file whose name is @var{filename}, and return a port\n"
  218. "representing that file. The attributes of the port are\n"
  219. "determined by the @var{mode} string. The way in which this is\n"
  220. "interpreted is similar to C stdio. The first character must be\n"
  221. "one of the following:\n"
  222. "@table @samp\n"
  223. "@item r\n"
  224. "Open an existing file for input.\n"
  225. "@item w\n"
  226. "Open a file for output, creating it if it doesn't already exist\n"
  227. "or removing its contents if it does.\n"
  228. "@item a\n"
  229. "Open a file for output, creating it if it doesn't already\n"
  230. "exist. All writes to the port will go to the end of the file.\n"
  231. "The \"append mode\" can be turned off while the port is in use\n"
  232. "@pxref{Ports and File Descriptors, fcntl}\n"
  233. "@end table\n"
  234. "The following additional characters can be appended:\n"
  235. "@table @samp\n"
  236. "@item +\n"
  237. "Open the port for both input and output. E.g., @code{r+}: open\n"
  238. "an existing file for both input and output.\n"
  239. "@item 0\n"
  240. "Create an \"unbuffered\" port. In this case input and output\n"
  241. "operations are passed directly to the underlying port\n"
  242. "implementation without additional buffering. This is likely to\n"
  243. "slow down I/O operations. The buffering mode can be changed\n"
  244. "while a port is in use @pxref{Ports and File Descriptors,\n"
  245. "setvbuf}\n"
  246. "@item l\n"
  247. "Add line-buffering to the port. The port output buffer will be\n"
  248. "automatically flushed whenever a newline character is written.\n"
  249. "@end table\n"
  250. "In theory we could create read/write ports which were buffered\n"
  251. "in one direction only. However this isn't included in the\n"
  252. "current interfaces. If a file cannot be opened with the access\n"
  253. "requested, @code{open-file} throws an exception.")
  254. #define FUNC_NAME s_scm_open_file
  255. {
  256. SCM port;
  257. int fdes;
  258. int flags = 0;
  259. char *file;
  260. char *md;
  261. char *ptr;
  262. SCM_VALIDATE_STRING (1, filename);
  263. SCM_VALIDATE_STRING (2, mode);
  264. SCM_STRING_COERCE_0TERMINATION_X (filename);
  265. SCM_STRING_COERCE_0TERMINATION_X (mode);
  266. file = SCM_STRING_CHARS (filename);
  267. md = SCM_STRING_CHARS (mode);
  268. switch (*md)
  269. {
  270. case 'r':
  271. flags |= O_RDONLY;
  272. break;
  273. case 'w':
  274. flags |= O_WRONLY | O_CREAT | O_TRUNC;
  275. break;
  276. case 'a':
  277. flags |= O_WRONLY | O_CREAT | O_APPEND;
  278. break;
  279. default:
  280. scm_out_of_range (FUNC_NAME, mode);
  281. }
  282. ptr = md + 1;
  283. while (*ptr != '\0')
  284. {
  285. switch (*ptr)
  286. {
  287. case '+':
  288. flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
  289. break;
  290. case 'b':
  291. #if defined (O_BINARY)
  292. flags |= O_BINARY;
  293. #endif
  294. break;
  295. case '0': /* unbuffered: handled later. */
  296. case 'l': /* line buffered: handled during output. */
  297. break;
  298. default:
  299. scm_out_of_range (FUNC_NAME, mode);
  300. }
  301. ptr++;
  302. }
  303. SCM_SYSCALL (fdes = open (file, flags, 0666));
  304. if (fdes == -1)
  305. {
  306. int en = errno;
  307. SCM_SYSERROR_MSG ("~A: ~S",
  308. scm_cons (scm_makfrom0str (strerror (en)),
  309. scm_cons (filename, SCM_EOL)), en);
  310. }
  311. port = scm_fdes_to_port (fdes, md, filename);
  312. return port;
  313. }
  314. #undef FUNC_NAME
  315. #ifdef __MINGW32__
  316. /*
  317. * Try getting the appropiate file flags for a given file descriptor
  318. * under Windows. This incorporates some fancy operations because Windows
  319. * differentiates between file, pipe and socket descriptors.
  320. */
  321. #ifndef O_ACCMODE
  322. # define O_ACCMODE 0x0003
  323. #endif
  324. static int getflags (int fdes)
  325. {
  326. int flags = 0;
  327. struct stat buf;
  328. int error, optlen = sizeof (int);
  329. /* Is this a socket ? */
  330. if (getsockopt (fdes, SOL_SOCKET, SO_ERROR, (void *) &error, &optlen) >= 0)
  331. flags = O_RDWR;
  332. /* Maybe a regular file ? */
  333. else if (fstat (fdes, &buf) < 0)
  334. flags = -1;
  335. else
  336. {
  337. /* Or an anonymous pipe handle ? */
  338. if (buf.st_mode & 0x1000 /* _O_SHORT_LIVED */)
  339. flags = O_RDWR;
  340. /* stdin ? */
  341. else if (fdes == 0 && isatty (fdes))
  342. flags = O_RDONLY;
  343. /* stdout / stderr ? */
  344. else if ((fdes == 1 || fdes == 2) && isatty (fdes))
  345. flags = O_WRONLY;
  346. else
  347. flags = buf.st_mode;
  348. }
  349. return flags;
  350. }
  351. #endif /* __MINGW32__ */
  352. /* Building Guile ports from a file descriptor. */
  353. /* Build a Scheme port from an open file descriptor `fdes'.
  354. MODE indicates whether FILE is open for reading or writing; it uses
  355. the same notation as open-file's second argument.
  356. NAME is a string to be used as the port's filename.
  357. */
  358. SCM
  359. scm_fdes_to_port (int fdes, char *mode, SCM name)
  360. #define FUNC_NAME "scm_fdes_to_port"
  361. {
  362. long mode_bits = scm_mode_bits (mode);
  363. SCM port;
  364. scm_t_port *pt;
  365. int flags;
  366. /* test that fdes is valid. */
  367. #ifdef __MINGW32__
  368. flags = getflags (fdes);
  369. #else
  370. flags = fcntl (fdes, F_GETFL, 0);
  371. #endif
  372. if (flags == -1)
  373. SCM_SYSERROR;
  374. flags &= O_ACCMODE;
  375. if (flags != O_RDWR
  376. && ((flags != O_WRONLY && (mode_bits & SCM_WRTNG))
  377. || (flags != O_RDONLY && (mode_bits & SCM_RDNG))))
  378. {
  379. SCM_MISC_ERROR ("requested file mode not available on fdes", SCM_EOL);
  380. }
  381. SCM_NEWCELL (port);
  382. SCM_DEFER_INTS;
  383. pt = scm_add_to_port_table (port);
  384. SCM_SETPTAB_ENTRY (port, pt);
  385. SCM_SET_CELL_TYPE (port, (scm_tc16_fport | mode_bits));
  386. {
  387. scm_t_fport *fp
  388. = (scm_t_fport *) scm_must_malloc (sizeof (scm_t_fport),
  389. FUNC_NAME);
  390. fp->fdes = fdes;
  391. pt->rw_random = SCM_FDES_RANDOM_P (fdes);
  392. SCM_SETSTREAM (port, fp);
  393. if (mode_bits & SCM_BUF0)
  394. scm_fport_buffer_add (port, 0, 0);
  395. else
  396. scm_fport_buffer_add (port, -1, -1);
  397. }
  398. SCM_SET_FILENAME (port, name);
  399. SCM_ALLOW_INTS;
  400. return port;
  401. }
  402. #undef FUNC_NAME
  403. /* Return a lower bound on the number of bytes available for input. */
  404. static int
  405. fport_input_waiting (SCM port)
  406. {
  407. int fdes = SCM_FSTREAM (port)->fdes;
  408. #ifdef HAVE_SELECT
  409. struct timeval timeout;
  410. SELECT_TYPE read_set;
  411. SELECT_TYPE write_set;
  412. SELECT_TYPE except_set;
  413. FD_ZERO (&read_set);
  414. FD_ZERO (&write_set);
  415. FD_ZERO (&except_set);
  416. FD_SET (fdes, &read_set);
  417. timeout.tv_sec = 0;
  418. timeout.tv_usec = 0;
  419. if (select (SELECT_SET_SIZE,
  420. &read_set, &write_set, &except_set, &timeout)
  421. < 0)
  422. scm_syserror ("fport_input_waiting");
  423. return FD_ISSET (fdes, &read_set) ? 1 : 0;
  424. #elif defined (FIONREAD)
  425. int remir;
  426. ioctl(fdes, FIONREAD, &remir);
  427. return remir;
  428. #else
  429. scm_misc_error ("fport_input_waiting",
  430. "Not fully implemented on this platform",
  431. SCM_EOL);
  432. #endif
  433. }
  434. static int
  435. fport_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
  436. {
  437. scm_puts ("#<", port);
  438. scm_print_port_mode (exp, port);
  439. if (SCM_OPFPORTP (exp))
  440. {
  441. int fdes;
  442. SCM name = SCM_FILENAME (exp);
  443. if (SCM_STRINGP (name) || SCM_SYMBOLP (name))
  444. scm_display (name, port);
  445. else
  446. scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
  447. scm_putc (' ', port);
  448. fdes = (SCM_FSTREAM (exp))->fdes;
  449. #ifdef HAVE_TTYNAME
  450. if (isatty (fdes))
  451. scm_puts (ttyname (fdes), port);
  452. else
  453. #endif /* HAVE_TTYNAME */
  454. scm_intprint (fdes, 10, port);
  455. }
  456. else
  457. {
  458. scm_puts (SCM_PTOBNAME (SCM_PTOBNUM (exp)), port);
  459. scm_putc (' ', port);
  460. scm_intprint (SCM_UNPACK (SCM_CDR (exp)), 16, port);
  461. }
  462. scm_putc ('>', port);
  463. return 1;
  464. }
  465. #ifdef GUILE_ISELECT
  466. /* thread-local block for input on fport's fdes. */
  467. static void
  468. fport_wait_for_input (SCM port)
  469. {
  470. int fdes = SCM_FSTREAM (port)->fdes;
  471. if (!fport_input_waiting (port))
  472. {
  473. int n;
  474. SELECT_TYPE readfds;
  475. int flags = fcntl (fdes, F_GETFL);
  476. if (flags == -1)
  477. scm_syserror ("scm_fdes_wait_for_input");
  478. if (!(flags & O_NONBLOCK))
  479. do
  480. {
  481. FD_ZERO (&readfds);
  482. FD_SET (fdes, &readfds);
  483. n = scm_internal_select (fdes + 1, &readfds, NULL, NULL, NULL);
  484. }
  485. while (n == -1 && errno == EINTR);
  486. }
  487. }
  488. #endif
  489. static void fport_flush (SCM port);
  490. /* fill a port's read-buffer with a single read. returns the first
  491. char or EOF if end of file. */
  492. static int
  493. fport_fill_input (SCM port)
  494. {
  495. long count;
  496. scm_t_port *pt = SCM_PTAB_ENTRY (port);
  497. scm_t_fport *fp = SCM_FSTREAM (port);
  498. #ifdef GUILE_ISELECT
  499. fport_wait_for_input (port);
  500. #endif
  501. SCM_SYSCALL (count = read (fp->fdes, pt->read_buf, pt->read_buf_size));
  502. if (count == -1)
  503. scm_syserror ("fport_fill_input");
  504. if (count == 0)
  505. return EOF;
  506. else
  507. {
  508. pt->read_pos = pt->read_buf;
  509. pt->read_end = pt->read_buf + count;
  510. return *pt->read_buf;
  511. }
  512. }
  513. static off_t
  514. fport_seek (SCM port, off_t offset, int whence)
  515. {
  516. scm_t_port *pt = SCM_PTAB_ENTRY (port);
  517. scm_t_fport *fp = SCM_FSTREAM (port);
  518. off_t rv;
  519. off_t result;
  520. if (pt->rw_active == SCM_PORT_WRITE)
  521. {
  522. if (offset != 0 || whence != SEEK_CUR)
  523. {
  524. fport_flush (port);
  525. result = rv = lseek (fp->fdes, offset, whence);
  526. }
  527. else
  528. {
  529. /* read current position without disturbing the buffer. */
  530. rv = lseek (fp->fdes, offset, whence);
  531. result = rv + (pt->write_pos - pt->write_buf);
  532. }
  533. }
  534. else if (pt->rw_active == SCM_PORT_READ)
  535. {
  536. if (offset != 0 || whence != SEEK_CUR)
  537. {
  538. /* could expand to avoid a second seek. */
  539. scm_end_input (port);
  540. result = rv = lseek (fp->fdes, offset, whence);
  541. }
  542. else
  543. {
  544. /* read current position without disturbing the buffer
  545. (particularly the unread-char buffer). */
  546. rv = lseek (fp->fdes, offset, whence);
  547. result = rv - (pt->read_end - pt->read_pos);
  548. if (pt->read_buf == pt->putback_buf)
  549. result -= pt->saved_read_end - pt->saved_read_pos;
  550. }
  551. }
  552. else /* SCM_PORT_NEITHER */
  553. {
  554. result = rv = lseek (fp->fdes, offset, whence);
  555. }
  556. if (rv == -1)
  557. scm_syserror ("fport_seek");
  558. return result;
  559. }
  560. static void
  561. fport_truncate (SCM port, off_t length)
  562. {
  563. scm_t_fport *fp = SCM_FSTREAM (port);
  564. if (ftruncate (fp->fdes, length) == -1)
  565. scm_syserror ("ftruncate");
  566. }
  567. /* helper for fport_write: try to write data, using multiple system
  568. calls if required. */
  569. #define FUNC_NAME "write_all"
  570. static void write_all (SCM port, const void *data, size_t remaining)
  571. {
  572. int fdes = SCM_FSTREAM (port)->fdes;
  573. while (remaining > 0)
  574. {
  575. size_t done;
  576. SCM_SYSCALL (done = write (fdes, data, remaining));
  577. if (done == -1)
  578. SCM_SYSERROR;
  579. remaining -= done;
  580. data = ((const char *) data) + done;
  581. }
  582. }
  583. #undef FUNC_NAME
  584. static void
  585. fport_write (SCM port, const void *data, size_t size)
  586. {
  587. /* this procedure tries to minimize the number of writes/flushes. */
  588. scm_t_port *pt = SCM_PTAB_ENTRY (port);
  589. if (pt->write_buf == &pt->shortbuf
  590. || (pt->write_pos == pt->write_buf && size >= pt->write_buf_size))
  591. {
  592. /* "unbuffered" port, or
  593. port with empty buffer and data won't fit in buffer. */
  594. write_all (port, data, size);
  595. return;
  596. }
  597. {
  598. off_t space = pt->write_end - pt->write_pos;
  599. if (size <= space)
  600. {
  601. /* data fits in buffer. */
  602. memcpy (pt->write_pos, data, size);
  603. pt->write_pos += size;
  604. if (pt->write_pos == pt->write_end)
  605. {
  606. fport_flush (port);
  607. /* we can skip the line-buffering check if nothing's buffered. */
  608. return;
  609. }
  610. }
  611. else
  612. {
  613. memcpy (pt->write_pos, data, space);
  614. pt->write_pos = pt->write_end;
  615. fport_flush (port);
  616. {
  617. const void *ptr = ((const char *) data) + space;
  618. size_t remaining = size - space;
  619. if (size >= pt->write_buf_size)
  620. {
  621. write_all (port, ptr, remaining);
  622. return;
  623. }
  624. else
  625. {
  626. memcpy (pt->write_pos, ptr, remaining);
  627. pt->write_pos += remaining;
  628. }
  629. }
  630. }
  631. /* handle line buffering. */
  632. if ((SCM_CELL_WORD_0 (port) & SCM_BUFLINE) && memchr (data, '\n', size))
  633. fport_flush (port);
  634. }
  635. }
  636. /* becomes 1 when process is exiting: normal exception handling won't
  637. work by this time. */
  638. extern int scm_i_terminating;
  639. static void
  640. fport_flush (SCM port)
  641. {
  642. scm_t_port *pt = SCM_PTAB_ENTRY (port);
  643. scm_t_fport *fp = SCM_FSTREAM (port);
  644. unsigned char *ptr = pt->write_buf;
  645. long init_size = pt->write_pos - pt->write_buf;
  646. long remaining = init_size;
  647. while (remaining > 0)
  648. {
  649. long count;
  650. SCM_SYSCALL (count = write (fp->fdes, ptr, remaining));
  651. if (count < 0)
  652. {
  653. /* error. assume nothing was written this call, but
  654. fix up the buffer for any previous successful writes. */
  655. long done = init_size - remaining;
  656. if (done > 0)
  657. {
  658. int i;
  659. for (i = 0; i < remaining; i++)
  660. {
  661. *(pt->write_buf + i) = *(pt->write_buf + done + i);
  662. }
  663. pt->write_pos = pt->write_buf + remaining;
  664. }
  665. if (scm_i_terminating)
  666. {
  667. const char *msg = "Error: could not flush file-descriptor ";
  668. char buf[11];
  669. write (2, msg, strlen (msg));
  670. sprintf (buf, "%d\n", fp->fdes);
  671. write (2, buf, strlen (buf));
  672. count = remaining;
  673. }
  674. else if (scm_gc_running_p)
  675. {
  676. /* silently ignore the error. scm_error would abort if we
  677. called it now. */
  678. count = remaining;
  679. }
  680. else
  681. scm_syserror ("fport_flush");
  682. }
  683. ptr += count;
  684. remaining -= count;
  685. }
  686. pt->write_pos = pt->write_buf;
  687. pt->rw_active = SCM_PORT_NEITHER;
  688. }
  689. /* clear the read buffer and adjust the file position for unread bytes. */
  690. static void
  691. fport_end_input (SCM port, int offset)
  692. {
  693. scm_t_fport *fp = SCM_FSTREAM (port);
  694. scm_t_port *pt = SCM_PTAB_ENTRY (port);
  695. offset += pt->read_end - pt->read_pos;
  696. if (offset > 0)
  697. {
  698. pt->read_pos = pt->read_end;
  699. /* will throw error if unread-char used at beginning of file
  700. then attempting to write. seems correct. */
  701. if (lseek (fp->fdes, -offset, SEEK_CUR) == -1)
  702. scm_syserror ("fport_end_input");
  703. }
  704. pt->rw_active = SCM_PORT_NEITHER;
  705. }
  706. static int
  707. fport_close (SCM port)
  708. {
  709. scm_t_fport *fp = SCM_FSTREAM (port);
  710. scm_t_port *pt = SCM_PTAB_ENTRY (port);
  711. int rv;
  712. fport_flush (port);
  713. SCM_SYSCALL (rv = close (fp->fdes));
  714. if (rv == -1 && errno != EBADF)
  715. {
  716. if (scm_gc_running_p)
  717. /* silently ignore the error. scm_error would abort if we
  718. called it now. */
  719. ;
  720. else
  721. scm_syserror ("fport_close");
  722. }
  723. if (pt->read_buf == pt->putback_buf)
  724. pt->read_buf = pt->saved_read_buf;
  725. if (pt->read_buf != &pt->shortbuf)
  726. scm_must_free (pt->read_buf);
  727. if (pt->write_buf != &pt->shortbuf)
  728. scm_must_free (pt->write_buf);
  729. scm_must_free ((char *) fp);
  730. return rv;
  731. }
  732. static size_t
  733. fport_free (SCM port)
  734. {
  735. fport_close (port);
  736. return 0;
  737. }
  738. static scm_t_bits
  739. scm_make_fptob ()
  740. {
  741. scm_t_bits tc = scm_make_port_type ("file", fport_fill_input, fport_write);
  742. scm_set_port_free (tc, fport_free);
  743. scm_set_port_print (tc, fport_print);
  744. scm_set_port_flush (tc, fport_flush);
  745. scm_set_port_end_input (tc, fport_end_input);
  746. scm_set_port_close (tc, fport_close);
  747. scm_set_port_seek (tc, fport_seek);
  748. scm_set_port_truncate (tc, fport_truncate);
  749. scm_set_port_input_waiting (tc, fport_input_waiting);
  750. return tc;
  751. }
  752. void
  753. scm_init_fports ()
  754. {
  755. scm_tc16_fport = scm_make_fptob ();
  756. scm_c_define ("_IOFBF", SCM_MAKINUM (_IOFBF));
  757. scm_c_define ("_IOLBF", SCM_MAKINUM (_IOLBF));
  758. scm_c_define ("_IONBF", SCM_MAKINUM (_IONBF));
  759. #include "libguile/fports.x"
  760. }
  761. /*
  762. Local Variables:
  763. c-file-style: "gnu"
  764. End:
  765. */