3 docCopyright("Steve Dekorte", 2002)
4 docLicense("BSD revised")
5 docDescription("""Encapsulates file i/o. Here's an example of opening a file, and reversing it's lines:
8 file = File clone openForUpdating("/tmp/test")
9 lines = file readLines reverse
11 lines foreach(i, line, file write(line, "\n"))
14 docCategory("FileSystem")
19 #include "IoFile_stat.h"
22 #include "IoCFunction.h"
27 #include "PortableTruncate.h"
30 #include <sys/types.h>
34 #if !defined(_MSC_VER) && !defined(__SYMBIAN32__)
35 #include <unistd.h> /* ok, this isn't ANSI */
38 #if defined(_MSC_VER) && !defined(__SYMBIAN32__)
40 #define getcwd _getcwd
41 #define popen(x,y) _popen(x,y)
42 #define pclose(x) _pclose(x)
45 #if defined(__SYMBIAN32__)
46 static int pclose(void* f
) { return 0; }
47 static int popen(void* f
, int m
) { return 0; }
48 static int rename(void* a
, void* b
) { return 0; }
49 static char* getcwd(char* buf
, int size
) { return 0; }
52 #define DATA(self) ((IoFileData *)IoObject_dataPointer(self))
54 IoTag
*IoFile_newTag(void *state
)
56 IoTag
*tag
= IoTag_newWithName_("File");
57 IoTag_state_(tag
, state
);
58 IoTag_cloneFunc_(tag
, (IoTagCloneFunc
*)IoFile_rawClone
);
59 IoTag_markFunc_(tag
, (IoTagMarkFunc
*)IoFile_mark
);
60 IoTag_freeFunc_(tag
, (IoTagFreeFunc
*)IoFile_free
);
61 IoTag_writeToStreamFunc_(tag
, (IoTagWriteToStreamFunc
*)IoFile_writeToStream_
);
62 IoTag_readFromStreamFunc_(tag
, (IoTagReadFromStreamFunc
*)IoFile_readFromStream_
);
66 IoFile
*IoFile_proto(void *state
)
68 IoMethodTable methodTable
[] = {
69 {"descriptor", IoFile_descriptor
},
71 {"standardInput", IoFile_standardInput
},
72 {"standardOutput", IoFile_standardOutput
},
73 {"standardError", IoFile_standardError
},
76 {"setPath", IoFile_setPath
},
77 {"path", IoFile_path
},
78 {"name", IoFile_lastPathComponent
},
79 {"temporaryFile", IoFile_temporaryFile
},
82 {"exists", IoFile_exists
},
83 {"size", IoFile_size
},
86 {"openForReading", IoFile_openForReading
},
87 {"openForUpdating", IoFile_openForUpdating
},
88 {"openForAppending", IoFile_openForAppending
},
89 {"mode", IoFile_mode
},
91 {"open", IoFile_open
},
92 {"popen", IoFile_popen
},
93 {"close", IoFile_close
},
95 {"isOpen", IoFile_isOpen
},
98 {"contents", IoFile_contents
},
99 {"asBuffer", IoFile_asBuffer
},
100 {"readLine", IoFile_readLine
},
101 {"readLines", IoFile_readLines
},
102 {"readStringOfLength", IoFile_readStringOfLength_
},
103 {"readBufferOfLength", IoFile_readBufferOfLength_
},
104 {"readToBufferLength", IoFile_readToBufferLength
},
106 {"foreach", IoFile_foreach
},
109 {"write", IoFile_write
},
110 {"atPut", IoFile_atPut
},
111 {"flush", IoFile_flush
},
114 {"rewind", IoFile_rewind
},
115 {"setPosition", IoFile_position_
},
116 {"position", IoFile_position
},
117 {"isAtEnd", IoFile_isAtEnd
},
120 {"remove", IoFile_remove
},
121 {"moveTo", IoFile_moveTo_
},
122 {"truncateToSize", IoFile_truncateToSize
},
127 IoObject
*self
= IoObject_new(state
);
128 IoObject_tag_(self
, IoFile_newTag(state
));
130 IoObject_setDataPointer_(self
, io_calloc(1, sizeof(IoFileData
)));
131 DATA(self
)->path
= IOSYMBOL("");
132 DATA(self
)->mode
= IOSYMBOL("r+");
133 DATA(self
)->flags
= IOFILE_FLAGS_NONE
;
134 IoState_registerProtoWithFunc_((IoState
*)state
, self
, IoFile_proto
);
136 IoObject_addMethodTable_(self
, methodTable
);
137 IoFile_statInit(self
);
141 IoFile
*IoFile_rawClone(IoFile
*proto
)
143 IoObject
*self
= IoObject_rawClonePrimitive(proto
);
144 IoObject_setDataPointer_(self
, cpalloc(IoObject_dataPointer(proto
), sizeof(IoFileData
)));
145 DATA(self
)->info
= NULL
;
149 IoFile
*IoFile_new(void *state
)
151 IoObject
*proto
= IoState_protoWithInitFunction_((IoState
*)state
, IoFile_proto
);
152 return IOCLONE(proto
);
155 IoFile
*IoFile_newWithPath_(void *state
, IoSymbol
*path
)
157 IoFile
*self
= IoFile_new(state
);
158 DATA(self
)->path
= IOREF(path
);
163 IoFile
*IoFile_newWithStream_(void *state
, FILE *stream
)
165 IoFile
*self
= IoFile_new(state
);
166 DATA(self
)->stream
= stream
;
170 IoFile
*IoFile_cloneWithPath_(IoFile
*self
, IoSymbol
*path
)
172 IoFile
*f
= IOCLONE(self
);
173 DATA(f
)->path
= IOREF(path
);
177 void IoFile_mark(IoFile
*self
)
179 IoObject_shouldMarkIfNonNull(DATA(self
)->path
);
180 IoObject_shouldMarkIfNonNull(DATA(self
)->mode
);
183 void IoFile_free(IoFile
*self
)
185 if (NULL
== IoObject_dataPointer(self
))
190 IoFile_justClose(self
);
192 if (DATA(self
)->info
)
194 io_free(DATA(self
)->info
);
197 io_free(IoObject_dataPointer(self
));
200 void IoFile_writeToStream_(IoFile
*self
, BStream
*stream
)
202 BStream_writeTaggedUArray_(stream
, IoSeq_rawUArray(DATA(self
)->path
));
203 BStream_writeTaggedUArray_(stream
, IoSeq_rawUArray(DATA(self
)->mode
));
206 void *IoFile_readFromStream_(IoFile
*self
, BStream
*stream
)
209 IoSymbol
*path
= IoState_symbolWithUArray_copy_(IOSTATE
, BStream_readTaggedUArray(stream
), 1);
210 DATA(self
)->path
= IOREF(path
);
211 mode
= IoState_symbolWithUArray_copy_(IOSTATE
, BStream_readTaggedUArray(stream
), 1);
212 DATA(self
)->mode
= IOREF(mode
);
216 void IoFile_justClose(IoFile
*self
)
218 FILE *stream
= DATA(self
)->stream
;
222 if (stream
!= stdout
&& stream
!= stdin
)
224 if (DATA(self
)->flags
== IOFILE_FLAGS_PIPE
)
231 DATA(self
)->flags
= IOFILE_FLAGS_NONE
;
235 DATA(self
)->stream
= (FILE *)NULL
;
239 int IoFile_justExists(IoFile
*self
)
241 struct stat statInfo
;
242 return stat(CSTRING(DATA(self
)->path
), &statInfo
) == 0;
245 int IoFile_create(IoFile
*self
)
247 FILE *fp
= fopen(CSTRING(DATA(self
)->path
), "w");
258 /* ----------------------------------------------------------- */
260 IoObject
*IoFile_descriptor(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
263 docSlot("escriptor", "Returns the file's descriptor as a number.")
266 return IONUMBER(fileno(DATA(self
)->stream
));
270 IoObject
*IoFile_standardInput(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
273 docSlot("standardInput",
274 "Returns a new File whose stream is set to the standard input stream.")
277 IoFile
*newFile
= IoFile_new(IOSTATE
);
278 DATA(newFile
)->path
= IOREF(IOSYMBOL("<standard input>"));
279 DATA(newFile
)->mode
= IOREF(IOSYMBOL("r"));
280 DATA(newFile
)->stream
= stdin
;
281 DATA(newFile
)->flags
= IOFILE_FLAGS_NONE
;
285 IoObject
*IoFile_standardOutput(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
288 docSlot("standardOutput",
289 "Returns a new File whose stream is set to the standard output stream.")
292 IoFile
*newFile
= IoFile_new(IOSTATE
);
293 DATA(newFile
)->path
= IOREF(IOSYMBOL("<standard output>"));
294 DATA(newFile
)->mode
= IOREF(IOSYMBOL("w"));
295 DATA(newFile
)->stream
= stdout
;
296 DATA(newFile
)->flags
= IOFILE_FLAGS_NONE
;
300 IoObject
*IoFile_standardError(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
303 docSlot("standardError",
304 "Returns a new File whose stream is set to the standard error stream.")
307 IoFile
*newFile
= IoFile_new(IOSTATE
);
308 DATA(newFile
)->path
= IOREF(IOSYMBOL("<standard error>"));
309 DATA(newFile
)->mode
= IOREF(IOSYMBOL("w"));
310 DATA(newFile
)->stream
= stderr
;
311 DATA(newFile
)->flags
= IOFILE_FLAGS_NONE
;
316 IoObject
*IoFile_setPath(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
319 docSlot("setPath(aString)",
320 "Sets the file path of the receiver to pathString.
321 The default path is an empty string. Returns self.")
324 DATA(self
)->path
= IOREF(IoMessage_locals_symbolArgAt_(m
, locals
, 0));
328 IoObject
*IoFile_path(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
332 "Returns the file path of the receiver.")
335 return DATA(self
)->path
;
338 IoObject
*IoFile_lastPathComponent(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
342 "Returns the last path component of the file path.")
345 return IoSeq_lastPathComponent(DATA(self
)->path
, locals
, m
);
348 IoObject
*IoFile_mode(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
352 "Returns the open mode of the file(either read, update or append).")
355 char *mode
= IoSeq_asCString(DATA(self
)->mode
);
357 if (!strcmp(mode
, "r")) { return IOSYMBOL("read"); }
358 if (!strcmp(mode
, "r+")) { return IOSYMBOL("update"); }
359 if (!strcmp(mode
, "a+")) { return IOSYMBOL("append"); }
364 IoObject
*IoFile_temporaryFile(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
367 docSlot("temporaryFile",
368 "Returns a new File object with an open temporary file. The file is
369 automatically deleted when the returned File object is closed or garbage collected. ")
372 IoFile
*newFile
= IoFile_new(IOSTATE
);
373 DATA(newFile
)->stream
= tmpfile();
377 IoObject
*IoFile_openForReading(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
380 docSlot("openForReading(optionalPathString)",
381 "Sets the file mode to read (reading only) and calls open(optionalPathString). ")
383 DATA(self
)->mode
= IOREF(IOSYMBOL("r"));
384 return IoFile_open(self
, locals
, m
);
387 IoObject
*IoFile_openForUpdating(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
390 docSlot("openForUpdating(optionalPathString)",
391 "Sets the file mode to update (reading and writing) and calls
392 open(optionalPathString). This will not delete the file if it already exists.
393 Use the remove method first if you need to delete an existing file before opening a new one.")
396 DATA(self
)->mode
= IOREF(IOSYMBOL("r+"));
397 return IoFile_open(self
, locals
, m
);
400 IoObject
*IoFile_openForAppending(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
403 docSlot("openForAppending(optionalPathString)",
404 "Sets the file mode to append (writing to the end of the file)
405 and calls open(optionalPathString).")
408 DATA(self
)->mode
= IOREF(IOSYMBOL("a+"));
409 return IoFile_open(self
, locals
, m
);
412 IoObject
*IoFile_open(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
415 docSlot("open(optionalPathString)",
416 "Opens the file. Creates one if it does not exist.
417 If the optionalPathString argument is provided, the path is set to it before
418 opening. Returns self or raises an File exception on error.")
421 char *mode
= CSTRING(DATA(self
)->mode
);
423 DATA(self
)->flags
= IOFILE_FLAGS_NONE
;
425 if (IoMessage_argCount(m
) > 0)
427 DATA(self
)->path
= IOREF(IoMessage_locals_symbolArgAt_(m
, locals
, 0));
430 if (!DATA(self
)->stream
)
432 if (!IoFile_justExists(self
) && strcmp(mode
, "r") != 0 )
436 if(!IoFile_justExists(self
))
438 IoState_error_(IOSTATE
, m
, "unable to create file '%s'", CSTRING(DATA(self
)->path
));
442 DATA(self
)->stream
= fopen(CSTRING(DATA(self
)->path
), mode
);
445 if (DATA(self
)->stream
== NULL
)
447 IoState_error_(IOSTATE
, m
, "unable to open file path '%s'", CSTRING(DATA(self
)->path
));
453 IoObject
*IoFile_popen(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
460 DATA(self
)->flags
= IOFILE_FLAGS_PIPE
;
462 if (IoMessage_argCount(m
) > 0)
464 DATA(self
)->path
= IOREF(IoMessage_locals_symbolArgAt_(m
, locals
, 0));
467 if (DATA(self
)->stream
)
469 IoFile_justClose(self
);
472 #if defined(SANE_POPEN)
473 DATA(self
)->mode
= IOREF(IOSYMBOL("a+"));
474 DATA(self
)->stream
= popen(CSTRING(DATA(self
)->path
), "r+");
475 #elif defined(__SYMBIAN32__)
476 /* Symbian does not implement popen.
477 * (There is popen3() but it is "internal and not intended for use.")
479 DATA(self
)->mode
= IOREF(IOSYMBOL("r"));
480 DATA(self
)->stream
= NULL
;
482 DATA(self
)->mode
= IOREF(IOSYMBOL("r"));
483 DATA(self
)->stream
= popen(CSTRING(DATA(self
)->path
), "r");
485 if (DATA(self
)->stream
== NULL
)
487 IoState_error_(IOSTATE
, m
, "error executing file path '%s'", CSTRING(DATA(self
)->path
));
494 IoObject
*IoFile_close(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
498 "Closes the receiver if open, otherwise does nothing. Returns self.")
501 IoFile_justClose(self
);
505 IoObject
*IoFile_flush(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
509 "Forces any buffered data to be written to disk. Returns self.")
512 fflush(DATA(self
)->stream
);
516 IoObject
*IoFile_rawAsString(IoFile
*self
)
518 UArray
*ba
= UArray_new();
520 if (UArray_readFromFilePath_(ba
, IoSeq_rawUArray(DATA(self
)->path
)) == 1)
522 return IoState_symbolWithUArray_copy_(IOSTATE
, ba
, 0);
527 IoState_error_(IOSTATE
, NULL
, "unable to read file '%s'", CSTRING(DATA(self
)->path
));
533 IoObject
*IoFile_contents(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
536 docSlot("contents", "Returns contents of the file as a mutable Sequence of bytes.")
539 UArray
*ba
= UArray_new();
542 if (DATA(self
)->stream
== stdin
)
544 result
= UArray_readFromCStream_(ba
, DATA(self
)->stream
);
548 result
= UArray_readFromFilePath_(ba
, IoSeq_rawUArray(DATA(self
)->path
));
553 return IoSeq_newWithUArray_copy_(IOSTATE
, ba
, 0);
558 IoState_error_(IOSTATE
, m
, "unable to read file '%s'", CSTRING(DATA(self
)->path
));
564 IoObject
*IoFile_asBuffer(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
567 docSlot("asBuffer", "Opens the receiver in read only mode, reads the whole
568 contents of the file into a buffer object, closes the file and returns the buffer.")
571 UArray
*ba
= UArray_new();
573 if (UArray_readFromFilePath_(ba
, IoSeq_rawUArray(DATA(self
)->path
)) == 1)
575 return IoSeq_newWithUArray_copy_(IOSTATE
, ba
, 0);
580 IoState_error_(IOSTATE
, m
, "unable to read file '%s'", CSTRING(DATA(self
)->path
));
586 IoObject
*IoFile_exists(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
589 docSlot("exists", "Returns true if the file specified by the receiver's
590 path exists, false otherwise.")
593 return IOBOOL(self
, IoFile_justExists(self
));
596 IoObject
*IoFile_remove(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
600 "Removes the file specified by the receiver's path.
601 Raises an error if the file exists but is not removed. Returns self.")
606 #if defined(__SYMBIAN32__)
609 error
= remove(CSTRING(DATA(self
)->path
));
612 if (error
&& IoFile_justExists(self
))
614 IoState_error_(IOSTATE
, m
, "error removing file '%s'", CSTRING(DATA(self
)->path
));
619 IoObject
*IoFile_truncateToSize(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
622 docSlot("truncateToSize(numberOfBytes)",
623 "Trunctates the file's size to the numberOfBytes. Returns self.")
626 long newSize
= IoMessage_locals_longArgAt_(m
, locals
, 0);
627 truncate(CSTRING(DATA(self
)->path
), newSize
);
631 IoObject
*IoFile_moveTo_(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
634 docSlot("moveTo(pathString)",
635 """Moves the file specified by the receiver's path to the
636 new path pathString. Raises an File doesNotExist exception if the
637 file does not exist or a File nameConflict exception if the file
638 nameString already exists.""")
641 IoSymbol
*newPath
= IoMessage_locals_symbolArgAt_(m
, locals
, 0);
642 int error
= rename(CSTRING(DATA(self
)->path
), CSTRING(newPath
));
646 IoState_error_(IOSTATE
, m
, "error moving file '%s' to '%s'", CSTRING(DATA(self
)->path
), CSTRING(newPath
));
651 IoObject
*IoFile_write(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
654 docSlot("write(aSequence1, aSequence2, ...)",
655 "Writes the arguments to the receiver file. Returns self.")
660 IoFile_assertOpen(self
, locals
, m
);
661 IoFile_assertWrite(self
, locals
, m
);
663 for (i
= 0; i
< IoMessage_argCount(m
); i
++)
665 IoSymbol
*string
= IoMessage_locals_seqArgAt_(m
, locals
, i
);
666 UArray_writeToCStream_(IoSeq_rawUArray(string
), DATA(self
)->stream
);
668 if (ferror(DATA(self
)->stream
) != 0)
670 IoState_error_(IOSTATE
, m
, "error writing to file '%s'",
671 CSTRING(DATA(self
)->path
));
678 IoObject
*IoFile_readLines(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
682 "Returns list containing all lines in the file.")
685 IoState
*state
= IOSTATE
;
687 if (!DATA(self
)->stream
)
689 IoFile_openForReading(self
, locals
, m
);
692 IoFile_assertOpen(self
, locals
, m
);
695 IoList
*lines
= IoList_new(state
);
698 IoState_pushRetainPool(state
);
702 IoState_clearTopPool(state
);
703 newLine
= IoFile_readLine(self
, locals
, m
);
710 IoList_rawAppend_(lines
, newLine
);
712 IoState_popRetainPool(state
);
718 IoObject
*IoFile_readLine(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
721 docSlot("readLine", "Reads the next line of the file and returns it as a
722 string without the return character. Returns Nil if the end of the file has been reached.")
724 //char *path = CSTRING(DATA(self)->path); // tmp for debugging
726 IoFile_assertOpen(self
, locals
, m
);
728 if (feof(DATA(self
)->stream
) != 0)
730 clearerr(DATA(self
)->stream
);
735 UArray
*ba
= UArray_new();
737 unsigned char didRead
= UArray_readLineFromCStream_(ba
, DATA(self
)->stream
);
745 error
= ferror(DATA(self
)->stream
);
750 clearerr(DATA(self
)->stream
);
751 IoState_error_(IOSTATE
, m
, "error reading from file '%s'", CSTRING(DATA(self
)->path
));
755 return IoSeq_newWithUArray_copy_(IOSTATE
, ba
, 0);
756 /*return IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);*/
760 UArray
*IoFile_readUArrayOfLength_(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
762 size_t length
= IoMessage_locals_sizetArgAt_(m
, locals
, 0);
763 UArray
*ba
= UArray_new();
764 IoFile_assertOpen(self
, locals
, m
);
766 UArray_readNumberOfItems_fromCStream_(ba
, length
, DATA(self
)->stream
);
768 if (ferror(DATA(self
)->stream
) != 0)
770 clearerr(DATA(self
)->stream
);
772 IoState_error_(IOSTATE
, m
, "error reading file '%s'", CSTRING(DATA(self
)->path
));
775 if (!UArray_size(ba
))
784 IoObject
*IoFile_readToBufferLength(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
787 docSlot("readToBufferOfLength(aBuffer, aNumber)",
788 "Reads at most aNumber number of items and appends them to aBuffer.
789 Returns number of items read.")
792 IoSeq
*buffer
= IoMessage_locals_mutableSeqArgAt_(m
, locals
, 0);
793 size_t length
= IoMessage_locals_longArgAt_(m
, locals
, 1);
794 UArray
*ba
= IoSeq_rawUArray(buffer
);
795 size_t itemsRead
= UArray_readNumberOfItems_fromCStream_(ba
, length
, DATA(self
)->stream
);
796 return IONUMBER(itemsRead
);
799 IoObject
*IoFile_readBufferOfLength_(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
802 docSlot("readBufferOfLength(aNumber)",
803 "Reads a Buffer of the specified length and returns it.
804 Returns Nil if the end of the file has been reached.")
807 UArray
*ba
= IoFile_readUArrayOfLength_(self
, locals
, m
);
814 return IoSeq_newWithUArray_copy_(IOSTATE
, ba
, 0);
817 IoObject
*IoFile_readStringOfLength_(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
820 docSlot("readStringOfLength(aNumber)",
821 "Reads a String of the specified length and returns it.
822 Returns Nil if the end of the file has been reached.")
825 UArray
*ba
= IoFile_readUArrayOfLength_(self
, locals
, m
);
832 return IoState_symbolWithUArray_copy_(IOSTATE
, ba
, 0);
835 IoObject
*IoFile_rewind(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
839 "Sets the file position pointer to the beginning of the file.")
841 IoFile_assertOpen(self
, locals
, m
);
843 if (DATA(self
)->stream
)
845 rewind(DATA(self
)->stream
);
851 IoObject
*IoFile_position_(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
854 docSlot("setPosition(aNumber)",
855 "Sets the file position pointer to the byte specified by aNumber. Returns self.")
858 long pos
= IoMessage_locals_longArgAt_(m
, locals
, 0);
859 IoFile_assertOpen(self
, locals
, m
);
861 if (fseek(DATA(self
)->stream
, pos
, 0) != 0)
863 IoState_error_(IOSTATE
, m
, "unable to set position %i file path '%s'",
864 (int)pos
, CSTRING(DATA(self
)->path
));
870 IoObject
*IoFile_position(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
874 "Returns the current file pointer byte position as a Number.")
877 IoFile_assertOpen(self
, locals
, m
);
878 return IONUMBER(ftell(DATA(self
)->stream
));
881 IoObject
*IoFile_isAtEnd(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
885 "Returns true if the file is at it's end. Otherwise returns false.")
888 IoFile_assertOpen(self
, locals
, m
);
889 return IOBOOL(self
, feof(DATA(self
)->stream
) != 0);
892 IoObject
*IoFile_size(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
896 "Returns the file size in bytes.")
899 FILE *fp
= fopen(CSTRING(DATA(self
)->path
), "r");
904 fseek(fp
, 0, SEEK_END
);
905 fileSize
= ftell(fp
);
907 return IONUMBER(fileSize
);
911 IoState_error_(IOSTATE
, m
, "unable to open file '%s'", CSTRING(DATA(self
)->path
));
917 IoObject
*IoFile_isOpen(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
921 "Returns self if the file is open. Otherwise returns Nil.")
924 return IOBOOL(self
, DATA(self
)->stream
!= 0);
927 IoObject
*IoFile_assertOpen(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
929 if (!DATA(self
)->stream
)
931 IoState_error_(IOSTATE
, m
, "file '%s' not yet open", CSTRING(DATA(self
)->path
));
936 IoObject
*IoFile_assertWrite(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
938 char *mode
= IoSeq_asCString(DATA(self
)->mode
);
940 if ((strcmp(mode
, "r+")) && (strcmp(mode
, "a+")) && (strcmp(mode
, "w")))
942 IoState_error_(IOSTATE
, m
, "file '%s' not open for write", CSTRING(DATA(self
)->path
));
948 IoObject
*IoFile_at(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
951 docSlot("at(aNumber)",
952 "Returns a Number containing the byte at the specified
953 byte index or Nil if the index is out of bounds.")
958 IoFile_assertOpen(self
, locals
, m
);
959 IoFile_position_(self
, locals
, m
); /* works since first arg is the same */
960 byte
= fgetc(DATA(self
)->stream
);
967 return IONUMBER(byte
);
970 IoObject
*IoFile_atPut(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
973 docSlot("atPut(positionNumber, byteNumber)",
974 "Writes the byte value of byteNumber to the file position
975 positionNumber. Returns self.")
978 int c
= IoMessage_locals_intArgAt_(m
, locals
, 1);
980 IoFile_assertOpen(self
, locals
, m
);
981 IoFile_assertWrite(self
, locals
, m
);
982 IoFile_position_(self
, locals
, m
); // works since first arg is the same
984 if (fputc(c
, DATA(self
)->stream
) == EOF
)
986 int pos
= IoMessage_locals_intArgAt_(m
, locals
, 0); // BUG - this may not be the same when evaled
987 IoState_error_(IOSTATE
, m
, "error writing to position %i in file '%s'", pos
, CSTRING(DATA(self
)->path
));
993 IoObject
*IoFile_foreach(IoFile
*self
, IoObject
*locals
, IoMessage
*m
)
996 docSlot("foreach(optionalIndex, value, message)",
997 """For each byte, set index to the index of the byte
998 and value to the number containing the byte value and execute aMessage.
1001 aFile foreach(i, v, writeln("byte at ", i, " is ", v))
1002 aFile foreach(v, writeln("byte ", v))
1007 IoObject
*result
= IONIL(self
);
1009 IoSymbol
*indexSlotName
, *characterSlotName
;
1010 IoMessage
*doMessage
;
1013 IoMessage_foreachArgs(m
, self
, &indexSlotName
, &characterSlotName
, &doMessage
);
1017 int c
= getc(DATA(self
)->stream
);
1026 IoObject_setSlot_to_(locals
, indexSlotName
, IONUMBER(i
));
1029 IoObject_setSlot_to_(locals
, characterSlotName
, IONUMBER(c
));
1030 result
= IoMessage_locals_performOn_(doMessage
, locals
, locals
);
1032 if (IoState_handleStatus(IOSTATE
))