author | Claus Gittinger <cg@exept.de> |
Wed, 30 Jul 1997 13:13:17 +0200 | |
changeset 2808 | 3a9ce7aadad8 |
parent 2796 | b45639a2fc1e |
child 2811 | 21136662e8f1 |
permissions | -rw-r--r-- |
1 | 1 |
" |
5 | 2 |
COPYRIGHT (c) 1989 by Claus Gittinger |
159 | 3 |
All Rights Reserved |
1 | 4 |
|
5 |
This software is furnished under a license and may be used |
|
6 |
only in accordance with the terms of that license and with the |
|
7 |
inclusion of the above copyright notice. This software may not |
|
8 |
be provided or otherwise made available to, or used by, any |
|
9 |
other person. No title to or ownership of the software is |
|
10 |
hereby transferred. |
|
11 |
" |
|
12 |
||
13 |
ExternalStream subclass:#FileStream |
|
1088 | 14 |
instanceVariableNames:'pathName' |
15 |
classVariableNames:'' |
|
16 |
poolDictionaries:'' |
|
17 |
category:'Streams-External' |
|
1 | 18 |
! |
19 |
||
216 | 20 |
!FileStream primitiveDefinitions! |
1 | 21 |
%{ |
22 |
#include <stdio.h> |
|
437 | 23 |
#define _STDIO_H_INCLUDED_ |
24 |
||
10 | 25 |
#include <errno.h> |
437 | 26 |
#define _ERRNO_H_INCLUDED_ |
1 | 27 |
|
28 |
#ifdef transputer |
|
29 |
# include <iocntrl.h> |
|
30 |
# ifndef fileno |
|
31 |
/* kludge: inmos forgot fileno */ |
|
32 |
# define fileno(f) ((f)->__file) |
|
33 |
# endif |
|
34 |
#else |
|
35 |
# include <sys/types.h> |
|
36 |
# include <sys/stat.h> |
|
37 |
#endif |
|
10 | 38 |
|
42 | 39 |
#ifdef hpux |
68 | 40 |
# define fileno(f) ((f->__fileH << 8) | (f->__fileL)) |
42 | 41 |
#endif |
42 |
||
10 | 43 |
#ifndef SEEK_SET |
13 | 44 |
# define SEEK_SET 0 |
10 | 45 |
#endif |
46 |
#ifndef SEEK_CUR |
|
13 | 47 |
# define SEEK_CUR 1 |
10 | 48 |
#endif |
49 |
#ifndef SEEK_END |
|
13 | 50 |
# define SEEK_END 2 |
10 | 51 |
#endif |
52 |
||
223 | 53 |
/* |
2808 | 54 |
* not all systems have time_t and off_t |
55 |
* explicit add of those we know to have ... |
|
56 |
*/ |
|
57 |
#ifdef __osf__ |
|
58 |
# define OFF_T off_t |
|
59 |
#endif |
|
60 |
||
61 |
#ifndef OFF_T |
|
62 |
# define OFF_T long |
|
63 |
#endif |
|
64 |
||
65 |
/* |
|
223 | 66 |
* on some systems errno is a macro ... check for it here |
67 |
*/ |
|
68 |
#ifndef errno |
|
69 |
extern errno; |
|
70 |
#endif |
|
71 |
||
1 | 72 |
%} |
173 | 73 |
! ! |
1 | 74 |
|
613 | 75 |
!FileStream class methodsFor:'documentation'! |
76 |
||
77 |
copyright |
|
78 |
" |
|
79 |
COPYRIGHT (c) 1989 by Claus Gittinger |
|
80 |
All Rights Reserved |
|
81 |
||
82 |
This software is furnished under a license and may be used |
|
83 |
only in accordance with the terms of that license and with the |
|
84 |
inclusion of the above copyright notice. This software may not |
|
85 |
be provided or otherwise made available to, or used by, any |
|
86 |
other person. No title to or ownership of the software is |
|
87 |
hereby transferred. |
|
88 |
" |
|
89 |
! |
|
90 |
||
91 |
documentation |
|
92 |
" |
|
93 |
This class provides access to the operating systems underlying file |
|
94 |
system (i.e. its an interface to the stdio library). |
|
95 |
||
96 |
Notice, that on some systems, the standard I/O library has performance |
|
97 |
problems when a file is opened for readwrite. |
|
98 |
For best results, open files either readonly or writeonly. |
|
1295 | 99 |
|
100 |
[author:] |
|
2161 | 101 |
Claus Gittinger |
1295 | 102 |
|
103 |
[see also:] |
|
2161 | 104 |
Filename DirectoryStream PipeStream Socket |
613 | 105 |
" |
106 |
! ! |
|
107 |
||
1 | 108 |
!FileStream class methodsFor:'instance creation'! |
109 |
||
613 | 110 |
appendingOldFileNamed:filename |
111 |
"return a FileStream for existing file named filename, aString. |
|
112 |
The file is opened for writeonly access." |
|
1 | 113 |
|
114 |
|newStream| |
|
2 | 115 |
newStream := self new pathName:filename. |
613 | 116 |
newStream openForAppending isNil ifTrue:[^nil]. |
117 |
" |
|
118 |
this is not a good idea; I might like to read the written stuff ... |
|
119 |
||
120 |
newStream readLimit:(newStream size). |
|
121 |
" |
|
122 |
^ newStream |
|
123 |
! |
|
124 |
||
125 |
appendingOldFileNamed:filename in:aDirectory |
|
126 |
"return a FileStream for existing file named filename, aString |
|
127 |
in aDirectory, a FileDirectory. |
|
128 |
The file is opened for writeonly access." |
|
129 |
||
130 |
|newStream| |
|
131 |
newStream := self new pathName:filename in:aDirectory. |
|
132 |
newStream openForAppending isNil ifTrue:[^nil]. |
|
133 |
" |
|
134 |
this is not a good idea; I might like to read the written stuff ... |
|
135 |
||
136 |
newStream readLimit:(newStream size). |
|
137 |
" |
|
1 | 138 |
^ newStream |
139 |
! |
|
140 |
||
613 | 141 |
fileNamed:filename |
142 |
"return a stream on file filename - if the file does not |
|
143 |
already exist, create it. |
|
92 | 144 |
The file is opened for read/write access." |
1 | 145 |
|
613 | 146 |
|stream| |
147 |
||
148 |
stream := self oldFileNamed:filename. |
|
149 |
stream isNil ifTrue:[ |
|
150 |
stream := self newFileNamed:filename |
|
151 |
]. |
|
152 |
^ stream |
|
153 |
! |
|
154 |
||
155 |
fileNamed:filename in:aDirectory |
|
156 |
"return a stream on file filename - if the file does not |
|
157 |
already exist, create it. |
|
158 |
The file is opened for read/write access." |
|
159 |
||
160 |
|stream| |
|
161 |
||
162 |
stream := self oldFileNamed:filename in:aDirectory. |
|
163 |
stream isNil ifTrue:[ |
|
164 |
stream := self newFileNamed:filename in:aDirectory |
|
165 |
]. |
|
166 |
^ stream |
|
1 | 167 |
! |
168 |
||
92 | 169 |
newFileForWritingNamed:filename |
170 |
"return a FileStream for new file named filename, aString. |
|
171 |
If the file exists, it is truncated, otherwise created. |
|
172 |
The file is opened for writeonly access." |
|
173 |
||
174 |
|newStream| |
|
175 |
newStream := self new pathName:filename. |
|
176 |
newStream createForWriting isNil ifTrue:[^nil]. |
|
177 |
^ newStream |
|
178 |
! |
|
179 |
||
180 |
newFileForWritingNamed:filename in:aDirectory |
|
181 |
"return a FileStream for new file named filename, aString |
|
182 |
in aDirectory, a FileDirectory. |
|
183 |
If the file exists, it is truncated, otherwise created. |
|
184 |
The file is opened for writeonly access." |
|
185 |
||
186 |
|newStream| |
|
187 |
newStream := self new pathName:filename in:aDirectory. |
|
188 |
newStream createForWriting isNil ifTrue:[^nil]. |
|
189 |
^ newStream |
|
190 |
! |
|
191 |
||
613 | 192 |
newFileNamed:filename |
193 |
"return a FileStream for new file named filename, aString. |
|
194 |
If the file exists, it is truncated, otherwise created. |
|
195 |
The file is opened for read/write access." |
|
196 |
||
197 |
|newStream| |
|
198 |
newStream := self new pathName:filename. |
|
199 |
newStream createForReadWrite isNil ifTrue:[^nil]. |
|
200 |
^ newStream |
|
201 |
! |
|
202 |
||
203 |
newFileNamed:filename in:aDirectory |
|
204 |
"return a FileStream for new file named filename, aString |
|
205 |
in aDirectory, a FileDirectory. |
|
206 |
If the file exists, it is truncated, otherwise created. |
|
207 |
The file is opened for read/write access." |
|
208 |
||
209 |
|newStream| |
|
210 |
newStream := self new pathName:filename in:aDirectory. |
|
211 |
newStream createForReadWrite isNil ifTrue:[^nil]. |
|
212 |
^ newStream |
|
213 |
! |
|
214 |
||
1 | 215 |
oldFileNamed:filename |
216 |
"return a FileStream for existing file named filename, aString. |
|
217 |
The file is opened for read/write access." |
|
218 |
||
219 |
|newStream| |
|
220 |
||
221 |
(OperatingSystem isReadable:filename) ifFalse:[^nil]. |
|
2 | 222 |
newStream := self new pathName:filename. |
1 | 223 |
newStream readwrite. |
224 |
newStream openForReadWrite isNil ifTrue:[^nil]. |
|
42 | 225 |
" |
226 |
this is not a good idea; someone else might be appending ... |
|
227 |
||
1 | 228 |
newStream readLimit:(newStream size). |
42 | 229 |
" |
1 | 230 |
^ newStream |
231 |
! |
|
232 |
||
233 |
oldFileNamed:filename in:aDirectory |
|
234 |
"return a FileStream for existing file named filename, aString |
|
235 |
in aDirectory, a FileDirectory. |
|
236 |
The file is opened for read/write access." |
|
237 |
||
238 |
|newStream| |
|
2 | 239 |
newStream := self new pathName:filename in:aDirectory. |
1 | 240 |
newStream openForReadWrite isNil ifTrue:[^nil]. |
42 | 241 |
" |
242 |
this is not a good idea; someone else might be appending ... |
|
243 |
||
1 | 244 |
newStream readLimit:(newStream size). |
42 | 245 |
" |
1 | 246 |
^ newStream |
247 |
! |
|
248 |
||
249 |
readonlyFileNamed:filename |
|
250 |
"return a readonly FileStream for existing file named filename, aString" |
|
251 |
||
252 |
|newStream| |
|
253 |
||
254 |
(OperatingSystem isReadable:filename) ifFalse:[^nil]. |
|
255 |
||
2 | 256 |
newStream := self new pathName:filename. |
1 | 257 |
newStream openForReading isNil ifTrue:[^nil]. |
42 | 258 |
" |
259 |
this is not a good idea; someone else might be appending ... |
|
260 |
||
1 | 261 |
newStream readLimit:(newStream size). |
42 | 262 |
" |
1 | 263 |
^ newStream |
264 |
! |
|
265 |
||
266 |
readonlyFileNamed:filename in:aDirectory |
|
267 |
"return a readonly FileStream for existing file named filename, aString |
|
268 |
in aDirectory, a FileDirectory" |
|
269 |
||
270 |
|newStream| |
|
2 | 271 |
newStream := self new pathName:filename in:aDirectory. |
1 | 272 |
newStream openForReading isNil ifTrue:[^nil]. |
42 | 273 |
" |
274 |
this is not a good idea; someone else might be appending ... |
|
275 |
||
1 | 276 |
newStream readLimit:(newStream size). |
42 | 277 |
" |
1 | 278 |
^ newStream |
159 | 279 |
! ! |
280 |
||
1 | 281 |
!FileStream methodsFor:'accessing'! |
282 |
||
283 |
directoryName |
|
284 |
"return the name of the directory I'm in" |
|
285 |
||
286 |
|path lastIndex index| |
|
287 |
||
288 |
path := pathName. |
|
289 |
lastIndex := 0. |
|
290 |
index := path indexOf:$/. |
|
291 |
[index ~~ 0] whileTrue:[ |
|
159 | 292 |
lastIndex := index. |
293 |
index := path indexOf:$/ startingAt:(index + 1) |
|
1 | 294 |
]. |
295 |
(lastIndex == 0) ifTrue:[^ '.']. |
|
296 |
(lastIndex == 1) ifTrue:[^ '/']. |
|
31 | 297 |
^ path copyTo:(lastIndex - 1) |
1 | 298 |
! |
299 |
||
300 |
name |
|
301 |
"return my name without leading direcory-path" |
|
302 |
||
303 |
|lastIndex index| |
|
304 |
||
305 |
lastIndex := 1. |
|
306 |
[true] whileTrue:[ |
|
159 | 307 |
index := pathName indexOf:$/ startingAt:lastIndex. |
308 |
(index == 0) ifTrue:[ |
|
309 |
^ pathName copyFrom:lastIndex |
|
310 |
]. |
|
311 |
lastIndex := index + 1 |
|
1 | 312 |
] |
313 |
! |
|
314 |
||
315 |
pathName |
|
316 |
"return the pathname" |
|
317 |
||
318 |
^ pathName |
|
613 | 319 |
! |
320 |
||
321 |
store:something |
|
322 |
"what really should this do" |
|
323 |
||
324 |
self nextPutAll:something storeString |
|
325 |
! ! |
|
326 |
||
327 |
!FileStream methodsFor:'error handling'! |
|
328 |
||
329 |
openError |
|
330 |
"report an error, that file open failed" |
|
331 |
||
332 |
"/ |
|
333 |
"/ for now, do not raise any signal (see super>>openError). |
|
334 |
"/ Its not yet handled anywhere. Instead, senders of open |
|
335 |
"/ check for nil return value (which is a historic leftover) |
|
336 |
"/ |
|
337 |
LastErrorNumber := lastErrorNumber. |
|
338 |
^ nil. |
|
339 |
! ! |
|
340 |
||
341 |
!FileStream methodsFor:'printing & storing'! |
|
342 |
||
343 |
printOn:aStream |
|
344 |
aStream nextPutAll:'(a FileStream for:'. |
|
345 |
aStream nextPutAll:pathName. |
|
346 |
aStream nextPut:$) |
|
347 |
! |
|
348 |
||
349 |
storeOn:aStream |
|
350 |
aStream nextPutAll:'(FileStream oldFileNamed:'. |
|
351 |
aStream nextPutAll:pathName. |
|
352 |
(self position ~~ 1) ifTrue:[ |
|
353 |
aStream nextPutAll:'; position:'. |
|
354 |
self position storeOn:aStream |
|
355 |
]. |
|
356 |
aStream nextPut:$) |
|
1 | 357 |
! ! |
358 |
||
359 |
!FileStream methodsFor:'private'! |
|
360 |
||
613 | 361 |
createForReadWrite |
362 |
"create/truncate the file for read/write. |
|
363 |
If the file existed, its truncated; otherwise its created." |
|
1 | 364 |
|
613 | 365 |
|
366 |
mode := #readwrite. |
|
367 |
^ self openWithMode:'w+' |
|
1 | 368 |
! |
369 |
||
613 | 370 |
createForWriting |
371 |
"create/truncate the file for writeonly. |
|
372 |
If the file existed, its truncated; otherwise its created." |
|
1 | 373 |
|
613 | 374 |
mode := #writeonly. |
375 |
didWrite := true. |
|
376 |
^ self openWithMode:'w' |
|
1 | 377 |
! |
378 |
||
379 |
open |
|
380 |
"open the file" |
|
381 |
||
382 |
pathName isNil ifTrue:[^nil]. |
|
383 |
(mode == #readonly) ifTrue: [ |
|
159 | 384 |
didWrite := false. |
385 |
^ self openWithMode:'r' |
|
1 | 386 |
]. |
387 |
(mode == #writeonly) ifTrue: [ |
|
159 | 388 |
didWrite := true. |
389 |
^ self openWithMode:'w' |
|
1 | 390 |
]. |
77 | 391 |
^ self openWithMode:'r+' |
1 | 392 |
! |
393 |
||
613 | 394 |
openForAppending |
395 |
"open the file for writeonly appending to the end. |
|
396 |
If the file does not exist its an error, return nil; |
|
397 |
otherwise return the receiver." |
|
398 |
||
399 |
mode := #writeonly. |
|
400 |
didWrite := true. |
|
401 |
^ self openWithMode:'a+' |
|
402 |
! |
|
403 |
||
404 |
openForReadWrite |
|
405 |
"open the file for read/write. |
|
406 |
If the file does not exist its an error, return nil; |
|
407 |
otherwise return the receiver." |
|
408 |
||
409 |
mode := #readwrite. |
|
410 |
^ self openWithMode:'r+' |
|
411 |
! |
|
412 |
||
413 |
openForReading |
|
414 |
"open the file for readonly. |
|
415 |
If the file does not exist its an error, return nil; |
|
416 |
otherwise return the receiver." |
|
417 |
||
418 |
mode := #readonly. |
|
419 |
didWrite := false. |
|
420 |
^ self openWithMode:'r' |
|
421 |
! |
|
422 |
||
423 |
openForWriting |
|
424 |
"open the file writeonly. |
|
425 |
If the file does not exist its an error, return nil; |
|
426 |
otherwise return the receiver." |
|
427 |
||
428 |
mode := #writeonly. |
|
429 |
didWrite := true. |
|
430 |
^ self openWithMode:'r+' "unix-io does not allow this; open for update here" |
|
431 |
! |
|
432 |
||
1 | 433 |
openWithMode:openmode |
434 |
"open the file; openmode is the string defining the way to open" |
|
435 |
||
2078
0a5a557b5194
Try to collect unref files if there are no filedescriptors available.
Stefan Vogel <sv@exept.de>
parents:
1295
diff
changeset
|
436 |
|retVal laspass| |
159 | 437 |
|
438 |
filePointer notNil ifTrue:[^ self errorOpen]. |
|
1 | 439 |
%{ |
440 |
FILE *f; |
|
2763 | 441 |
FILE *fopen(); |
477
8710aba7876b
oops - making id's real objects requires a store macro
Claus Gittinger <cg@exept.de>
parents:
475
diff
changeset
|
442 |
OBJ path, fp; |
2078
0a5a557b5194
Try to collect unref files if there are no filedescriptors available.
Stefan Vogel <sv@exept.de>
parents:
1295
diff
changeset
|
443 |
int pass = 0; |
1 | 444 |
|
2078
0a5a557b5194
Try to collect unref files if there are no filedescriptors available.
Stefan Vogel <sv@exept.de>
parents:
1295
diff
changeset
|
445 |
retry: |
1133 | 446 |
path = __INST(pathName); |
328 | 447 |
if (__isNonNilObject(path) && (__qClass(path)==String)) { |
2161 | 448 |
__BEGIN_INTERRUPTABLE__ |
449 |
do { |
|
13 | 450 |
#ifdef LINUX |
2161 | 451 |
/* LINUX returns a non-NULL f even when interrupted */ |
452 |
errno = 0; |
|
2763 | 453 |
f = fopen((char *) __stringVal(path), (char *) __stringVal(openmode)); |
2161 | 454 |
if (errno == EINTR) |
455 |
f = NULL; |
|
13 | 456 |
#else |
457 |
||
2763 | 458 |
f = fopen((char *) __stringVal(path), (char *) __stringVal(openmode)); |
13 | 459 |
#endif |
2161 | 460 |
} while ((f == NULL) && (errno == EINTR)); |
461 |
__END_INTERRUPTABLE__ |
|
462 |
if (f == NULL) { |
|
463 |
/* |
|
464 |
* If no filedescriptors available, try to finalize |
|
465 |
* possibly collected fd's and try again. |
|
466 |
*/ |
|
467 |
if (pass == 0 && (errno == ENFILE || errno == EMFILE)) { |
|
468 |
pass = 1; |
|
469 |
__SSEND0(@global(ObjectMemory), @symbol(scavenge), 0); |
|
470 |
__SSEND0(@global(ObjectMemory), @symbol(finalize), 0); |
|
471 |
goto retry; |
|
472 |
} |
|
473 |
__INST(lastErrorNumber) = __MKSMALLINT(errno); |
|
474 |
__INST(position) = nil; |
|
475 |
} else { |
|
2766 | 476 |
__INST(filePointer) = fp = __MKOBJ((INT)f); __STORE(self, fp); |
2161 | 477 |
__INST(position) = __MKSMALLINT(1); |
478 |
retVal = self; |
|
479 |
} |
|
1 | 480 |
} |
159 | 481 |
%}. |
1 | 482 |
retVal notNil ifTrue:[ |
2161 | 483 |
buffered := true. "default is buffered" |
484 |
Lobby register:self. |
|
485 |
^ retVal |
|
2078
0a5a557b5194
Try to collect unref files if there are no filedescriptors available.
Stefan Vogel <sv@exept.de>
parents:
1295
diff
changeset
|
486 |
] ifFalse:[ |
2161 | 487 |
" |
488 |
the open failed for some reason ... |
|
489 |
" |
|
490 |
^ self openError |
|
1 | 491 |
]. |
2078
0a5a557b5194
Try to collect unref files if there are no filedescriptors available.
Stefan Vogel <sv@exept.de>
parents:
1295
diff
changeset
|
492 |
|
1 | 493 |
! |
494 |
||
613 | 495 |
pathName:filename |
496 |
"set the pathname" |
|
1 | 497 |
|
613 | 498 |
pathName := filename |
1 | 499 |
! |
500 |
||
613 | 501 |
pathName:filename in:aDirectory |
502 |
"set the pathname starting at aDirectory, a FileDirectory" |
|
77 | 503 |
|
613 | 504 |
((filename at:1) == $/) ifTrue:[ |
505 |
"filename may not start with a '/'" |
|
506 |
pathName := nil |
|
507 |
] ifFalse:[ |
|
508 |
pathName := aDirectory pathName. |
|
509 |
(pathName endsWith:'/') ifFalse:[ |
|
510 |
pathName := pathName , '/' |
|
511 |
]. |
|
512 |
pathName := pathName , filename |
|
513 |
] |
|
1 | 514 |
! |
515 |
||
516 |
reOpen |
|
517 |
"sent after snapin to reopen streams" |
|
518 |
||
173 | 519 |
|oldPos| |
520 |
||
1 | 521 |
filePointer notNil ifTrue:[ |
2161 | 522 |
"it was open, when snapped-out" |
523 |
filePointer := nil. |
|
524 |
Lobby unregister:self. |
|
525 |
oldPos := position. |
|
526 |
self open. |
|
527 |
filePointer isNil ifTrue:[ |
|
528 |
"this happens, if after a restart, the file is no longer accessable ..." |
|
13 | 529 |
|
2161 | 530 |
(self class name , ' [warning]: could not reOpen file: ', pathName) errorPrintCR. |
531 |
] ifFalse:[ |
|
532 |
self position:oldPos. |
|
533 |
] |
|
1 | 534 |
] |
1088 | 535 |
|
2134
246a3bdab8b4
newStyle info & error messages
Claus Gittinger <cg@exept.de>
parents:
2078
diff
changeset
|
536 |
"Modified: 10.1.1997 / 17:50:51 / cg" |
31 | 537 |
! ! |
538 |
||
539 |
!FileStream methodsFor:'queries'! |
|
1 | 540 |
|
541 |
position |
|
542 |
"return the read/write position in the file - |
|
31 | 543 |
notice, in smalltalk indices start at 1 so begin of file is 1" |
1 | 544 |
|
545 |
%{ /* NOCONTEXT */ |
|
546 |
||
547 |
FILE *f; |
|
548 |
long currentPosition; |
|
2796 | 549 |
extern long ftell(), lseek(); |
1 | 550 |
|
1133 | 551 |
if (__INST(filePointer) != nil) { |
552 |
f = __FILEVal(__INST(filePointer)); |
|
159 | 553 |
do { |
1133 | 554 |
if (__INST(buffered) == true) { |
2796 | 555 |
currentPosition = ftell(f); |
159 | 556 |
} else { |
2796 | 557 |
currentPosition = lseek(fileno(f), 0L, SEEK_CUR); |
159 | 558 |
} |
559 |
} while ((currentPosition < 0) && (errno == EINTR)); |
|
560 |
if (currentPosition >= 0) { |
|
561 |
/* |
|
562 |
* notice: Smalltalk index starts at 1 |
|
563 |
*/ |
|
1133 | 564 |
RETURN ( __MKSMALLINT(currentPosition + 1) ); |
159 | 565 |
} |
1133 | 566 |
__INST(lastErrorNumber) = __MKSMALLINT(errno); |
1 | 567 |
} |
159 | 568 |
%}. |
569 |
lastErrorNumber notNil ifTrue:[^ self ioError]. |
|
1 | 570 |
filePointer isNil ifTrue:[^ self errorNotOpen]. |
571 |
^ self primitiveFailed |
|
572 |
! |
|
573 |
||
574 |
position:newPos |
|
575 |
"set the read/write position in the file" |
|
576 |
||
577 |
%{ /* NOCONTEXT */ |
|
578 |
||
579 |
FILE *f; |
|
2796 | 580 |
long ret; |
249 | 581 |
OBJ fp; |
2796 | 582 |
long nP; |
583 |
extern long lseek(); |
|
1 | 584 |
|
1133 | 585 |
if ((fp = __INST(filePointer)) != nil) { |
249 | 586 |
if (__isSmallInteger(newPos)) { |
475
b57530aa1b0a
use new FILE* wrapper macros (based on externalAddress)
Claus Gittinger <cg@exept.de>
parents:
437
diff
changeset
|
587 |
f = __FILEVal(fp); |
2796 | 588 |
nP = (long)__intVal(newPos); |
589 |
||
159 | 590 |
/* |
591 |
* notice: Smalltalk index starts at 1 |
|
592 |
*/ |
|
2796 | 593 |
nP--; |
594 |
||
159 | 595 |
do { |
1133 | 596 |
if (__INST(buffered) == true) { |
2796 | 597 |
ret = fseek(f, nP, SEEK_SET); |
159 | 598 |
} else { |
2796 | 599 |
ret = lseek(fileno(f), nP, SEEK_SET); |
159 | 600 |
} |
601 |
} while ((ret < 0) && (errno == EINTR)); |
|
602 |
if (ret >= 0) { |
|
1133 | 603 |
__INST(position) = newPos; |
159 | 604 |
/* |
605 |
* just to make certain ... |
|
606 |
*/ |
|
1133 | 607 |
__INST(hitEOF) = false; |
159 | 608 |
RETURN ( self ); |
609 |
} |
|
1133 | 610 |
__INST(lastErrorNumber) = __MKSMALLINT(errno); |
159 | 611 |
} |
1 | 612 |
} |
159 | 613 |
%}. |
614 |
lastErrorNumber notNil ifTrue:[^ self ioError]. |
|
1 | 615 |
filePointer isNil ifTrue:[^ self errorNotOpen]. |
616 |
^ self primitiveFailed |
|
617 |
! |
|
618 |
||
619 |
setToEnd |
|
620 |
"set the read/write position in the file to be at the end of the file" |
|
621 |
||
622 |
%{ |
|
623 |
FILE *f; |
|
2796 | 624 |
long ret; |
625 |
extern long lseek(); |
|
1 | 626 |
|
1133 | 627 |
if (__INST(filePointer) != nil) { |
628 |
f = __FILEVal(__INST(filePointer)); |
|
629 |
__INST(position) = nil; |
|
159 | 630 |
do { |
1133 | 631 |
if (__INST(buffered) == true) { |
159 | 632 |
ret = fseek(f, 0L, SEEK_END); |
633 |
} else { |
|
2796 | 634 |
ret = lseek(fileno(f), 0L, SEEK_END); |
159 | 635 |
} |
636 |
} while ((ret < 0) && (errno == EINTR)); |
|
637 |
if (ret >= 0) { |
|
638 |
RETURN ( self ); |
|
639 |
} |
|
1133 | 640 |
__INST(lastErrorNumber) = __MKSMALLINT(errno); |
1 | 641 |
} |
159 | 642 |
%}. |
643 |
lastErrorNumber notNil ifTrue:[^ self ioError]. |
|
49 | 644 |
filePointer isNil ifTrue:[^ self errorNotOpen]. |
1 | 645 |
^ self primitiveFailed |
613 | 646 |
! |
647 |
||
648 |
size |
|
649 |
"return the size in bytes of the file" |
|
650 |
||
651 |
%{ /* NOCONTEXT */ |
|
652 |
||
653 |
#ifdef transputer |
|
654 |
FILE *f; |
|
655 |
int size; |
|
656 |
||
1133 | 657 |
if (__INST(filePointer) != nil) { |
658 |
f = __FILEVal(__INST(filePointer)); |
|
613 | 659 |
if ((size = filesize(fileno(f))) >= 0) { |
1133 | 660 |
RETURN ( __MKSMALLINT(size) ); |
613 | 661 |
} |
662 |
} |
|
663 |
#else |
|
664 |
FILE *f; |
|
665 |
struct stat buf; |
|
666 |
int ret; |
|
667 |
int fd; |
|
668 |
||
1133 | 669 |
if (__INST(filePointer) != nil) { |
670 |
f = __FILEVal(__INST(filePointer)); |
|
613 | 671 |
fd = fileno(f); |
672 |
do { |
|
673 |
ret = fstat(fd, &buf); |
|
674 |
} while ((ret < 0) && (errno == EINTR)); |
|
675 |
if (ret >= 0) { |
|
1133 | 676 |
RETURN ( __MKSMALLINT(buf.st_size) ); |
613 | 677 |
} |
1133 | 678 |
__INST(lastErrorNumber) = __MKSMALLINT(errno); |
613 | 679 |
} |
680 |
#endif |
|
681 |
%}. |
|
682 |
||
683 |
"could add a fall-back here: |
|
684 |
||
685 |
oldPosition := self position. |
|
686 |
self setToEnd. |
|
687 |
sz := self position. |
|
688 |
self position:oldPosition. |
|
689 |
^ sz |
|
690 |
" |
|
691 |
lastErrorNumber notNil ifTrue:[^ self ioError]. |
|
692 |
filePointer isNil ifTrue:[^ self errorNotOpen]. |
|
693 |
^ self primitiveFailed |
|
1 | 694 |
! ! |
695 |
||
2 | 696 |
!FileStream methodsFor:'testing'! |
697 |
||
698 |
isFileStream |
|
699 |
"return true, if the receiver is some kind of fileStream. |
|
700 |
redefined from Object" |
|
701 |
||
702 |
^ true |
|
703 |
! ! |
|
704 |
||
1088 | 705 |
!FileStream class methodsFor:'documentation'! |
706 |
||
707 |
version |
|
2808 | 708 |
^ '$Header: /cvs/stx/stx/libbasic/FileStream.st,v 1.40 1997-07-30 11:13:17 cg Exp $' |
1088 | 709 |
! ! |