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