ioext.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. /* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2006 Free Software Foundation, Inc.
  2. *
  3. * This library is free software; you can redistribute it and/or
  4. * modify it under the terms of the GNU Lesser General Public License
  5. * as published by the Free Software Foundation; either version 3 of
  6. * the License, or (at your option) any later version.
  7. *
  8. * This library is distributed in the hope that it will be useful, but
  9. * WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. * Lesser General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Lesser General Public
  14. * License along with this library; if not, write to the Free Software
  15. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  16. * 02110-1301 USA
  17. */
  18. #ifdef HAVE_CONFIG_H
  19. # include <config.h>
  20. #endif
  21. #include <stdio.h>
  22. #include <errno.h>
  23. #include "libguile/_scm.h"
  24. #include "libguile/dynwind.h"
  25. #include "libguile/feature.h"
  26. #include "libguile/fports.h"
  27. #include "libguile/hashtab.h"
  28. #include "libguile/ioext.h"
  29. #include "libguile/ports.h"
  30. #include "libguile/strings.h"
  31. #include "libguile/validate.h"
  32. #include <fcntl.h>
  33. #ifdef HAVE_IO_H
  34. #include <io.h>
  35. #endif
  36. #ifdef HAVE_UNISTD_H
  37. #include <unistd.h>
  38. #endif
  39. SCM_DEFINE (scm_ftell, "ftell", 1, 0, 0,
  40. (SCM fd_port),
  41. "Return an integer representing the current position of\n"
  42. "@var{fd/port}, measured from the beginning. Equivalent to:\n"
  43. "\n"
  44. "@lisp\n"
  45. "(seek port 0 SEEK_CUR)\n"
  46. "@end lisp")
  47. #define FUNC_NAME s_scm_ftell
  48. {
  49. return scm_seek (fd_port, SCM_INUM0, scm_from_int (SEEK_CUR));
  50. }
  51. #undef FUNC_NAME
  52. SCM_DEFINE (scm_redirect_port, "redirect-port", 2, 0, 0,
  53. (SCM old, SCM new),
  54. "This procedure takes two ports and duplicates the underlying file\n"
  55. "descriptor from @var{old-port} into @var{new-port}. The\n"
  56. "current file descriptor in @var{new-port} will be closed.\n"
  57. "After the redirection the two ports will share a file position\n"
  58. "and file status flags.\n\n"
  59. "The return value is unspecified.\n\n"
  60. "Unexpected behaviour can result if both ports are subsequently used\n"
  61. "and the original and/or duplicate ports are buffered.\n\n"
  62. "This procedure does not have any side effects on other ports or\n"
  63. "revealed counts.")
  64. #define FUNC_NAME s_scm_redirect_port
  65. {
  66. int ans, oldfd, newfd;
  67. scm_t_fport *fp;
  68. old = SCM_COERCE_OUTPORT (old);
  69. new = SCM_COERCE_OUTPORT (new);
  70. SCM_VALIDATE_OPFPORT (1, old);
  71. SCM_VALIDATE_OPFPORT (2, new);
  72. oldfd = SCM_FPORT_FDES (old);
  73. fp = SCM_FSTREAM (new);
  74. newfd = fp->fdes;
  75. if (oldfd != newfd)
  76. {
  77. scm_t_port *pt = SCM_PTAB_ENTRY (new);
  78. scm_t_port *old_pt = SCM_PTAB_ENTRY (old);
  79. scm_t_ptob_descriptor *ptob = &scm_ptobs[SCM_PTOBNUM (new)];
  80. /* must flush to old fdes. */
  81. if (pt->rw_active == SCM_PORT_WRITE)
  82. ptob->flush (new);
  83. else if (pt->rw_active == SCM_PORT_READ)
  84. scm_end_input (new);
  85. ans = dup2 (oldfd, newfd);
  86. if (ans == -1)
  87. SCM_SYSERROR;
  88. pt->rw_random = old_pt->rw_random;
  89. /* continue using existing buffers, even if inappropriate. */
  90. }
  91. return SCM_UNSPECIFIED;
  92. }
  93. #undef FUNC_NAME
  94. SCM_DEFINE (scm_dup_to_fdes, "dup->fdes", 1, 1, 0,
  95. (SCM fd_or_port, SCM fd),
  96. "Return a new integer file descriptor referring to the open file\n"
  97. "designated by @var{fd_or_port}, which must be either an open\n"
  98. "file port or a file descriptor.")
  99. #define FUNC_NAME s_scm_dup_to_fdes
  100. {
  101. int oldfd, newfd, rv;
  102. fd_or_port = SCM_COERCE_OUTPORT (fd_or_port);
  103. if (scm_is_integer (fd_or_port))
  104. oldfd = scm_to_int (fd_or_port);
  105. else
  106. {
  107. SCM_VALIDATE_OPFPORT (1, fd_or_port);
  108. oldfd = SCM_FPORT_FDES (fd_or_port);
  109. }
  110. if (SCM_UNBNDP (fd))
  111. {
  112. newfd = dup (oldfd);
  113. if (newfd == -1)
  114. SCM_SYSERROR;
  115. fd = scm_from_int (newfd);
  116. }
  117. else
  118. {
  119. newfd = scm_to_int (fd);
  120. if (oldfd != newfd)
  121. {
  122. scm_evict_ports (newfd); /* see scsh manual. */
  123. rv = dup2 (oldfd, newfd);
  124. if (rv == -1)
  125. SCM_SYSERROR;
  126. }
  127. }
  128. return fd;
  129. }
  130. #undef FUNC_NAME
  131. SCM_DEFINE (scm_dup2, "dup2", 2, 0, 0,
  132. (SCM oldfd, SCM newfd),
  133. "A simple wrapper for the @code{dup2} system call.\n"
  134. "Copies the file descriptor @var{oldfd} to descriptor\n"
  135. "number @var{newfd}, replacing the previous meaning\n"
  136. "of @var{newfd}. Both @var{oldfd} and @var{newfd} must\n"
  137. "be integers.\n"
  138. "Unlike for dup->fdes or primitive-move->fdes, no attempt\n"
  139. "is made to move away ports which are using @var{newfd}.\n"
  140. "The return value is unspecified.")
  141. #define FUNC_NAME s_scm_dup2
  142. {
  143. int c_oldfd;
  144. int c_newfd;
  145. int rv;
  146. c_oldfd = scm_to_int (oldfd);
  147. c_newfd = scm_to_int (newfd);
  148. rv = dup2 (c_oldfd, c_newfd);
  149. if (rv == -1)
  150. SCM_SYSERROR;
  151. return SCM_UNSPECIFIED;
  152. }
  153. #undef FUNC_NAME
  154. SCM_DEFINE (scm_fileno, "fileno", 1, 0, 0,
  155. (SCM port),
  156. "Return the integer file descriptor underlying @var{port}. Does\n"
  157. "not change its revealed count.")
  158. #define FUNC_NAME s_scm_fileno
  159. {
  160. port = SCM_COERCE_OUTPORT (port);
  161. SCM_VALIDATE_OPFPORT (1, port);
  162. return scm_from_int (SCM_FPORT_FDES (port));
  163. }
  164. #undef FUNC_NAME
  165. /* GJB:FIXME:: why does this not throw
  166. an error if the arg is not a port?
  167. This proc as is would be better names isattyport?
  168. if it is not going to assume that the arg is a port
  169. [cmm] I don't see any problem with the above. why should a type
  170. predicate assume _anything_ about its argument?
  171. */
  172. SCM_DEFINE (scm_isatty_p, "isatty?", 1, 0, 0,
  173. (SCM port),
  174. "Return @code{#t} if @var{port} is using a serial non--file\n"
  175. "device, otherwise @code{#f}.")
  176. #define FUNC_NAME s_scm_isatty_p
  177. {
  178. int rv;
  179. port = SCM_COERCE_OUTPORT (port);
  180. if (!SCM_OPFPORTP (port))
  181. return SCM_BOOL_F;
  182. rv = isatty (SCM_FPORT_FDES (port));
  183. return scm_from_bool(rv);
  184. }
  185. #undef FUNC_NAME
  186. SCM_DEFINE (scm_fdopen, "fdopen", 2, 0, 0,
  187. (SCM fdes, SCM modes),
  188. "Return a new port based on the file descriptor @var{fdes}.\n"
  189. "Modes are given by the string @var{modes}. The revealed count\n"
  190. "of the port is initialized to zero. The modes string is the\n"
  191. "same as that accepted by @ref{File Ports, open-file}.")
  192. #define FUNC_NAME s_scm_fdopen
  193. {
  194. return scm_i_fdes_to_port (scm_to_int (fdes),
  195. scm_i_mode_bits (modes), SCM_BOOL_F);
  196. }
  197. #undef FUNC_NAME
  198. /* Move a port's underlying file descriptor to a given value.
  199. * Returns #f if fdes is already the given value.
  200. * #t if fdes moved.
  201. * MOVE->FDES is implemented in Scheme and calls this primitive.
  202. */
  203. SCM_DEFINE (scm_primitive_move_to_fdes, "primitive-move->fdes", 2, 0, 0,
  204. (SCM port, SCM fd),
  205. "Moves the underlying file descriptor for @var{port} to the integer\n"
  206. "value @var{fdes} without changing the revealed count of @var{port}.\n"
  207. "Any other ports already using this descriptor will be automatically\n"
  208. "shifted to new descriptors and their revealed counts reset to zero.\n"
  209. "The return value is @code{#f} if the file descriptor already had the\n"
  210. "required value or @code{#t} if it was moved.")
  211. #define FUNC_NAME s_scm_primitive_move_to_fdes
  212. {
  213. scm_t_fport *stream;
  214. int old_fd;
  215. int new_fd;
  216. int rv;
  217. port = SCM_COERCE_OUTPORT (port);
  218. SCM_VALIDATE_OPFPORT (1, port);
  219. stream = SCM_FSTREAM (port);
  220. old_fd = stream->fdes;
  221. new_fd = scm_to_int (fd);
  222. if (old_fd == new_fd)
  223. {
  224. return SCM_BOOL_F;
  225. }
  226. scm_evict_ports (new_fd);
  227. rv = dup2 (old_fd, new_fd);
  228. if (rv == -1)
  229. SCM_SYSERROR;
  230. stream->fdes = new_fd;
  231. SCM_SYSCALL (close (old_fd));
  232. return SCM_BOOL_T;
  233. }
  234. #undef FUNC_NAME
  235. static SCM
  236. get_matching_port (void *closure, SCM port, SCM val, SCM result)
  237. {
  238. int fd = * (int *) closure;
  239. scm_t_port *entry = SCM_PTAB_ENTRY (port);
  240. if (SCM_OPFPORTP (port)
  241. && ((scm_t_fport *) entry->stream)->fdes == fd)
  242. result = scm_cons (port, result);
  243. return result;
  244. }
  245. /* Return a list of ports using a given file descriptor. */
  246. SCM_DEFINE (scm_fdes_to_ports, "fdes->ports", 1, 0, 0,
  247. (SCM fd),
  248. "Return a list of existing ports which have @var{fdes} as an\n"
  249. "underlying file descriptor, without changing their revealed\n"
  250. "counts.")
  251. #define FUNC_NAME s_scm_fdes_to_ports
  252. {
  253. SCM result = SCM_EOL;
  254. int int_fd = scm_to_int (fd);
  255. scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
  256. result = scm_internal_hash_fold (get_matching_port,
  257. (void*) &int_fd, result,
  258. scm_i_port_weak_hash);
  259. scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
  260. return result;
  261. }
  262. #undef FUNC_NAME
  263. void
  264. scm_init_ioext ()
  265. {
  266. scm_add_feature ("i/o-extensions");
  267. #include "libguile/ioext.x"
  268. }
  269. /*
  270. Local Variables:
  271. c-file-style: "gnu"
  272. End:
  273. */