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