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