Merge branch 'master' into boehm-demers-weiser-gc
[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
83079454
RB
27#if HAVE_CONFIG_H
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
a1ec6916 583SCM_DEFINE (scm_stat, "stat", 1, 0, 0,
1bbd0b84 584 (SCM object),
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"
591 "The object returned by @code{stat} can be passed as a single\n"
592 "parameter to the following procedures, all of which return\n"
593 "integers:\n"
594 "\n"
d3818c29
MD
595 "@table @code\n"
596 "@item stat:dev\n"
597 "The device containing the file.\n"
598 "@item stat:ino\n"
1e6808ea
MG
599 "The file serial number, which distinguishes this file from all\n"
600 "other files on the same device.\n"
d3818c29 601 "@item stat:mode\n"
1e6808ea
MG
602 "The mode of the file. This includes file type information and\n"
603 "the file permission bits. See @code{stat:type} and\n"
604 "@code{stat:perms} below.\n"
d3818c29
MD
605 "@item stat:nlink\n"
606 "The number of hard links to the file.\n"
607 "@item stat:uid\n"
608 "The user ID of the file's owner.\n"
609 "@item stat:gid\n"
610 "The group ID of the file.\n"
611 "@item stat:rdev\n"
612 "Device ID; this entry is defined only for character or block\n"
613 "special files.\n"
614 "@item stat:size\n"
615 "The size of a regular file in bytes.\n"
616 "@item stat:atime\n"
617 "The last access time for the file.\n"
618 "@item stat:mtime\n"
619 "The last modification time for the file.\n"
620 "@item stat:ctime\n"
621 "The last modification time for the attributes of the file.\n"
622 "@item stat:blksize\n"
1e6808ea
MG
623 "The optimal block size for reading or writing the file, in\n"
624 "bytes.\n"
d3818c29 625 "@item stat:blocks\n"
1e6808ea
MG
626 "The amount of disk space that the file occupies measured in\n"
627 "units of 512 byte blocks.\n"
628 "@end table\n"
629 "\n"
d3818c29 630 "In addition, the following procedures return the information\n"
1e6808ea
MG
631 "from stat:mode in a more convenient form:\n"
632 "\n"
d3818c29
MD
633 "@table @code\n"
634 "@item stat:type\n"
635 "A symbol representing the type of file. Possible values are\n"
1e6808ea
MG
636 "regular, directory, symlink, block-special, char-special, fifo,\n"
637 "socket and unknown\n"
d3818c29
MD
638 "@item stat:perms\n"
639 "An integer representing the access permission bits.\n"
640 "@end table")
1bbd0b84 641#define FUNC_NAME s_scm_stat
0f2d19dd 642{
6afcd3b2
GH
643 int rv;
644 int fdes;
2b829bbb 645 struct stat_or_stat64 stat_temp;
0f2d19dd 646
e11e83f3 647 if (scm_is_integer (object))
36284627 648 {
e0c73a1c 649#ifdef __MINGW32__
e11e83f3 650 SCM_SYSCALL (rv = fstat_Win32 (scm_to_int (object), &stat_temp));
e0c73a1c 651#else
2b829bbb 652 SCM_SYSCALL (rv = fstat_or_fstat64 (scm_to_int (object), &stat_temp));
e0c73a1c 653#endif
36284627 654 }
7f9994d9 655 else if (scm_is_string (object))
36284627 656 {
7f9994d9 657 char *file = scm_to_locale_string (object);
e0c73a1c 658#ifdef __MINGW32__
7f9994d9 659 char *p;
e0c73a1c
MV
660 p = file + strlen (file) - 1;
661 while (p > file && (*p == '/' || *p == '\\'))
662 *p-- = '\0';
7f9994d9 663#endif
2b829bbb 664 SCM_SYSCALL (rv = stat_or_stat64 (file, &stat_temp));
e0c73a1c 665 free (file);
36284627 666 }
1ea47048 667 else
0f2d19dd 668 {
36284627
DH
669 object = SCM_COERCE_OUTPORT (object);
670 SCM_VALIDATE_OPFPORT (1, object);
671 fdes = SCM_FPORT_FDES (object);
e0c73a1c
MV
672#ifdef __MINGW32__
673 SCM_SYSCALL (rv = fstat_Win32 (fdes, &stat_temp));
674#else
2b829bbb 675 SCM_SYSCALL (rv = fstat_or_fstat64 (fdes, &stat_temp));
e0c73a1c 676#endif
6afcd3b2 677 }
36284627 678
6afcd3b2 679 if (rv == -1)
3d8d56df
GH
680 {
681 int en = errno;
682
5d2d2ffc 683 SCM_SYSERROR_MSG ("~A: ~S",
3572cd6b 684 scm_list_2 (scm_strerror (scm_from_int (en)),
1afff620 685 object),
e0c08f17 686 en);
3d8d56df 687 }
02b754d3 688 return scm_stat2scm (&stat_temp);
0f2d19dd 689}
1bbd0b84 690#undef FUNC_NAME
0f2d19dd 691
0f2d19dd
JB
692\f
693/* {Modifying Directories}
694 */
695
82893676 696#ifdef HAVE_LINK
a1ec6916 697SCM_DEFINE (scm_link, "link", 2, 0, 0,
1bbd0b84 698 (SCM oldpath, SCM newpath),
6d36532c
GH
699 "Creates a new name @var{newpath} in the file system for the\n"
700 "file named by @var{oldpath}. If @var{oldpath} is a symbolic\n"
701 "link, the link may or may not be followed depending on the\n"
702 "system.")
1bbd0b84 703#define FUNC_NAME s_scm_link
0f2d19dd
JB
704{
705 int val;
02b754d3 706
1299a0f1
MV
707 STRING2_SYSCALL (oldpath, c_oldpath,
708 newpath, c_newpath,
709 val = link (c_oldpath, c_newpath));
02b754d3 710 if (val != 0)
1bbd0b84 711 SCM_SYSERROR;
02b754d3 712 return SCM_UNSPECIFIED;
0f2d19dd 713}
1bbd0b84 714#undef FUNC_NAME
82893676 715#endif /* HAVE_LINK */
0f2d19dd 716
1299a0f1
MV
717#ifdef HAVE_RENAME
718#define my_rename rename
719#else
720static int
721my_rename (const char *oldname, const char *newname)
722{
723 int rv;
0f2d19dd 724
1299a0f1
MV
725 SCM_SYSCALL (rv = link (oldname, newname));
726 if (rv == 0)
727 {
728 SCM_SYSCALL (rv = unlink (oldname));
729 if (rv != 0)
730 /* unlink failed. remove new name */
731 SCM_SYSCALL (unlink (newname));
732 }
733 return rv;
734}
735#endif
0f2d19dd 736
a1ec6916 737SCM_DEFINE (scm_rename, "rename-file", 2, 0, 0,
1bbd0b84 738 (SCM oldname, SCM newname),
6d36532c 739 "Renames the file specified by @var{oldname} to @var{newname}.\n"
d3818c29 740 "The return value is unspecified.")
1bbd0b84 741#define FUNC_NAME s_scm_rename
0f2d19dd
JB
742{
743 int rv;
1299a0f1
MV
744
745 STRING2_SYSCALL (oldname, c_oldname,
746 newname, c_newname,
747 rv = my_rename (c_oldname, c_newname));
02b754d3 748 if (rv != 0)
1bbd0b84 749 SCM_SYSERROR;
02b754d3 750 return SCM_UNSPECIFIED;
0f2d19dd 751}
1bbd0b84 752#undef FUNC_NAME
0f2d19dd
JB
753
754
3b3b36dd 755SCM_DEFINE (scm_delete_file, "delete-file", 1, 0, 0,
1bbd0b84 756 (SCM str),
d3818c29 757 "Deletes (or \"unlinks\") the file specified by @var{path}.")
1bbd0b84 758#define FUNC_NAME s_scm_delete_file
2f3ed1ba
JB
759{
760 int ans;
1299a0f1 761 STRING_SYSCALL (str, c_str, ans = unlink (c_str));
2f3ed1ba 762 if (ans != 0)
1bbd0b84 763 SCM_SYSERROR;
2f3ed1ba
JB
764 return SCM_UNSPECIFIED;
765}
1bbd0b84 766#undef FUNC_NAME
2f3ed1ba 767
f25f761d 768#ifdef HAVE_MKDIR
a1ec6916 769SCM_DEFINE (scm_mkdir, "mkdir", 1, 1, 0,
1bbd0b84 770 (SCM path, SCM mode),
d3818c29
MD
771 "Create a new directory named by @var{path}. If @var{mode} is omitted\n"
772 "then the permissions of the directory file are set using the current\n"
773 "umask. Otherwise they are set to the decimal value specified with\n"
774 "@var{mode}. The return value is unspecified.")
1bbd0b84 775#define FUNC_NAME s_scm_mkdir
0f2d19dd 776{
0f2d19dd
JB
777 int rv;
778 mode_t mask;
1299a0f1 779
0f2d19dd
JB
780 if (SCM_UNBNDP (mode))
781 {
782 mask = umask (0);
783 umask (mask);
1299a0f1 784 STRING_SYSCALL (path, c_path, rv = mkdir (c_path, 0777 ^ mask));
0f2d19dd
JB
785 }
786 else
787 {
1299a0f1 788 STRING_SYSCALL (path, c_path, rv = mkdir (c_path, scm_to_uint (mode)));
0f2d19dd 789 }
02b754d3 790 if (rv != 0)
1bbd0b84 791 SCM_SYSERROR;
02b754d3 792 return SCM_UNSPECIFIED;
0f2d19dd 793}
1bbd0b84 794#undef FUNC_NAME
f25f761d 795#endif /* HAVE_MKDIR */
0f2d19dd 796
f25f761d 797#ifdef HAVE_RMDIR
a1ec6916 798SCM_DEFINE (scm_rmdir, "rmdir", 1, 0, 0,
1bbd0b84 799 (SCM path),
d3818c29
MD
800 "Remove the existing directory named by @var{path}. The directory must\n"
801 "be empty for this to succeed. The return value is unspecified.")
1bbd0b84 802#define FUNC_NAME s_scm_rmdir
0f2d19dd 803{
0f2d19dd 804 int val;
02b754d3 805
1299a0f1 806 STRING_SYSCALL (path, c_path, val = rmdir (c_path));
02b754d3 807 if (val != 0)
1bbd0b84 808 SCM_SYSERROR;
02b754d3 809 return SCM_UNSPECIFIED;
0f2d19dd 810}
1bbd0b84 811#undef FUNC_NAME
f25f761d 812#endif
0f2d19dd
JB
813
814\f
30ea841d 815
0f2d19dd
JB
816/* {Examining Directories}
817 */
818
92c2555f 819scm_t_bits scm_tc16_dir;
0f2d19dd 820
30ea841d 821
a1ec6916 822SCM_DEFINE (scm_directory_stream_p, "directory-stream?", 1, 0, 0,
1bbd0b84 823 (SCM obj),
1e6808ea
MG
824 "Return a boolean indicating whether @var{object} is a directory\n"
825 "stream as returned by @code{opendir}.")
1bbd0b84 826#define FUNC_NAME s_scm_directory_stream_p
77242ff9 827{
7888309b 828 return scm_from_bool (SCM_DIRP (obj));
77242ff9 829}
1bbd0b84 830#undef FUNC_NAME
77242ff9 831
30ea841d 832
a1ec6916 833SCM_DEFINE (scm_opendir, "opendir", 1, 0, 0,
1bbd0b84 834 (SCM dirname),
d3818c29
MD
835 "Open the directory specified by @var{path} and return a directory\n"
836 "stream.")
1bbd0b84 837#define FUNC_NAME s_scm_opendir
0f2d19dd
JB
838{
839 DIR *ds;
1299a0f1 840 STRING_SYSCALL (dirname, c_dirname, ds = opendir (c_dirname));
02b754d3 841 if (ds == NULL)
1bbd0b84 842 SCM_SYSERROR;
30ea841d 843 SCM_RETURN_NEWSMOB (scm_tc16_dir | SCM_DIR_FLAG_OPEN, ds);
0f2d19dd 844}
1bbd0b84 845#undef FUNC_NAME
0f2d19dd
JB
846
847
9be808d8
KR
848/* FIXME: The glibc manual has a portability note that readdir_r may not
849 null-terminate its return string. The circumstances outlined for this
2b829bbb
KR
850 are not clear, nor is it clear what should be done about it. Lets use
851 NAMLEN and worry about what else should be done if/when someone can
852 figure it out. */
9be808d8 853
a1ec6916 854SCM_DEFINE (scm_readdir, "readdir", 1, 0, 0,
1bbd0b84 855 (SCM port),
d3818c29
MD
856 "Return (as a string) the next directory entry from the directory stream\n"
857 "@var{stream}. If there is no remaining entry to be read then the\n"
858 "end of file object is returned.")
1bbd0b84 859#define FUNC_NAME s_scm_readdir
0f2d19dd 860{
2b829bbb 861 struct dirent_or_dirent64 *rdent;
30ea841d
DH
862
863 SCM_VALIDATE_DIR (1, port);
864 if (!SCM_DIR_OPEN_P (port))
1afff620 865 SCM_MISC_ERROR ("Directory ~S is not open.", scm_list_1 (port));
30ea841d 866
9be808d8 867#if HAVE_READDIR_R
2b829bbb
KR
868 /* As noted in the glibc manual, on various systems (such as Solaris) the
869 d_name[] field is only 1 char and you're expected to size the dirent
870 buffer for readdir_r based on NAME_MAX. The SCM_MAX expressions below
871 effectively give either sizeof(d_name) or NAME_MAX+1, whichever is
872 bigger.
873
874 On solaris 10 there's no NAME_MAX constant, it's necessary to use
875 pathconf(). We prefer NAME_MAX though, since it should be a constant
876 and will therefore save a system call. We also prefer it since dirfd()
877 is not available everywhere.
878
879 An alternative to dirfd() would be to open() the directory and then use
880 fdopendir(), if the latter is available. That'd let us hold the fd
881 somewhere in the smob, or just the dirent size calculated once. */
882 {
883 struct dirent_or_dirent64 de; /* just for sizeof */
884 DIR *ds = (DIR *) SCM_CELL_WORD_1 (port);
885 size_t namlen;
886#ifdef NAME_MAX
887 char buf [SCM_MAX (sizeof (de),
888 sizeof (de) - sizeof (de.d_name) + NAME_MAX + 1)];
9be808d8 889#else
2b829bbb
KR
890 char *buf;
891 long name_max = fpathconf (dirfd (ds), _PC_NAME_MAX);
892 if (name_max == -1)
893 SCM_SYSERROR;
894 buf = alloca (SCM_MAX (sizeof (de),
895 sizeof (de) - sizeof (de.d_name) + name_max + 1));
9be808d8 896#endif
2b829bbb
KR
897
898 errno = 0;
899 SCM_SYSCALL (readdir_r_or_readdir64_r (ds, (struct dirent_or_dirent64 *) buf, &rdent));
9be808d8
KR
900 if (errno != 0)
901 SCM_SYSERROR;
2b829bbb
KR
902 if (! rdent)
903 return SCM_EOF_VAL;
904
905 namlen = NAMLEN (rdent);
30ea841d 906
cc95e00a 907 return (rdent ? scm_from_locale_stringn (rdent->d_name, NAMLEN (rdent))
9be808d8
KR
908 : SCM_EOF_VAL);
909 }
2b829bbb
KR
910#else
911 {
912 SCM ret;
913 scm_dynwind_begin (0);
914 scm_i_dynwind_pthread_mutex_lock (&scm_i_misc_mutex);
915
916 errno = 0;
917 SCM_SYSCALL (rdent = readdir_or_readdir64 ((DIR *) SCM_CELL_WORD_1 (port)));
918 if (errno != 0)
919 SCM_SYSERROR;
920
921 ret = (rdent ? scm_from_locale_stringn (rdent->d_name, NAMLEN (rdent))
922 : SCM_EOF_VAL);
923
924 scm_dynwind_end ();
925 return ret;
926 }
927#endif
0f2d19dd 928}
1bbd0b84 929#undef FUNC_NAME
0f2d19dd
JB
930
931
a1ec6916 932SCM_DEFINE (scm_rewinddir, "rewinddir", 1, 0, 0,
1bbd0b84 933 (SCM port),
d3818c29
MD
934 "Reset the directory port @var{stream} so that the next call to\n"
935 "@code{readdir} will return the first directory entry.")
1bbd0b84 936#define FUNC_NAME s_scm_rewinddir
0f2d19dd 937{
30ea841d
DH
938 SCM_VALIDATE_DIR (1, port);
939 if (!SCM_DIR_OPEN_P (port))
1afff620 940 SCM_MISC_ERROR ("Directory ~S is not open.", scm_list_1 (port));
30ea841d 941
4260a7fc 942 rewinddir ((DIR *) SCM_CELL_WORD_1 (port));
30ea841d 943
0f2d19dd
JB
944 return SCM_UNSPECIFIED;
945}
1bbd0b84 946#undef FUNC_NAME
0f2d19dd
JB
947
948
a1ec6916 949SCM_DEFINE (scm_closedir, "closedir", 1, 0, 0,
1bbd0b84 950 (SCM port),
d3818c29
MD
951 "Close the directory stream @var{stream}.\n"
952 "The return value is unspecified.")
1bbd0b84 953#define FUNC_NAME s_scm_closedir
0f2d19dd 954{
30ea841d 955 SCM_VALIDATE_DIR (1, port);
02b754d3 956
30ea841d 957 if (SCM_DIR_OPEN_P (port))
0f2d19dd 958 {
30ea841d
DH
959 int sts;
960
961 SCM_SYSCALL (sts = closedir ((DIR *) SCM_CELL_WORD_1 (port)));
962 if (sts != 0)
963 SCM_SYSERROR;
964
965 SCM_SET_CELL_WORD_0 (port, scm_tc16_dir);
0f2d19dd 966 }
30ea841d 967
02b754d3 968 return SCM_UNSPECIFIED;
0f2d19dd 969}
1bbd0b84 970#undef FUNC_NAME
0f2d19dd
JB
971
972
0f2d19dd 973static int
e81d98ec 974scm_dir_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 975{
f8b16091 976 scm_puts ("#<", port);
30ea841d 977 if (!SCM_DIR_OPEN_P (exp))
f8b16091 978 scm_puts ("closed: ", port);
0d03da62 979 scm_puts ("directory stream ", port);
0345e278 980 scm_uintprint (SCM_CELL_WORD_1 (exp), 16, port);
f8b16091 981 scm_putc ('>', port);
0f2d19dd
JB
982 return 1;
983}
984
1cc91f1b 985
1be6b49c 986static size_t
1bbd0b84 987scm_dir_free (SCM p)
0f2d19dd 988{
30ea841d 989 if (SCM_DIR_OPEN_P (p))
4260a7fc 990 closedir ((DIR *) SCM_CELL_WORD_1 (p));
0f2d19dd
JB
991 return 0;
992}
993
0f2d19dd
JB
994\f
995/* {Navigating Directories}
996 */
997
998
a1ec6916 999SCM_DEFINE (scm_chdir, "chdir", 1, 0, 0,
1bbd0b84 1000 (SCM str),
d3818c29
MD
1001 "Change the current working directory to @var{path}.\n"
1002 "The return value is unspecified.")
1bbd0b84 1003#define FUNC_NAME s_scm_chdir
0f2d19dd
JB
1004{
1005 int ans;
02b754d3 1006
1299a0f1 1007 STRING_SYSCALL (str, c_str, ans = chdir (c_str));
02b754d3 1008 if (ans != 0)
1bbd0b84 1009 SCM_SYSERROR;
02b754d3 1010 return SCM_UNSPECIFIED;
0f2d19dd 1011}
1bbd0b84 1012#undef FUNC_NAME
0f2d19dd 1013
f25f761d 1014#ifdef HAVE_GETCWD
a1ec6916 1015SCM_DEFINE (scm_getcwd, "getcwd", 0, 0, 0,
1bbd0b84 1016 (),
1e6808ea 1017 "Return the name of the current working directory.")
1bbd0b84 1018#define FUNC_NAME s_scm_getcwd
0f2d19dd 1019{
0f2d19dd 1020 char *rv;
1be6b49c 1021 size_t size = 100;
0f2d19dd
JB
1022 char *wd;
1023 SCM result;
1024
4c9419ac 1025 wd = scm_malloc (size);
0f2d19dd
JB
1026 while ((rv = getcwd (wd, size)) == 0 && errno == ERANGE)
1027 {
4c9419ac 1028 free (wd);
0f2d19dd 1029 size *= 2;
4c9419ac 1030 wd = scm_malloc (size);
0f2d19dd 1031 }
02b754d3 1032 if (rv == 0)
11e1db06
KR
1033 {
1034 int save_errno = errno;
1035 free (wd);
1036 errno = save_errno;
1037 SCM_SYSERROR;
1038 }
cc95e00a 1039 result = scm_from_locale_stringn (wd, strlen (wd));
4c9419ac 1040 free (wd);
0f2d19dd 1041 return result;
0f2d19dd 1042}
1bbd0b84 1043#undef FUNC_NAME
f25f761d 1044#endif /* HAVE_GETCWD */
0f2d19dd
JB
1045
1046\f
1047
28d77376
GH
1048#ifdef HAVE_SELECT
1049
1050/* check that element is a port or file descriptor. if it's a port
1051 and its buffer is ready for use, add it to the ports_ready list.
1052 otherwise add its file descriptor to *set. the type of list can be
1053 determined from pos: SCM_ARG1 for reads, SCM_ARG2 for writes,
1054 SCM_ARG3 for excepts. */
cafc12ff 1055static int
28d77376 1056set_element (SELECT_TYPE *set, SCM *ports_ready, SCM element, int pos)
a48a89bc 1057{
cafc12ff 1058 int fd;
d831b039 1059
e11e83f3 1060 if (scm_is_integer (element))
28d77376 1061 {
e11e83f3 1062 fd = scm_to_int (element);
28d77376
GH
1063 }
1064 else
1065 {
1066 int use_buf = 0;
1067
1068 element = SCM_COERCE_OUTPORT (element);
1069 SCM_ASSERT (SCM_OPFPORTP (element), element, pos, "select");
1070 if (pos == SCM_ARG1)
1071 {
1072 /* check whether port has buffered input. */
92c2555f 1073 scm_t_port *pt = SCM_PTAB_ENTRY (element);
28d77376
GH
1074
1075 if (pt->read_pos < pt->read_end)
1076 use_buf = 1;
1077 }
1078 else if (pos == SCM_ARG2)
1079 {
1080 /* check whether port's output buffer has room. */
92c2555f 1081 scm_t_port *pt = SCM_PTAB_ENTRY (element);
28d77376
GH
1082
1083 /* > 1 since writing the last byte in the buffer causes flush. */
1084 if (pt->write_end - pt->write_pos > 1)
1085 use_buf = 1;
1086 }
1087 fd = use_buf ? -1 : SCM_FPORT_FDES (element);
1088 }
1089 if (fd == -1)
1090 *ports_ready = scm_cons (element, *ports_ready);
1091 else
1092 FD_SET (fd, set);
cafc12ff 1093 return fd;
a48a89bc 1094}
1cc91f1b 1095
28d77376
GH
1096/* check list_or_vec, a list or vector of ports or file descriptors,
1097 adding each member to either the ports_ready list (if it's a port
1098 with a usable buffer) or to *set. the kind of list_or_vec can be
1099 determined from pos: SCM_ARG1 for reads, SCM_ARG2 for writes,
1100 SCM_ARG3 for excepts. */
cafc12ff 1101static int
28d77376 1102fill_select_type (SELECT_TYPE *set, SCM *ports_ready, SCM list_or_vec, int pos)
0f2d19dd 1103{
28d77376
GH
1104 int max_fd = 0;
1105
4057a3e0 1106 if (scm_is_simple_vector (list_or_vec))
0f2d19dd 1107 {
4057a3e0 1108 int i = SCM_SIMPLE_VECTOR_LENGTH (list_or_vec);
a48a89bc 1109
28d77376 1110 while (--i >= 0)
a48a89bc 1111 {
4057a3e0
MV
1112 int fd = set_element (set, ports_ready,
1113 SCM_SIMPLE_VECTOR_REF (list_or_vec, i), pos);
28d77376 1114
cafc12ff
MD
1115 if (fd > max_fd)
1116 max_fd = fd;
a48a89bc
GH
1117 }
1118 }
1119 else
1120 {
c96d76b8 1121 while (!SCM_NULL_OR_NIL_P (list_or_vec))
a48a89bc 1122 {
28d77376
GH
1123 int fd = set_element (set, ports_ready, SCM_CAR (list_or_vec), pos);
1124
cafc12ff
MD
1125 if (fd > max_fd)
1126 max_fd = fd;
28d77376 1127 list_or_vec = SCM_CDR (list_or_vec);
a48a89bc 1128 }
0f2d19dd 1129 }
cafc12ff
MD
1130
1131 return max_fd;
0f2d19dd
JB
1132}
1133
28d77376
GH
1134/* if element (a file descriptor or port) appears in *set, cons it to
1135 list. return list. */
a48a89bc
GH
1136static SCM
1137get_element (SELECT_TYPE *set, SCM element, SCM list)
1138{
28d77376
GH
1139 int fd;
1140
e11e83f3 1141 if (scm_is_integer (element))
a48a89bc 1142 {
e11e83f3 1143 fd = scm_to_int (element);
a48a89bc 1144 }
28d77376 1145 else
a48a89bc 1146 {
28d77376 1147 fd = SCM_FPORT_FDES (SCM_COERCE_OUTPORT (element));
a48a89bc 1148 }
28d77376
GH
1149 if (FD_ISSET (fd, set))
1150 list = scm_cons (element, list);
a48a89bc
GH
1151 return list;
1152}
1cc91f1b 1153
28d77376
GH
1154/* construct component of scm_select return value.
1155 set: pointer to set of file descriptors found by select to be ready
1156 ports_ready: ports ready due to buffering
1157 list_or_vec: original list/vector handed to scm_select.
1158 the return value is a list/vector of ready ports/file descriptors.
1159 works by finding the objects in list which correspond to members of
1160 *set and appending them to ports_ready. result is converted to a
1161 vector if list_or_vec is a vector. */
0f2d19dd 1162static SCM
28d77376 1163retrieve_select_type (SELECT_TYPE *set, SCM ports_ready, SCM list_or_vec)
0f2d19dd 1164{
28d77376 1165 SCM answer_list = ports_ready;
a48a89bc 1166
4057a3e0 1167 if (scm_is_simple_vector (list_or_vec))
0f2d19dd 1168 {
4057a3e0 1169 int i = SCM_SIMPLE_VECTOR_LENGTH (list_or_vec);
a48a89bc 1170
28d77376 1171 while (--i >= 0)
0f2d19dd 1172 {
4057a3e0
MV
1173 answer_list = get_element (set,
1174 SCM_SIMPLE_VECTOR_REF (list_or_vec, i),
1175 answer_list);
0f2d19dd 1176 }
a48a89bc
GH
1177 return scm_vector (answer_list);
1178 }
1179 else
1180 {
28d77376 1181 /* list_or_vec must be a list. */
c96d76b8 1182 while (!SCM_NULL_OR_NIL_P (list_or_vec))
0f2d19dd 1183 {
28d77376
GH
1184 answer_list = get_element (set, SCM_CAR (list_or_vec), answer_list);
1185 list_or_vec = SCM_CDR (list_or_vec);
0f2d19dd 1186 }
a48a89bc 1187 return answer_list;
0f2d19dd 1188 }
0f2d19dd
JB
1189}
1190
1bbd0b84 1191/* Static helper functions above refer to s_scm_select directly as s_select */
a1ec6916 1192SCM_DEFINE (scm_select, "select", 3, 2, 0,
1bbd0b84 1193 (SCM reads, SCM writes, SCM excepts, SCM secs, SCM usecs),
28d77376 1194 "This procedure has a variety of uses: waiting for the ability\n"
bb2c02f2 1195 "to provide input, accept output, or the existence of\n"
28d77376
GH
1196 "exceptional conditions on a collection of ports or file\n"
1197 "descriptors, or waiting for a timeout to occur.\n"
1198 "It also returns if interrupted by a signal.\n\n"
1199 "@var{reads}, @var{writes} and @var{excepts} can be lists or\n"
1200 "vectors, with each member a port or a file descriptor.\n"
1201 "The value returned is a list of three corresponding\n"
1202 "lists or vectors containing only the members which meet the\n"
1203 "specified requirement. The ability of port buffers to\n"
1204 "provide input or accept output is taken into account.\n"
1205 "Ordering of the input lists or vectors is not preserved.\n\n"
1206 "The optional arguments @var{secs} and @var{usecs} specify the\n"
1207 "timeout. Either @var{secs} can be specified alone, as\n"
1208 "either an integer or a real number, or both @var{secs} and\n"
1209 "@var{usecs} can be specified as integers, in which case\n"
1210 "@var{usecs} is an additional timeout expressed in\n"
1211 "microseconds. If @var{secs} is omitted or is @code{#f} then\n"
1212 "select will wait for as long as it takes for one of the other\n"
1213 "conditions to be satisfied.\n\n"
1214 "The scsh version of @code{select} differs as follows:\n"
1215 "Only vectors are accepted for the first three arguments.\n"
1216 "The @var{usecs} argument is not supported.\n"
1217 "Multiple values are returned instead of a list.\n"
1218 "Duplicates in the input vectors appear only once in output.\n"
9401323e 1219 "An additional @code{select!} interface is provided.")
1bbd0b84 1220#define FUNC_NAME s_scm_select
0f2d19dd 1221{
0f2d19dd 1222 struct timeval timeout;
28d77376 1223 struct timeval * time_ptr;
0f2d19dd
JB
1224 SELECT_TYPE read_set;
1225 SELECT_TYPE write_set;
1226 SELECT_TYPE except_set;
28d77376
GH
1227 int read_count;
1228 int write_count;
1229 int except_count;
1230 /* these lists accumulate ports which are ready due to buffering.
1231 their file descriptors don't need to be added to the select sets. */
1232 SCM read_ports_ready = SCM_EOL;
1233 SCM write_ports_ready = SCM_EOL;
1234 int max_fd;
1235
4057a3e0 1236 if (scm_is_simple_vector (reads))
28d77376 1237 {
4057a3e0 1238 read_count = SCM_SIMPLE_VECTOR_LENGTH (reads);
28d77376
GH
1239 }
1240 else
1241 {
1242 read_count = scm_ilength (reads);
1243 SCM_ASSERT (read_count >= 0, reads, SCM_ARG1, FUNC_NAME);
1244 }
4057a3e0 1245 if (scm_is_simple_vector (writes))
28d77376 1246 {
4057a3e0 1247 write_count = SCM_SIMPLE_VECTOR_LENGTH (writes);
28d77376
GH
1248 }
1249 else
1250 {
1251 write_count = scm_ilength (writes);
1252 SCM_ASSERT (write_count >= 0, writes, SCM_ARG2, FUNC_NAME);
1253 }
4057a3e0 1254 if (scm_is_simple_vector (excepts))
28d77376 1255 {
4057a3e0 1256 except_count = SCM_SIMPLE_VECTOR_LENGTH (excepts);
28d77376
GH
1257 }
1258 else
1259 {
1260 except_count = scm_ilength (excepts);
1261 SCM_ASSERT (except_count >= 0, excepts, SCM_ARG3, FUNC_NAME);
1262 }
0f2d19dd
JB
1263
1264 FD_ZERO (&read_set);
1265 FD_ZERO (&write_set);
1266 FD_ZERO (&except_set);
1267
28d77376
GH
1268 max_fd = fill_select_type (&read_set, &read_ports_ready, reads, SCM_ARG1);
1269
1270 {
1271 int write_max = fill_select_type (&write_set, &write_ports_ready,
1272 writes, SCM_ARG2);
1273 int except_max = fill_select_type (&except_set, NULL,
1274 excepts, SCM_ARG3);
1275
1276 if (write_max > max_fd)
1277 max_fd = write_max;
1278 if (except_max > max_fd)
1279 max_fd = except_max;
1280 }
0f2d19dd 1281
ae1b098b
GH
1282 /* if there's a port with a ready buffer, don't block, just
1283 check for ready file descriptors. */
d2e53ed6 1284 if (!scm_is_null (read_ports_ready) || !scm_is_null (write_ports_ready))
ae1b098b
GH
1285 {
1286 timeout.tv_sec = 0;
1287 timeout.tv_usec = 0;
1288 time_ptr = &timeout;
1289 }
7888309b 1290 else if (SCM_UNBNDP (secs) || scm_is_false (secs))
28d77376 1291 time_ptr = 0;
0f2d19dd
JB
1292 else
1293 {
a55c2b68 1294 if (scm_is_unsigned_integer (secs, 0, ULONG_MAX))
a48a89bc 1295 {
a55c2b68 1296 timeout.tv_sec = scm_to_ulong (secs);
a48a89bc
GH
1297 if (SCM_UNBNDP (usecs))
1298 timeout.tv_usec = 0;
1299 else
a55c2b68 1300 timeout.tv_usec = scm_to_long (usecs);
a48a89bc 1301 }
0f2d19dd 1302 else
a48a89bc 1303 {
d9a67fc4 1304 double fl = scm_to_double (secs);
a48a89bc
GH
1305
1306 if (!SCM_UNBNDP (usecs))
c1bfcf60 1307 SCM_WRONG_TYPE_ARG (4, secs);
a48a89bc 1308 if (fl > LONG_MAX)
c1bfcf60 1309 SCM_OUT_OF_RANGE (4, secs);
a48a89bc
GH
1310 timeout.tv_sec = (long) fl;
1311 timeout.tv_usec = (long) ((fl - timeout.tv_sec) * 1000000);
1312 }
28d77376 1313 time_ptr = &timeout;
0f2d19dd
JB
1314 }
1315
28d77376 1316 {
9de87eea
MV
1317 int rv = scm_std_select (max_fd + 1,
1318 &read_set, &write_set, &except_set,
1319 time_ptr);
28d77376
GH
1320 if (rv < 0)
1321 SCM_SYSERROR;
1322 }
1afff620
KN
1323 return scm_list_3 (retrieve_select_type (&read_set, read_ports_ready, reads),
1324 retrieve_select_type (&write_set, write_ports_ready, writes),
1325 retrieve_select_type (&except_set, SCM_EOL, excepts));
0f2d19dd 1326}
1bbd0b84 1327#undef FUNC_NAME
f25f761d 1328#endif /* HAVE_SELECT */
0f2d19dd
JB
1329
1330\f
4c1feaa5 1331
82893676 1332#ifdef HAVE_FCNTL
af45e3b0 1333SCM_DEFINE (scm_fcntl, "fcntl", 2, 1, 0,
1bbd0b84 1334 (SCM object, SCM cmd, SCM value),
d3818c29
MD
1335 "Apply @var{command} to the specified file descriptor or the underlying\n"
1336 "file descriptor of the specified port. @var{value} is an optional\n"
1337 "integer argument.\n\n"
1338 "Values for @var{command} are:\n\n"
1339 "@table @code\n"
1340 "@item F_DUPFD\n"
1341 "Duplicate a file descriptor\n"
1342 "@item F_GETFD\n"
1343 "Get flags associated with the file descriptor.\n"
1344 "@item F_SETFD\n"
1345 "Set flags associated with the file descriptor to @var{value}.\n"
1346 "@item F_GETFL\n"
1347 "Get flags associated with the open file.\n"
1348 "@item F_SETFL\n"
1349 "Set flags associated with the open file to @var{value}\n"
1350 "@item F_GETOWN\n"
1351 "Get the process ID of a socket's owner, for @code{SIGIO} signals.\n"
1352 "@item F_SETOWN\n"
1353 "Set the process that owns a socket to @var{value}, for @code{SIGIO} signals.\n"
1354 "@item FD_CLOEXEC\n"
55892d87
NJ
1355 "The value used to indicate the \"close on exec\" flag with @code{F_GETFL} or\n"
1356 "@code{F_SETFL}.\n"
a3c8b9fc 1357 "@end table")
1bbd0b84 1358#define FUNC_NAME s_scm_fcntl
4c1feaa5
JB
1359{
1360 int rv;
6afcd3b2
GH
1361 int fdes;
1362 int ivalue;
4c1feaa5 1363
78446828
MV
1364 object = SCM_COERCE_OUTPORT (object);
1365
0c95b57d 1366 if (SCM_OPFPORTP (object))
77a76b64 1367 fdes = SCM_FPORT_FDES (object);
6afcd3b2 1368 else
a55c2b68 1369 fdes = scm_to_int (object);
af45e3b0 1370
a55c2b68 1371 if (SCM_UNBNDP (value))
6afcd3b2 1372 ivalue = 0;
a55c2b68
MV
1373 else
1374 ivalue = scm_to_int (value);
af45e3b0 1375
a55c2b68 1376 SCM_SYSCALL (rv = fcntl (fdes, scm_to_int (cmd), ivalue));
77a76b64 1377 if (rv == -1)
1bbd0b84 1378 SCM_SYSERROR;
a55c2b68 1379 return scm_from_int (rv);
4c1feaa5 1380}
1bbd0b84 1381#undef FUNC_NAME
82893676 1382#endif /* HAVE_FCNTL */
6afcd3b2 1383
a1ec6916 1384SCM_DEFINE (scm_fsync, "fsync", 1, 0, 0,
1bbd0b84 1385 (SCM object),
d3818c29
MD
1386 "Copies any unwritten data for the specified output file descriptor to disk.\n"
1387 "If @var{port/fd} is a port, its buffer is flushed before the underlying\n"
1388 "file descriptor is fsync'd.\n"
1389 "The return value is unspecified.")
1bbd0b84 1390#define FUNC_NAME s_scm_fsync
6afcd3b2
GH
1391{
1392 int fdes;
1393
78446828
MV
1394 object = SCM_COERCE_OUTPORT (object);
1395
0c95b57d 1396 if (SCM_OPFPORTP (object))
6afcd3b2 1397 {
affc96b5 1398 scm_flush (object);
77a76b64 1399 fdes = SCM_FPORT_FDES (object);
6afcd3b2
GH
1400 }
1401 else
a55c2b68
MV
1402 fdes = scm_to_int (object);
1403
6afcd3b2 1404 if (fsync (fdes) == -1)
1bbd0b84 1405 SCM_SYSERROR;
6afcd3b2
GH
1406 return SCM_UNSPECIFIED;
1407}
1bbd0b84 1408#undef FUNC_NAME
0f2d19dd 1409
f25f761d 1410#ifdef HAVE_SYMLINK
a1ec6916 1411SCM_DEFINE (scm_symlink, "symlink", 2, 0, 0,
1bbd0b84 1412 (SCM oldpath, SCM newpath),
d3818c29
MD
1413 "Create a symbolic link named @var{path-to} with the value (i.e., pointing to)\n"
1414 "@var{path-from}. The return value is unspecified.")
1bbd0b84 1415#define FUNC_NAME s_scm_symlink
0f2d19dd 1416{
0f2d19dd 1417 int val;
02b754d3 1418
1299a0f1
MV
1419 STRING2_SYSCALL (oldpath, c_oldpath,
1420 newpath, c_newpath,
1421 val = symlink (c_oldpath, c_newpath));
02b754d3 1422 if (val != 0)
1bbd0b84 1423 SCM_SYSERROR;
02b754d3 1424 return SCM_UNSPECIFIED;
0f2d19dd 1425}
1bbd0b84 1426#undef FUNC_NAME
f25f761d 1427#endif /* HAVE_SYMLINK */
0f2d19dd 1428
f25f761d 1429#ifdef HAVE_READLINK
a1ec6916 1430SCM_DEFINE (scm_readlink, "readlink", 1, 0, 0,
1bbd0b84 1431 (SCM path),
1e6808ea
MG
1432 "Return the value of the symbolic link named by @var{path} (a\n"
1433 "string), i.e., the file that the link points to.")
1bbd0b84 1434#define FUNC_NAME s_scm_readlink
0f2d19dd 1435{
6a738a25
JB
1436 int rv;
1437 int size = 100;
0f2d19dd
JB
1438 char *buf;
1439 SCM result;
1299a0f1
MV
1440 char *c_path;
1441
661ae7ab 1442 scm_dynwind_begin (0);
1299a0f1
MV
1443
1444 c_path = scm_to_locale_string (path);
661ae7ab 1445 scm_dynwind_free (c_path);
1299a0f1 1446
4c9419ac 1447 buf = scm_malloc (size);
1299a0f1
MV
1448
1449 while ((rv = readlink (c_path, buf, size)) == size)
0f2d19dd 1450 {
4c9419ac 1451 free (buf);
0f2d19dd 1452 size *= 2;
4c9419ac 1453 buf = scm_malloc (size);
0f2d19dd 1454 }
02b754d3 1455 if (rv == -1)
11e1db06
KR
1456 {
1457 int save_errno = errno;
1458 free (buf);
1459 errno = save_errno;
1460 SCM_SYSERROR;
1461 }
1299a0f1
MV
1462 result = scm_take_locale_stringn (buf, rv);
1463
661ae7ab 1464 scm_dynwind_end ();
0f2d19dd 1465 return result;
0f2d19dd 1466}
1bbd0b84 1467#undef FUNC_NAME
f25f761d 1468#endif /* HAVE_READLINK */
0f2d19dd 1469
f25f761d 1470#ifdef HAVE_LSTAT
a1ec6916 1471SCM_DEFINE (scm_lstat, "lstat", 1, 0, 0,
1bbd0b84 1472 (SCM str),
d3818c29 1473 "Similar to @code{stat}, but does not follow symbolic links, i.e.,\n"
9401323e 1474 "it will return information about a symbolic link itself, not the\n"
d3818c29 1475 "file it points to. @var{path} must be a string.")
1bbd0b84 1476#define FUNC_NAME s_scm_lstat
0f2d19dd 1477{
02b754d3 1478 int rv;
2b829bbb 1479 struct stat_or_stat64 stat_temp;
02b754d3 1480
2b829bbb 1481 STRING_SYSCALL (str, c_str, rv = lstat_or_lstat64 (c_str, &stat_temp));
02b754d3 1482 if (rv != 0)
3d8d56df
GH
1483 {
1484 int en = errno;
1485
5d2d2ffc 1486 SCM_SYSERROR_MSG ("~A: ~S",
3572cd6b 1487 scm_list_2 (scm_strerror (scm_from_int (en)), str),
e0c08f17 1488 en);
3d8d56df 1489 }
1299a0f1 1490 return scm_stat2scm (&stat_temp);
0f2d19dd 1491}
1bbd0b84 1492#undef FUNC_NAME
f25f761d 1493#endif /* HAVE_LSTAT */
0f2d19dd 1494
a1ec6916 1495SCM_DEFINE (scm_copy_file, "copy-file", 2, 0, 0,
1bbd0b84 1496 (SCM oldfile, SCM newfile),
d3818c29
MD
1497 "Copy the file specified by @var{path-from} to @var{path-to}.\n"
1498 "The return value is unspecified.")
1bbd0b84 1499#define FUNC_NAME s_scm_copy_file
0f2d19dd 1500{
1299a0f1 1501 char *c_oldfile, *c_newfile;
0f2d19dd 1502 int oldfd, newfd;
37eb673b 1503 int n, rv;
77a76b64 1504 char buf[BUFSIZ];
2b829bbb 1505 struct stat_or_stat64 oldstat;
0f2d19dd 1506
661ae7ab 1507 scm_dynwind_begin (0);
1299a0f1
MV
1508
1509 c_oldfile = scm_to_locale_string (oldfile);
661ae7ab 1510 scm_dynwind_free (c_oldfile);
1299a0f1 1511 c_newfile = scm_to_locale_string (newfile);
661ae7ab 1512 scm_dynwind_free (c_newfile);
37eb673b 1513
2b829bbb 1514 oldfd = open_or_open64 (c_oldfile, O_RDONLY);
0f2d19dd 1515 if (oldfd == -1)
1bbd0b84 1516 SCM_SYSERROR;
02b754d3 1517
37eb673b
KR
1518#ifdef __MINGW32__
1519 SCM_SYSCALL (rv = fstat_Win32 (oldfd, &oldstat));
1520#else
2b829bbb 1521 SCM_SYSCALL (rv = fstat_or_fstat64 (oldfd, &oldstat));
37eb673b
KR
1522#endif
1523 if (rv == -1)
1524 goto err_close_oldfd;
1525
02b754d3 1526 /* use POSIX flags instead of 07777?. */
2b829bbb
KR
1527 newfd = open_or_open64 (c_newfile, O_WRONLY | O_CREAT | O_TRUNC,
1528 oldstat.st_mode & 07777);
0f2d19dd 1529 if (newfd == -1)
01046395 1530 {
37eb673b 1531 err_close_oldfd:
01046395
KR
1532 close (oldfd);
1533 SCM_SYSERROR;
1534 }
02b754d3 1535
0f2d19dd
JB
1536 while ((n = read (oldfd, buf, sizeof buf)) > 0)
1537 if (write (newfd, buf, n) != n)
1538 {
1539 close (oldfd);
1540 close (newfd);
1bbd0b84 1541 SCM_SYSERROR;
0f2d19dd
JB
1542 }
1543 close (oldfd);
1544 if (close (newfd) == -1)
1bbd0b84 1545 SCM_SYSERROR;
1299a0f1 1546
661ae7ab 1547 scm_dynwind_end ();
02b754d3 1548 return SCM_UNSPECIFIED;
0f2d19dd 1549}
1bbd0b84 1550#undef FUNC_NAME
0f2d19dd
JB
1551
1552\f
6a738a25
JB
1553/* Filename manipulation */
1554
1555SCM scm_dot_string;
1556
a1ec6916 1557SCM_DEFINE (scm_dirname, "dirname", 1, 0, 0,
1bbd0b84 1558 (SCM filename),
fa6a543f
MG
1559 "Return the directory name component of the file name\n"
1560 "@var{filename}. If @var{filename} does not contain a directory\n"
1561 "component, @code{.} is returned.")
1bbd0b84 1562#define FUNC_NAME s_scm_dirname
6a738a25 1563{
cc95e00a 1564 const char *s;
9fd38a3d
DH
1565 long int i;
1566 unsigned long int len;
1567
34d19ef6 1568 SCM_VALIDATE_STRING (1, filename);
9fd38a3d 1569
cc95e00a
MV
1570 s = scm_i_string_chars (filename);
1571 len = scm_i_string_length (filename);
9fd38a3d 1572
6a738a25 1573 i = len - 1;
82893676
MG
1574#ifdef __MINGW32__
1575 while (i >= 0 && (s[i] == '/' || s[i] == '\\')) --i;
e0c73a1c 1576 while (i >= 0 && (s[i] != '/' && s[i] != '\\')) --i;
82893676
MG
1577 while (i >= 0 && (s[i] == '/' || s[i] == '\\')) --i;
1578#else
6a738a25
JB
1579 while (i >= 0 && s[i] == '/') --i;
1580 while (i >= 0 && s[i] != '/') --i;
1581 while (i >= 0 && s[i] == '/') --i;
82893676 1582#endif /* ndef __MINGW32__ */
6a738a25
JB
1583 if (i < 0)
1584 {
82893676
MG
1585#ifdef __MINGW32__
1586 if (len > 0 && (s[0] == '/' || s[0] == '\\'))
1587#else
6a738a25 1588 if (len > 0 && s[0] == '/')
82893676 1589#endif /* ndef __MINGW32__ */
cc95e00a 1590 return scm_c_substring (filename, 0, 1);
6a738a25
JB
1591 else
1592 return scm_dot_string;
1593 }
1594 else
cc95e00a 1595 return scm_c_substring (filename, 0, i + 1);
6a738a25 1596}
1bbd0b84 1597#undef FUNC_NAME
6a738a25 1598
a1ec6916 1599SCM_DEFINE (scm_basename, "basename", 1, 1, 0,
1bbd0b84 1600 (SCM filename, SCM suffix),
fa6a543f
MG
1601 "Return the base name of the file name @var{filename}. The\n"
1602 "base name is the file name without any directory components.\n"
bb2c02f2 1603 "If @var{suffix} is provided, and is equal to the end of\n"
fa6a543f 1604 "@var{basename}, it is removed also.")
1bbd0b84 1605#define FUNC_NAME s_scm_basename
6a738a25 1606{
cc95e00a 1607 const char *f, *s = 0;
6a738a25 1608 int i, j, len, end;
9fd38a3d 1609
34d19ef6 1610 SCM_VALIDATE_STRING (1, filename);
cc95e00a
MV
1611 f = scm_i_string_chars (filename);
1612 len = scm_i_string_length (filename);
9fd38a3d 1613
6a738a25
JB
1614 if (SCM_UNBNDP (suffix))
1615 j = -1;
1616 else
1617 {
9fd38a3d 1618 SCM_VALIDATE_STRING (2, suffix);
cc95e00a
MV
1619 s = scm_i_string_chars (suffix);
1620 j = scm_i_string_length (suffix) - 1;
6a738a25 1621 }
6a738a25 1622 i = len - 1;
82893676
MG
1623#ifdef __MINGW32__
1624 while (i >= 0 && (f[i] == '/' || f[i] == '\\')) --i;
1625#else
6a738a25 1626 while (i >= 0 && f[i] == '/') --i;
82893676 1627#endif /* ndef __MINGW32__ */
6a738a25
JB
1628 end = i;
1629 while (i >= 0 && j >= 0 && f[i] == s[j]) --i, --j;
1630 if (j == -1)
1631 end = i;
82893676 1632#ifdef __MINGW32__
2e945bcc 1633 while (i >= 0 && f[i] != '/' && f[i] != '\\') --i;
82893676 1634#else
6a738a25 1635 while (i >= 0 && f[i] != '/') --i;
82893676 1636#endif /* ndef __MINGW32__ */
6a738a25
JB
1637 if (i == end)
1638 {
82893676 1639#ifdef __MINGW32__
2e945bcc 1640 if (len > 0 && (f[0] == '/' || f[0] == '\\'))
82893676 1641#else
6a738a25 1642 if (len > 0 && f[0] == '/')
82893676 1643#endif /* ndef __MINGW32__ */
cc95e00a 1644 return scm_c_substring (filename, 0, 1);
6a738a25
JB
1645 else
1646 return scm_dot_string;
1647 }
1648 else
cc95e00a 1649 return scm_c_substring (filename, i+1, end+1);
6a738a25 1650}
1bbd0b84 1651#undef FUNC_NAME
6a738a25
JB
1652
1653
1654
1655\f
1cc91f1b 1656
0f2d19dd
JB
1657void
1658scm_init_filesys ()
0f2d19dd 1659{
e841c3e0
KN
1660 scm_tc16_dir = scm_make_smob_type ("directory", 0);
1661 scm_set_smob_free (scm_tc16_dir, scm_dir_free);
1662 scm_set_smob_print (scm_tc16_dir, scm_dir_print);
0f2d19dd 1663
cc95e00a 1664 scm_dot_string = scm_permanent_object (scm_from_locale_string ("."));
a163dda9 1665
3d8d56df 1666#ifdef O_RDONLY
23d72566 1667 scm_c_define ("O_RDONLY", scm_from_int (O_RDONLY));
3d8d56df
GH
1668#endif
1669#ifdef O_WRONLY
23d72566 1670 scm_c_define ("O_WRONLY", scm_from_int (O_WRONLY));
3d8d56df
GH
1671#endif
1672#ifdef O_RDWR
23d72566 1673 scm_c_define ("O_RDWR", scm_from_int (O_RDWR));
3d8d56df
GH
1674#endif
1675#ifdef O_CREAT
23d72566 1676 scm_c_define ("O_CREAT", scm_from_int (O_CREAT));
3d8d56df
GH
1677#endif
1678#ifdef O_EXCL
23d72566 1679 scm_c_define ("O_EXCL", scm_from_int (O_EXCL));
3d8d56df
GH
1680#endif
1681#ifdef O_NOCTTY
23d72566 1682 scm_c_define ("O_NOCTTY", scm_from_int (O_NOCTTY));
3d8d56df
GH
1683#endif
1684#ifdef O_TRUNC
23d72566 1685 scm_c_define ("O_TRUNC", scm_from_int (O_TRUNC));
3d8d56df
GH
1686#endif
1687#ifdef O_APPEND
23d72566 1688 scm_c_define ("O_APPEND", scm_from_int (O_APPEND));
3d8d56df 1689#endif
6afcd3b2 1690#ifdef O_NONBLOCK
23d72566 1691 scm_c_define ("O_NONBLOCK", scm_from_int (O_NONBLOCK));
3d8d56df
GH
1692#endif
1693#ifdef O_NDELAY
23d72566 1694 scm_c_define ("O_NDELAY", scm_from_int (O_NDELAY));
3d8d56df
GH
1695#endif
1696#ifdef O_SYNC
23d72566 1697 scm_c_define ("O_SYNC", scm_from_int (O_SYNC));
3d8d56df 1698#endif
23f2b9a3 1699#ifdef O_LARGEFILE
23d72566 1700 scm_c_define ("O_LARGEFILE", scm_from_int (O_LARGEFILE));
23f2b9a3 1701#endif
3d8d56df 1702
4c1feaa5 1703#ifdef F_DUPFD
23d72566 1704 scm_c_define ("F_DUPFD", scm_from_int (F_DUPFD));
4c1feaa5
JB
1705#endif
1706#ifdef F_GETFD
23d72566 1707 scm_c_define ("F_GETFD", scm_from_int (F_GETFD));
4c1feaa5
JB
1708#endif
1709#ifdef F_SETFD
23d72566 1710 scm_c_define ("F_SETFD", scm_from_int (F_SETFD));
4c1feaa5
JB
1711#endif
1712#ifdef F_GETFL
23d72566 1713 scm_c_define ("F_GETFL", scm_from_int (F_GETFL));
4c1feaa5
JB
1714#endif
1715#ifdef F_SETFL
23d72566 1716 scm_c_define ("F_SETFL", scm_from_int (F_SETFL));
4c1feaa5
JB
1717#endif
1718#ifdef F_GETOWN
23d72566 1719 scm_c_define ("F_GETOWN", scm_from_int (F_GETOWN));
4c1feaa5
JB
1720#endif
1721#ifdef F_SETOWN
23d72566 1722 scm_c_define ("F_SETOWN", scm_from_int (F_SETOWN));
4c1feaa5
JB
1723#endif
1724#ifdef FD_CLOEXEC
23d72566 1725 scm_c_define ("FD_CLOEXEC", scm_from_int (FD_CLOEXEC));
bd9e24b3 1726#endif
3d8d56df 1727
a0599745 1728#include "libguile/filesys.x"
0f2d19dd 1729}
89e00824
ML
1730
1731/*
1732 Local Variables:
1733 c-file-style: "gnu"
1734 End:
1735*/