* Removed lots of deprecated stuff.
[bpt/guile.git] / libguile / filesys.c
CommitLineData
e4b265d8 1/* Copyright (C) 1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc.
0f2d19dd
JB
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
82892bed
JB
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
0f2d19dd
JB
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.
82892bed 40 * If you do not wish that, delete this exception notice. */
1bbd0b84 41
1bbd0b84 42
0f2d19dd 43\f
3d8d56df 44#include <stdio.h>
e6e2e95a
MD
45#include <errno.h>
46
a0599745
MD
47#include "libguile/_scm.h"
48#include "libguile/smob.h"
49#include "libguile/feature.h"
50#include "libguile/fports.h"
51#include "libguile/iselect.h"
52#include "libguile/strings.h"
53#include "libguile/vectors.h"
0f2d19dd 54
a0599745
MD
55#include "libguile/validate.h"
56#include "libguile/filesys.h"
def804a3 57
0f2d19dd 58\f
def804a3
JB
59#ifdef HAVE_IO_H
60#include <io.h>
61#endif
62
0f2d19dd
JB
63#ifdef TIME_WITH_SYS_TIME
64# include <sys/time.h>
65# include <time.h>
66#else
67# if HAVE_SYS_TIME_H
68# include <sys/time.h>
69# else
70# include <time.h>
71# endif
72#endif
73
74#ifdef HAVE_UNISTD_H
75#include <unistd.h>
76#endif
77
3594582b 78#ifdef LIBC_H_WITH_UNISTD_H
1f9e2226
JB
79#include <libc.h>
80#endif
81
0f2d19dd
JB
82#ifdef HAVE_SYS_SELECT_H
83#include <sys/select.h>
84#endif
85
1f9e2226
JB
86#ifdef HAVE_STRING_H
87#include <string.h>
88#endif
89
8cc71382 90#include <sys/types.h>
0f2d19dd
JB
91#include <sys/stat.h>
92#include <fcntl.h>
93
82893676 94#ifdef HAVE_PWD_H
0f2d19dd 95#include <pwd.h>
82893676 96#endif
0f2d19dd
JB
97
98
0f2d19dd
JB
99#if HAVE_DIRENT_H
100# include <dirent.h>
101# define NAMLEN(dirent) strlen((dirent)->d_name)
102#else
103# define dirent direct
104# define NAMLEN(dirent) (dirent)->d_namlen
105# if HAVE_SYS_NDIR_H
106# include <sys/ndir.h>
107# endif
108# if HAVE_SYS_DIR_H
109# include <sys/dir.h>
110# endif
111# if HAVE_NDIR_H
112# include <ndir.h>
113# endif
114#endif
115
d7b8a21a
JB
116/* Ultrix has S_IFSOCK, but no S_ISSOCK. Ipe! */
117#if defined (S_IFSOCK) && ! defined (S_ISSOCK)
118#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
119#endif
82893676
MG
120
121/* The MinGW gcc does not define the S_ISSOCK macro. Any other native Windows
122 compiler like BorlandC or MSVC has none of these macros defined. */
123#ifdef __MINGW32__
124# define S_ISSOCK(mode) (0)
125#endif
126#if defined (__BORLANDC__) || defined (_MSC_VER)
127# define S_ISBLK(mode) (0)
128# define S_ISFIFO(mode) (((mode) & _S_IFMT) == _S_IFIFO)
129# define S_ISCHR(mode) (((mode) & _S_IFMT) == _S_IFCHR)
130# define S_ISDIR(mode) (((mode) & _S_IFMT) == _S_IFDIR)
131# define S_ISREG(mode) (((mode) & _S_IFMT) == _S_IFREG)
132#endif
133
134/* Some more definitions for the native Windows port. */
135#ifdef __MINGW32__
136# define mkdir(path, mode) mkdir (path)
137# define fsync(fd) _commit (fd)
138# define fchmod(fd, mode) (-1)
139#endif /* __MINGW32__ */
0f2d19dd
JB
140\f
141
0f2d19dd
JB
142
143\f
144
145/* {Permissions}
146 */
147
82893676 148#ifdef HAVE_CHOWN
a1ec6916 149SCM_DEFINE (scm_chown, "chown", 3, 0, 0,
1bbd0b84 150 (SCM object, SCM owner, SCM group),
d831b039
GH
151 "Change the ownership and group of the file referred to by @var{object} to\n"
152 "the integer values @var{owner} and @var{group}. @var{object} can be\n"
153 "a string containing a file name or, if the platform\n"
154 "supports fchown, a port or integer file descriptor\n"
155 "which is open on the file. The return value\n"
d3818c29 156 "is unspecified.\n\n"
d831b039 157 "If @var{object} is a symbolic link, either the\n"
d3818c29
MD
158 "ownership of the link or the ownership of the referenced file will be\n"
159 "changed depending on the operating system (lchown is\n"
160 "unsupported at present). If @var{owner} or @var{group} is specified\n"
161 "as @code{-1}, then that ID is not changed.")
1bbd0b84 162#define FUNC_NAME s_scm_chown
0f2d19dd 163{
6afcd3b2 164 int rv;
02b754d3 165
78446828
MV
166 object = SCM_COERCE_OUTPORT (object);
167
3b3b36dd
GB
168 SCM_VALIDATE_INUM (2,owner);
169 SCM_VALIDATE_INUM (3,group);
d831b039 170#ifdef HAVE_FCHOWN
0c95b57d 171 if (SCM_INUMP (object) || (SCM_OPFPORTP (object)))
6afcd3b2 172 {
d831b039
GH
173 int fdes = SCM_INUMP (object) ? SCM_INUM (object)
174 : SCM_FPORT_FDES (object);
175
6afcd3b2
GH
176 SCM_SYSCALL (rv = fchown (fdes, SCM_INUM (owner), SCM_INUM (group)));
177 }
178 else
d831b039 179#endif
6afcd3b2 180 {
a6d9e5ab 181 SCM_VALIDATE_STRING (1, object);
a6d9e5ab 182 SCM_SYSCALL (rv = chown (SCM_STRING_CHARS (object),
6afcd3b2
GH
183 SCM_INUM (owner), SCM_INUM (group)));
184 }
185 if (rv == -1)
1bbd0b84 186 SCM_SYSERROR;
02b754d3 187 return SCM_UNSPECIFIED;
0f2d19dd 188}
1bbd0b84 189#undef FUNC_NAME
82893676 190#endif /* HAVE_CHOWN */
0f2d19dd
JB
191
192
a1ec6916 193SCM_DEFINE (scm_chmod, "chmod", 2, 0, 0,
1bbd0b84 194 (SCM object, SCM mode),
d3818c29
MD
195 "Changes the permissions of the file referred to by @var{obj}.\n"
196 "@var{obj} can be a string containing a file name or a port or integer file\n"
197 "descriptor which is open on a file (in which case @code{fchmod} is used\n"
198 "as the underlying system call).\n"
199 "@var{mode} specifies\n"
200 "the new permissions as a decimal number, e.g., @code{(chmod \"foo\" #o755)}.\n"
201 "The return value is unspecified.")
1bbd0b84 202#define FUNC_NAME s_scm_chmod
0f2d19dd
JB
203{
204 int rv;
6afcd3b2
GH
205 int fdes;
206
78446828
MV
207 object = SCM_COERCE_OUTPORT (object);
208
3b3b36dd 209 SCM_VALIDATE_INUM (2,mode);
0c95b57d 210 if (SCM_INUMP (object) || SCM_OPFPORTP (object))
89958ad0 211 {
6afcd3b2
GH
212 if (SCM_INUMP (object))
213 fdes = SCM_INUM (object);
214 else
77a76b64 215 fdes = SCM_FPORT_FDES (object);
6afcd3b2 216 SCM_SYSCALL (rv = fchmod (fdes, SCM_INUM (mode)));
89958ad0 217 }
0f2d19dd
JB
218 else
219 {
a6d9e5ab 220 SCM_VALIDATE_STRING (1, object);
a6d9e5ab 221 SCM_SYSCALL (rv = chmod (SCM_STRING_CHARS (object), SCM_INUM (mode)));
0f2d19dd 222 }
6afcd3b2 223 if (rv == -1)
1bbd0b84 224 SCM_SYSERROR;
02b754d3 225 return SCM_UNSPECIFIED;
0f2d19dd 226}
1bbd0b84 227#undef FUNC_NAME
0f2d19dd 228
a1ec6916 229SCM_DEFINE (scm_umask, "umask", 0, 1, 0,
1bbd0b84 230 (SCM mode),
d3818c29
MD
231 "If @var{mode} is omitted, retuns a decimal number representing the current\n"
232 "file creation mask. Otherwise the file creation mask is set to\n"
233 "@var{mode} and the previous value is returned.\n\n"
234 "E.g., @code{(umask #o022)} sets the mask to octal 22, decimal 18.")
1bbd0b84 235#define FUNC_NAME s_scm_umask
0f2d19dd
JB
236{
237 mode_t mask;
238 if (SCM_UNBNDP (mode))
239 {
240 mask = umask (0);
241 umask (mask);
242 }
243 else
244 {
3b3b36dd 245 SCM_VALIDATE_INUM (1,mode);
0f2d19dd
JB
246 mask = umask (SCM_INUM (mode));
247 }
248 return SCM_MAKINUM (mask);
249}
1bbd0b84 250#undef FUNC_NAME
0f2d19dd
JB
251
252\f
0f2d19dd 253
a1ec6916 254SCM_DEFINE (scm_open_fdes, "open-fdes", 2, 1, 0,
1bbd0b84 255 (SCM path, SCM flags, SCM mode),
1e6808ea
MG
256 "Similar to @code{open} but return a file descriptor instead of\n"
257 "a port.")
1bbd0b84 258#define FUNC_NAME s_scm_open_fdes
0f2d19dd
JB
259{
260 int fd;
3d8d56df 261 int iflags;
6afcd3b2 262 int imode;
0f2d19dd 263
a6d9e5ab 264 SCM_VALIDATE_STRING (1, path);
1be6b49c
ML
265 iflags = SCM_NUM2INT (2, flags);
266 imode = SCM_NUM2INT_DEF (3, mode, 0666);
a6d9e5ab 267 SCM_SYSCALL (fd = open (SCM_STRING_CHARS (path), iflags, imode));
3d8d56df 268 if (fd == -1)
1bbd0b84 269 SCM_SYSERROR;
6afcd3b2
GH
270 return SCM_MAKINUM (fd);
271}
1bbd0b84 272#undef FUNC_NAME
6afcd3b2 273
a1ec6916 274SCM_DEFINE (scm_open, "open", 2, 1, 0,
1bbd0b84 275 (SCM path, SCM flags, SCM mode),
d3818c29
MD
276 "Open the file named by @var{path} for reading and/or writing.\n"
277 "@var{flags} is an integer specifying how the file should be opened.\n"
278 "@var{mode} is an integer specifying the permission bits of the file, if\n"
279 "it needs to be created, before the umask is applied. The default is 666\n"
280 "(Unix itself has no default).\n\n"
281 "@var{flags} can be constructed by combining variables using @code{logior}.\n"
282 "Basic flags are:\n\n"
283 "@defvar O_RDONLY\n"
284 "Open the file read-only.\n"
285 "@end defvar\n"
286 "@defvar O_WRONLY\n"
287 "Open the file write-only. \n"
288 "@end defvar\n"
289 "@defvar O_RDWR\n"
290 "Open the file read/write.\n"
291 "@end defvar\n"
292 "@defvar O_APPEND\n"
293 "Append to the file instead of truncating.\n"
294 "@end defvar\n"
295 "@defvar O_CREAT\n"
296 "Create the file if it does not already exist.\n"
297 "@end defvar\n\n"
298 "See the Unix documentation of the @code{open} system call\n"
299 "for additional flags.")
1bbd0b84 300#define FUNC_NAME s_scm_open
6afcd3b2
GH
301{
302 SCM newpt;
303 char *port_mode;
304 int fd;
6afcd3b2
GH
305 int iflags;
306
307 fd = SCM_INUM (scm_open_fdes (path, flags, mode));
1be6b49c 308 iflags = SCM_NUM2INT (2, flags);
3d8d56df 309 if (iflags & O_RDWR)
77a76b64
JB
310 {
311 if (iflags & O_APPEND)
312 port_mode = "a+";
313 else if (iflags & O_CREAT)
314 port_mode = "w+";
315 else
316 port_mode = "r+";
317 }
3d8d56df 318 else {
77a76b64
JB
319 if (iflags & O_APPEND)
320 port_mode = "a";
321 else if (iflags & O_WRONLY)
3d8d56df
GH
322 port_mode = "w";
323 else
324 port_mode = "r";
325 }
77a76b64 326 newpt = scm_fdes_to_port (fd, port_mode, path);
3d8d56df 327 return newpt;
0f2d19dd 328}
1bbd0b84 329#undef FUNC_NAME
0f2d19dd 330
a1ec6916 331SCM_DEFINE (scm_close, "close", 1, 0, 0,
1bbd0b84 332 (SCM fd_or_port),
d3818c29
MD
333 "Similar to close-port (@pxref{Generic Port Operations, close-port}),\n"
334 "but also works on file descriptors. A side\n"
335 "effect of closing a file descriptor is that any ports using that file\n"
336 "descriptor are moved to a different file descriptor and have\n"
337 "their revealed counts set to zero.")
1bbd0b84 338#define FUNC_NAME s_scm_close
eadd48de
GH
339{
340 int rv;
341 int fd;
342
78446828
MV
343 fd_or_port = SCM_COERCE_OUTPORT (fd_or_port);
344
0c95b57d 345 if (SCM_PORTP (fd_or_port))
eadd48de 346 return scm_close_port (fd_or_port);
3b3b36dd 347 SCM_VALIDATE_INUM (1,fd_or_port);
eadd48de 348 fd = SCM_INUM (fd_or_port);
eadd48de 349 scm_evict_ports (fd); /* see scsh manual. */
a9488d12 350 SCM_SYSCALL (rv = close (fd));
eadd48de
GH
351 /* following scsh, closing an already closed file descriptor is
352 not an error. */
353 if (rv < 0 && errno != EBADF)
1bbd0b84 354 SCM_SYSERROR;
36284627 355 return SCM_BOOL (rv >= 0);
eadd48de 356}
1bbd0b84 357#undef FUNC_NAME
eadd48de 358
c2ca4493
GH
359SCM_DEFINE (scm_close_fdes, "close-fdes", 1, 0, 0,
360 (SCM fd),
361 "A simple wrapper for the @code{close} system call.\n"
362 "Close file descriptor @var{fd}, which must be an integer.\n"
363 "Unlike close (@pxref{Ports and File Descriptors, close}),\n"
364 "the file descriptor will be closed even if a port is using it.\n"
365 "The return value is unspecified.")
366#define FUNC_NAME s_scm_close_fdes
367{
368 int c_fd;
369 int rv;
370
371 SCM_VALIDATE_INUM_COPY (1, fd, c_fd);
372 SCM_SYSCALL (rv = close (c_fd));
373 if (rv < 0)
374 SCM_SYSERROR;
375 return SCM_UNSPECIFIED;
376}
377#undef FUNC_NAME
378
0f2d19dd
JB
379\f
380/* {Files}
381 */
1cc91f1b 382
ae5253c5
GH
383SCM_SYMBOL (scm_sym_regular, "regular");
384SCM_SYMBOL (scm_sym_directory, "directory");
f326ecf3 385#ifdef HAVE_S_ISLNK
ae5253c5 386SCM_SYMBOL (scm_sym_symlink, "symlink");
f326ecf3 387#endif
ae5253c5
GH
388SCM_SYMBOL (scm_sym_block_special, "block-special");
389SCM_SYMBOL (scm_sym_char_special, "char-special");
390SCM_SYMBOL (scm_sym_fifo, "fifo");
391SCM_SYMBOL (scm_sym_sock, "socket");
392SCM_SYMBOL (scm_sym_unknown, "unknown");
393
0f2d19dd 394static SCM
1bbd0b84 395scm_stat2scm (struct stat *stat_temp)
0f2d19dd 396{
00ffa0e7 397 SCM ans = scm_c_make_vector (15, SCM_UNSPECIFIED);
0f2d19dd 398 SCM *ve = SCM_VELTS (ans);
ae5253c5 399
0f2d19dd
JB
400 ve[0] = scm_ulong2num ((unsigned long) stat_temp->st_dev);
401 ve[1] = scm_ulong2num ((unsigned long) stat_temp->st_ino);
402 ve[2] = scm_ulong2num ((unsigned long) stat_temp->st_mode);
403 ve[3] = scm_ulong2num ((unsigned long) stat_temp->st_nlink);
404 ve[4] = scm_ulong2num ((unsigned long) stat_temp->st_uid);
405 ve[5] = scm_ulong2num ((unsigned long) stat_temp->st_gid);
1fd85bc5 406#ifdef HAVE_STRUCT_STAT_ST_RDEV
0f2d19dd
JB
407 ve[6] = scm_ulong2num ((unsigned long) stat_temp->st_rdev);
408#else
409 ve[6] = SCM_BOOL_F;
410#endif
411 ve[7] = scm_ulong2num ((unsigned long) stat_temp->st_size);
412 ve[8] = scm_ulong2num ((unsigned long) stat_temp->st_atime);
413 ve[9] = scm_ulong2num ((unsigned long) stat_temp->st_mtime);
414 ve[10] = scm_ulong2num ((unsigned long) stat_temp->st_ctime);
1fd85bc5 415#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
0f2d19dd
JB
416 ve[11] = scm_ulong2num ((unsigned long) stat_temp->st_blksize);
417#else
418 ve[11] = scm_ulong2num (4096L);
419#endif
1fd85bc5 420#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
0f2d19dd
JB
421 ve[12] = scm_ulong2num ((unsigned long) stat_temp->st_blocks);
422#else
423 ve[12] = SCM_BOOL_F;
424#endif
ae5253c5
GH
425 {
426 int mode = stat_temp->st_mode;
427
428 if (S_ISREG (mode))
429 ve[13] = scm_sym_regular;
430 else if (S_ISDIR (mode))
431 ve[13] = scm_sym_directory;
f326ecf3 432#ifdef HAVE_S_ISLNK
ae5253c5
GH
433 else if (S_ISLNK (mode))
434 ve[13] = scm_sym_symlink;
f326ecf3 435#endif
ae5253c5
GH
436 else if (S_ISBLK (mode))
437 ve[13] = scm_sym_block_special;
438 else if (S_ISCHR (mode))
439 ve[13] = scm_sym_char_special;
440 else if (S_ISFIFO (mode))
441 ve[13] = scm_sym_fifo;
e655d034 442#ifdef S_ISSOCK
ae5253c5
GH
443 else if (S_ISSOCK (mode))
444 ve[13] = scm_sym_sock;
e655d034 445#endif
ae5253c5
GH
446 else
447 ve[13] = scm_sym_unknown;
448
449 ve[14] = SCM_MAKINUM ((~S_IFMT) & mode);
450
451 /* the layout of the bits in ve[14] is intended to be portable.
452 If there are systems that don't follow the usual convention,
453 the following could be used:
454
455 tmp = 0;
456 if (S_ISUID & mode) tmp += 1;
457 tmp <<= 1;
458 if (S_IRGRP & mode) tmp += 1;
459 tmp <<= 1;
460 if (S_ISVTX & mode) tmp += 1;
461 tmp <<= 1;
462 if (S_IRUSR & mode) tmp += 1;
463 tmp <<= 1;
464 if (S_IWUSR & mode) tmp += 1;
465 tmp <<= 1;
466 if (S_IXUSR & mode) tmp += 1;
467 tmp <<= 1;
468 if (S_IWGRP & mode) tmp += 1;
469 tmp <<= 1;
470 if (S_IXGRP & mode) tmp += 1;
471 tmp <<= 1;
472 if (S_IROTH & mode) tmp += 1;
473 tmp <<= 1;
474 if (S_IWOTH & mode) tmp += 1;
475 tmp <<= 1;
476 if (S_IXOTH & mode) tmp += 1;
477
478 ve[14] = SCM_MAKINUM (tmp);
479
480 */
481 }
0f2d19dd
JB
482
483 return ans;
484}
485
a1ec6916 486SCM_DEFINE (scm_stat, "stat", 1, 0, 0,
1bbd0b84 487 (SCM object),
1e6808ea
MG
488 "Return an object containing various information about the file\n"
489 "determined by @var{obj}. @var{obj} can be a string containing\n"
490 "a file name or a port or integer file descriptor which is open\n"
491 "on a file (in which case @code{fstat} is used as the underlying\n"
492 "system call).\n"
493 "\n"
494 "The object returned by @code{stat} can be passed as a single\n"
495 "parameter to the following procedures, all of which return\n"
496 "integers:\n"
497 "\n"
d3818c29
MD
498 "@table @code\n"
499 "@item stat:dev\n"
500 "The device containing the file.\n"
501 "@item stat:ino\n"
1e6808ea
MG
502 "The file serial number, which distinguishes this file from all\n"
503 "other files on the same device.\n"
d3818c29 504 "@item stat:mode\n"
1e6808ea
MG
505 "The mode of the file. This includes file type information and\n"
506 "the file permission bits. See @code{stat:type} and\n"
507 "@code{stat:perms} below.\n"
d3818c29
MD
508 "@item stat:nlink\n"
509 "The number of hard links to the file.\n"
510 "@item stat:uid\n"
511 "The user ID of the file's owner.\n"
512 "@item stat:gid\n"
513 "The group ID of the file.\n"
514 "@item stat:rdev\n"
515 "Device ID; this entry is defined only for character or block\n"
516 "special files.\n"
517 "@item stat:size\n"
518 "The size of a regular file in bytes.\n"
519 "@item stat:atime\n"
520 "The last access time for the file.\n"
521 "@item stat:mtime\n"
522 "The last modification time for the file.\n"
523 "@item stat:ctime\n"
524 "The last modification time for the attributes of the file.\n"
525 "@item stat:blksize\n"
1e6808ea
MG
526 "The optimal block size for reading or writing the file, in\n"
527 "bytes.\n"
d3818c29 528 "@item stat:blocks\n"
1e6808ea
MG
529 "The amount of disk space that the file occupies measured in\n"
530 "units of 512 byte blocks.\n"
531 "@end table\n"
532 "\n"
d3818c29 533 "In addition, the following procedures return the information\n"
1e6808ea
MG
534 "from stat:mode in a more convenient form:\n"
535 "\n"
d3818c29
MD
536 "@table @code\n"
537 "@item stat:type\n"
538 "A symbol representing the type of file. Possible values are\n"
1e6808ea
MG
539 "regular, directory, symlink, block-special, char-special, fifo,\n"
540 "socket and unknown\n"
d3818c29
MD
541 "@item stat:perms\n"
542 "An integer representing the access permission bits.\n"
543 "@end table")
1bbd0b84 544#define FUNC_NAME s_scm_stat
0f2d19dd 545{
6afcd3b2
GH
546 int rv;
547 int fdes;
0f2d19dd
JB
548 struct stat stat_temp;
549
1ea47048 550 if (SCM_INUMP (object))
36284627
DH
551 {
552 SCM_SYSCALL (rv = fstat (SCM_INUM (object), &stat_temp));
553 }
554 else if (SCM_STRINGP (object))
555 {
36284627
DH
556 SCM_SYSCALL (rv = stat (SCM_STRING_CHARS (object), &stat_temp));
557 }
1ea47048 558 else
0f2d19dd 559 {
36284627
DH
560 object = SCM_COERCE_OUTPORT (object);
561 SCM_VALIDATE_OPFPORT (1, object);
562 fdes = SCM_FPORT_FDES (object);
563 SCM_SYSCALL (rv = fstat (fdes, &stat_temp));
6afcd3b2 564 }
36284627 565
6afcd3b2 566 if (rv == -1)
3d8d56df
GH
567 {
568 int en = errno;
569
5d2d2ffc 570 SCM_SYSERROR_MSG ("~A: ~S",
1afff620
KN
571 scm_list_2 (scm_makfrom0str (strerror (errno)),
572 object),
e0c08f17 573 en);
3d8d56df 574 }
02b754d3 575 return scm_stat2scm (&stat_temp);
0f2d19dd 576}
1bbd0b84 577#undef FUNC_NAME
0f2d19dd 578
0f2d19dd
JB
579\f
580/* {Modifying Directories}
581 */
582
82893676 583#ifdef HAVE_LINK
a1ec6916 584SCM_DEFINE (scm_link, "link", 2, 0, 0,
1bbd0b84 585 (SCM oldpath, SCM newpath),
6d36532c
GH
586 "Creates a new name @var{newpath} in the file system for the\n"
587 "file named by @var{oldpath}. If @var{oldpath} is a symbolic\n"
588 "link, the link may or may not be followed depending on the\n"
589 "system.")
1bbd0b84 590#define FUNC_NAME s_scm_link
0f2d19dd
JB
591{
592 int val;
02b754d3 593
a6d9e5ab 594 SCM_VALIDATE_STRING (1, oldpath);
a6d9e5ab 595 SCM_VALIDATE_STRING (2, newpath);
6d36532c
GH
596 SCM_SYSCALL (val = link (SCM_STRING_CHARS (oldpath),
597 SCM_STRING_CHARS (newpath)));
02b754d3 598 if (val != 0)
1bbd0b84 599 SCM_SYSERROR;
02b754d3 600 return SCM_UNSPECIFIED;
0f2d19dd 601}
1bbd0b84 602#undef FUNC_NAME
82893676 603#endif /* HAVE_LINK */
0f2d19dd
JB
604
605
606
a1ec6916 607SCM_DEFINE (scm_rename, "rename-file", 2, 0, 0,
1bbd0b84 608 (SCM oldname, SCM newname),
6d36532c 609 "Renames the file specified by @var{oldname} to @var{newname}.\n"
d3818c29 610 "The return value is unspecified.")
1bbd0b84 611#define FUNC_NAME s_scm_rename
0f2d19dd
JB
612{
613 int rv;
a6d9e5ab
DH
614 SCM_VALIDATE_STRING (1, oldname);
615 SCM_VALIDATE_STRING (2, newname);
0f2d19dd 616#ifdef HAVE_RENAME
a6d9e5ab 617 SCM_SYSCALL (rv = rename (SCM_STRING_CHARS (oldname), SCM_STRING_CHARS (newname)));
0f2d19dd 618#else
a6d9e5ab 619 SCM_SYSCALL (rv = link (SCM_STRING_CHARS (oldname), SCM_STRING_CHARS (newname)));
02b754d3 620 if (rv == 0)
0f2d19dd 621 {
a6d9e5ab 622 SCM_SYSCALL (rv = unlink (SCM_STRING_CHARS (oldname)));;
02b754d3 623 if (rv != 0)
0f2d19dd 624 /* unlink failed. remove new name */
a6d9e5ab 625 SCM_SYSCALL (unlink (SCM_STRING_CHARS (newname)));
0f2d19dd 626 }
6afcd3b2 627#endif
02b754d3 628 if (rv != 0)
1bbd0b84 629 SCM_SYSERROR;
02b754d3 630 return SCM_UNSPECIFIED;
0f2d19dd 631}
1bbd0b84 632#undef FUNC_NAME
0f2d19dd
JB
633
634
3b3b36dd 635SCM_DEFINE (scm_delete_file, "delete-file", 1, 0, 0,
1bbd0b84 636 (SCM str),
d3818c29 637 "Deletes (or \"unlinks\") the file specified by @var{path}.")
1bbd0b84 638#define FUNC_NAME s_scm_delete_file
2f3ed1ba
JB
639{
640 int ans;
a6d9e5ab 641 SCM_VALIDATE_STRING (1, str);
a6d9e5ab 642 SCM_SYSCALL (ans = unlink (SCM_STRING_CHARS (str)));
2f3ed1ba 643 if (ans != 0)
1bbd0b84 644 SCM_SYSERROR;
2f3ed1ba
JB
645 return SCM_UNSPECIFIED;
646}
1bbd0b84 647#undef FUNC_NAME
2f3ed1ba 648
f25f761d 649#ifdef HAVE_MKDIR
a1ec6916 650SCM_DEFINE (scm_mkdir, "mkdir", 1, 1, 0,
1bbd0b84 651 (SCM path, SCM mode),
d3818c29
MD
652 "Create a new directory named by @var{path}. If @var{mode} is omitted\n"
653 "then the permissions of the directory file are set using the current\n"
654 "umask. Otherwise they are set to the decimal value specified with\n"
655 "@var{mode}. The return value is unspecified.")
1bbd0b84 656#define FUNC_NAME s_scm_mkdir
0f2d19dd 657{
0f2d19dd
JB
658 int rv;
659 mode_t mask;
a6d9e5ab 660 SCM_VALIDATE_STRING (1, path);
0f2d19dd
JB
661 if (SCM_UNBNDP (mode))
662 {
663 mask = umask (0);
664 umask (mask);
a6d9e5ab 665 SCM_SYSCALL (rv = mkdir (SCM_STRING_CHARS (path), 0777 ^ mask));
0f2d19dd
JB
666 }
667 else
668 {
3b3b36dd 669 SCM_VALIDATE_INUM (2,mode);
a6d9e5ab 670 SCM_SYSCALL (rv = mkdir (SCM_STRING_CHARS (path), SCM_INUM (mode)));
0f2d19dd 671 }
02b754d3 672 if (rv != 0)
1bbd0b84 673 SCM_SYSERROR;
02b754d3 674 return SCM_UNSPECIFIED;
0f2d19dd 675}
1bbd0b84 676#undef FUNC_NAME
f25f761d 677#endif /* HAVE_MKDIR */
0f2d19dd 678
f25f761d 679#ifdef HAVE_RMDIR
a1ec6916 680SCM_DEFINE (scm_rmdir, "rmdir", 1, 0, 0,
1bbd0b84 681 (SCM path),
d3818c29
MD
682 "Remove the existing directory named by @var{path}. The directory must\n"
683 "be empty for this to succeed. The return value is unspecified.")
1bbd0b84 684#define FUNC_NAME s_scm_rmdir
0f2d19dd 685{
0f2d19dd 686 int val;
02b754d3 687
a6d9e5ab 688 SCM_VALIDATE_STRING (1, path);
a6d9e5ab 689 SCM_SYSCALL (val = rmdir (SCM_STRING_CHARS (path)));
02b754d3 690 if (val != 0)
1bbd0b84 691 SCM_SYSERROR;
02b754d3 692 return SCM_UNSPECIFIED;
0f2d19dd 693}
1bbd0b84 694#undef FUNC_NAME
f25f761d 695#endif
0f2d19dd
JB
696
697\f
30ea841d 698
0f2d19dd
JB
699/* {Examining Directories}
700 */
701
92c2555f 702scm_t_bits scm_tc16_dir;
0f2d19dd 703
30ea841d 704
a1ec6916 705SCM_DEFINE (scm_directory_stream_p, "directory-stream?", 1, 0, 0,
1bbd0b84 706 (SCM obj),
1e6808ea
MG
707 "Return a boolean indicating whether @var{object} is a directory\n"
708 "stream as returned by @code{opendir}.")
1bbd0b84 709#define FUNC_NAME s_scm_directory_stream_p
77242ff9 710{
30ea841d 711 return SCM_BOOL (SCM_DIRP (obj));
77242ff9 712}
1bbd0b84 713#undef FUNC_NAME
77242ff9 714
30ea841d 715
a1ec6916 716SCM_DEFINE (scm_opendir, "opendir", 1, 0, 0,
1bbd0b84 717 (SCM dirname),
d3818c29
MD
718 "Open the directory specified by @var{path} and return a directory\n"
719 "stream.")
1bbd0b84 720#define FUNC_NAME s_scm_opendir
0f2d19dd
JB
721{
722 DIR *ds;
a6d9e5ab 723 SCM_VALIDATE_STRING (1, dirname);
a6d9e5ab 724 SCM_SYSCALL (ds = opendir (SCM_STRING_CHARS (dirname)));
02b754d3 725 if (ds == NULL)
1bbd0b84 726 SCM_SYSERROR;
30ea841d 727 SCM_RETURN_NEWSMOB (scm_tc16_dir | SCM_DIR_FLAG_OPEN, ds);
0f2d19dd 728}
1bbd0b84 729#undef FUNC_NAME
0f2d19dd
JB
730
731
a1ec6916 732SCM_DEFINE (scm_readdir, "readdir", 1, 0, 0,
1bbd0b84 733 (SCM port),
d3818c29
MD
734 "Return (as a string) the next directory entry from the directory stream\n"
735 "@var{stream}. If there is no remaining entry to be read then the\n"
736 "end of file object is returned.")
1bbd0b84 737#define FUNC_NAME s_scm_readdir
0f2d19dd
JB
738{
739 struct dirent *rdent;
30ea841d
DH
740
741 SCM_VALIDATE_DIR (1, port);
742 if (!SCM_DIR_OPEN_P (port))
1afff620 743 SCM_MISC_ERROR ("Directory ~S is not open.", scm_list_1 (port));
30ea841d 744
0f2d19dd 745 errno = 0;
4260a7fc 746 SCM_SYSCALL (rdent = readdir ((DIR *) SCM_CELL_WORD_1 (port)));
02b754d3 747 if (errno != 0)
1bbd0b84 748 SCM_SYSERROR;
30ea841d 749
36284627 750 return (rdent ? scm_mem2string (rdent->d_name, NAMLEN (rdent))
02b754d3 751 : SCM_EOF_VAL);
0f2d19dd 752}
1bbd0b84 753#undef FUNC_NAME
0f2d19dd
JB
754
755
a1ec6916 756SCM_DEFINE (scm_rewinddir, "rewinddir", 1, 0, 0,
1bbd0b84 757 (SCM port),
d3818c29
MD
758 "Reset the directory port @var{stream} so that the next call to\n"
759 "@code{readdir} will return the first directory entry.")
1bbd0b84 760#define FUNC_NAME s_scm_rewinddir
0f2d19dd 761{
30ea841d
DH
762 SCM_VALIDATE_DIR (1, port);
763 if (!SCM_DIR_OPEN_P (port))
1afff620 764 SCM_MISC_ERROR ("Directory ~S is not open.", scm_list_1 (port));
30ea841d 765
4260a7fc 766 rewinddir ((DIR *) SCM_CELL_WORD_1 (port));
30ea841d 767
0f2d19dd
JB
768 return SCM_UNSPECIFIED;
769}
1bbd0b84 770#undef FUNC_NAME
0f2d19dd
JB
771
772
a1ec6916 773SCM_DEFINE (scm_closedir, "closedir", 1, 0, 0,
1bbd0b84 774 (SCM port),
d3818c29
MD
775 "Close the directory stream @var{stream}.\n"
776 "The return value is unspecified.")
1bbd0b84 777#define FUNC_NAME s_scm_closedir
0f2d19dd 778{
30ea841d 779 SCM_VALIDATE_DIR (1, port);
02b754d3 780
30ea841d 781 if (SCM_DIR_OPEN_P (port))
0f2d19dd 782 {
30ea841d
DH
783 int sts;
784
785 SCM_SYSCALL (sts = closedir ((DIR *) SCM_CELL_WORD_1 (port)));
786 if (sts != 0)
787 SCM_SYSERROR;
788
789 SCM_SET_CELL_WORD_0 (port, scm_tc16_dir);
0f2d19dd 790 }
30ea841d 791
02b754d3 792 return SCM_UNSPECIFIED;
0f2d19dd 793}
1bbd0b84 794#undef FUNC_NAME
0f2d19dd
JB
795
796
0f2d19dd 797static int
e81d98ec 798scm_dir_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 799{
f8b16091 800 scm_puts ("#<", port);
30ea841d 801 if (!SCM_DIR_OPEN_P (exp))
f8b16091 802 scm_puts ("closed: ", port);
0d03da62 803 scm_puts ("directory stream ", port);
4260a7fc 804 scm_intprint (SCM_CELL_WORD_1 (exp), 16, port);
f8b16091 805 scm_putc ('>', port);
0f2d19dd
JB
806 return 1;
807}
808
1cc91f1b 809
1be6b49c 810static size_t
1bbd0b84 811scm_dir_free (SCM p)
0f2d19dd 812{
30ea841d 813 if (SCM_DIR_OPEN_P (p))
4260a7fc 814 closedir ((DIR *) SCM_CELL_WORD_1 (p));
0f2d19dd
JB
815 return 0;
816}
817
0f2d19dd
JB
818\f
819/* {Navigating Directories}
820 */
821
822
a1ec6916 823SCM_DEFINE (scm_chdir, "chdir", 1, 0, 0,
1bbd0b84 824 (SCM str),
d3818c29
MD
825 "Change the current working directory to @var{path}.\n"
826 "The return value is unspecified.")
1bbd0b84 827#define FUNC_NAME s_scm_chdir
0f2d19dd
JB
828{
829 int ans;
02b754d3 830
a6d9e5ab 831 SCM_VALIDATE_STRING (1, str);
a6d9e5ab 832 SCM_SYSCALL (ans = chdir (SCM_STRING_CHARS (str)));
02b754d3 833 if (ans != 0)
1bbd0b84 834 SCM_SYSERROR;
02b754d3 835 return SCM_UNSPECIFIED;
0f2d19dd 836}
1bbd0b84 837#undef FUNC_NAME
0f2d19dd 838
f25f761d 839#ifdef HAVE_GETCWD
a1ec6916 840SCM_DEFINE (scm_getcwd, "getcwd", 0, 0, 0,
1bbd0b84 841 (),
1e6808ea 842 "Return the name of the current working directory.")
1bbd0b84 843#define FUNC_NAME s_scm_getcwd
0f2d19dd 844{
0f2d19dd 845 char *rv;
1be6b49c 846 size_t size = 100;
0f2d19dd
JB
847 char *wd;
848 SCM result;
849
1bbd0b84 850 wd = scm_must_malloc (size, FUNC_NAME);
0f2d19dd
JB
851 while ((rv = getcwd (wd, size)) == 0 && errno == ERANGE)
852 {
853 scm_must_free (wd);
854 size *= 2;
1bbd0b84 855 wd = scm_must_malloc (size, FUNC_NAME);
0f2d19dd 856 }
02b754d3 857 if (rv == 0)
1bbd0b84 858 SCM_SYSERROR;
36284627 859 result = scm_mem2string (wd, strlen (wd));
0f2d19dd 860 scm_must_free (wd);
0f2d19dd 861 return result;
0f2d19dd 862}
1bbd0b84 863#undef FUNC_NAME
f25f761d 864#endif /* HAVE_GETCWD */
0f2d19dd
JB
865
866\f
867
28d77376
GH
868#ifdef HAVE_SELECT
869
870/* check that element is a port or file descriptor. if it's a port
871 and its buffer is ready for use, add it to the ports_ready list.
872 otherwise add its file descriptor to *set. the type of list can be
873 determined from pos: SCM_ARG1 for reads, SCM_ARG2 for writes,
874 SCM_ARG3 for excepts. */
cafc12ff 875static int
28d77376 876set_element (SELECT_TYPE *set, SCM *ports_ready, SCM element, int pos)
a48a89bc 877{
cafc12ff 878 int fd;
d831b039 879
28d77376
GH
880 if (SCM_INUMP (element))
881 {
882 fd = SCM_INUM (element);
883 }
884 else
885 {
886 int use_buf = 0;
887
888 element = SCM_COERCE_OUTPORT (element);
889 SCM_ASSERT (SCM_OPFPORTP (element), element, pos, "select");
890 if (pos == SCM_ARG1)
891 {
892 /* check whether port has buffered input. */
92c2555f 893 scm_t_port *pt = SCM_PTAB_ENTRY (element);
28d77376
GH
894
895 if (pt->read_pos < pt->read_end)
896 use_buf = 1;
897 }
898 else if (pos == SCM_ARG2)
899 {
900 /* check whether port's output buffer has room. */
92c2555f 901 scm_t_port *pt = SCM_PTAB_ENTRY (element);
28d77376
GH
902
903 /* > 1 since writing the last byte in the buffer causes flush. */
904 if (pt->write_end - pt->write_pos > 1)
905 use_buf = 1;
906 }
907 fd = use_buf ? -1 : SCM_FPORT_FDES (element);
908 }
909 if (fd == -1)
910 *ports_ready = scm_cons (element, *ports_ready);
911 else
912 FD_SET (fd, set);
cafc12ff 913 return fd;
a48a89bc 914}
1cc91f1b 915
28d77376
GH
916/* check list_or_vec, a list or vector of ports or file descriptors,
917 adding each member to either the ports_ready list (if it's a port
918 with a usable buffer) or to *set. the kind of list_or_vec can be
919 determined from pos: SCM_ARG1 for reads, SCM_ARG2 for writes,
920 SCM_ARG3 for excepts. */
cafc12ff 921static int
28d77376 922fill_select_type (SELECT_TYPE *set, SCM *ports_ready, SCM list_or_vec, int pos)
0f2d19dd 923{
28d77376
GH
924 int max_fd = 0;
925
926 if (SCM_VECTORP (list_or_vec))
0f2d19dd 927 {
9fd38a3d 928 int i = SCM_VECTOR_LENGTH (list_or_vec);
28d77376 929 SCM *ve = SCM_VELTS (list_or_vec);
a48a89bc 930
28d77376 931 while (--i >= 0)
a48a89bc 932 {
28d77376
GH
933 int fd = set_element (set, ports_ready, ve[i], pos);
934
cafc12ff
MD
935 if (fd > max_fd)
936 max_fd = fd;
a48a89bc
GH
937 }
938 }
939 else
940 {
4260a7fc 941 while (!SCM_NULLP (list_or_vec))
a48a89bc 942 {
28d77376
GH
943 int fd = set_element (set, ports_ready, SCM_CAR (list_or_vec), pos);
944
cafc12ff
MD
945 if (fd > max_fd)
946 max_fd = fd;
28d77376 947 list_or_vec = SCM_CDR (list_or_vec);
a48a89bc 948 }
0f2d19dd 949 }
cafc12ff
MD
950
951 return max_fd;
0f2d19dd
JB
952}
953
28d77376
GH
954/* if element (a file descriptor or port) appears in *set, cons it to
955 list. return list. */
a48a89bc
GH
956static SCM
957get_element (SELECT_TYPE *set, SCM element, SCM list)
958{
28d77376
GH
959 int fd;
960
961 if (SCM_INUMP (element))
a48a89bc 962 {
28d77376 963 fd = SCM_INUM (element);
a48a89bc 964 }
28d77376 965 else
a48a89bc 966 {
28d77376 967 fd = SCM_FPORT_FDES (SCM_COERCE_OUTPORT (element));
a48a89bc 968 }
28d77376
GH
969 if (FD_ISSET (fd, set))
970 list = scm_cons (element, list);
a48a89bc
GH
971 return list;
972}
1cc91f1b 973
28d77376
GH
974/* construct component of scm_select return value.
975 set: pointer to set of file descriptors found by select to be ready
976 ports_ready: ports ready due to buffering
977 list_or_vec: original list/vector handed to scm_select.
978 the return value is a list/vector of ready ports/file descriptors.
979 works by finding the objects in list which correspond to members of
980 *set and appending them to ports_ready. result is converted to a
981 vector if list_or_vec is a vector. */
0f2d19dd 982static SCM
28d77376 983retrieve_select_type (SELECT_TYPE *set, SCM ports_ready, SCM list_or_vec)
0f2d19dd 984{
28d77376 985 SCM answer_list = ports_ready;
a48a89bc 986
28d77376 987 if (SCM_VECTORP (list_or_vec))
0f2d19dd 988 {
9fd38a3d 989 int i = SCM_VECTOR_LENGTH (list_or_vec);
28d77376 990 SCM *ve = SCM_VELTS (list_or_vec);
a48a89bc 991
28d77376 992 while (--i >= 0)
0f2d19dd 993 {
28d77376 994 answer_list = get_element (set, ve[i], answer_list);
0f2d19dd 995 }
a48a89bc
GH
996 return scm_vector (answer_list);
997 }
998 else
999 {
28d77376 1000 /* list_or_vec must be a list. */
4260a7fc 1001 while (!SCM_NULLP (list_or_vec))
0f2d19dd 1002 {
28d77376
GH
1003 answer_list = get_element (set, SCM_CAR (list_or_vec), answer_list);
1004 list_or_vec = SCM_CDR (list_or_vec);
0f2d19dd 1005 }
a48a89bc 1006 return answer_list;
0f2d19dd 1007 }
0f2d19dd
JB
1008}
1009
1bbd0b84 1010/* Static helper functions above refer to s_scm_select directly as s_select */
a1ec6916 1011SCM_DEFINE (scm_select, "select", 3, 2, 0,
1bbd0b84 1012 (SCM reads, SCM writes, SCM excepts, SCM secs, SCM usecs),
28d77376
GH
1013 "This procedure has a variety of uses: waiting for the ability\n"
1014 "to provide input, accept output, or the existance of\n"
1015 "exceptional conditions on a collection of ports or file\n"
1016 "descriptors, or waiting for a timeout to occur.\n"
1017 "It also returns if interrupted by a signal.\n\n"
1018 "@var{reads}, @var{writes} and @var{excepts} can be lists or\n"
1019 "vectors, with each member a port or a file descriptor.\n"
1020 "The value returned is a list of three corresponding\n"
1021 "lists or vectors containing only the members which meet the\n"
1022 "specified requirement. The ability of port buffers to\n"
1023 "provide input or accept output is taken into account.\n"
1024 "Ordering of the input lists or vectors is not preserved.\n\n"
1025 "The optional arguments @var{secs} and @var{usecs} specify the\n"
1026 "timeout. Either @var{secs} can be specified alone, as\n"
1027 "either an integer or a real number, or both @var{secs} and\n"
1028 "@var{usecs} can be specified as integers, in which case\n"
1029 "@var{usecs} is an additional timeout expressed in\n"
1030 "microseconds. If @var{secs} is omitted or is @code{#f} then\n"
1031 "select will wait for as long as it takes for one of the other\n"
1032 "conditions to be satisfied.\n\n"
1033 "The scsh version of @code{select} differs as follows:\n"
1034 "Only vectors are accepted for the first three arguments.\n"
1035 "The @var{usecs} argument is not supported.\n"
1036 "Multiple values are returned instead of a list.\n"
1037 "Duplicates in the input vectors appear only once in output.\n"
1038 "An additional @code{select!} interface is provided.\n"
1039 )
1bbd0b84 1040#define FUNC_NAME s_scm_select
0f2d19dd 1041{
0f2d19dd 1042 struct timeval timeout;
28d77376 1043 struct timeval * time_ptr;
0f2d19dd
JB
1044 SELECT_TYPE read_set;
1045 SELECT_TYPE write_set;
1046 SELECT_TYPE except_set;
28d77376
GH
1047 int read_count;
1048 int write_count;
1049 int except_count;
1050 /* these lists accumulate ports which are ready due to buffering.
1051 their file descriptors don't need to be added to the select sets. */
1052 SCM read_ports_ready = SCM_EOL;
1053 SCM write_ports_ready = SCM_EOL;
1054 int max_fd;
1055
1056 if (SCM_VECTORP (reads))
1057 {
9fd38a3d 1058 read_count = SCM_VECTOR_LENGTH (reads);
28d77376
GH
1059 }
1060 else
1061 {
1062 read_count = scm_ilength (reads);
1063 SCM_ASSERT (read_count >= 0, reads, SCM_ARG1, FUNC_NAME);
1064 }
1065 if (SCM_VECTORP (writes))
1066 {
9fd38a3d 1067 write_count = SCM_VECTOR_LENGTH (writes);
28d77376
GH
1068 }
1069 else
1070 {
1071 write_count = scm_ilength (writes);
1072 SCM_ASSERT (write_count >= 0, writes, SCM_ARG2, FUNC_NAME);
1073 }
1074 if (SCM_VECTORP (excepts))
1075 {
9fd38a3d 1076 except_count = SCM_VECTOR_LENGTH (excepts);
28d77376
GH
1077 }
1078 else
1079 {
1080 except_count = scm_ilength (excepts);
1081 SCM_ASSERT (except_count >= 0, excepts, SCM_ARG3, FUNC_NAME);
1082 }
0f2d19dd
JB
1083
1084 FD_ZERO (&read_set);
1085 FD_ZERO (&write_set);
1086 FD_ZERO (&except_set);
1087
28d77376
GH
1088 max_fd = fill_select_type (&read_set, &read_ports_ready, reads, SCM_ARG1);
1089
1090 {
1091 int write_max = fill_select_type (&write_set, &write_ports_ready,
1092 writes, SCM_ARG2);
1093 int except_max = fill_select_type (&except_set, NULL,
1094 excepts, SCM_ARG3);
1095
1096 if (write_max > max_fd)
1097 max_fd = write_max;
1098 if (except_max > max_fd)
1099 max_fd = except_max;
1100 }
0f2d19dd 1101
ae1b098b
GH
1102 /* if there's a port with a ready buffer, don't block, just
1103 check for ready file descriptors. */
4260a7fc 1104 if (!SCM_NULLP (read_ports_ready) || !SCM_NULLP (write_ports_ready))
ae1b098b
GH
1105 {
1106 timeout.tv_sec = 0;
1107 timeout.tv_usec = 0;
1108 time_ptr = &timeout;
1109 }
1110 else if (SCM_UNBNDP (secs) || SCM_FALSEP (secs))
28d77376 1111 time_ptr = 0;
0f2d19dd
JB
1112 else
1113 {
ae1b098b 1114 if (SCM_INUMP (secs))
a48a89bc
GH
1115 {
1116 timeout.tv_sec = SCM_INUM (secs);
1117 if (SCM_UNBNDP (usecs))
1118 timeout.tv_usec = 0;
1119 else
1120 {
3b3b36dd 1121 SCM_VALIDATE_INUM (5,usecs);
a48a89bc
GH
1122 timeout.tv_usec = SCM_INUM (usecs);
1123 }
1124 }
0f2d19dd 1125 else
a48a89bc 1126 {
1bbd0b84 1127 double fl = scm_num2dbl (secs, FUNC_NAME);
a48a89bc
GH
1128
1129 if (!SCM_UNBNDP (usecs))
c1bfcf60 1130 SCM_WRONG_TYPE_ARG (4, secs);
a48a89bc 1131 if (fl > LONG_MAX)
c1bfcf60 1132 SCM_OUT_OF_RANGE (4, secs);
a48a89bc
GH
1133 timeout.tv_sec = (long) fl;
1134 timeout.tv_usec = (long) ((fl - timeout.tv_sec) * 1000000);
1135 }
28d77376 1136 time_ptr = &timeout;
0f2d19dd
JB
1137 }
1138
28d77376 1139 {
44e8413c 1140#ifdef GUILE_ISELECT
28d77376
GH
1141 int rv = scm_internal_select (max_fd + 1,
1142 &read_set, &write_set, &except_set,
1143 time_ptr);
44e8413c 1144#else
28d77376
GH
1145 int rv = select (max_fd + 1,
1146 &read_set, &write_set, &except_set, time_ptr);
44e8413c 1147#endif
28d77376
GH
1148 if (rv < 0)
1149 SCM_SYSERROR;
1150 }
1afff620
KN
1151 return scm_list_3 (retrieve_select_type (&read_set, read_ports_ready, reads),
1152 retrieve_select_type (&write_set, write_ports_ready, writes),
1153 retrieve_select_type (&except_set, SCM_EOL, excepts));
0f2d19dd 1154}
1bbd0b84 1155#undef FUNC_NAME
f25f761d 1156#endif /* HAVE_SELECT */
0f2d19dd
JB
1157
1158\f
4c1feaa5 1159
82893676 1160#ifdef HAVE_FCNTL
af45e3b0 1161SCM_DEFINE (scm_fcntl, "fcntl", 2, 1, 0,
1bbd0b84 1162 (SCM object, SCM cmd, SCM value),
d3818c29
MD
1163 "Apply @var{command} to the specified file descriptor or the underlying\n"
1164 "file descriptor of the specified port. @var{value} is an optional\n"
1165 "integer argument.\n\n"
1166 "Values for @var{command} are:\n\n"
1167 "@table @code\n"
1168 "@item F_DUPFD\n"
1169 "Duplicate a file descriptor\n"
1170 "@item F_GETFD\n"
1171 "Get flags associated with the file descriptor.\n"
1172 "@item F_SETFD\n"
1173 "Set flags associated with the file descriptor to @var{value}.\n"
1174 "@item F_GETFL\n"
1175 "Get flags associated with the open file.\n"
1176 "@item F_SETFL\n"
1177 "Set flags associated with the open file to @var{value}\n"
1178 "@item F_GETOWN\n"
1179 "Get the process ID of a socket's owner, for @code{SIGIO} signals.\n"
1180 "@item F_SETOWN\n"
1181 "Set the process that owns a socket to @var{value}, for @code{SIGIO} signals.\n"
1182 "@item FD_CLOEXEC\n"
55892d87
NJ
1183 "The value used to indicate the \"close on exec\" flag with @code{F_GETFL} or\n"
1184 "@code{F_SETFL}.\n"
a3c8b9fc 1185 "@end table")
1bbd0b84 1186#define FUNC_NAME s_scm_fcntl
4c1feaa5
JB
1187{
1188 int rv;
6afcd3b2
GH
1189 int fdes;
1190 int ivalue;
4c1feaa5 1191
78446828
MV
1192 object = SCM_COERCE_OUTPORT (object);
1193
3b3b36dd 1194 SCM_VALIDATE_INUM (2,cmd);
0c95b57d 1195 if (SCM_OPFPORTP (object))
77a76b64 1196 fdes = SCM_FPORT_FDES (object);
6afcd3b2
GH
1197 else
1198 {
3b3b36dd 1199 SCM_VALIDATE_INUM (1,object);
6afcd3b2
GH
1200 fdes = SCM_INUM (object);
1201 }
af45e3b0
DH
1202
1203 if (SCM_UNBNDP (value)) {
6afcd3b2 1204 ivalue = 0;
af45e3b0
DH
1205 } else {
1206 SCM_VALIDATE_INUM_COPY (SCM_ARG3, value, ivalue);
1207 }
1208
77a76b64
JB
1209 SCM_SYSCALL (rv = fcntl (fdes, SCM_INUM (cmd), ivalue));
1210 if (rv == -1)
1bbd0b84 1211 SCM_SYSERROR;
4c1feaa5
JB
1212 return SCM_MAKINUM (rv);
1213}
1bbd0b84 1214#undef FUNC_NAME
82893676 1215#endif /* HAVE_FCNTL */
6afcd3b2 1216
a1ec6916 1217SCM_DEFINE (scm_fsync, "fsync", 1, 0, 0,
1bbd0b84 1218 (SCM object),
d3818c29
MD
1219 "Copies any unwritten data for the specified output file descriptor to disk.\n"
1220 "If @var{port/fd} is a port, its buffer is flushed before the underlying\n"
1221 "file descriptor is fsync'd.\n"
1222 "The return value is unspecified.")
1bbd0b84 1223#define FUNC_NAME s_scm_fsync
6afcd3b2
GH
1224{
1225 int fdes;
1226
78446828
MV
1227 object = SCM_COERCE_OUTPORT (object);
1228
0c95b57d 1229 if (SCM_OPFPORTP (object))
6afcd3b2 1230 {
affc96b5 1231 scm_flush (object);
77a76b64 1232 fdes = SCM_FPORT_FDES (object);
6afcd3b2
GH
1233 }
1234 else
1235 {
3b3b36dd 1236 SCM_VALIDATE_INUM (1,object);
6afcd3b2
GH
1237 fdes = SCM_INUM (object);
1238 }
1239 if (fsync (fdes) == -1)
1bbd0b84 1240 SCM_SYSERROR;
6afcd3b2
GH
1241 return SCM_UNSPECIFIED;
1242}
1bbd0b84 1243#undef FUNC_NAME
0f2d19dd 1244
f25f761d 1245#ifdef HAVE_SYMLINK
a1ec6916 1246SCM_DEFINE (scm_symlink, "symlink", 2, 0, 0,
1bbd0b84 1247 (SCM oldpath, SCM newpath),
d3818c29
MD
1248 "Create a symbolic link named @var{path-to} with the value (i.e., pointing to)\n"
1249 "@var{path-from}. The return value is unspecified.")
1bbd0b84 1250#define FUNC_NAME s_scm_symlink
0f2d19dd 1251{
0f2d19dd 1252 int val;
02b754d3 1253
a6d9e5ab
DH
1254 SCM_VALIDATE_STRING (1, oldpath);
1255 SCM_VALIDATE_STRING (2, newpath);
a6d9e5ab 1256 SCM_SYSCALL (val = symlink (SCM_STRING_CHARS (oldpath), SCM_STRING_CHARS (newpath)));
02b754d3 1257 if (val != 0)
1bbd0b84 1258 SCM_SYSERROR;
02b754d3 1259 return SCM_UNSPECIFIED;
0f2d19dd 1260}
1bbd0b84 1261#undef FUNC_NAME
f25f761d 1262#endif /* HAVE_SYMLINK */
0f2d19dd 1263
f25f761d 1264#ifdef HAVE_READLINK
a1ec6916 1265SCM_DEFINE (scm_readlink, "readlink", 1, 0, 0,
1bbd0b84 1266 (SCM path),
1e6808ea
MG
1267 "Return the value of the symbolic link named by @var{path} (a\n"
1268 "string), i.e., the file that the link points to.")
1bbd0b84 1269#define FUNC_NAME s_scm_readlink
0f2d19dd 1270{
6a738a25
JB
1271 int rv;
1272 int size = 100;
0f2d19dd
JB
1273 char *buf;
1274 SCM result;
a6d9e5ab 1275 SCM_VALIDATE_STRING (1, path);
1bbd0b84 1276 buf = scm_must_malloc (size, FUNC_NAME);
a6d9e5ab 1277 while ((rv = readlink (SCM_STRING_CHARS (path), buf, size)) == size)
0f2d19dd
JB
1278 {
1279 scm_must_free (buf);
1280 size *= 2;
1bbd0b84 1281 buf = scm_must_malloc (size, FUNC_NAME);
0f2d19dd 1282 }
02b754d3 1283 if (rv == -1)
1bbd0b84 1284 SCM_SYSERROR;
36284627 1285 result = scm_mem2string (buf, rv);
0f2d19dd 1286 scm_must_free (buf);
0f2d19dd 1287 return result;
0f2d19dd 1288}
1bbd0b84 1289#undef FUNC_NAME
f25f761d 1290#endif /* HAVE_READLINK */
0f2d19dd 1291
f25f761d 1292#ifdef HAVE_LSTAT
a1ec6916 1293SCM_DEFINE (scm_lstat, "lstat", 1, 0, 0,
1bbd0b84 1294 (SCM str),
d3818c29
MD
1295 "Similar to @code{stat}, but does not follow symbolic links, i.e.,\n"
1296 "it will return information about a symbolic link itself, not the \n"
1297 "file it points to. @var{path} must be a string.")
1bbd0b84 1298#define FUNC_NAME s_scm_lstat
0f2d19dd 1299{
02b754d3 1300 int rv;
0f2d19dd 1301 struct stat stat_temp;
02b754d3 1302
a6d9e5ab 1303 SCM_VALIDATE_STRING (1, str);
a6d9e5ab 1304 SCM_SYSCALL (rv = lstat (SCM_STRING_CHARS (str), &stat_temp));
02b754d3 1305 if (rv != 0)
3d8d56df
GH
1306 {
1307 int en = errno;
1308
5d2d2ffc 1309 SCM_SYSERROR_MSG ("~A: ~S",
1afff620 1310 scm_list_2 (scm_makfrom0str (strerror (errno)), str),
e0c08f17 1311 en);
3d8d56df 1312 }
02b754d3 1313 return scm_stat2scm(&stat_temp);
0f2d19dd 1314}
1bbd0b84 1315#undef FUNC_NAME
f25f761d 1316#endif /* HAVE_LSTAT */
0f2d19dd 1317
a1ec6916 1318SCM_DEFINE (scm_copy_file, "copy-file", 2, 0, 0,
1bbd0b84 1319 (SCM oldfile, SCM newfile),
d3818c29
MD
1320 "Copy the file specified by @var{path-from} to @var{path-to}.\n"
1321 "The return value is unspecified.")
1bbd0b84 1322#define FUNC_NAME s_scm_copy_file
0f2d19dd
JB
1323{
1324 int oldfd, newfd;
1325 int n;
77a76b64 1326 char buf[BUFSIZ];
0f2d19dd
JB
1327 struct stat oldstat;
1328
a6d9e5ab 1329 SCM_VALIDATE_STRING (1, oldfile);
a6d9e5ab 1330 SCM_VALIDATE_STRING (2, newfile);
a6d9e5ab 1331 if (stat (SCM_STRING_CHARS (oldfile), &oldstat) == -1)
1bbd0b84 1332 SCM_SYSERROR;
a6d9e5ab 1333 oldfd = open (SCM_STRING_CHARS (oldfile), O_RDONLY);
0f2d19dd 1334 if (oldfd == -1)
1bbd0b84 1335 SCM_SYSERROR;
02b754d3
GH
1336
1337 /* use POSIX flags instead of 07777?. */
a6d9e5ab 1338 newfd = open (SCM_STRING_CHARS (newfile), O_WRONLY | O_CREAT | O_TRUNC,
0f2d19dd
JB
1339 oldstat.st_mode & 07777);
1340 if (newfd == -1)
1bbd0b84 1341 SCM_SYSERROR;
02b754d3 1342
0f2d19dd
JB
1343 while ((n = read (oldfd, buf, sizeof buf)) > 0)
1344 if (write (newfd, buf, n) != n)
1345 {
1346 close (oldfd);
1347 close (newfd);
1bbd0b84 1348 SCM_SYSERROR;
0f2d19dd
JB
1349 }
1350 close (oldfd);
1351 if (close (newfd) == -1)
1bbd0b84 1352 SCM_SYSERROR;
02b754d3 1353 return SCM_UNSPECIFIED;
0f2d19dd 1354}
1bbd0b84 1355#undef FUNC_NAME
0f2d19dd
JB
1356
1357\f
6a738a25
JB
1358/* Filename manipulation */
1359
1360SCM scm_dot_string;
1361
a1ec6916 1362SCM_DEFINE (scm_dirname, "dirname", 1, 0, 0,
1bbd0b84 1363 (SCM filename),
fa6a543f
MG
1364 "Return the directory name component of the file name\n"
1365 "@var{filename}. If @var{filename} does not contain a directory\n"
1366 "component, @code{.} is returned.")
1bbd0b84 1367#define FUNC_NAME s_scm_dirname
6a738a25
JB
1368{
1369 char *s;
9fd38a3d
DH
1370 long int i;
1371 unsigned long int len;
1372
1373 SCM_VALIDATE_STRING (1,filename);
1374
34f0f2b8 1375 s = SCM_STRING_CHARS (filename);
9fd38a3d
DH
1376 len = SCM_STRING_LENGTH (filename);
1377
6a738a25 1378 i = len - 1;
82893676
MG
1379#ifdef __MINGW32__
1380 while (i >= 0 && (s[i] == '/' || s[i] == '\\')) --i;
1381 while (i >= 0 && (s[i] != '/' || s[i] != '\\')) --i;
1382 while (i >= 0 && (s[i] == '/' || s[i] == '\\')) --i;
1383#else
6a738a25
JB
1384 while (i >= 0 && s[i] == '/') --i;
1385 while (i >= 0 && s[i] != '/') --i;
1386 while (i >= 0 && s[i] == '/') --i;
82893676 1387#endif /* ndef __MINGW32__ */
6a738a25
JB
1388 if (i < 0)
1389 {
82893676
MG
1390#ifdef __MINGW32__
1391 if (len > 0 && (s[0] == '/' || s[0] == '\\'))
1392#else
6a738a25 1393 if (len > 0 && s[0] == '/')
82893676 1394#endif /* ndef __MINGW32__ */
d1ca2c64 1395 return scm_substring (filename, SCM_INUM0, SCM_MAKINUM (1));
6a738a25
JB
1396 else
1397 return scm_dot_string;
1398 }
1399 else
d1ca2c64 1400 return scm_substring (filename, SCM_INUM0, SCM_MAKINUM (i + 1));
6a738a25 1401}
1bbd0b84 1402#undef FUNC_NAME
6a738a25 1403
a1ec6916 1404SCM_DEFINE (scm_basename, "basename", 1, 1, 0,
1bbd0b84 1405 (SCM filename, SCM suffix),
fa6a543f
MG
1406 "Return the base name of the file name @var{filename}. The\n"
1407 "base name is the file name without any directory components.\n"
1408 "If @var{suffix} is privided, and is equal to the end of\n"
1409 "@var{basename}, it is removed also.")
1bbd0b84 1410#define FUNC_NAME s_scm_basename
6a738a25
JB
1411{
1412 char *f, *s = 0;
1413 int i, j, len, end;
9fd38a3d
DH
1414
1415 SCM_VALIDATE_STRING (1,filename);
34f0f2b8 1416 f = SCM_STRING_CHARS (filename);
9fd38a3d
DH
1417 len = SCM_STRING_LENGTH (filename);
1418
6a738a25
JB
1419 if (SCM_UNBNDP (suffix))
1420 j = -1;
1421 else
1422 {
9fd38a3d 1423 SCM_VALIDATE_STRING (2, suffix);
34f0f2b8 1424 s = SCM_STRING_CHARS (suffix);
9fd38a3d 1425 j = SCM_STRING_LENGTH (suffix) - 1;
6a738a25 1426 }
6a738a25 1427 i = len - 1;
82893676
MG
1428#ifdef __MINGW32__
1429 while (i >= 0 && (f[i] == '/' || f[i] == '\\')) --i;
1430#else
6a738a25 1431 while (i >= 0 && f[i] == '/') --i;
82893676 1432#endif /* ndef __MINGW32__ */
6a738a25
JB
1433 end = i;
1434 while (i >= 0 && j >= 0 && f[i] == s[j]) --i, --j;
1435 if (j == -1)
1436 end = i;
82893676
MG
1437#ifdef __MINGW32__
1438 while (i >= 0 && (f[i] != '/' || f[i] != '\\')) --i;
1439#else
6a738a25 1440 while (i >= 0 && f[i] != '/') --i;
82893676 1441#endif /* ndef __MINGW32__ */
6a738a25
JB
1442 if (i == end)
1443 {
82893676
MG
1444#ifdef __MINGW32__
1445 if (len > 0 && (f[0] == '/' || f[i] == '\\'))
1446#else
6a738a25 1447 if (len > 0 && f[0] == '/')
82893676 1448#endif /* ndef __MINGW32__ */
d1ca2c64 1449 return scm_substring (filename, SCM_INUM0, SCM_MAKINUM (1));
6a738a25
JB
1450 else
1451 return scm_dot_string;
1452 }
1453 else
d1ca2c64 1454 return scm_substring (filename, SCM_MAKINUM (i + 1), SCM_MAKINUM (end + 1));
6a738a25 1455}
1bbd0b84 1456#undef FUNC_NAME
6a738a25
JB
1457
1458
1459
1460\f
1cc91f1b 1461
0f2d19dd
JB
1462void
1463scm_init_filesys ()
0f2d19dd 1464{
e841c3e0
KN
1465 scm_tc16_dir = scm_make_smob_type ("directory", 0);
1466 scm_set_smob_free (scm_tc16_dir, scm_dir_free);
1467 scm_set_smob_print (scm_tc16_dir, scm_dir_print);
0f2d19dd 1468
a163dda9
MD
1469 scm_dot_string = scm_permanent_object (scm_makfrom0str ("."));
1470
3d8d56df 1471#ifdef O_RDONLY
86d31dfe 1472 scm_c_define ("O_RDONLY", scm_long2num (O_RDONLY));
3d8d56df
GH
1473#endif
1474#ifdef O_WRONLY
86d31dfe 1475 scm_c_define ("O_WRONLY", scm_long2num (O_WRONLY));
3d8d56df
GH
1476#endif
1477#ifdef O_RDWR
86d31dfe 1478 scm_c_define ("O_RDWR", scm_long2num (O_RDWR));
3d8d56df
GH
1479#endif
1480#ifdef O_CREAT
86d31dfe 1481 scm_c_define ("O_CREAT", scm_long2num (O_CREAT));
3d8d56df
GH
1482#endif
1483#ifdef O_EXCL
86d31dfe 1484 scm_c_define ("O_EXCL", scm_long2num (O_EXCL));
3d8d56df
GH
1485#endif
1486#ifdef O_NOCTTY
86d31dfe 1487 scm_c_define ("O_NOCTTY", scm_long2num (O_NOCTTY));
3d8d56df
GH
1488#endif
1489#ifdef O_TRUNC
86d31dfe 1490 scm_c_define ("O_TRUNC", scm_long2num (O_TRUNC));
3d8d56df
GH
1491#endif
1492#ifdef O_APPEND
86d31dfe 1493 scm_c_define ("O_APPEND", scm_long2num (O_APPEND));
3d8d56df 1494#endif
6afcd3b2 1495#ifdef O_NONBLOCK
86d31dfe 1496 scm_c_define ("O_NONBLOCK", scm_long2num (O_NONBLOCK));
3d8d56df
GH
1497#endif
1498#ifdef O_NDELAY
86d31dfe 1499 scm_c_define ("O_NDELAY", scm_long2num (O_NDELAY));
3d8d56df
GH
1500#endif
1501#ifdef O_SYNC
86d31dfe 1502 scm_c_define ("O_SYNC", scm_long2num (O_SYNC));
3d8d56df
GH
1503#endif
1504
4c1feaa5 1505#ifdef F_DUPFD
86d31dfe 1506 scm_c_define ("F_DUPFD", scm_long2num (F_DUPFD));
4c1feaa5
JB
1507#endif
1508#ifdef F_GETFD
86d31dfe 1509 scm_c_define ("F_GETFD", scm_long2num (F_GETFD));
4c1feaa5
JB
1510#endif
1511#ifdef F_SETFD
86d31dfe 1512 scm_c_define ("F_SETFD", scm_long2num (F_SETFD));
4c1feaa5
JB
1513#endif
1514#ifdef F_GETFL
86d31dfe 1515 scm_c_define ("F_GETFL", scm_long2num (F_GETFL));
4c1feaa5
JB
1516#endif
1517#ifdef F_SETFL
86d31dfe 1518 scm_c_define ("F_SETFL", scm_long2num (F_SETFL));
4c1feaa5
JB
1519#endif
1520#ifdef F_GETOWN
86d31dfe 1521 scm_c_define ("F_GETOWN", scm_long2num (F_GETOWN));
4c1feaa5
JB
1522#endif
1523#ifdef F_SETOWN
86d31dfe 1524 scm_c_define ("F_SETOWN", scm_long2num (F_SETOWN));
4c1feaa5
JB
1525#endif
1526#ifdef FD_CLOEXEC
86d31dfe 1527 scm_c_define ("FD_CLOEXEC", scm_long2num (FD_CLOEXEC));
bd9e24b3 1528#endif
3d8d56df 1529
8dc9439f 1530#ifndef SCM_MAGIC_SNARFER
a0599745 1531#include "libguile/filesys.x"
8dc9439f 1532#endif
0f2d19dd 1533}
89e00824
ML
1534
1535/*
1536 Local Variables:
1537 c-file-style: "gnu"
1538 End:
1539*/