ioext.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. /* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2002 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., 59 Temple Place, Suite 330,
  16. * Boston, MA 02111-1307 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 "libguile/_scm.h"
  43. #include "libguile/ports.h"
  44. #include "libguile/read.h"
  45. #include "libguile/fports.h"
  46. #include "libguile/unif.h"
  47. #include "libguile/chars.h"
  48. #include "libguile/feature.h"
  49. #include "libguile/root.h"
  50. #include "libguile/strings.h"
  51. #include "libguile/validate.h"
  52. #include "libguile/ioext.h"
  53. #include <fcntl.h>
  54. #ifdef HAVE_STRING_H
  55. #include <string.h>
  56. #endif
  57. #ifdef HAVE_UNISTD_H
  58. #include <unistd.h>
  59. #endif
  60. SCM_DEFINE (scm_read_delimited_x, "%read-delimited!", 3, 3, 0,
  61. (SCM delims, SCM buf, SCM gobble, SCM port, SCM start, SCM end),
  62. "Read characters from @var{port} into @var{buf} until one of the\n"
  63. "characters in the @var{delims} string is encountered. If @var{gobble?}\n"
  64. "is true, store the delimiter character in @var{buf} as well; otherwise,\n"
  65. "discard it. If @var{port} is not specified, use the value of\n"
  66. "@code{(current-input-port)}. If @var{start} or @var{end} are specified,\n"
  67. "store data only into the substring of @var{buf} bounded by @var{start}\n"
  68. "and @var{end} (which default to the beginning and end of the buffer,\n"
  69. "respectively).\n\n"
  70. "Return a pair consisting of the delimiter that terminated the string and\n"
  71. "the number of characters read. If reading stopped at the end of file,\n"
  72. "the delimiter returned is the @var{eof-object}; if the buffer was filled\n"
  73. "without encountering a delimiter, this value is @var{#f}.")
  74. #define FUNC_NAME s_scm_read_delimited_x
  75. {
  76. long j;
  77. char *cbuf;
  78. long cstart;
  79. long cend, tend;
  80. int c;
  81. char *cdelims;
  82. int num_delims;
  83. SCM_VALIDATE_ROSTRING_COPY (1,delims,cdelims);
  84. num_delims = SCM_ROLENGTH (delims);
  85. SCM_VALIDATE_STRING_COPY (2,buf,cbuf);
  86. cend = SCM_LENGTH (buf);
  87. if (SCM_UNBNDP (port))
  88. port = scm_cur_inp;
  89. else
  90. SCM_VALIDATE_OPINPORT (4,port);
  91. SCM_VALIDATE_INUM_DEF_COPY (5,start,0,cstart);
  92. SCM_ASSERT_RANGE(5, start, cstart >= 0 && cstart < cend);
  93. SCM_VALIDATE_INUM_DEF_COPY (6,end,cend,tend);
  94. SCM_ASSERT_RANGE(6, end, tend > cstart && tend <= cend);
  95. cend = tend;
  96. for (j = cstart; j < cend; j++)
  97. {
  98. int k;
  99. c = scm_getc (port);
  100. for (k = 0; k < num_delims; k++)
  101. {
  102. if (cdelims[k] == c)
  103. {
  104. if (SCM_FALSEP (gobble))
  105. scm_ungetc (c, port);
  106. return scm_cons (SCM_MAKE_CHAR (c),
  107. scm_long2num (j - cstart));
  108. }
  109. }
  110. if (c == EOF)
  111. return scm_cons (SCM_EOF_VAL,
  112. scm_long2num (j - cstart));
  113. cbuf[j] = c;
  114. }
  115. return scm_cons (SCM_BOOL_F, scm_long2num (j - cstart));
  116. }
  117. #undef FUNC_NAME
  118. static unsigned char *
  119. scm_do_read_line (SCM port, int *len_p)
  120. {
  121. scm_port *pt = SCM_PTAB_ENTRY (port);
  122. unsigned char *end;
  123. /* I thought reading lines was simple. Mercy me. */
  124. /* The common case: the buffer contains a complete line.
  125. This needs to be fast. */
  126. if ((end = memchr (pt->read_pos, '\n', (pt->read_end - pt->read_pos)))
  127. != 0)
  128. {
  129. int buf_len = (end + 1) - pt->read_pos;
  130. /* Allocate a buffer of the perfect size. */
  131. unsigned char *buf = scm_must_malloc (buf_len + 1, "%read-line");
  132. memcpy (buf, pt->read_pos, buf_len);
  133. pt->read_pos += buf_len;
  134. buf[buf_len] = '\0';
  135. *len_p = buf_len;
  136. return buf;
  137. }
  138. /* The buffer contains no newlines. */
  139. {
  140. /* When live, len is always the number of characters in the
  141. current buffer that are part of the current line. */
  142. int len = (pt->read_end - pt->read_pos);
  143. int buf_size = (len < 50) ? 60 : len * 2;
  144. /* Invariant: buf always has buf_size + 1 characters allocated;
  145. the `+ 1' is for the final '\0'. */
  146. unsigned char *buf = scm_must_malloc (buf_size + 1, "%read-line");
  147. int buf_len = 0;
  148. for (;;)
  149. {
  150. if (buf_len + len > buf_size)
  151. {
  152. int new_size = (buf_len + len) * 2;
  153. buf = scm_must_realloc (buf, buf_size + 1, new_size + 1,
  154. "%read-line");
  155. buf_size = new_size;
  156. }
  157. /* Copy what we've got out of the port, into our buffer. */
  158. memcpy (buf + buf_len, pt->read_pos, len);
  159. buf_len += len;
  160. pt->read_pos += len;
  161. /* If we had seen a newline, we're done now. */
  162. if (end)
  163. break;
  164. /* Get more characters. */
  165. if (scm_fill_input (port) == EOF)
  166. {
  167. /* If we're missing a final newline in the file, return
  168. what we did get, sans newline. */
  169. if (buf_len > 0)
  170. break;
  171. free (buf);
  172. return 0;
  173. }
  174. /* Search the buffer for newlines. */
  175. if ((end = memchr (pt->read_pos, '\n',
  176. (len = (pt->read_end - pt->read_pos))))
  177. != 0)
  178. len = (end - pt->read_pos) + 1;
  179. }
  180. /* I wonder how expensive this realloc is. */
  181. buf = scm_must_realloc (buf, buf_size + 1, buf_len + 1, "%read-line");
  182. buf[buf_len] = '\0';
  183. *len_p = buf_len;
  184. return buf;
  185. }
  186. }
  187. /*
  188. * %read-line
  189. * truncates any terminating newline from its input, and returns
  190. * a cons of the string read and its terminating character. Doing
  191. * so makes it easy to implement the hairy `read-line' options
  192. * efficiently in Scheme.
  193. */
  194. SCM_DEFINE (scm_read_line, "%read-line", 0, 1, 0,
  195. (SCM port),
  196. "Read a newline-terminated line from @var{port}, allocating storage as\n"
  197. "necessary. The newline terminator (if any) is removed from the string,\n"
  198. "and a pair consisting of the line and its delimiter is returned. The\n"
  199. "delimiter may be either a newline or the @var{eof-object}; if\n"
  200. "@code{%read-line} is called at the end of file, it returns the pair\n"
  201. "@code{(#<eof> . #<eof>)}.")
  202. #define FUNC_NAME s_scm_read_line
  203. {
  204. scm_port *pt;
  205. char *s;
  206. int slen;
  207. SCM line, term;
  208. if (SCM_UNBNDP (port))
  209. port = scm_cur_inp;
  210. SCM_VALIDATE_OPINPORT (1,port);
  211. pt = SCM_PTAB_ENTRY (port);
  212. if (pt->rw_active == SCM_PORT_WRITE)
  213. scm_ptobs[SCM_PTOBNUM (port)].flush (port);
  214. s = (char *) scm_do_read_line (port, &slen);
  215. if (s == NULL)
  216. term = line = SCM_EOF_VAL;
  217. else
  218. {
  219. if (s[slen-1] == '\n')
  220. {
  221. term = SCM_MAKE_CHAR ('\n');
  222. s[slen-1] = '\0';
  223. line = scm_take_str (s, slen-1);
  224. scm_done_malloc (-1);
  225. SCM_INCLINE (port);
  226. }
  227. else
  228. {
  229. /* Fix: we should check for eof on the port before assuming this. */
  230. term = SCM_EOF_VAL;
  231. line = scm_take_str (s, slen);
  232. SCM_COL (port) += slen;
  233. }
  234. }
  235. if (pt->rw_random)
  236. pt->rw_active = SCM_PORT_READ;
  237. return scm_cons (line, term);
  238. }
  239. #undef FUNC_NAME
  240. SCM_DEFINE (scm_write_line, "write-line", 1, 1, 0,
  241. (SCM obj, SCM port),
  242. "Display @var{obj} and a newline character to @var{port}. If @var{port}\n"
  243. "is not specified, @code{(current-output-port)} is used. This function\n"
  244. "is equivalent to:\n\n"
  245. "@smalllisp\n"
  246. "(display obj [port])\n"
  247. "(newline [port])\n"
  248. "@end smalllisp")
  249. #define FUNC_NAME s_scm_write_line
  250. {
  251. scm_display (obj, port);
  252. return scm_newline (port);
  253. }
  254. #undef FUNC_NAME
  255. SCM_DEFINE (scm_ftell, "ftell", 1, 0, 0,
  256. (SCM object),
  257. "Returns an integer representing the current position of @var{fd/port},\n"
  258. "measured from the beginning. Equivalent to:\n"
  259. "@smalllisp\n"
  260. "(seek port 0 SEEK_CUR)\n"
  261. "@end smalllisp")
  262. #define FUNC_NAME s_scm_ftell
  263. {
  264. return scm_seek (object, SCM_INUM0, SCM_MAKINUM (SEEK_CUR));
  265. }
  266. #undef FUNC_NAME
  267. #if (SCM_DEBUG_DEPRECATED == 0)
  268. SCM_DEFINE (scm_fseek, "fseek", 3, 0, 0,
  269. (SCM object, SCM offset, SCM whence),
  270. "Obsolete. Almost the same as seek, above, but the return value is\n"
  271. "unspecified.")
  272. #define FUNC_NAME s_scm_fseek
  273. {
  274. scm_seek (object, offset, whence);
  275. return SCM_UNSPECIFIED;
  276. }
  277. #undef FUNC_NAME
  278. #endif /* SCM_DEBUG_DEPRECATED == 0 */
  279. SCM_DEFINE (scm_redirect_port, "redirect-port", 2, 0, 0,
  280. (SCM old, SCM new),
  281. "This procedure takes two ports and duplicates the underlying file\n"
  282. "descriptor from @var{old-port} into @var{new-port}. The\n"
  283. "current file descriptor in @var{new-port} will be closed.\n"
  284. "After the redirection the two ports will share a file position\n"
  285. "and file status flags.\n\n"
  286. "The return value is unspecified.\n\n"
  287. "Unexpected behaviour can result if both ports are subsequently used\n"
  288. "and the original and/or duplicate ports are buffered.\n\n"
  289. "This procedure does not have any side effects on other ports or\n"
  290. "revealed counts.")
  291. #define FUNC_NAME s_scm_redirect_port
  292. {
  293. int ans, oldfd, newfd;
  294. struct scm_fport *fp;
  295. old = SCM_COERCE_OUTPORT (old);
  296. new = SCM_COERCE_OUTPORT (new);
  297. SCM_VALIDATE_OPFPORT (1,old);
  298. SCM_VALIDATE_OPFPORT (2,new);
  299. oldfd = SCM_FPORT_FDES (old);
  300. fp = SCM_FSTREAM (new);
  301. newfd = fp->fdes;
  302. if (oldfd != newfd)
  303. {
  304. scm_port *pt = SCM_PTAB_ENTRY (new);
  305. scm_port *old_pt = SCM_PTAB_ENTRY (old);
  306. scm_ptob_descriptor *ptob = &scm_ptobs[SCM_PTOBNUM (new)];
  307. /* must flush to old fdes. */
  308. if (pt->rw_active == SCM_PORT_WRITE)
  309. ptob->flush (new);
  310. else if (pt->rw_active == SCM_PORT_READ)
  311. scm_end_input (new);
  312. ans = dup2 (oldfd, newfd);
  313. if (ans == -1)
  314. SCM_SYSERROR;
  315. pt->rw_random = old_pt->rw_random;
  316. /* continue using existing buffers, even if inappropriate. */
  317. }
  318. return SCM_UNSPECIFIED;
  319. }
  320. #undef FUNC_NAME
  321. SCM_DEFINE (scm_dup_to_fdes, "dup->fdes", 1, 1, 0,
  322. (SCM fd_or_port, SCM fd),
  323. "Returns an integer file descriptor.")
  324. #define FUNC_NAME s_scm_dup_to_fdes
  325. {
  326. int oldfd, newfd, rv;
  327. fd_or_port = SCM_COERCE_OUTPORT (fd_or_port);
  328. if (SCM_INUMP (fd_or_port))
  329. oldfd = SCM_INUM (fd_or_port);
  330. else
  331. {
  332. SCM_VALIDATE_OPFPORT (1,fd_or_port);
  333. oldfd = SCM_FPORT_FDES (fd_or_port);
  334. }
  335. if (SCM_UNBNDP (fd))
  336. {
  337. newfd = dup (oldfd);
  338. if (newfd == -1)
  339. SCM_SYSERROR;
  340. fd = SCM_MAKINUM (newfd);
  341. }
  342. else
  343. {
  344. SCM_VALIDATE_INUM_COPY (2, fd, newfd);
  345. if (oldfd != newfd)
  346. {
  347. scm_evict_ports (newfd); /* see scsh manual. */
  348. rv = dup2 (oldfd, newfd);
  349. if (rv == -1)
  350. SCM_SYSERROR;
  351. }
  352. }
  353. return fd;
  354. }
  355. #undef FUNC_NAME
  356. SCM_DEFINE (scm_fileno, "fileno", 1, 0, 0,
  357. (SCM port),
  358. "Returns the integer file descriptor underlying @var{port}.\n"
  359. "Does not change its revealed count.")
  360. #define FUNC_NAME s_scm_fileno
  361. {
  362. port = SCM_COERCE_OUTPORT (port);
  363. SCM_VALIDATE_OPFPORT (1,port);
  364. return SCM_MAKINUM (SCM_FPORT_FDES (port));
  365. }
  366. #undef FUNC_NAME
  367. /* GJB:FIXME:: why does this not throw
  368. an error if the arg is not a port?
  369. This proc as is would be better names isattyport?
  370. if it is not going to assume that the arg is a port */
  371. SCM_DEFINE (scm_isatty_p, "isatty?", 1, 0, 0,
  372. (SCM port),
  373. "Returns @code{#t} if @var{port} is using a serial\n"
  374. "non-file device, otherwise @code{#f}.")
  375. #define FUNC_NAME s_scm_isatty_p
  376. {
  377. int rv;
  378. port = SCM_COERCE_OUTPORT (port);
  379. if (!SCM_OPFPORTP (port))
  380. return SCM_BOOL_F;
  381. rv = isatty (SCM_FPORT_FDES (port));
  382. return SCM_BOOL(rv);
  383. }
  384. #undef FUNC_NAME
  385. SCM_DEFINE (scm_fdopen, "fdopen", 2, 0, 0,
  386. (SCM fdes, SCM modes),
  387. "Returns a new port based on the file descriptor @var{fdes}.\n"
  388. "Modes are given by the string @var{modes}. The revealed count of the port\n"
  389. "is initialized to zero. The modes string is the same as that accepted\n"
  390. "by @ref{File Ports, open-file}.")
  391. #define FUNC_NAME s_scm_fdopen
  392. {
  393. SCM_VALIDATE_INUM (1,fdes);
  394. SCM_VALIDATE_ROSTRING (2,modes);
  395. SCM_COERCE_SUBSTR (modes);
  396. return scm_fdes_to_port (SCM_INUM (fdes), SCM_ROCHARS (modes), SCM_BOOL_F);
  397. }
  398. #undef FUNC_NAME
  399. /* Move a port's underlying file descriptor to a given value.
  400. * Returns #f if fdes is already the given value.
  401. * #t if fdes moved.
  402. * MOVE->FDES is implemented in Scheme and calls this primitive.
  403. */
  404. SCM_DEFINE (scm_primitive_move_to_fdes, "primitive-move->fdes", 2, 0, 0,
  405. (SCM port, SCM fd),
  406. "Moves the underlying file descriptor for @var{port} to the integer\n"
  407. "value @var{fdes} without changing the revealed count of @var{port}.\n"
  408. "Any other ports already using this descriptor will be automatically\n"
  409. "shifted to new descriptors and their revealed counts reset to zero.\n"
  410. "The return value is @code{#f} if the file descriptor already had the\n"
  411. "required value or @code{#t} if it was moved.")
  412. #define FUNC_NAME s_scm_primitive_move_to_fdes
  413. {
  414. struct scm_fport *stream;
  415. int old_fd;
  416. int new_fd;
  417. int rv;
  418. port = SCM_COERCE_OUTPORT (port);
  419. SCM_VALIDATE_OPFPORT (1,port);
  420. SCM_VALIDATE_INUM (2,fd);
  421. stream = SCM_FSTREAM (port);
  422. old_fd = stream->fdes;
  423. new_fd = SCM_INUM (fd);
  424. if (old_fd == new_fd)
  425. {
  426. return SCM_BOOL_F;
  427. }
  428. scm_evict_ports (new_fd);
  429. rv = dup2 (old_fd, new_fd);
  430. if (rv == -1)
  431. SCM_SYSERROR;
  432. stream->fdes = new_fd;
  433. SCM_SYSCALL (close (old_fd));
  434. return SCM_BOOL_T;
  435. }
  436. #undef FUNC_NAME
  437. /* Return a list of ports using a given file descriptor. */
  438. SCM_DEFINE (scm_fdes_to_ports, "fdes->ports", 1, 0, 0,
  439. (SCM fd),
  440. "Returns a list of existing ports which have @var{fdes} as an\n"
  441. "underlying file descriptor, without changing their revealed counts.")
  442. #define FUNC_NAME s_scm_fdes_to_ports
  443. {
  444. SCM result = SCM_EOL;
  445. int int_fd;
  446. int i;
  447. SCM_VALIDATE_INUM_COPY (1,fd,int_fd);
  448. for (i = 0; i < scm_port_table_size; i++)
  449. {
  450. if (SCM_OPFPORTP (scm_port_table[i]->port)
  451. && ((struct scm_fport *) scm_port_table[i]->stream)->fdes == int_fd)
  452. result = scm_cons (scm_port_table[i]->port, result);
  453. }
  454. return result;
  455. }
  456. #undef FUNC_NAME
  457. void
  458. scm_init_ioext ()
  459. {
  460. scm_add_feature ("i/o-extensions");
  461. #include "libguile/ioext.x"
  462. }
  463. /*
  464. Local Variables:
  465. c-file-style: "gnu"
  466. End:
  467. */