1999-08-11 Gary Houston <ghouston@easynet.co.uk>
[bpt/guile.git] / libguile / filesys.c
1 /* Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
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, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
40 * If you do not wish that, delete this exception notice. */
41 \f
42 #include <stdio.h>
43 #include "_scm.h"
44 #include "genio.h"
45 #include "smob.h"
46 #include "feature.h"
47 #include "fports.h"
48 #include "iselect.h"
49
50 #include "filesys.h"
51
52 \f
53 #ifdef HAVE_IO_H
54 #include <io.h>
55 #endif
56
57 #ifdef TIME_WITH_SYS_TIME
58 # include <sys/time.h>
59 # include <time.h>
60 #else
61 # if HAVE_SYS_TIME_H
62 # include <sys/time.h>
63 # else
64 # include <time.h>
65 # endif
66 #endif
67
68 #ifdef HAVE_UNISTD_H
69 #include <unistd.h>
70 #endif
71
72 #ifdef LIBC_H_WITH_UNISTD_H
73 #include <libc.h>
74 #endif
75
76 #ifdef HAVE_SYS_SELECT_H
77 #include <sys/select.h>
78 #endif
79
80 #ifdef HAVE_STRING_H
81 #include <string.h>
82 #endif
83
84 #include <sys/types.h>
85 #include <sys/stat.h>
86 #include <fcntl.h>
87
88 #include <pwd.h>
89
90
91 #if HAVE_DIRENT_H
92 # include <dirent.h>
93 # define NAMLEN(dirent) strlen((dirent)->d_name)
94 #else
95 # define dirent direct
96 # define NAMLEN(dirent) (dirent)->d_namlen
97 # if HAVE_SYS_NDIR_H
98 # include <sys/ndir.h>
99 # endif
100 # if HAVE_SYS_DIR_H
101 # include <sys/dir.h>
102 # endif
103 # if HAVE_NDIR_H
104 # include <ndir.h>
105 # endif
106 #endif
107
108 /* Ultrix has S_IFSOCK, but no S_ISSOCK. Ipe! */
109 #if defined (S_IFSOCK) && ! defined (S_ISSOCK)
110 #define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
111 #endif
112 \f
113
114
115 \f
116
117 /* {Permissions}
118 */
119
120 SCM_PROC (s_chown, "chown", 3, 0, 0, scm_chown);
121
122 SCM
123 scm_chown (object, owner, group)
124 SCM object;
125 SCM owner;
126 SCM group;
127 {
128 int rv;
129 int fdes;
130
131 object = SCM_COERCE_OUTPORT (object);
132
133 SCM_ASSERT (SCM_INUMP (owner), owner, SCM_ARG2, s_chown);
134 SCM_ASSERT (SCM_INUMP (group), group, SCM_ARG3, s_chown);
135 if (SCM_INUMP (object) || (SCM_NIMP (object) && SCM_OPFPORTP (object)))
136 {
137 if (SCM_INUMP (object))
138 fdes = SCM_INUM (object);
139 else
140 fdes = SCM_FPORT_FDES (object);
141 SCM_SYSCALL (rv = fchown (fdes, SCM_INUM (owner), SCM_INUM (group)));
142 }
143 else
144 {
145 SCM_ASSERT (SCM_NIMP (object) && SCM_ROSTRINGP (object),
146 object, SCM_ARG1, s_chown);
147 SCM_COERCE_SUBSTR (object);
148 SCM_SYSCALL (rv = chown (SCM_ROCHARS (object),
149 SCM_INUM (owner), SCM_INUM (group)));
150 }
151 if (rv == -1)
152 scm_syserror (s_chown);
153 return SCM_UNSPECIFIED;
154 }
155
156
157 SCM_PROC (s_chmod, "chmod", 2, 0, 0, scm_chmod);
158
159 SCM
160 scm_chmod (object, mode)
161 SCM object;
162 SCM mode;
163 {
164 int rv;
165 int fdes;
166
167 object = SCM_COERCE_OUTPORT (object);
168
169 SCM_ASSERT (SCM_INUMP (mode), mode, SCM_ARG2, s_chmod);
170 if (SCM_INUMP (object) || (SCM_NIMP (object) && SCM_OPFPORTP (object)))
171 {
172 if (SCM_INUMP (object))
173 fdes = SCM_INUM (object);
174 else
175 fdes = SCM_FPORT_FDES (object);
176 SCM_SYSCALL (rv = fchmod (fdes, SCM_INUM (mode)));
177 }
178 else
179 {
180 SCM_ASSERT (SCM_NIMP (object) && SCM_ROSTRINGP (object),
181 object, SCM_ARG1, s_chmod);
182 SCM_COERCE_SUBSTR (object);
183 SCM_SYSCALL (rv = chmod (SCM_ROCHARS (object), SCM_INUM (mode)));
184 }
185 if (rv == -1)
186 scm_syserror (s_chmod);
187 return SCM_UNSPECIFIED;
188 }
189
190 SCM_PROC (s_umask, "umask", 0, 1, 0, scm_umask);
191
192 SCM
193 scm_umask (mode)
194 SCM mode;
195 {
196 mode_t mask;
197 if (SCM_UNBNDP (mode))
198 {
199 mask = umask (0);
200 umask (mask);
201 }
202 else
203 {
204 SCM_ASSERT (SCM_INUMP (mode), mode, SCM_ARG1, s_umask);
205 mask = umask (SCM_INUM (mode));
206 }
207 return SCM_MAKINUM (mask);
208 }
209
210 \f
211
212 SCM_PROC (s_open_fdes, "open-fdes", 2, 1, 0, scm_open_fdes);
213 SCM
214 scm_open_fdes (SCM path, SCM flags, SCM mode)
215 {
216 int fd;
217 int iflags;
218 int imode;
219
220 SCM_ASSERT (SCM_NIMP (path) && SCM_ROSTRINGP (path), path, SCM_ARG1,
221 s_open_fdes);
222 SCM_COERCE_SUBSTR (path);
223 iflags = scm_num2long (flags, (char *) SCM_ARG2, s_open_fdes);
224
225 if (SCM_UNBNDP (mode))
226 imode = 0666;
227 else
228 {
229 SCM_ASSERT (SCM_INUMP (mode), mode, SCM_ARG3, s_open_fdes);
230 imode = SCM_INUM (mode);
231 }
232 SCM_SYSCALL (fd = open (SCM_ROCHARS (path), iflags, imode));
233 if (fd == -1)
234 scm_syserror (s_open_fdes);
235 return SCM_MAKINUM (fd);
236 }
237
238 SCM_PROC (s_open, "open", 2, 1, 0, scm_open);
239 SCM
240 scm_open (SCM path, SCM flags, SCM mode)
241 {
242 SCM newpt;
243 char *port_mode;
244 int fd;
245 int iflags;
246
247 fd = SCM_INUM (scm_open_fdes (path, flags, mode));
248 iflags = scm_num2long (flags, (char *) SCM_ARG2, s_open_fdes);
249 if (iflags & O_RDWR)
250 {
251 if (iflags & O_APPEND)
252 port_mode = "a+";
253 else if (iflags & O_CREAT)
254 port_mode = "w+";
255 else
256 port_mode = "r+";
257 }
258 else {
259 if (iflags & O_APPEND)
260 port_mode = "a";
261 else if (iflags & O_WRONLY)
262 port_mode = "w";
263 else
264 port_mode = "r";
265 }
266 newpt = scm_fdes_to_port (fd, port_mode, path);
267 return newpt;
268 }
269
270 SCM_PROC (s_close, "close", 1, 0, 0, scm_close);
271 SCM
272 scm_close (SCM fd_or_port)
273 {
274 int rv;
275 int fd;
276
277 fd_or_port = SCM_COERCE_OUTPORT (fd_or_port);
278
279 if (SCM_NIMP (fd_or_port) && SCM_PORTP (fd_or_port))
280 return scm_close_port (fd_or_port);
281 SCM_ASSERT (SCM_INUMP (fd_or_port), fd_or_port, SCM_ARG1, s_close);
282 fd = SCM_INUM (fd_or_port);
283 scm_evict_ports (fd); /* see scsh manual. */
284 SCM_SYSCALL (rv = close (fd));
285 /* following scsh, closing an already closed file descriptor is
286 not an error. */
287 if (rv < 0 && errno != EBADF)
288 scm_syserror (s_close);
289 return (rv < 0) ? SCM_BOOL_F : SCM_BOOL_T;
290 }
291
292 \f
293 /* {Files}
294 */
295
296 SCM_SYMBOL (scm_sym_regular, "regular");
297 SCM_SYMBOL (scm_sym_directory, "directory");
298 SCM_SYMBOL (scm_sym_symlink, "symlink");
299 SCM_SYMBOL (scm_sym_block_special, "block-special");
300 SCM_SYMBOL (scm_sym_char_special, "char-special");
301 SCM_SYMBOL (scm_sym_fifo, "fifo");
302 SCM_SYMBOL (scm_sym_sock, "socket");
303 SCM_SYMBOL (scm_sym_unknown, "unknown");
304
305 static SCM scm_stat2scm SCM_P ((struct stat *stat_temp));
306
307 static SCM
308 scm_stat2scm (stat_temp)
309 struct stat *stat_temp;
310 {
311 SCM ans = scm_make_vector (SCM_MAKINUM (15), SCM_UNSPECIFIED);
312 SCM *ve = SCM_VELTS (ans);
313
314 ve[0] = scm_ulong2num ((unsigned long) stat_temp->st_dev);
315 ve[1] = scm_ulong2num ((unsigned long) stat_temp->st_ino);
316 ve[2] = scm_ulong2num ((unsigned long) stat_temp->st_mode);
317 ve[3] = scm_ulong2num ((unsigned long) stat_temp->st_nlink);
318 ve[4] = scm_ulong2num ((unsigned long) stat_temp->st_uid);
319 ve[5] = scm_ulong2num ((unsigned long) stat_temp->st_gid);
320 #ifdef HAVE_ST_RDEV
321 ve[6] = scm_ulong2num ((unsigned long) stat_temp->st_rdev);
322 #else
323 ve[6] = SCM_BOOL_F;
324 #endif
325 ve[7] = scm_ulong2num ((unsigned long) stat_temp->st_size);
326 ve[8] = scm_ulong2num ((unsigned long) stat_temp->st_atime);
327 ve[9] = scm_ulong2num ((unsigned long) stat_temp->st_mtime);
328 ve[10] = scm_ulong2num ((unsigned long) stat_temp->st_ctime);
329 #ifdef HAVE_ST_BLKSIZE
330 ve[11] = scm_ulong2num ((unsigned long) stat_temp->st_blksize);
331 #else
332 ve[11] = scm_ulong2num (4096L);
333 #endif
334 #ifdef HAVE_ST_BLOCKS
335 ve[12] = scm_ulong2num ((unsigned long) stat_temp->st_blocks);
336 #else
337 ve[12] = SCM_BOOL_F;
338 #endif
339 {
340 int mode = stat_temp->st_mode;
341
342 if (S_ISREG (mode))
343 ve[13] = scm_sym_regular;
344 else if (S_ISDIR (mode))
345 ve[13] = scm_sym_directory;
346 else if (S_ISLNK (mode))
347 ve[13] = scm_sym_symlink;
348 else if (S_ISBLK (mode))
349 ve[13] = scm_sym_block_special;
350 else if (S_ISCHR (mode))
351 ve[13] = scm_sym_char_special;
352 else if (S_ISFIFO (mode))
353 ve[13] = scm_sym_fifo;
354 else if (S_ISSOCK (mode))
355 ve[13] = scm_sym_sock;
356 else
357 ve[13] = scm_sym_unknown;
358
359 ve[14] = SCM_MAKINUM ((~S_IFMT) & mode);
360
361 /* the layout of the bits in ve[14] is intended to be portable.
362 If there are systems that don't follow the usual convention,
363 the following could be used:
364
365 tmp = 0;
366 if (S_ISUID & mode) tmp += 1;
367 tmp <<= 1;
368 if (S_IRGRP & mode) tmp += 1;
369 tmp <<= 1;
370 if (S_ISVTX & mode) tmp += 1;
371 tmp <<= 1;
372 if (S_IRUSR & mode) tmp += 1;
373 tmp <<= 1;
374 if (S_IWUSR & mode) tmp += 1;
375 tmp <<= 1;
376 if (S_IXUSR & mode) tmp += 1;
377 tmp <<= 1;
378 if (S_IWGRP & mode) tmp += 1;
379 tmp <<= 1;
380 if (S_IXGRP & mode) tmp += 1;
381 tmp <<= 1;
382 if (S_IROTH & mode) tmp += 1;
383 tmp <<= 1;
384 if (S_IWOTH & mode) tmp += 1;
385 tmp <<= 1;
386 if (S_IXOTH & mode) tmp += 1;
387
388 ve[14] = SCM_MAKINUM (tmp);
389
390 */
391 }
392
393 return ans;
394 }
395
396 SCM_PROC (s_stat, "stat", 1, 0, 0, scm_stat);
397
398 SCM
399 scm_stat (object)
400 SCM object;
401 {
402 int rv;
403 int fdes;
404 struct stat stat_temp;
405
406 if (SCM_INUMP (object))
407 SCM_SYSCALL (rv = fstat (SCM_INUM (object), &stat_temp));
408 else
409 {
410 SCM_ASSERT (SCM_NIMP (object), object, SCM_ARG1, s_stat);
411 if (SCM_ROSTRINGP (object))
412 {
413 SCM_COERCE_SUBSTR (object);
414 SCM_SYSCALL (rv = stat (SCM_ROCHARS (object), &stat_temp));
415 }
416 else
417 {
418 object = SCM_COERCE_OUTPORT (object);
419 SCM_ASSERT (SCM_OPFPORTP (object), object, SCM_ARG1, s_stat);
420 fdes = SCM_FPORT_FDES (object);
421 SCM_SYSCALL (rv = fstat (fdes, &stat_temp));
422 }
423 }
424 if (rv == -1)
425 {
426 int en = errno;
427
428 scm_syserror_msg (s_stat, "%s: %S",
429 scm_listify (scm_makfrom0str (strerror (errno)),
430 object,
431 SCM_UNDEFINED),
432 en);
433 }
434 return scm_stat2scm (&stat_temp);
435 }
436
437 \f
438 /* {Modifying Directories}
439 */
440
441 SCM_PROC (s_link, "link", 2, 0, 0, scm_link);
442
443 SCM
444 scm_link (oldpath, newpath)
445 SCM oldpath;
446 SCM newpath;
447 {
448 int val;
449
450 SCM_ASSERT (SCM_NIMP (oldpath) && SCM_ROSTRINGP (oldpath), oldpath,
451 SCM_ARG1, s_link);
452 if (SCM_SUBSTRP (oldpath))
453 oldpath = scm_makfromstr (SCM_ROCHARS (oldpath),
454 SCM_ROLENGTH (oldpath), 0);
455 SCM_ASSERT (SCM_NIMP (newpath) && SCM_ROSTRINGP (newpath), newpath,
456 SCM_ARG2, s_link);
457 if (SCM_SUBSTRP (newpath))
458 newpath = scm_makfromstr (SCM_ROCHARS (newpath),
459 SCM_ROLENGTH (newpath), 0);
460 SCM_SYSCALL (val = link (SCM_ROCHARS (oldpath), SCM_ROCHARS (newpath)));
461 if (val != 0)
462 scm_syserror (s_link);
463 return SCM_UNSPECIFIED;
464 }
465
466
467
468 SCM_PROC (s_rename, "rename-file", 2, 0, 0, scm_rename);
469
470 SCM
471 scm_rename (oldname, newname)
472 SCM oldname;
473 SCM newname;
474 {
475 int rv;
476 SCM_ASSERT (SCM_NIMP (oldname) && SCM_ROSTRINGP (oldname), oldname, SCM_ARG1,
477 s_rename);
478 SCM_ASSERT (SCM_NIMP (newname) && SCM_ROSTRINGP (newname), newname, SCM_ARG2,
479 s_rename);
480 SCM_COERCE_SUBSTR (oldname);
481 SCM_COERCE_SUBSTR (newname);
482 #ifdef HAVE_RENAME
483 SCM_SYSCALL (rv = rename (SCM_ROCHARS (oldname), SCM_ROCHARS (newname)));
484 #else
485 SCM_SYSCALL (rv = link (SCM_ROCHARS (oldname), SCM_ROCHARS (newname)));
486 if (rv == 0)
487 {
488 SCM_SYSCALL (rv = unlink (SCM_ROCHARS (oldname)));;
489 if (rv != 0)
490 /* unlink failed. remove new name */
491 SCM_SYSCALL (unlink (SCM_ROCHARS (newname)));
492 }
493 #endif
494 if (rv != 0)
495 scm_syserror (s_rename);
496 return SCM_UNSPECIFIED;
497 }
498
499
500 SCM_PROC(s_delete_file, "delete-file", 1, 0, 0, scm_delete_file);
501
502 SCM
503 scm_delete_file (str)
504 SCM str;
505 {
506 int ans;
507 SCM_ASSERT (SCM_NIMP (str) && SCM_ROSTRINGP (str), str, SCM_ARG1,
508 s_delete_file);
509 SCM_COERCE_SUBSTR (str);
510 SCM_SYSCALL (ans = unlink (SCM_ROCHARS (str)));
511 if (ans != 0)
512 scm_syserror (s_delete_file);
513 return SCM_UNSPECIFIED;
514 }
515
516 SCM_PROC (s_mkdir, "mkdir", 1, 1, 0, scm_mkdir);
517
518 SCM
519 scm_mkdir (path, mode)
520 SCM path;
521 SCM mode;
522 {
523 #ifdef HAVE_MKDIR
524 int rv;
525 mode_t mask;
526 SCM_ASSERT (SCM_NIMP (path) && SCM_ROSTRINGP (path), path, SCM_ARG1,
527 s_mkdir);
528 SCM_COERCE_SUBSTR (path);
529 if (SCM_UNBNDP (mode))
530 {
531 mask = umask (0);
532 umask (mask);
533 SCM_SYSCALL (rv = mkdir (SCM_ROCHARS (path), 0777 ^ mask));
534 }
535 else
536 {
537 SCM_ASSERT (SCM_INUMP (mode), mode, SCM_ARG2, s_mkdir);
538 SCM_SYSCALL (rv = mkdir (SCM_ROCHARS (path), SCM_INUM (mode)));
539 }
540 if (rv != 0)
541 scm_syserror (s_mkdir);
542 return SCM_UNSPECIFIED;
543 #else
544 scm_sysmissing (s_mkdir);
545 /* not reached. */
546 return SCM_BOOL_F;
547 #endif
548 }
549
550
551 SCM_PROC (s_rmdir, "rmdir", 1, 0, 0, scm_rmdir);
552
553 SCM
554 scm_rmdir (path)
555 SCM path;
556 {
557 #ifdef HAVE_RMDIR
558 int val;
559
560 SCM_ASSERT (SCM_NIMP (path) && SCM_ROSTRINGP (path), path, SCM_ARG1,
561 s_rmdir);
562 SCM_COERCE_SUBSTR (path);
563 SCM_SYSCALL (val = rmdir (SCM_ROCHARS (path)));
564 if (val != 0)
565 scm_syserror (s_rmdir);
566 return SCM_UNSPECIFIED;
567 #else
568 scm_sysmissing (s_rmdir);
569 /* not reached. */
570 return SCM_BOOL_F;
571 #endif
572 }
573
574 \f
575 /* {Examining Directories}
576 */
577
578 long scm_tc16_dir;
579
580 SCM_PROC (s_opendir, "opendir", 1, 0, 0, scm_opendir);
581
582 SCM
583 scm_opendir (dirname)
584 SCM dirname;
585 {
586 DIR *ds;
587 SCM_ASSERT (SCM_NIMP (dirname) && SCM_ROSTRINGP (dirname), dirname, SCM_ARG1,
588 s_opendir);
589 SCM_COERCE_SUBSTR (dirname);
590 SCM_SYSCALL (ds = opendir (SCM_ROCHARS (dirname)));
591 if (ds == NULL)
592 scm_syserror (s_opendir);
593 SCM_RETURN_NEWSMOB (scm_tc16_dir | SCM_OPN, ds);
594 }
595
596
597 SCM_PROC (s_readdir, "readdir", 1, 0, 0, scm_readdir);
598
599 SCM
600 scm_readdir (port)
601 SCM port;
602 {
603 struct dirent *rdent;
604 SCM_ASSERT (SCM_NIMP (port) && SCM_OPDIRP (port), port, SCM_ARG1, s_readdir);
605 errno = 0;
606 SCM_SYSCALL (rdent = readdir ((DIR *) SCM_CDR (port)));
607 if (errno != 0)
608 scm_syserror (s_readdir);
609 return (rdent ? scm_makfromstr (rdent->d_name, NAMLEN (rdent), 0)
610 : SCM_EOF_VAL);
611 }
612
613
614
615 SCM_PROC (s_rewinddir, "rewinddir", 1, 0, 0, scm_rewinddir);
616
617 SCM
618 scm_rewinddir (port)
619 SCM port;
620 {
621 SCM_ASSERT (SCM_NIMP (port) && SCM_OPDIRP (port), port, SCM_ARG1, s_rewinddir);
622 rewinddir ((DIR *) SCM_CDR (port));
623 return SCM_UNSPECIFIED;
624 }
625
626
627
628 SCM_PROC (s_closedir, "closedir", 1, 0, 0, scm_closedir);
629
630 SCM
631 scm_closedir (port)
632 SCM port;
633 {
634 int sts;
635
636 SCM_ASSERT (SCM_NIMP (port) && SCM_DIRP (port), port, SCM_ARG1, s_closedir);
637 if (SCM_CLOSEDP (port))
638 {
639 return SCM_UNSPECIFIED;
640 }
641 SCM_SYSCALL (sts = closedir ((DIR *) SCM_CDR (port)));
642 if (sts != 0)
643 scm_syserror (s_closedir);
644 SCM_SETCAR (port, scm_tc16_dir);
645 return SCM_UNSPECIFIED;
646 }
647
648
649
650
651 static int scm_dir_print SCM_P ((SCM sexp, SCM port, scm_print_state *pstate));
652
653 static int
654 scm_dir_print (SCM exp, SCM port, scm_print_state *pstate)
655 {
656 scm_puts ("#<", port);
657 if (SCM_CLOSEDP (exp))
658 scm_puts ("closed: ", port);
659 scm_puts ("directory ", port);
660 scm_intprint (SCM_CDR (exp), 16, port);
661 scm_putc ('>', port);
662 return 1;
663 }
664
665
666 static scm_sizet scm_dir_free SCM_P ((SCM p));
667
668 static scm_sizet
669 scm_dir_free (p)
670 SCM p;
671 {
672 if (SCM_OPENP (p))
673 closedir ((DIR *) SCM_CDR (p));
674 return 0;
675 }
676
677 \f
678 /* {Navigating Directories}
679 */
680
681
682 SCM_PROC (s_chdir, "chdir", 1, 0, 0, scm_chdir);
683
684 SCM
685 scm_chdir (str)
686 SCM str;
687 {
688 int ans;
689
690 SCM_ASSERT (SCM_NIMP (str) && SCM_ROSTRINGP (str), str, SCM_ARG1, s_chdir);
691 SCM_COERCE_SUBSTR (str);
692 SCM_SYSCALL (ans = chdir (SCM_ROCHARS (str)));
693 if (ans != 0)
694 scm_syserror (s_chdir);
695 return SCM_UNSPECIFIED;
696 }
697
698
699
700 SCM_PROC (s_getcwd, "getcwd", 0, 0, 0, scm_getcwd);
701
702 SCM
703 scm_getcwd ()
704 {
705 #ifdef HAVE_GETCWD
706 char *rv;
707
708 scm_sizet size = 100;
709 char *wd;
710 SCM result;
711
712 wd = scm_must_malloc (size, s_getcwd);
713 while ((rv = getcwd (wd, size)) == 0 && errno == ERANGE)
714 {
715 scm_must_free (wd);
716 size *= 2;
717 wd = scm_must_malloc (size, s_getcwd);
718 }
719 if (rv == 0)
720 scm_syserror (s_getcwd);
721 result = scm_makfromstr (wd, strlen (wd), 0);
722 scm_must_free (wd);
723 return result;
724 #else
725 scm_sysmissing (s_getcwd);
726 /* not reached. */
727 return SCM_BOOL_F;
728 #endif
729 }
730
731 \f
732
733 SCM_PROC (s_select, "select", 3, 2, 0, scm_select);
734
735
736 static int
737 set_element (SELECT_TYPE *set, SCM element, int arg)
738 {
739 int fd;
740 element = SCM_COERCE_OUTPORT (element);
741 if (SCM_NIMP (element) && SCM_OPFPORTP (element))
742 fd = SCM_FPORT_FDES (element);
743 else {
744 SCM_ASSERT (SCM_INUMP (element), element, arg, s_select);
745 fd = SCM_INUM (element);
746 }
747 FD_SET (fd, set);
748 return fd;
749 }
750
751 static int
752 fill_select_type (SELECT_TYPE *set, SCM list, int arg)
753 {
754 int max_fd = 0, fd;
755 if (SCM_NIMP (list) && SCM_VECTORP (list))
756 {
757 int len = SCM_LENGTH (list);
758 SCM *ve = SCM_VELTS (list);
759
760 while (len > 0)
761 {
762 fd = set_element (set, ve[len - 1], arg);
763 if (fd > max_fd)
764 max_fd = fd;
765 len--;
766 }
767 }
768 else
769 {
770 while (list != SCM_EOL)
771 {
772 fd = set_element (set, SCM_CAR (list), arg);
773 if (fd > max_fd)
774 max_fd = fd;
775 list = SCM_CDR (list);
776 }
777 }
778
779 return max_fd;
780 }
781
782 static SCM
783 get_element (SELECT_TYPE *set, SCM element, SCM list)
784 {
785 element = SCM_COERCE_OUTPORT (element);
786 if (SCM_NIMP (element) && SCM_OPFPORTP (element))
787 {
788 if (FD_ISSET (SCM_FPORT_FDES (element), set))
789 list = scm_cons (element, list);
790 }
791 else if (SCM_INUMP (element))
792 {
793 if (FD_ISSET (SCM_INUM (element), set))
794 list = scm_cons (element, list);
795 }
796 return list;
797 }
798
799 static SCM
800 retrieve_select_type (SELECT_TYPE *set, SCM list)
801 {
802 SCM answer_list = SCM_EOL;
803
804 if (SCM_NIMP (list) && SCM_VECTORP (list))
805 {
806 int len = SCM_LENGTH (list);
807 SCM *ve = SCM_VELTS (list);
808
809 while (len > 0)
810 {
811 answer_list = get_element (set, ve[len - 1], answer_list);
812 len--;
813 }
814 return scm_vector (answer_list);
815 }
816 else
817 {
818 /* list is a list. */
819 while (list != SCM_EOL)
820 {
821 answer_list = get_element (set, SCM_CAR (list), answer_list);
822 list = SCM_CDR (list);
823 }
824 return answer_list;
825 }
826 }
827
828
829 SCM
830 scm_select (reads, writes, excepts, secs, usecs)
831 SCM reads;
832 SCM writes;
833 SCM excepts;
834 SCM secs;
835 SCM usecs;
836 {
837 #ifdef HAVE_SELECT
838 struct timeval timeout;
839 struct timeval * time_p;
840 SELECT_TYPE read_set;
841 SELECT_TYPE write_set;
842 SELECT_TYPE except_set;
843 int max_fd, fd;
844 int sreturn;
845
846 #define assert_set(x, arg) \
847 SCM_ASSERT (scm_ilength (x) > -1 || (SCM_NIMP (x) && SCM_VECTORP (x)), \
848 x, arg, s_select)
849 assert_set (reads, SCM_ARG1);
850 assert_set (writes, SCM_ARG2);
851 assert_set (excepts, SCM_ARG3);
852 #undef assert_set
853
854 FD_ZERO (&read_set);
855 FD_ZERO (&write_set);
856 FD_ZERO (&except_set);
857
858 max_fd = fill_select_type (&read_set, reads, SCM_ARG1);
859 fd = fill_select_type (&write_set, writes, SCM_ARG2);
860 if (fd > max_fd)
861 max_fd = fd;
862 fd = fill_select_type (&except_set, excepts, SCM_ARG3);
863 if (fd > max_fd)
864 max_fd = fd;
865
866 if (SCM_UNBNDP (secs) || SCM_FALSEP (secs))
867 time_p = 0;
868 else
869 {
870 if (SCM_INUMP (secs))
871 {
872 timeout.tv_sec = SCM_INUM (secs);
873 if (SCM_UNBNDP (usecs))
874 timeout.tv_usec = 0;
875 else
876 {
877 SCM_ASSERT (SCM_INUMP (usecs), usecs, SCM_ARG5, s_select);
878
879 timeout.tv_usec = SCM_INUM (usecs);
880 }
881 }
882 else
883 {
884 double fl = scm_num2dbl (secs, s_select);
885
886 if (!SCM_UNBNDP (usecs))
887 scm_wrong_type_arg (s_select, 4, secs);
888 if (fl > LONG_MAX)
889 scm_out_of_range (s_select, secs);
890 timeout.tv_sec = (long) fl;
891 timeout.tv_usec = (long) ((fl - timeout.tv_sec) * 1000000);
892 }
893 time_p = &timeout;
894 }
895
896 #ifdef GUILE_ISELECT
897 sreturn = scm_internal_select (max_fd + 1,
898 &read_set, &write_set, &except_set, time_p);
899 #else
900 sreturn = select (max_fd + 1,
901 &read_set, &write_set, &except_set, time_p);
902 #endif
903 if (sreturn < 0)
904 scm_syserror (s_select);
905 return scm_listify (retrieve_select_type (&read_set, reads),
906 retrieve_select_type (&write_set, writes),
907 retrieve_select_type (&except_set, excepts),
908 SCM_UNDEFINED);
909 #else
910 scm_sysmissing (s_select);
911 /* not reached. */
912 return SCM_BOOL_F;
913 #endif
914 }
915
916 \f
917
918 SCM_PROC (s_fcntl, "fcntl", 2, 0, 1, scm_fcntl);
919 SCM
920 scm_fcntl (SCM object, SCM cmd, SCM value)
921 {
922 int rv;
923 int fdes;
924 int ivalue;
925
926 object = SCM_COERCE_OUTPORT (object);
927
928 SCM_ASSERT (SCM_INUMP (cmd), cmd, SCM_ARG2, s_fcntl);
929 if (SCM_NIMP (object) && SCM_OPFPORTP (object))
930 fdes = SCM_FPORT_FDES (object);
931 else
932 {
933 SCM_ASSERT (SCM_INUMP (object), object, SCM_ARG1, s_fcntl);
934 fdes = SCM_INUM (object);
935 }
936 if (SCM_NULLP (value))
937 ivalue = 0;
938 else
939 {
940 SCM_ASSERT (SCM_INUMP (SCM_CAR (value)), value, SCM_ARG3, s_fcntl);
941 ivalue = SCM_INUM (SCM_CAR (value));
942 }
943 SCM_SYSCALL (rv = fcntl (fdes, SCM_INUM (cmd), ivalue));
944 if (rv == -1)
945 scm_syserror (s_fcntl);
946 return SCM_MAKINUM (rv);
947 }
948
949 SCM_PROC (s_fsync, "fsync", 1, 0, 0, scm_fsync);
950 SCM
951 scm_fsync (SCM object)
952 {
953 int fdes;
954
955 object = SCM_COERCE_OUTPORT (object);
956
957 if (SCM_NIMP (object) && SCM_OPFPORTP (object))
958 {
959 scm_flush (object);
960 fdes = SCM_FPORT_FDES (object);
961 }
962 else
963 {
964 SCM_ASSERT (SCM_INUMP (object), object, SCM_ARG1, s_fsync);
965 fdes = SCM_INUM (object);
966 }
967 if (fsync (fdes) == -1)
968 scm_syserror (s_fsync);
969 return SCM_UNSPECIFIED;
970 }
971
972 SCM_PROC (s_symlink, "symlink", 2, 0, 0, scm_symlink);
973
974 SCM
975 scm_symlink(oldpath, newpath)
976 SCM oldpath;
977 SCM newpath;
978 {
979 #ifdef HAVE_SYMLINK
980 int val;
981
982 SCM_ASSERT (SCM_NIMP (oldpath) && SCM_ROSTRINGP (oldpath), oldpath, SCM_ARG1,
983 s_symlink);
984 SCM_ASSERT (SCM_NIMP (newpath) && SCM_ROSTRINGP (newpath), newpath, SCM_ARG2,
985 s_symlink);
986 SCM_COERCE_SUBSTR (oldpath);
987 SCM_COERCE_SUBSTR (newpath);
988 SCM_SYSCALL (val = symlink(SCM_ROCHARS(oldpath), SCM_ROCHARS(newpath)));
989 if (val != 0)
990 scm_syserror (s_symlink);
991 return SCM_UNSPECIFIED;
992 #else
993 scm_sysmissing (s_symlink);
994 /* not reached. */
995 return SCM_BOOL_F;
996 #endif
997 }
998
999
1000 SCM_PROC (s_readlink, "readlink", 1, 0, 0, scm_readlink);
1001
1002 SCM
1003 scm_readlink(path)
1004 SCM path;
1005 {
1006 #ifdef HAVE_READLINK
1007 int rv;
1008 int size = 100;
1009 char *buf;
1010 SCM result;
1011 SCM_ASSERT (SCM_NIMP (path) && SCM_ROSTRINGP (path), path, (char *) SCM_ARG1,
1012 s_readlink);
1013 SCM_COERCE_SUBSTR (path);
1014 buf = scm_must_malloc (size, s_readlink);
1015 while ((rv = readlink (SCM_ROCHARS (path), buf, size)) == size)
1016 {
1017 scm_must_free (buf);
1018 size *= 2;
1019 buf = scm_must_malloc (size, s_readlink);
1020 }
1021 if (rv == -1)
1022 scm_syserror (s_readlink);
1023 result = scm_makfromstr (buf, rv, 0);
1024 scm_must_free (buf);
1025 return result;
1026 #else
1027 scm_sysmissing (s_readlink);
1028 /* not reached. */
1029 return SCM_BOOL_F;
1030 #endif
1031 }
1032
1033
1034 SCM_PROC (s_lstat, "lstat", 1, 0, 0, scm_lstat);
1035
1036 SCM
1037 scm_lstat(str)
1038 SCM str;
1039 {
1040 #ifdef HAVE_LSTAT
1041 int rv;
1042 struct stat stat_temp;
1043
1044 SCM_ASSERT (SCM_NIMP (str) && SCM_ROSTRINGP (str), str, (char *) SCM_ARG1,
1045 s_lstat);
1046 SCM_COERCE_SUBSTR (str);
1047 SCM_SYSCALL(rv = lstat(SCM_ROCHARS(str), &stat_temp));
1048 if (rv != 0)
1049 {
1050 int en = errno;
1051
1052 scm_syserror_msg (s_lstat, "%s: %S",
1053 scm_listify (scm_makfrom0str (strerror (errno)),
1054 str,
1055 SCM_UNDEFINED),
1056 en);
1057 }
1058 return scm_stat2scm(&stat_temp);
1059 #else
1060 scm_sysmissing (s_lstat);
1061 /* not reached. */
1062 return SCM_BOOL_F;
1063 #endif
1064 }
1065
1066
1067 SCM_PROC (s_copy_file, "copy-file", 2, 0, 0, scm_copy_file);
1068
1069 SCM
1070 scm_copy_file (oldfile, newfile)
1071 SCM oldfile;
1072 SCM newfile;
1073 {
1074 int oldfd, newfd;
1075 int n;
1076 char buf[BUFSIZ];
1077 struct stat oldstat;
1078
1079 SCM_ASSERT (SCM_NIMP (oldfile) && SCM_ROSTRINGP (oldfile), oldfile, SCM_ARG1, s_copy_file);
1080 if (SCM_SUBSTRP (oldfile))
1081 oldfile = scm_makfromstr (SCM_ROCHARS (oldfile), SCM_ROLENGTH (oldfile), 0);
1082 SCM_ASSERT (SCM_NIMP (newfile) && SCM_ROSTRINGP (newfile), newfile, SCM_ARG2, s_copy_file);
1083 if (SCM_SUBSTRP (newfile))
1084 newfile = scm_makfromstr (SCM_ROCHARS (newfile), SCM_ROLENGTH (newfile), 0);
1085 if (stat (SCM_ROCHARS (oldfile), &oldstat) == -1)
1086 scm_syserror (s_copy_file);
1087 oldfd = open (SCM_ROCHARS (oldfile), O_RDONLY);
1088 if (oldfd == -1)
1089 scm_syserror (s_copy_file);
1090
1091 /* use POSIX flags instead of 07777?. */
1092 newfd = open (SCM_ROCHARS (newfile), O_WRONLY | O_CREAT | O_TRUNC,
1093 oldstat.st_mode & 07777);
1094 if (newfd == -1)
1095 scm_syserror (s_copy_file);
1096
1097 while ((n = read (oldfd, buf, sizeof buf)) > 0)
1098 if (write (newfd, buf, n) != n)
1099 {
1100 close (oldfd);
1101 close (newfd);
1102 scm_syserror (s_copy_file);
1103 }
1104 close (oldfd);
1105 if (close (newfd) == -1)
1106 scm_syserror (s_copy_file);
1107 return SCM_UNSPECIFIED;
1108 }
1109
1110 \f
1111 /* Filename manipulation */
1112
1113 SCM scm_dot_string;
1114
1115 SCM_PROC (s_dirname, "dirname", 1, 0, 0, scm_dirname);
1116
1117 SCM
1118 scm_dirname (SCM filename)
1119 {
1120 char *s;
1121 int i, len;
1122 SCM_ASSERT (SCM_NIMP (filename) && SCM_ROSTRINGP (filename),
1123 filename,
1124 SCM_ARG1,
1125 s_dirname);
1126 s = SCM_ROCHARS (filename);
1127 len = SCM_LENGTH (filename);
1128 i = len - 1;
1129 while (i >= 0 && s[i] == '/') --i;
1130 while (i >= 0 && s[i] != '/') --i;
1131 while (i >= 0 && s[i] == '/') --i;
1132 if (i < 0)
1133 {
1134 if (len > 0 && s[0] == '/')
1135 return scm_make_shared_substring (filename, SCM_INUM0, SCM_MAKINUM (1));
1136 else
1137 return scm_dot_string;
1138 }
1139 else
1140 return scm_make_shared_substring (filename, SCM_INUM0, SCM_MAKINUM (i + 1));
1141 }
1142
1143 SCM_PROC (s_basename, "basename", 1, 1, 0, scm_basename);
1144
1145 SCM
1146 scm_basename (SCM filename, SCM suffix)
1147 {
1148 char *f, *s = 0;
1149 int i, j, len, end;
1150 SCM_ASSERT (SCM_NIMP (filename) && SCM_ROSTRINGP (filename),
1151 filename,
1152 SCM_ARG1,
1153 s_basename);
1154 SCM_ASSERT (SCM_UNBNDP (suffix)
1155 || (SCM_NIMP (suffix) && SCM_ROSTRINGP (suffix)),
1156 suffix,
1157 SCM_ARG2,
1158 s_basename);
1159 f = SCM_ROCHARS (filename);
1160 if (SCM_UNBNDP (suffix))
1161 j = -1;
1162 else
1163 {
1164 s = SCM_ROCHARS (suffix);
1165 j = SCM_LENGTH (suffix) - 1;
1166 }
1167 len = SCM_LENGTH (filename);
1168 i = len - 1;
1169 while (i >= 0 && f[i] == '/') --i;
1170 end = i;
1171 while (i >= 0 && j >= 0 && f[i] == s[j]) --i, --j;
1172 if (j == -1)
1173 end = i;
1174 while (i >= 0 && f[i] != '/') --i;
1175 if (i == end)
1176 {
1177 if (len > 0 && f[0] == '/')
1178 return scm_make_shared_substring (filename, SCM_INUM0, SCM_MAKINUM (1));
1179 else
1180 return scm_dot_string;
1181 }
1182 else
1183 return scm_make_shared_substring (filename,
1184 SCM_MAKINUM (i + 1),
1185 SCM_MAKINUM (end + 1));
1186 }
1187
1188
1189
1190 \f
1191
1192 void
1193 scm_init_filesys ()
1194 {
1195 scm_add_feature ("i/o-extensions");
1196
1197 scm_tc16_dir = scm_make_smob_type_mfpe ("directory", 0,
1198 NULL, scm_dir_free,scm_dir_print, NULL);
1199
1200 scm_dot_string = scm_permanent_object (scm_makfrom0str ("."));
1201
1202 #ifdef O_RDONLY
1203 scm_sysintern ("O_RDONLY", scm_long2num (O_RDONLY));
1204 #endif
1205 #ifdef O_WRONLY
1206 scm_sysintern ("O_WRONLY", scm_long2num (O_WRONLY));
1207 #endif
1208 #ifdef O_RDWR
1209 scm_sysintern ("O_RDWR", scm_long2num (O_RDWR));
1210 #endif
1211 #ifdef O_CREAT
1212 scm_sysintern ("O_CREAT", scm_long2num (O_CREAT));
1213 #endif
1214 #ifdef O_EXCL
1215 scm_sysintern ("O_EXCL", scm_long2num (O_EXCL));
1216 #endif
1217 #ifdef O_NOCTTY
1218 scm_sysintern ("O_NOCTTY", scm_long2num (O_NOCTTY));
1219 #endif
1220 #ifdef O_TRUNC
1221 scm_sysintern ("O_TRUNC", scm_long2num (O_TRUNC));
1222 #endif
1223 #ifdef O_APPEND
1224 scm_sysintern ("O_APPEND", scm_long2num (O_APPEND));
1225 #endif
1226 #ifdef O_NONBLOCK
1227 scm_sysintern ("O_NONBLOCK", scm_long2num (O_NONBLOCK));
1228 #endif
1229 #ifdef O_NDELAY
1230 scm_sysintern ("O_NDELAY", scm_long2num (O_NDELAY));
1231 #endif
1232 #ifdef O_SYNC
1233 scm_sysintern ("O_SYNC", scm_long2num (O_SYNC));
1234 #endif
1235
1236 #ifdef F_DUPFD
1237 scm_sysintern ("F_DUPFD", scm_long2num (F_DUPFD));
1238 #endif
1239 #ifdef F_GETFD
1240 scm_sysintern ("F_GETFD", scm_long2num (F_GETFD));
1241 #endif
1242 #ifdef F_SETFD
1243 scm_sysintern ("F_SETFD", scm_long2num (F_SETFD));
1244 #endif
1245 #ifdef F_GETFL
1246 scm_sysintern ("F_GETFL", scm_long2num (F_GETFL));
1247 #endif
1248 #ifdef F_SETFL
1249 scm_sysintern ("F_SETFL", scm_long2num (F_SETFL));
1250 #endif
1251 #ifdef F_GETOWN
1252 scm_sysintern ("F_GETOWN", scm_long2num (F_GETOWN));
1253 #endif
1254 #ifdef F_SETOWN
1255 scm_sysintern ("F_SETOWN", scm_long2num (F_SETOWN));
1256 #endif
1257 #ifdef FD_CLOEXEC
1258 scm_sysintern ("FD_CLOEXEC", scm_long2num (FD_CLOEXEC));
1259 #endif
1260
1261 #include "filesys.x"
1262 }