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