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