ioext.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001 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 <errno.h>
  43. #include "libguile/_scm.h"
  44. #include "libguile/ioext.h"
  45. #include "libguile/fports.h"
  46. #include "libguile/feature.h"
  47. #include "libguile/ports.h"
  48. #include "libguile/strings.h"
  49. #include "libguile/validate.h"
  50. #include <fcntl.h>
  51. #ifdef HAVE_UNISTD_H
  52. #include <unistd.h>
  53. #endif
  54. SCM_DEFINE (scm_ftell, "ftell", 1, 0, 0,
  55. (SCM fd_port),
  56. "Return an integer representing the current position of\n"
  57. "@var{fd/port}, measured from the beginning. Equivalent to:\n"
  58. "\n"
  59. "@lisp\n"
  60. "(seek port 0 SEEK_CUR)\n"
  61. "@end lisp")
  62. #define FUNC_NAME s_scm_ftell
  63. {
  64. return scm_seek (fd_port, SCM_INUM0, SCM_MAKINUM (SEEK_CUR));
  65. }
  66. #undef FUNC_NAME
  67. SCM_DEFINE (scm_redirect_port, "redirect-port", 2, 0, 0,
  68. (SCM old, SCM new),
  69. "This procedure takes two ports and duplicates the underlying file\n"
  70. "descriptor from @var{old-port} into @var{new-port}. The\n"
  71. "current file descriptor in @var{new-port} will be closed.\n"
  72. "After the redirection the two ports will share a file position\n"
  73. "and file status flags.\n\n"
  74. "The return value is unspecified.\n\n"
  75. "Unexpected behaviour can result if both ports are subsequently used\n"
  76. "and the original and/or duplicate ports are buffered.\n\n"
  77. "This procedure does not have any side effects on other ports or\n"
  78. "revealed counts.")
  79. #define FUNC_NAME s_scm_redirect_port
  80. {
  81. int ans, oldfd, newfd;
  82. scm_t_fport *fp;
  83. old = SCM_COERCE_OUTPORT (old);
  84. new = SCM_COERCE_OUTPORT (new);
  85. SCM_VALIDATE_OPFPORT (1,old);
  86. SCM_VALIDATE_OPFPORT (2,new);
  87. oldfd = SCM_FPORT_FDES (old);
  88. fp = SCM_FSTREAM (new);
  89. newfd = fp->fdes;
  90. if (oldfd != newfd)
  91. {
  92. scm_t_port *pt = SCM_PTAB_ENTRY (new);
  93. scm_t_port *old_pt = SCM_PTAB_ENTRY (old);
  94. scm_t_ptob_descriptor *ptob = &scm_ptobs[SCM_PTOBNUM (new)];
  95. /* must flush to old fdes. */
  96. if (pt->rw_active == SCM_PORT_WRITE)
  97. ptob->flush (new);
  98. else if (pt->rw_active == SCM_PORT_READ)
  99. scm_end_input (new);
  100. ans = dup2 (oldfd, newfd);
  101. if (ans == -1)
  102. SCM_SYSERROR;
  103. pt->rw_random = old_pt->rw_random;
  104. /* continue using existing buffers, even if inappropriate. */
  105. }
  106. return SCM_UNSPECIFIED;
  107. }
  108. #undef FUNC_NAME
  109. SCM_DEFINE (scm_dup_to_fdes, "dup->fdes", 1, 1, 0,
  110. (SCM fd_or_port, SCM fd),
  111. "Return a new integer file descriptor referring to the open file\n"
  112. "designated by @var{fd_or_port}, which must be either an open\n"
  113. "file port or a file descriptor.")
  114. #define FUNC_NAME s_scm_dup_to_fdes
  115. {
  116. int oldfd, newfd, rv;
  117. fd_or_port = SCM_COERCE_OUTPORT (fd_or_port);
  118. if (SCM_INUMP (fd_or_port))
  119. oldfd = SCM_INUM (fd_or_port);
  120. else
  121. {
  122. SCM_VALIDATE_OPFPORT (1,fd_or_port);
  123. oldfd = SCM_FPORT_FDES (fd_or_port);
  124. }
  125. if (SCM_UNBNDP (fd))
  126. {
  127. newfd = dup (oldfd);
  128. if (newfd == -1)
  129. SCM_SYSERROR;
  130. fd = SCM_MAKINUM (newfd);
  131. }
  132. else
  133. {
  134. SCM_VALIDATE_INUM_COPY (2, fd, newfd);
  135. if (oldfd != newfd)
  136. {
  137. scm_evict_ports (newfd); /* see scsh manual. */
  138. rv = dup2 (oldfd, newfd);
  139. if (rv == -1)
  140. SCM_SYSERROR;
  141. }
  142. }
  143. return fd;
  144. }
  145. #undef FUNC_NAME
  146. SCM_DEFINE (scm_dup2, "dup2", 2, 0, 0,
  147. (SCM oldfd, SCM newfd),
  148. "A simple wrapper for the @code{dup2} system call.\n"
  149. "Copies the file descriptor @var{oldfd} to descriptor\n"
  150. "number @var{newfd}, replacing the previous meaning\n"
  151. "of @var{newfd}. Both @var{oldfd} and @var{newfd} must\n"
  152. "be integers.\n"
  153. "Unlike for dup->fdes or primitive-move->fdes, no attempt\n"
  154. "is made to move away ports which are using @var{newfd}.\n"
  155. "The return value is unspecified.")
  156. #define FUNC_NAME s_scm_dup2
  157. {
  158. int c_oldfd;
  159. int c_newfd;
  160. int rv;
  161. SCM_VALIDATE_INUM_COPY (1, oldfd, c_oldfd);
  162. SCM_VALIDATE_INUM_COPY (2, newfd, c_newfd);
  163. rv = dup2 (c_oldfd, c_newfd);
  164. if (rv == -1)
  165. SCM_SYSERROR;
  166. return SCM_UNSPECIFIED;
  167. }
  168. #undef FUNC_NAME
  169. SCM_DEFINE (scm_fileno, "fileno", 1, 0, 0,
  170. (SCM port),
  171. "Return the integer file descriptor underlying @var{port}. Does\n"
  172. "not change its revealed count.")
  173. #define FUNC_NAME s_scm_fileno
  174. {
  175. port = SCM_COERCE_OUTPORT (port);
  176. SCM_VALIDATE_OPFPORT (1,port);
  177. return SCM_MAKINUM (SCM_FPORT_FDES (port));
  178. }
  179. #undef FUNC_NAME
  180. /* GJB:FIXME:: why does this not throw
  181. an error if the arg is not a port?
  182. This proc as is would be better names isattyport?
  183. if it is not going to assume that the arg is a port
  184. [cmm] I don't see any problem with the above. why should a type
  185. predicate assume _anything_ about its argument?
  186. */
  187. SCM_DEFINE (scm_isatty_p, "isatty?", 1, 0, 0,
  188. (SCM port),
  189. "Return @code{#t} if @var{port} is using a serial non--file\n"
  190. "device, otherwise @code{#f}.")
  191. #define FUNC_NAME s_scm_isatty_p
  192. {
  193. int rv;
  194. port = SCM_COERCE_OUTPORT (port);
  195. if (!SCM_OPFPORTP (port))
  196. return SCM_BOOL_F;
  197. rv = isatty (SCM_FPORT_FDES (port));
  198. return SCM_BOOL(rv);
  199. }
  200. #undef FUNC_NAME
  201. SCM_DEFINE (scm_fdopen, "fdopen", 2, 0, 0,
  202. (SCM fdes, SCM modes),
  203. "Return a new port based on the file descriptor @var{fdes}.\n"
  204. "Modes are given by the string @var{modes}. The revealed count\n"
  205. "of the port is initialized to zero. The modes string is the\n"
  206. "same as that accepted by @ref{File Ports, open-file}.")
  207. #define FUNC_NAME s_scm_fdopen
  208. {
  209. SCM_VALIDATE_INUM (1,fdes);
  210. SCM_VALIDATE_STRING (2, modes);
  211. SCM_STRING_COERCE_0TERMINATION_X (modes);
  212. return scm_fdes_to_port (SCM_INUM (fdes), SCM_STRING_CHARS (modes), SCM_BOOL_F);
  213. }
  214. #undef FUNC_NAME
  215. /* Move a port's underlying file descriptor to a given value.
  216. * Returns #f if fdes is already the given value.
  217. * #t if fdes moved.
  218. * MOVE->FDES is implemented in Scheme and calls this primitive.
  219. */
  220. SCM_DEFINE (scm_primitive_move_to_fdes, "primitive-move->fdes", 2, 0, 0,
  221. (SCM port, SCM fd),
  222. "Moves the underlying file descriptor for @var{port} to the integer\n"
  223. "value @var{fdes} without changing the revealed count of @var{port}.\n"
  224. "Any other ports already using this descriptor will be automatically\n"
  225. "shifted to new descriptors and their revealed counts reset to zero.\n"
  226. "The return value is @code{#f} if the file descriptor already had the\n"
  227. "required value or @code{#t} if it was moved.")
  228. #define FUNC_NAME s_scm_primitive_move_to_fdes
  229. {
  230. scm_t_fport *stream;
  231. int old_fd;
  232. int new_fd;
  233. int rv;
  234. port = SCM_COERCE_OUTPORT (port);
  235. SCM_VALIDATE_OPFPORT (1,port);
  236. SCM_VALIDATE_INUM (2,fd);
  237. stream = SCM_FSTREAM (port);
  238. old_fd = stream->fdes;
  239. new_fd = SCM_INUM (fd);
  240. if (old_fd == new_fd)
  241. {
  242. return SCM_BOOL_F;
  243. }
  244. scm_evict_ports (new_fd);
  245. rv = dup2 (old_fd, new_fd);
  246. if (rv == -1)
  247. SCM_SYSERROR;
  248. stream->fdes = new_fd;
  249. SCM_SYSCALL (close (old_fd));
  250. return SCM_BOOL_T;
  251. }
  252. #undef FUNC_NAME
  253. /* Return a list of ports using a given file descriptor. */
  254. SCM_DEFINE (scm_fdes_to_ports, "fdes->ports", 1, 0, 0,
  255. (SCM fd),
  256. "Return a list of existing ports which have @var{fdes} as an\n"
  257. "underlying file descriptor, without changing their revealed\n"
  258. "counts.")
  259. #define FUNC_NAME s_scm_fdes_to_ports
  260. {
  261. SCM result = SCM_EOL;
  262. int int_fd;
  263. long i;
  264. SCM_VALIDATE_INUM_COPY (1,fd,int_fd);
  265. for (i = 0; i < scm_port_table_size; i++)
  266. {
  267. if (SCM_OPFPORTP (scm_port_table[i]->port)
  268. && ((scm_t_fport *) scm_port_table[i]->stream)->fdes == int_fd)
  269. result = scm_cons (scm_port_table[i]->port, result);
  270. }
  271. return result;
  272. }
  273. #undef FUNC_NAME
  274. void
  275. scm_init_ioext ()
  276. {
  277. scm_add_feature ("i/o-extensions");
  278. #include "libguile/ioext.x"
  279. }
  280. /*
  281. Local Variables:
  282. c-file-style: "gnu"
  283. End:
  284. */