*** empty log message ***
[bpt/guile.git] / libguile / filesys.c
CommitLineData
3d8d56df 1/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
0f2d19dd
JB
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program 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
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
15 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
16 *
17 * As a special exception, the Free Software Foundation gives permission
18 * for additional uses of the text contained in its release of GUILE.
19 *
20 * The exception is that, if you link the GUILE library with other files
21 * to produce an executable, this does not by itself cause the
22 * resulting executable to be covered by the GNU General Public License.
23 * Your use of that executable is in no way restricted on account of
24 * linking the GUILE library code into it.
25 *
26 * This exception does not however invalidate any other reasons why
27 * the executable file might be covered by the GNU General Public License.
28 *
29 * This exception applies only to the code released by the
30 * Free Software Foundation under the name GUILE. If you copy
31 * code from other Free Software Foundation releases into a copy of
32 * GUILE, as the General Public License permits, the exception does
33 * not apply to the code that you add in this way. To avoid misleading
34 * anyone as to the status of such modified files, you must delete
35 * this exception notice from them.
36 *
37 * If you write modifications of your own for GUILE, it is your choice
38 * whether to permit this exception to apply to your modifications.
39 * If you do not wish that, delete this exception notice.
40 */
41\f
3d8d56df 42#include <stdio.h>
0f2d19dd 43#include "_scm.h"
20e6290e
JB
44#include "genio.h"
45#include "smob.h"
52f4f4d6 46#include "feature.h"
3d8d56df 47#include "fports.h"
0f2d19dd 48
20e6290e 49#include "filesys.h"
0f2d19dd
JB
50\f
51#ifdef TIME_WITH_SYS_TIME
52# include <sys/time.h>
53# include <time.h>
54#else
55# if HAVE_SYS_TIME_H
56# include <sys/time.h>
57# else
58# include <time.h>
59# endif
60#endif
61
62#ifdef HAVE_UNISTD_H
63#include <unistd.h>
64#endif
65
3594582b 66#ifdef LIBC_H_WITH_UNISTD_H
1f9e2226
JB
67#include <libc.h>
68#endif
69
0f2d19dd
JB
70#ifdef HAVE_SYS_SELECT_H
71#include <sys/select.h>
72#endif
73
1f9e2226
JB
74#ifdef HAVE_STRING_H
75#include <string.h>
76#endif
77
8cc71382 78#include <sys/types.h>
0f2d19dd
JB
79#include <sys/stat.h>
80#include <fcntl.h>
81
82#include <pwd.h>
83
84
85#ifdef FD_SET
86
87#define SELECT_TYPE fd_set
88#define SELECT_SET_SIZE FD_SETSIZE
89
90#else /* no FD_SET */
91
92/* Define the macros to access a single-int bitmap of descriptors. */
93#define SELECT_SET_SIZE 32
94#define SELECT_TYPE int
95#define FD_SET(n, p) (*(p) |= (1 << (n)))
96#define FD_CLR(n, p) (*(p) &= ~(1 << (n)))
97#define FD_ISSET(n, p) (*(p) & (1 << (n)))
98#define FD_ZERO(p) (*(p) = 0)
99
100#endif /* no FD_SET */
101
102#if HAVE_DIRENT_H
103# include <dirent.h>
104# define NAMLEN(dirent) strlen((dirent)->d_name)
105#else
106# define dirent direct
107# define NAMLEN(dirent) (dirent)->d_namlen
108# if HAVE_SYS_NDIR_H
109# include <sys/ndir.h>
110# endif
111# if HAVE_SYS_DIR_H
112# include <sys/dir.h>
113# endif
114# if HAVE_NDIR_H
115# include <ndir.h>
116# endif
117#endif
118
119\f
120
0f2d19dd
JB
121
122\f
123
124/* {Permissions}
125 */
126
3d8d56df 127SCM_PROC (s_chown, "chown", 3, 0, 0, scm_chown);
1cc91f1b 128
0f2d19dd 129SCM
3d8d56df 130scm_chown (path, owner, group)
0f2d19dd
JB
131 SCM path;
132 SCM owner;
133 SCM group;
0f2d19dd
JB
134{
135 int val;
02b754d3 136
3d8d56df 137 SCM_ASSERT (SCM_NIMP (path) && SCM_ROSTRINGP (path), path, SCM_ARG1, s_chown);
0f2d19dd
JB
138 if (SCM_SUBSTRP (path))
139 path = scm_makfromstr (SCM_ROCHARS (path), SCM_ROLENGTH (path), 0);
3d8d56df
GH
140 SCM_ASSERT (SCM_INUMP (owner), owner, SCM_ARG2, s_chown);
141 SCM_ASSERT (SCM_INUMP (group), group, SCM_ARG3, s_chown);
02b754d3
GH
142 SCM_SYSCALL (val = chown (SCM_ROCHARS (path),
143 SCM_INUM (owner), SCM_INUM (group)));
144 if (val != 0)
3d8d56df 145 scm_syserror (s_chown);
02b754d3 146 return SCM_UNSPECIFIED;
0f2d19dd
JB
147}
148
149
3d8d56df 150SCM_PROC (s_chmod, "chmod", 2, 0, 0, scm_chmod);
1cc91f1b 151
0f2d19dd 152SCM
3d8d56df 153scm_chmod (port_or_path, mode)
0f2d19dd
JB
154 SCM port_or_path;
155 SCM mode;
0f2d19dd
JB
156{
157 int rv;
3d8d56df
GH
158 SCM_ASSERT (SCM_INUMP (mode), mode, SCM_ARG2, s_chmod);
159 SCM_ASSERT (SCM_NIMP (port_or_path), port_or_path, SCM_ARG1, s_chmod);
0f2d19dd
JB
160 if (SCM_STRINGP (port_or_path))
161 SCM_SYSCALL (rv = chmod (SCM_CHARS (port_or_path), SCM_INUM (mode)));
162 else
163 {
3d8d56df 164 SCM_ASSERT (SCM_OPFPORTP (port_or_path), port_or_path, SCM_ARG1, s_chmod);
0f2d19dd
JB
165 rv = fileno ((FILE *)SCM_STREAM (port_or_path));
166 if (rv != -1)
167 SCM_SYSCALL (rv = fchmod (rv, SCM_INUM (mode)));
168 }
02b754d3 169 if (rv != 0)
3d8d56df 170 scm_syserror (s_chmod);
02b754d3 171 return SCM_UNSPECIFIED;
0f2d19dd
JB
172}
173
174SCM_PROC (s_umask, "umask", 0, 1, 0, scm_umask);
1cc91f1b 175
0f2d19dd
JB
176SCM
177scm_umask (mode)
178 SCM mode;
0f2d19dd
JB
179{
180 mode_t mask;
181 if (SCM_UNBNDP (mode))
182 {
183 mask = umask (0);
184 umask (mask);
185 }
186 else
187 {
188 SCM_ASSERT (SCM_INUMP (mode), mode, SCM_ARG1, s_umask);
189 mask = umask (SCM_INUM (mode));
190 }
191 return SCM_MAKINUM (mask);
192}
193
194\f
0f2d19dd 195
3d8d56df 196SCM_PROC (s_open, "open", 2, 1, 0, scm_open);
1cc91f1b 197
0f2d19dd 198SCM
3d8d56df 199scm_open (path, flags, mode)
0f2d19dd
JB
200 SCM path;
201 SCM flags;
202 SCM mode;
0f2d19dd
JB
203{
204 int fd;
3d8d56df
GH
205 SCM newpt;
206 FILE *f;
207 char *port_mode;
208 int iflags;
0f2d19dd 209
3d8d56df
GH
210 SCM_ASSERT (SCM_NIMP (path) && SCM_ROSTRINGP (path), path, SCM_ARG1, s_open);
211 iflags = scm_num2long (flags, (char *) SCM_ARG2, s_open);
0f2d19dd
JB
212
213 if (SCM_SUBSTRP (path))
214 path = scm_makfromstr (SCM_ROCHARS (path), SCM_ROLENGTH (path), 0);
215
216 SCM_DEFER_INTS;
3d8d56df
GH
217 if (SCM_UNBNDP (mode))
218 SCM_SYSCALL (fd = open (SCM_ROCHARS (path), iflags));
0f2d19dd
JB
219 else
220 {
3d8d56df
GH
221 SCM_ASSERT (SCM_INUMP (mode), mode, SCM_ARG3, s_open);
222 SCM_SYSCALL (fd = open (SCM_ROCHARS (path), iflags, SCM_INUM (mode)));
0f2d19dd 223 }
3d8d56df
GH
224 if (fd == -1)
225 scm_syserror (s_open);
226 SCM_NEWCELL (newpt);
227 if (iflags & O_RDWR)
228 port_mode = "r+";
229 else {
230 if (iflags & O_WRONLY)
231 port_mode = "w";
232 else
233 port_mode = "r";
234 }
235 f = fdopen (fd, port_mode);
236 if (!f)
0f2d19dd 237 {
3d8d56df
GH
238 SCM_SYSCALL (close (fd));
239 scm_syserror (s_open);
0f2d19dd 240 }
3d8d56df
GH
241 {
242 struct scm_port_table * pt;
243
244 pt = scm_add_to_port_table (newpt);
245 SCM_SETPTAB_ENTRY (newpt, pt);
246 SCM_SETCAR (newpt, scm_tc16_fport | scm_mode_bits (port_mode));
247 /* if (SCM_BUF0 & SCM_CAR (newpt))
248 scm_setbuf0 (newpt); */
249 SCM_SETSTREAM (newpt, (SCM)f);
250 SCM_PTAB_ENTRY (newpt)->file_name = path;
251 }
0f2d19dd 252 SCM_ALLOW_INTS;
1cc91f1b 253
3d8d56df 254 return newpt;
0f2d19dd
JB
255}
256
0f2d19dd
JB
257\f
258/* {Files}
259 */
1cc91f1b 260
ae5253c5
GH
261SCM_SYMBOL (scm_sym_regular, "regular");
262SCM_SYMBOL (scm_sym_directory, "directory");
263SCM_SYMBOL (scm_sym_symlink, "symlink");
264SCM_SYMBOL (scm_sym_block_special, "block-special");
265SCM_SYMBOL (scm_sym_char_special, "char-special");
266SCM_SYMBOL (scm_sym_fifo, "fifo");
267SCM_SYMBOL (scm_sym_sock, "socket");
268SCM_SYMBOL (scm_sym_unknown, "unknown");
269
1cc91f1b
JB
270static SCM scm_stat2scm SCM_P ((struct stat *stat_temp));
271
0f2d19dd
JB
272static SCM
273scm_stat2scm (stat_temp)
274 struct stat *stat_temp;
0f2d19dd 275{
ae5253c5 276 SCM ans = scm_make_vector (SCM_MAKINUM (15), SCM_UNSPECIFIED, SCM_BOOL_F);
0f2d19dd 277 SCM *ve = SCM_VELTS (ans);
ae5253c5 278
0f2d19dd
JB
279 ve[0] = scm_ulong2num ((unsigned long) stat_temp->st_dev);
280 ve[1] = scm_ulong2num ((unsigned long) stat_temp->st_ino);
281 ve[2] = scm_ulong2num ((unsigned long) stat_temp->st_mode);
282 ve[3] = scm_ulong2num ((unsigned long) stat_temp->st_nlink);
283 ve[4] = scm_ulong2num ((unsigned long) stat_temp->st_uid);
284 ve[5] = scm_ulong2num ((unsigned long) stat_temp->st_gid);
285#ifdef HAVE_ST_RDEV
286 ve[6] = scm_ulong2num ((unsigned long) stat_temp->st_rdev);
287#else
288 ve[6] = SCM_BOOL_F;
289#endif
290 ve[7] = scm_ulong2num ((unsigned long) stat_temp->st_size);
291 ve[8] = scm_ulong2num ((unsigned long) stat_temp->st_atime);
292 ve[9] = scm_ulong2num ((unsigned long) stat_temp->st_mtime);
293 ve[10] = scm_ulong2num ((unsigned long) stat_temp->st_ctime);
294#ifdef HAVE_ST_BLKSIZE
295 ve[11] = scm_ulong2num ((unsigned long) stat_temp->st_blksize);
296#else
297 ve[11] = scm_ulong2num (4096L);
298#endif
299#ifdef HAVE_ST_BLOCKS
300 ve[12] = scm_ulong2num ((unsigned long) stat_temp->st_blocks);
301#else
302 ve[12] = SCM_BOOL_F;
303#endif
ae5253c5
GH
304 {
305 int mode = stat_temp->st_mode;
306
307 if (S_ISREG (mode))
308 ve[13] = scm_sym_regular;
309 else if (S_ISDIR (mode))
310 ve[13] = scm_sym_directory;
311 else if (S_ISLNK (mode))
312 ve[13] = scm_sym_symlink;
313 else if (S_ISBLK (mode))
314 ve[13] = scm_sym_block_special;
315 else if (S_ISCHR (mode))
316 ve[13] = scm_sym_char_special;
317 else if (S_ISFIFO (mode))
318 ve[13] = scm_sym_fifo;
319 else if (S_ISSOCK (mode))
320 ve[13] = scm_sym_sock;
321 else
322 ve[13] = scm_sym_unknown;
323
324 ve[14] = SCM_MAKINUM ((~S_IFMT) & mode);
325
326 /* the layout of the bits in ve[14] is intended to be portable.
327 If there are systems that don't follow the usual convention,
328 the following could be used:
329
330 tmp = 0;
331 if (S_ISUID & mode) tmp += 1;
332 tmp <<= 1;
333 if (S_IRGRP & mode) tmp += 1;
334 tmp <<= 1;
335 if (S_ISVTX & mode) tmp += 1;
336 tmp <<= 1;
337 if (S_IRUSR & mode) tmp += 1;
338 tmp <<= 1;
339 if (S_IWUSR & mode) tmp += 1;
340 tmp <<= 1;
341 if (S_IXUSR & mode) tmp += 1;
342 tmp <<= 1;
343 if (S_IWGRP & mode) tmp += 1;
344 tmp <<= 1;
345 if (S_IXGRP & mode) tmp += 1;
346 tmp <<= 1;
347 if (S_IROTH & mode) tmp += 1;
348 tmp <<= 1;
349 if (S_IWOTH & mode) tmp += 1;
350 tmp <<= 1;
351 if (S_IXOTH & mode) tmp += 1;
352
353 ve[14] = SCM_MAKINUM (tmp);
354
355 */
356 }
0f2d19dd
JB
357
358 return ans;
359}
360
3d8d56df 361SCM_PROC (s_stat, "stat", 1, 0, 0, scm_stat);
1cc91f1b 362
0f2d19dd 363SCM
c0ebd8c5
MD
364scm_stat (file)
365 SCM file;
0f2d19dd 366{
657c49b3 367 int rv = 1;
0f2d19dd
JB
368 struct stat stat_temp;
369
c0ebd8c5
MD
370 if (SCM_INUMP (file))
371 SCM_SYSCALL (rv = fstat (SCM_INUM (file), &stat_temp));
0f2d19dd
JB
372 else
373 {
c0ebd8c5
MD
374 SCM_ASSERT (SCM_NIMP (file), file, SCM_ARG1, s_stat);
375 if (SCM_FPORTP (file))
376 SCM_SYSCALL (rv = fstat (fileno ((FILE *) SCM_STREAM (file)),
377 &stat_temp));
378 else
0f2d19dd 379 {
c0ebd8c5
MD
380 SCM_ASSERT (SCM_ROSTRINGP (file), file, SCM_ARG1, s_stat);
381 if (SCM_SUBSTRP (file))
382 file = scm_makfromstr (SCM_ROCHARS (file),
383 SCM_ROLENGTH (file),
384 0);
385 SCM_SYSCALL (rv = stat (SCM_CHARS (file), &stat_temp));
0f2d19dd 386 }
0f2d19dd 387 }
02b754d3 388 if (rv != 0)
3d8d56df
GH
389 {
390 int en = errno;
391
392 scm_syserror_msg (s_stat, "%s: %S",
393 scm_listify (scm_makfrom0str (strerror (errno)),
c0ebd8c5 394 file,
3d8d56df
GH
395 SCM_UNDEFINED),
396 en);
397 }
02b754d3 398 return scm_stat2scm (&stat_temp);
0f2d19dd
JB
399}
400
401
402\f
403/* {Modifying Directories}
404 */
405
3d8d56df 406SCM_PROC (s_link, "link", 2, 0, 0, scm_link);
1cc91f1b 407
0f2d19dd 408SCM
3d8d56df 409scm_link (oldpath, newpath)
0f2d19dd
JB
410 SCM oldpath;
411 SCM newpath;
0f2d19dd
JB
412{
413 int val;
02b754d3 414
3d8d56df 415 SCM_ASSERT (SCM_NIMP (oldpath) && SCM_ROSTRINGP (oldpath), oldpath, SCM_ARG1, s_link);
0f2d19dd
JB
416 if (SCM_SUBSTRP (oldpath))
417 oldpath = scm_makfromstr (SCM_ROCHARS (oldpath), SCM_ROLENGTH (oldpath), 0);
3d8d56df 418 SCM_ASSERT (SCM_NIMP (newpath) && SCM_ROSTRINGP (newpath), newpath, SCM_ARG2, s_link);
0f2d19dd
JB
419 if (SCM_SUBSTRP (newpath))
420 newpath = scm_makfromstr (SCM_ROCHARS (newpath), SCM_ROLENGTH (newpath), 0);
421 SCM_SYSCALL (val = link (SCM_ROCHARS (oldpath), SCM_ROCHARS (newpath)));
02b754d3 422 if (val != 0)
3d8d56df 423 scm_syserror (s_link);
02b754d3 424 return SCM_UNSPECIFIED;
0f2d19dd
JB
425}
426
427
428
3d8d56df 429SCM_PROC (s_rename, "rename-file", 2, 0, 0, scm_rename);
1cc91f1b 430
0f2d19dd 431SCM
3d8d56df 432scm_rename (oldname, newname)
0f2d19dd
JB
433 SCM oldname;
434 SCM newname;
0f2d19dd
JB
435{
436 int rv;
3d8d56df
GH
437 SCM_ASSERT (SCM_NIMP (oldname) && SCM_STRINGP (oldname), oldname, SCM_ARG1, s_rename);
438 SCM_ASSERT (SCM_NIMP (newname) && SCM_STRINGP (newname), newname, SCM_ARG2, s_rename);
0f2d19dd
JB
439#ifdef HAVE_RENAME
440 SCM_SYSCALL (rv = rename (SCM_CHARS (oldname), SCM_CHARS (newname)));
02b754d3 441 if (rv != 0)
3d8d56df 442 scm_syserror (s_rename);
02b754d3 443 return SCM_UNSPECIFIED;
0f2d19dd
JB
444#else
445 SCM_DEFER_INTS;
446 SCM_SYSCALL (rv = link (SCM_CHARS (oldname), SCM_CHARS (newname)));
02b754d3 447 if (rv == 0)
0f2d19dd
JB
448 {
449 SCM_SYSCALL (rv = unlink (SCM_CHARS (oldname)));;
02b754d3 450 if (rv != 0)
0f2d19dd
JB
451 /* unlink failed. remove new name */
452 SCM_SYSCALL (unlink (SCM_CHARS (newname)));
453 }
454 SCM_ALLOW_INTS;
02b754d3 455 if (rv != 0)
3d8d56df 456 scm_syserror (s_rename);
02b754d3 457 return SCM_UNSPECIFIED;
0f2d19dd
JB
458#endif
459}
460
461
3d8d56df 462SCM_PROC(s_delete_file, "delete-file", 1, 0, 0, scm_delete_file);
1cc91f1b 463
2f3ed1ba 464SCM
3d8d56df 465scm_delete_file (str)
2f3ed1ba 466 SCM str;
2f3ed1ba
JB
467{
468 int ans;
3d8d56df 469 SCM_ASSERT (SCM_NIMP (str) && SCM_STRINGP (str), str, SCM_ARG1, s_delete_file);
2f3ed1ba
JB
470 SCM_SYSCALL (ans = unlink (SCM_CHARS (str)));
471 if (ans != 0)
3d8d56df 472 scm_syserror (s_delete_file);
2f3ed1ba
JB
473 return SCM_UNSPECIFIED;
474}
475
0f2d19dd 476
3d8d56df 477SCM_PROC (s_mkdir, "mkdir", 1, 1, 0, scm_mkdir);
1cc91f1b 478
0f2d19dd 479SCM
3d8d56df 480scm_mkdir (path, mode)
0f2d19dd
JB
481 SCM path;
482 SCM mode;
0f2d19dd
JB
483{
484#ifdef HAVE_MKDIR
485 int rv;
486 mode_t mask;
3d8d56df 487 SCM_ASSERT (SCM_NIMP (path) && SCM_STRINGP (path), path, SCM_ARG1, s_mkdir);
0f2d19dd
JB
488 if (SCM_UNBNDP (mode))
489 {
490 mask = umask (0);
491 umask (mask);
492 SCM_SYSCALL (rv = mkdir (SCM_CHARS (path), 0777 ^ mask));
493 }
494 else
495 {
3d8d56df 496 SCM_ASSERT (SCM_INUMP (mode), mode, SCM_ARG2, s_mkdir);
0f2d19dd
JB
497 SCM_SYSCALL (rv = mkdir (SCM_CHARS (path), SCM_INUM (mode)));
498 }
02b754d3 499 if (rv != 0)
3d8d56df 500 scm_syserror (s_mkdir);
02b754d3 501 return SCM_UNSPECIFIED;
0f2d19dd 502#else
3d8d56df 503 scm_sysmissing (s_mkdir);
02b754d3
GH
504 /* not reached. */
505 return SCM_BOOL_F;
0f2d19dd
JB
506#endif
507}
508
509
3d8d56df 510SCM_PROC (s_rmdir, "rmdir", 1, 0, 0, scm_rmdir);
1cc91f1b 511
0f2d19dd 512SCM
3d8d56df 513scm_rmdir (path)
0f2d19dd 514 SCM path;
0f2d19dd
JB
515{
516#ifdef HAVE_RMDIR
517 int val;
02b754d3 518
3d8d56df 519 SCM_ASSERT (SCM_NIMP (path) && SCM_STRINGP (path), path, SCM_ARG1, s_rmdir);
0f2d19dd 520 SCM_SYSCALL (val = rmdir (SCM_CHARS (path)));
02b754d3 521 if (val != 0)
3d8d56df 522 scm_syserror (s_rmdir);
02b754d3 523 return SCM_UNSPECIFIED;
0f2d19dd 524#else
3d8d56df 525 scm_sysmissing (s_rmdir);
02b754d3
GH
526 /* not reached. */
527 return SCM_BOOL_F;
0f2d19dd
JB
528#endif
529}
530
531\f
532/* {Examining Directories}
533 */
534
535long scm_tc16_dir;
536
3d8d56df 537SCM_PROC (s_opendir, "opendir", 1, 0, 0, scm_opendir);
1cc91f1b 538
0f2d19dd 539SCM
3d8d56df 540scm_opendir (dirname)
0f2d19dd 541 SCM dirname;
0f2d19dd
JB
542{
543 DIR *ds;
544 SCM dir;
3d8d56df 545 SCM_ASSERT (SCM_NIMP (dirname) && SCM_STRINGP (dirname), dirname, SCM_ARG1, s_opendir);
0f2d19dd
JB
546 SCM_NEWCELL (dir);
547 SCM_DEFER_INTS;
548 SCM_SYSCALL (ds = opendir (SCM_CHARS (dirname)));
02b754d3 549 if (ds == NULL)
3d8d56df 550 scm_syserror (s_opendir);
a6c64c3c 551 SCM_SETCAR (dir, scm_tc16_dir | SCM_OPN);
0f2d19dd
JB
552 SCM_SETCDR (dir, ds);
553 SCM_ALLOW_INTS;
554 return dir;
555}
556
557
3d8d56df 558SCM_PROC (s_readdir, "readdir", 1, 0, 0, scm_readdir);
1cc91f1b 559
0f2d19dd 560SCM
3d8d56df 561scm_readdir (port)
0f2d19dd 562 SCM port;
0f2d19dd
JB
563{
564 struct dirent *rdent;
565 SCM_DEFER_INTS;
3d8d56df 566 SCM_ASSERT (SCM_NIMP (port) && SCM_OPDIRP (port), port, SCM_ARG1, s_readdir);
0f2d19dd
JB
567 errno = 0;
568 SCM_SYSCALL (rdent = readdir ((DIR *) SCM_CDR (port)));
569 SCM_ALLOW_INTS;
02b754d3 570 if (errno != 0)
3d8d56df 571 scm_syserror (s_readdir);
02b754d3
GH
572 return (rdent ? scm_makfromstr (rdent->d_name, NAMLEN (rdent), 0)
573 : SCM_EOF_VAL);
0f2d19dd
JB
574}
575
576
577
578SCM_PROC (s_rewinddir, "rewinddir", 1, 0, 0, scm_rewinddir);
1cc91f1b 579
0f2d19dd
JB
580SCM
581scm_rewinddir (port)
582 SCM port;
0f2d19dd
JB
583{
584 SCM_ASSERT (SCM_NIMP (port) && SCM_OPDIRP (port), port, SCM_ARG1, s_rewinddir);
585 rewinddir ((DIR *) SCM_CDR (port));
586 return SCM_UNSPECIFIED;
587}
588
589
590
3d8d56df 591SCM_PROC (s_closedir, "closedir", 1, 0, 0, scm_closedir);
1cc91f1b 592
0f2d19dd 593SCM
3d8d56df 594scm_closedir (port)
0f2d19dd 595 SCM port;
0f2d19dd
JB
596{
597 int sts;
02b754d3 598
3d8d56df 599 SCM_ASSERT (SCM_NIMP (port) && SCM_DIRP (port), port, SCM_ARG1, s_closedir);
0f2d19dd
JB
600 SCM_DEFER_INTS;
601 if (SCM_CLOSEDP (port))
602 {
603 SCM_ALLOW_INTS;
02b754d3 604 return SCM_UNSPECIFIED;
0f2d19dd
JB
605 }
606 SCM_SYSCALL (sts = closedir ((DIR *) SCM_CDR (port)));
02b754d3 607 if (sts != 0)
3d8d56df 608 scm_syserror (s_closedir);
a6c64c3c 609 SCM_SETCAR (port, scm_tc16_dir);
0f2d19dd 610 SCM_ALLOW_INTS;
02b754d3 611 return SCM_UNSPECIFIED;
0f2d19dd
JB
612}
613
614
615
1cc91f1b
JB
616
617static int scm_dir_print SCM_P ((SCM sexp, SCM port, scm_print_state *pstate));
618
0f2d19dd 619static int
9882ea19 620scm_dir_print (sexp, port, pstate)
0f2d19dd
JB
621 SCM sexp;
622 SCM port;
9882ea19 623 scm_print_state *pstate;
0f2d19dd
JB
624{
625 scm_prinport (sexp, port, "directory");
626 return 1;
627}
628
1cc91f1b
JB
629
630static scm_sizet scm_dir_free SCM_P ((SCM p));
631
0f2d19dd
JB
632static scm_sizet
633scm_dir_free (p)
634 SCM p;
0f2d19dd
JB
635{
636 if (SCM_OPENP (p))
637 closedir ((DIR *) SCM_CDR (p));
638 return 0;
639}
640
641static scm_smobfuns dir_smob = {scm_mark0, scm_dir_free, scm_dir_print, 0};
642
643\f
644/* {Navigating Directories}
645 */
646
647
3d8d56df 648SCM_PROC (s_chdir, "chdir", 1, 0, 0, scm_chdir);
1cc91f1b 649
0f2d19dd 650SCM
3d8d56df 651scm_chdir (str)
0f2d19dd 652 SCM str;
0f2d19dd
JB
653{
654 int ans;
02b754d3 655
3d8d56df 656 SCM_ASSERT (SCM_NIMP (str) && SCM_STRINGP (str), str, SCM_ARG1, s_chdir);
0f2d19dd 657 SCM_SYSCALL (ans = chdir (SCM_CHARS (str)));
02b754d3 658 if (ans != 0)
3d8d56df 659 scm_syserror (s_chdir);
02b754d3 660 return SCM_UNSPECIFIED;
0f2d19dd
JB
661}
662
663
664
3d8d56df 665SCM_PROC (s_getcwd, "getcwd", 0, 0, 0, scm_getcwd);
1cc91f1b 666
0f2d19dd 667SCM
3d8d56df 668scm_getcwd ()
0f2d19dd
JB
669{
670#ifdef HAVE_GETCWD
671 char *rv;
672
673 scm_sizet size = 100;
674 char *wd;
675 SCM result;
676
677 SCM_DEFER_INTS;
3d8d56df 678 wd = scm_must_malloc (size, s_getcwd);
0f2d19dd
JB
679 while ((rv = getcwd (wd, size)) == 0 && errno == ERANGE)
680 {
681 scm_must_free (wd);
682 size *= 2;
3d8d56df 683 wd = scm_must_malloc (size, s_getcwd);
0f2d19dd 684 }
02b754d3 685 if (rv == 0)
3d8d56df 686 scm_syserror (s_getcwd);
02b754d3 687 result = scm_makfromstr (wd, strlen (wd), 0);
0f2d19dd
JB
688 scm_must_free (wd);
689 SCM_ALLOW_INTS;
690 return result;
691#else
3d8d56df 692 scm_sysmissing (s_getcwd);
02b754d3
GH
693 /* not reached. */
694 return SCM_BOOL_F;
0f2d19dd
JB
695#endif
696}
697
698\f
699
1cc91f1b
JB
700
701static void fill_select_type SCM_P ((SELECT_TYPE * set, SCM list));
702
0f2d19dd
JB
703static void
704fill_select_type (set, list)
705 SELECT_TYPE * set;
706 SCM list;
0f2d19dd
JB
707{
708 while (list != SCM_EOL)
709 {
710 if ( SCM_NIMP (SCM_CAR (list))
711 && (scm_tc16_fport == SCM_TYP16 (SCM_CAR (list)))
712 && SCM_OPPORTP (SCM_CAR (list)))
713 FD_SET (fileno ((FILE *)SCM_STREAM (SCM_CAR (list))), set);
714 else if (SCM_INUMP (SCM_CAR (list)))
715 FD_SET (SCM_INUM (SCM_CAR (list)), set);
0f2d19dd
JB
716 list = SCM_CDR (list);
717 }
718}
719
1cc91f1b
JB
720
721static SCM retrieve_select_type SCM_P ((SELECT_TYPE * set, SCM list));
722
0f2d19dd
JB
723static SCM
724retrieve_select_type (set, list)
725 SELECT_TYPE * set;
726 SCM list;
0f2d19dd
JB
727{
728 SCM answer;
729 answer = SCM_EOL;
730 while (list != SCM_EOL)
731 {
732 if ( SCM_NIMP (SCM_CAR (list))
733 && (scm_tc16_fport == SCM_TYP16 (SCM_CAR (list)))
734 && SCM_OPPORTP (SCM_CAR (list)))
735 {
736 if (FD_ISSET (fileno ((FILE *)SCM_STREAM (SCM_CAR (list))), set))
737 answer = scm_cons (SCM_CAR (list), answer);
738 }
739 else if (SCM_INUMP (SCM_CAR (list)))
740 {
741 if (FD_ISSET (SCM_INUM (SCM_CAR (list)), set))
742 answer = scm_cons (SCM_CAR (list), answer);
743 }
0f2d19dd
JB
744 list = SCM_CDR (list);
745 }
746 return answer;
747}
748
749
66b47b6c
MD
750/* {Checking for events}
751 */
752
3d8d56df 753SCM_PROC (s_select, "select", 3, 2, 0, scm_select);
1cc91f1b 754
0f2d19dd 755SCM
3d8d56df 756scm_select (reads, writes, excepts, secs, msecs)
0f2d19dd
JB
757 SCM reads;
758 SCM writes;
759 SCM excepts;
760 SCM secs;
761 SCM msecs;
0f2d19dd
JB
762{
763#ifdef HAVE_SELECT
764 struct timeval timeout;
765 struct timeval * time_p;
766 SELECT_TYPE read_set;
767 SELECT_TYPE write_set;
768 SELECT_TYPE except_set;
769 int sreturn;
770
3d8d56df
GH
771 SCM_ASSERT (-1 < scm_ilength (reads), reads, SCM_ARG1, s_select);
772 SCM_ASSERT (-1 < scm_ilength (writes), reads, SCM_ARG1, s_select);
773 SCM_ASSERT (-1 < scm_ilength (excepts), reads, SCM_ARG1, s_select);
0f2d19dd
JB
774
775 FD_ZERO (&read_set);
776 FD_ZERO (&write_set);
777 FD_ZERO (&except_set);
778
779 fill_select_type (&read_set, reads);
780 fill_select_type (&write_set, writes);
781 fill_select_type (&except_set, excepts);
782
783 if (SCM_UNBNDP (secs))
784 time_p = 0;
785 else
786 {
3d8d56df 787 SCM_ASSERT (SCM_INUMP (secs), secs, SCM_ARG4, s_select);
0f2d19dd
JB
788 if (SCM_UNBNDP (msecs))
789 msecs = SCM_INUM0;
790 else
3d8d56df 791 SCM_ASSERT (SCM_INUMP (msecs), msecs, SCM_ARG5, s_select);
0f2d19dd
JB
792
793 timeout.tv_sec = SCM_INUM (secs);
794 timeout.tv_usec = 1000 * SCM_INUM (msecs);
795 time_p = &timeout;
796 }
797
798 SCM_DEFER_INTS;
799 sreturn = select (SELECT_SET_SIZE,
800 &read_set, &write_set, &except_set, time_p);
0f2d19dd 801 if (sreturn < 0)
3d8d56df 802 scm_syserror (s_select);
52f4f4d6 803 SCM_ALLOW_INTS;
02b754d3
GH
804 return scm_listify (retrieve_select_type (&read_set, reads),
805 retrieve_select_type (&write_set, writes),
806 retrieve_select_type (&except_set, excepts),
807 SCM_UNDEFINED);
0f2d19dd 808#else
3d8d56df 809 scm_sysmissing (s_select);
02b754d3
GH
810 /* not reached. */
811 return SCM_BOOL_F;
0f2d19dd
JB
812#endif
813}
814
66b47b6c
MD
815/* Check if FILE has characters waiting to be read. */
816
817#ifdef __IBMC__
818# define MSDOS
819#endif
820#ifdef MSDOS
821# ifndef GO32
822# include <io.h>
823# include <conio.h>
824
825int
826scm_input_waiting_p (f, caller)
827 FILE *f;
828 char *caller;
829{
830 if (feof (f))
831 return 1;
832 if (fileno (f) == fileno (stdin) && (isatty (fileno (stdin))))
833 return kbhit ();
834 return -1;
835}
836
837# endif
838#else
839# ifdef _DCC
840# include <ioctl.h>
841# else
842# ifndef AMIGA
843# ifndef vms
844# ifdef MWC
845# include <sys/io.h>
846# else
847# ifndef THINK_C
848# ifndef ARM_ULIB
849# include <sys/ioctl.h>
850# endif
851# endif
852# endif
853# endif
854# endif
855# endif
856
857int
858scm_input_waiting_p (f, caller)
859 FILE *f;
860 char *caller;
861{
862 /* Can we return an end-of-file character? */
863 if (feof (f))
864 return 1;
865
866 /* Do we have characters in the stdio buffer? */
867# ifdef FILE_CNT_FIELD
868 if (f->FILE_CNT_FIELD > 0)
869 return 1;
870# else
871# ifdef FILE_CNT_GPTR
872 if (f->_gptr != f->_egptr)
873 return 1;
874# else
875# ifdef FILE_CNT_READPTR
876 if (f->_IO_read_end != f->_IO_read_ptr)
877 return 1;
878# else
879 Configure.in could not guess the name of the correct field in a FILE *.
880 This function needs to be ported to your system.
881 It should return zero iff no characters are waiting to be read.;
882# endif
883# endif
884# endif
885
886 /* Is the file prepared to deliver input? */
370312ae 887# ifdef HAVE_SELECT
66b47b6c
MD
888 {
889 struct timeval timeout;
890 SELECT_TYPE read_set;
891 SELECT_TYPE write_set;
892 SELECT_TYPE except_set;
893 int fno = fileno ((FILE *)f);
894
895 FD_ZERO (&read_set);
896 FD_ZERO (&write_set);
897 FD_ZERO (&except_set);
898
899 FD_SET (fno, &read_set);
900
901 timeout.tv_sec = 0;
902 timeout.tv_usec = 0;
903
904 SCM_DEFER_INTS;
905 if (select (SELECT_SET_SIZE,
906 &read_set, &write_set, &except_set, &timeout)
907 < 0)
908 scm_syserror (caller);
909 SCM_ALLOW_INTS;
910 return FD_ISSET (fno, &read_set);
911 }
370312ae
GH
912# else
913# ifdef FIONREAD
914 {
915 long remir;
916 ioctl(fileno(f), FIONREAD, &remir);
917 return remir;
918 }
66b47b6c 919# else
67ec3667 920 scm_misc_error ("char-ready?", "Not fully implemented");
66b47b6c
MD
921# endif
922# endif
923}
924#endif
925
0f2d19dd
JB
926\f
927/* {Symbolic Links}
928 */
929
3d8d56df 930SCM_PROC (s_symlink, "symlink", 2, 0, 0, scm_symlink);
1cc91f1b 931
0f2d19dd 932SCM
3d8d56df 933scm_symlink(oldpath, newpath)
0f2d19dd
JB
934 SCM oldpath;
935 SCM newpath;
0f2d19dd
JB
936{
937#ifdef HAVE_SYMLINK
938 int val;
02b754d3 939
3d8d56df
GH
940 SCM_ASSERT(SCM_NIMP(oldpath) && SCM_STRINGP(oldpath), oldpath, SCM_ARG1, s_symlink);
941 SCM_ASSERT(SCM_NIMP(newpath) && SCM_STRINGP(newpath), newpath, SCM_ARG2, s_symlink);
02b754d3
GH
942 SCM_SYSCALL (val = symlink(SCM_CHARS(oldpath), SCM_CHARS(newpath)));
943 if (val != 0)
3d8d56df 944 scm_syserror (s_symlink);
02b754d3 945 return SCM_UNSPECIFIED;
0f2d19dd 946#else
3d8d56df 947 scm_sysmissing (s_symlink);
02b754d3
GH
948 /* not reached. */
949 return SCM_BOOL_F;
0f2d19dd
JB
950#endif
951}
952
953
3d8d56df 954SCM_PROC (s_readlink, "readlink", 1, 0, 0, scm_readlink);
1cc91f1b 955
0f2d19dd 956SCM
3d8d56df 957scm_readlink(path)
0f2d19dd 958 SCM path;
0f2d19dd
JB
959{
960#ifdef HAVE_READLINK
961 scm_sizet rv;
962 scm_sizet size = 100;
963 char *buf;
964 SCM result;
3d8d56df 965 SCM_ASSERT (SCM_NIMP (path) && SCM_STRINGP (path), path, (char *) SCM_ARG1, s_readlink);
0f2d19dd 966 SCM_DEFER_INTS;
3d8d56df 967 buf = scm_must_malloc (size, s_readlink);
0f2d19dd
JB
968 while ((rv = readlink (SCM_CHARS (path), buf, (scm_sizet) size)) == size)
969 {
970 scm_must_free (buf);
971 size *= 2;
3d8d56df 972 buf = scm_must_malloc (size, s_readlink);
0f2d19dd 973 }
02b754d3 974 if (rv == -1)
3d8d56df 975 scm_syserror (s_readlink);
02b754d3 976 result = scm_makfromstr (buf, rv, 0);
0f2d19dd
JB
977 scm_must_free (buf);
978 SCM_ALLOW_INTS;
979 return result;
980#else
3d8d56df 981 scm_sysmissing (s_readlink);
02b754d3
GH
982 /* not reached. */
983 return SCM_BOOL_F;
0f2d19dd
JB
984#endif
985}
986
987
3d8d56df 988SCM_PROC (s_lstat, "lstat", 1, 0, 0, scm_lstat);
1cc91f1b 989
0f2d19dd 990SCM
3d8d56df 991scm_lstat(str)
0f2d19dd 992 SCM str;
0f2d19dd 993{
02b754d3
GH
994#ifdef HAVE_LSTAT
995 int rv;
0f2d19dd 996 struct stat stat_temp;
02b754d3 997
3d8d56df 998 SCM_ASSERT(SCM_NIMP(str) && SCM_STRINGP(str), str, (char *)SCM_ARG1, s_lstat);
02b754d3
GH
999 SCM_SYSCALL(rv = lstat(SCM_CHARS(str), &stat_temp));
1000 if (rv != 0)
3d8d56df
GH
1001 {
1002 int en = errno;
1003
1004 scm_syserror_msg (s_lstat, "%s: %S",
1005 scm_listify (scm_makfrom0str (strerror (errno)),
1006 str,
1007 SCM_UNDEFINED),
1008 en);
1009 }
02b754d3 1010 return scm_stat2scm(&stat_temp);
0f2d19dd 1011#else
3d8d56df 1012 scm_sysmissing (s_lstat);
02b754d3
GH
1013 /* not reached. */
1014 return SCM_BOOL_F;
0f2d19dd
JB
1015#endif
1016}
1017
1018
3d8d56df 1019SCM_PROC (s_copy_file, "copy-file", 2, 0, 0, scm_copy_file);
1cc91f1b 1020
0f2d19dd 1021SCM
3d8d56df 1022scm_copy_file (oldfile, newfile)
0f2d19dd
JB
1023 SCM oldfile;
1024 SCM newfile;
0f2d19dd
JB
1025{
1026 int oldfd, newfd;
1027 int n;
1028 char buf[BUFSIZ]; /* this space could be shared. */
1029 struct stat oldstat;
1030
3d8d56df 1031 SCM_ASSERT (SCM_NIMP (oldfile) && SCM_ROSTRINGP (oldfile), oldfile, SCM_ARG1, s_copy_file);
0f2d19dd
JB
1032 if (SCM_SUBSTRP (oldfile))
1033 oldfile = scm_makfromstr (SCM_ROCHARS (oldfile), SCM_ROLENGTH (oldfile), 0);
3d8d56df 1034 SCM_ASSERT (SCM_NIMP (newfile) && SCM_ROSTRINGP (newfile), newfile, SCM_ARG2, s_copy_file);
0f2d19dd
JB
1035 if (SCM_SUBSTRP (newfile))
1036 newfile = scm_makfromstr (SCM_ROCHARS (newfile), SCM_ROLENGTH (newfile), 0);
1037 if (stat (SCM_ROCHARS (oldfile), &oldstat) == -1)
3d8d56df 1038 scm_syserror (s_copy_file);
0f2d19dd
JB
1039 SCM_DEFER_INTS;
1040 oldfd = open (SCM_ROCHARS (oldfile), O_RDONLY);
1041 if (oldfd == -1)
3d8d56df 1042 scm_syserror (s_copy_file);
02b754d3
GH
1043
1044 /* use POSIX flags instead of 07777?. */
0f2d19dd
JB
1045 newfd = open (SCM_ROCHARS (newfile), O_WRONLY | O_CREAT | O_TRUNC,
1046 oldstat.st_mode & 07777);
1047 if (newfd == -1)
3d8d56df 1048 scm_syserror (s_copy_file);
02b754d3 1049
0f2d19dd
JB
1050 while ((n = read (oldfd, buf, sizeof buf)) > 0)
1051 if (write (newfd, buf, n) != n)
1052 {
1053 close (oldfd);
1054 close (newfd);
3d8d56df 1055 scm_syserror (s_copy_file);
0f2d19dd
JB
1056 }
1057 close (oldfd);
1058 if (close (newfd) == -1)
3d8d56df 1059 scm_syserror (s_copy_file);
0f2d19dd 1060 SCM_ALLOW_INTS;
02b754d3 1061 return SCM_UNSPECIFIED;
0f2d19dd
JB
1062}
1063
1064\f
1cc91f1b 1065
0f2d19dd
JB
1066void
1067scm_init_filesys ()
0f2d19dd 1068{
52f4f4d6 1069 scm_add_feature ("i/o-extensions");
0f2d19dd 1070
0f2d19dd
JB
1071 scm_tc16_dir = scm_newsmob (&dir_smob);
1072
3d8d56df
GH
1073#ifdef O_RDONLY
1074scm_sysintern ("O_RDONLY", scm_long2num (O_RDONLY));
1075#endif
1076#ifdef O_WRONLY
1077scm_sysintern ("O_WRONLY", scm_long2num (O_WRONLY));
1078#endif
1079#ifdef O_RDWR
1080scm_sysintern ("O_RDWR", scm_long2num (O_RDWR));
1081#endif
1082#ifdef O_CREAT
1083scm_sysintern ("O_CREAT", scm_long2num (O_CREAT));
1084#endif
1085#ifdef O_EXCL
1086scm_sysintern ("O_EXCL", scm_long2num (O_EXCL));
1087#endif
1088#ifdef O_NOCTTY
1089scm_sysintern ("O_NOCTTY", scm_long2num (O_NOCTTY));
1090#endif
1091#ifdef O_TRUNC
1092scm_sysintern ("O_TRUNC", scm_long2num (O_TRUNC));
1093#endif
1094#ifdef O_APPEND
1095scm_sysintern ("O_APPEND", scm_long2num (O_APPEND));
1096#endif
1097#ifdef O_NONBLO
1098scm_sysintern ("O_NONBLOCK", scm_long2num (O_NONBLOCK));
1099#endif
1100#ifdef O_NDELAY
1101scm_sysintern ("O_NDELAY", scm_long2num (O_NDELAY));
1102#endif
1103#ifdef O_SYNC
1104scm_sysintern ("O_SYNC", scm_long2num (O_SYNC));
1105#endif
1106
1107
1108
0f2d19dd
JB
1109#include "filesys.x"
1110}