1 " |
1 " |
2 COPYRIGHT (c) 1989 by Claus Gittinger |
2 COPYRIGHT (c) 1989 by Claus Gittinger |
3 All Rights Reserved |
3 All Rights Reserved |
4 |
4 |
5 This software is furnished under a license and may be used |
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 |
6 only in accordance with the terms of that license and with the |
7 inclusion of the above copyright notice. This software may not |
7 inclusion of the above copyright notice. This software may not |
8 be provided or otherwise made available to, or used by, any |
8 be provided or otherwise made available to, or used by, any |
10 hereby transferred. |
10 hereby transferred. |
11 " |
11 " |
12 |
12 |
13 ExternalStream subclass:#FileStream |
13 ExternalStream subclass:#FileStream |
14 instanceVariableNames:'pathName' |
14 instanceVariableNames:'pathName' |
15 classVariableNames:'' |
15 classVariableNames:'OpenErrorSignal' |
16 poolDictionaries:'' |
16 poolDictionaries:'' |
17 category:'Streams-External' |
17 category:'Streams-External' |
18 ! |
18 ! |
19 |
19 |
20 FileStream comment:' |
20 FileStream comment:' |
21 COPYRIGHT (c) 1989 by Claus Gittinger |
21 COPYRIGHT (c) 1989 by Claus Gittinger |
22 All Rights Reserved |
22 All Rights Reserved |
23 |
23 |
24 $Header: /cvs/stx/stx/libbasic/FileStream.st,v 1.14 1994-08-05 00:54:46 claus Exp $ |
24 $Header: /cvs/stx/stx/libbasic/FileStream.st,v 1.15 1994-10-10 00:26:04 claus Exp $ |
25 '! |
25 '! |
26 |
26 |
27 !FileStream class methodsFor:'documentation'! |
27 !FileStream class methodsFor:'documentation'! |
28 |
28 |
29 copyright |
29 copyright |
30 " |
30 " |
31 COPYRIGHT (c) 1989 by Claus Gittinger |
31 COPYRIGHT (c) 1989 by Claus Gittinger |
32 All Rights Reserved |
32 All Rights Reserved |
33 |
33 |
34 This software is furnished under a license and may be used |
34 This software is furnished under a license and may be used |
35 only in accordance with the terms of that license and with the |
35 only in accordance with the terms of that license and with the |
36 inclusion of the above copyright notice. This software may not |
36 inclusion of the above copyright notice. This software may not |
37 be provided or otherwise made available to, or used by, any |
37 be provided or otherwise made available to, or used by, any |
86 # define SEEK_END 2 |
86 # define SEEK_END 2 |
87 #endif |
87 #endif |
88 |
88 |
89 %} |
89 %} |
90 |
90 |
|
91 !FileStream class methodsFor:'initialization'! |
|
92 |
|
93 initialize |
|
94 OpenErrorSignal isNil ifTrue:[ |
|
95 super initialize. |
|
96 |
|
97 OpenErrorSignal := StreamErrorSignal newSignalMayProceed:true. |
|
98 OpenErrorSignal nameClass:self message:#openErrorSignal. |
|
99 OpenErrorSignal notifierString:'open error'. |
|
100 ]. |
|
101 ! ! |
|
102 |
91 !FileStream class methodsFor:'instance creation'! |
103 !FileStream class methodsFor:'instance creation'! |
92 |
104 |
93 newFileNamed:filename |
105 newFileNamed:filename |
94 "return a FileStream for new file named filename, aString. |
106 "return a FileStream for new file named filename, aString. |
95 If the file exists, it is truncated, otherwise created. |
107 If the file exists, it is truncated, otherwise created. |
259 newStream readLimit:(newStream size). |
271 newStream readLimit:(newStream size). |
260 " |
272 " |
261 ^ newStream |
273 ^ newStream |
262 ! ! |
274 ! ! |
263 |
275 |
|
276 !FileStream methodsFor:'error handling'! |
|
277 |
|
278 errorOpen |
|
279 "report an error, that the stream is already opened" |
|
280 |
|
281 ^ StreamErrorSignal |
|
282 raiseRequestWith:self |
|
283 errorString:(self class name , ' is already open') |
|
284 ! |
|
285 |
|
286 openError |
|
287 "report an error, that file open failed" |
|
288 |
|
289 LastErrorNumber := lastErrorNumber. |
|
290 ^nil. |
|
291 ^ OpenErrorSignal |
|
292 raiseRequestWith:self |
|
293 errorString:('error on open: ' , self lastErrorString) |
|
294 ! ! |
|
295 |
264 !FileStream methodsFor:'accessing'! |
296 !FileStream methodsFor:'accessing'! |
265 |
297 |
266 store:something |
298 store:something |
267 "what really should this do" |
299 "what really should this do" |
268 |
300 |
317 |
349 |
318 pathName:filename in:aDirectory |
350 pathName:filename in:aDirectory |
319 "set the pathname starting at aDirectory, a FileDirectory" |
351 "set the pathname starting at aDirectory, a FileDirectory" |
320 |
352 |
321 ((filename at:1) == $/) ifTrue:[ |
353 ((filename at:1) == $/) ifTrue:[ |
322 "filename may not start with a '/'" |
354 "filename may not start with a '/'" |
323 pathName := nil |
355 pathName := nil |
324 ] ifFalse:[ |
356 ] ifFalse:[ |
325 pathName := aDirectory pathName. |
357 pathName := aDirectory pathName. |
326 (pathName endsWith:'/') ifFalse:[ |
358 (pathName endsWith:'/') ifFalse:[ |
327 pathName := pathName , '/' |
359 pathName := pathName , '/' |
328 ]. |
360 ]. |
329 pathName := pathName , filename |
361 pathName := pathName , filename |
330 ] |
362 ] |
331 ! |
363 ! |
332 |
364 |
333 open |
365 open |
334 "open the file" |
366 "open the file" |
335 |
367 |
336 pathName isNil ifTrue:[^nil]. |
368 pathName isNil ifTrue:[^nil]. |
337 (mode == #readonly) ifTrue: [ |
369 (mode == #readonly) ifTrue: [ |
338 didWrite := false. |
370 didWrite := false. |
339 ^ self openWithMode:'r' |
371 ^ self openWithMode:'r' |
340 ]. |
372 ]. |
341 (mode == #writeonly) ifTrue: [ |
373 (mode == #writeonly) ifTrue: [ |
342 didWrite := true. |
374 didWrite := true. |
343 ^ self openWithMode:'w' |
375 ^ self openWithMode:'w' |
344 ]. |
376 ]. |
345 ^ self openWithMode:'r+' |
377 ^ self openWithMode:'r+' |
346 ! |
378 ! |
347 |
379 |
348 openWithMode:openmode |
380 openWithMode:openmode |
349 "open the file; openmode is the string defining the way to open" |
381 "open the file; openmode is the string defining the way to open" |
350 |
382 |
351 |retVal| |
383 |retVal| |
|
384 |
|
385 filePointer notNil ifTrue:[^ self errorOpen]. |
352 %{ |
386 %{ |
353 FILE *f; |
387 FILE *f; |
354 OBJ path; |
388 OBJ path; |
355 extern OBJ Filename; |
|
356 extern errno; |
389 extern errno; |
357 |
390 |
358 if (_INST(filePointer) == nil) { |
391 if (_INST(filePointer) == nil) { |
359 path = _INST(pathName); |
392 path = _INST(pathName); |
360 if (path != nil |
393 if (_isNonNilObject(path) && (_qClass(path)==String)) { |
361 && ((_qClass(path)==String) || (_qClass(path) == Filename))) { |
394 do { |
362 do { |
|
363 #ifdef LINUX |
395 #ifdef LINUX |
364 /* LINUX returns a non-NULL f even when interrupted */ |
396 /* LINUX returns a non-NULL f even when interrupted */ |
365 errno = 0; |
397 errno = 0; |
366 f = (FILE *) fopen((char *) _stringVal(path), (char *) _stringVal(openmode)); |
398 f = (FILE *) fopen((char *) _stringVal(path), (char *) _stringVal(openmode)); |
367 if (errno == EINTR) |
399 if (errno == EINTR) |
368 f = NULL; |
400 f = NULL; |
369 #else |
401 #else |
370 |
402 |
371 f = (FILE *) fopen((char *) _stringVal(path), (char *) _stringVal(openmode)); |
403 f = (FILE *) fopen((char *) _stringVal(path), (char *) _stringVal(openmode)); |
372 #endif |
404 #endif |
373 } while ((f == NULL) && (errno == EINTR)); |
405 } while ((f == NULL) && (errno == EINTR)); |
374 if (f == NULL) { |
406 if (f == NULL) { |
375 ExternalStream_LastErrorNumber = _MKSMALLINT(errno); |
407 _INST(lastErrorNumber) = _MKSMALLINT(errno); |
376 _INST(position) = nil; |
408 _INST(position) = nil; |
377 } else { |
409 } else { |
378 _INST(filePointer) = MKOBJ((int)f); |
410 _INST(filePointer) = MKOBJ((int)f); |
379 _INST(position) = _MKSMALLINT(1); |
411 _INST(position) = _MKSMALLINT(1); |
380 retVal = self; |
412 retVal = self; |
381 } |
413 } |
382 } |
414 } |
383 } |
415 } |
384 %} |
416 %}. |
385 . |
|
386 retVal notNil ifTrue:[ |
417 retVal notNil ifTrue:[ |
387 buffered := true. "default is buffered" |
418 buffered := true. "default is buffered" |
388 Lobby register:self |
419 Lobby register:self |
389 ]. |
420 ]. |
|
421 lastErrorNumber notNil ifTrue:[^ self openError]. |
390 ^ retVal |
422 ^ retVal |
391 ! |
423 ! |
392 |
424 |
393 openForReading |
425 openForReading |
394 "open the file for readonly. |
426 "open the file for readonly. |
449 |
481 |
450 reOpen |
482 reOpen |
451 "sent after snapin to reopen streams" |
483 "sent after snapin to reopen streams" |
452 |
484 |
453 filePointer notNil ifTrue:[ |
485 filePointer notNil ifTrue:[ |
454 "it was open, when snapped-out" |
486 "it was open, when snapped-out" |
455 filePointer := nil. |
487 filePointer := nil. |
456 Lobby unregister:self. |
488 Lobby unregister:self. |
457 self open. |
489 self open. |
458 filePointer isNil ifTrue:[ |
490 filePointer isNil ifTrue:[ |
459 "this happens, if after a restart, the file is no longer accessable ..." |
491 "this happens, if after a restart, the file is no longer accessable ..." |
460 |
492 |
461 ('could not reopen file: ', pathName) errorPrintNewline. |
493 ('could not reopen file: ', pathName) errorPrintNewline. |
462 ] ifFalse:[ |
494 ] ifFalse:[ |
463 self position:position. |
495 self position:position. |
464 ] |
496 ] |
465 ] |
497 ] |
466 ! ! |
498 ! ! |
467 |
499 |
468 !FileStream methodsFor:'queries'! |
500 !FileStream methodsFor:'queries'! |
469 |
501 |
475 #ifdef transputer |
507 #ifdef transputer |
476 FILE *f; |
508 FILE *f; |
477 int size; |
509 int size; |
478 |
510 |
479 if (_INST(filePointer) != nil) { |
511 if (_INST(filePointer) != nil) { |
480 f = (FILE *)MKFD(_INST(filePointer)); |
512 f = (FILE *)MKFD(_INST(filePointer)); |
481 if ((size = filesize(fileno(f))) >= 0) { |
513 if ((size = filesize(fileno(f))) >= 0) { |
482 RETURN ( _MKSMALLINT(size) ); |
514 RETURN ( _MKSMALLINT(size) ); |
483 } |
515 } |
484 } |
516 } |
485 #else |
517 #else |
486 FILE *f; |
518 FILE *f; |
487 struct stat buf; |
519 struct stat buf; |
488 int ret; |
520 int ret; |
489 extern errno; |
521 extern errno; |
490 int fd; |
522 int fd; |
491 |
523 |
492 if (_INST(filePointer) != nil) { |
524 if (_INST(filePointer) != nil) { |
493 f = (FILE *)MKFD(_INST(filePointer)); |
525 f = (FILE *)MKFD(_INST(filePointer)); |
494 fd = fileno(f); |
526 fd = fileno(f); |
495 do { |
527 do { |
496 ret = fstat(fd, &buf); |
528 ret = fstat(fd, &buf); |
497 } while ((ret < 0) && (errno == EINTR)); |
529 } while ((ret < 0) && (errno == EINTR)); |
498 if (ret >= 0) { |
530 if (ret >= 0) { |
499 RETURN ( _MKSMALLINT(buf.st_size) ); |
531 RETURN ( _MKSMALLINT(buf.st_size) ); |
500 } |
532 } |
501 ExternalStream_LastErrorNumber = _MKSMALLINT(errno); |
533 _INST(lastErrorNumber) = _MKSMALLINT(errno); |
502 } |
534 } |
503 #endif |
535 #endif |
504 %} |
536 %}. |
505 . |
537 |
506 "could add a fall-back here: |
538 "could add a fall-back here: |
507 |
539 |
508 oldPosition := self position. |
540 oldPosition := self position. |
509 self setToEnd. |
541 self setToEnd. |
510 sz := self position. |
542 sz := self position. |
511 self position:oldPosition. |
543 self position:oldPosition. |
512 ^ sz |
544 ^ sz |
513 " |
545 " |
|
546 lastErrorNumber notNil ifTrue:[^ self ioError]. |
514 filePointer isNil ifTrue:[^ self errorNotOpen]. |
547 filePointer isNil ifTrue:[^ self errorNotOpen]. |
515 ^ self primitiveFailed |
548 ^ self primitiveFailed |
516 ! |
549 ! |
517 |
550 |
518 position |
551 position |
524 FILE *f; |
557 FILE *f; |
525 long currentPosition; |
558 long currentPosition; |
526 extern errno; |
559 extern errno; |
527 |
560 |
528 if (_INST(filePointer) != nil) { |
561 if (_INST(filePointer) != nil) { |
529 f = (FILE *)MKFD(_INST(filePointer)); |
562 f = (FILE *)MKFD(_INST(filePointer)); |
530 do { |
563 do { |
531 if (_INST(buffered) == true) { |
564 if (_INST(buffered) == true) { |
532 currentPosition = (long) ftell(f); |
565 currentPosition = (long) ftell(f); |
533 } else { |
566 } else { |
534 currentPosition = (long) lseek(fileno(f), 0L, SEEK_CUR); |
567 currentPosition = (long) lseek(fileno(f), 0L, SEEK_CUR); |
535 } |
568 } |
536 } while ((currentPosition < 0) && (errno == EINTR)); |
569 } while ((currentPosition < 0) && (errno == EINTR)); |
537 if (currentPosition >= 0) { |
570 if (currentPosition >= 0) { |
538 /* |
571 /* |
539 * notice: Smalltalk index starts at 1 |
572 * notice: Smalltalk index starts at 1 |
540 */ |
573 */ |
541 RETURN ( _MKSMALLINT(currentPosition + 1) ); |
574 RETURN ( _MKSMALLINT(currentPosition + 1) ); |
542 } |
575 } |
543 ExternalStream_LastErrorNumber = _MKSMALLINT(errno); |
576 _INST(lastErrorNumber) = _MKSMALLINT(errno); |
544 } |
577 } |
545 %} |
578 %}. |
546 . |
579 lastErrorNumber notNil ifTrue:[^ self ioError]. |
547 filePointer isNil ifTrue:[^ self errorNotOpen]. |
580 filePointer isNil ifTrue:[^ self errorNotOpen]. |
548 ^ self primitiveFailed |
581 ^ self primitiveFailed |
549 ! |
582 ! |
550 |
583 |
551 position:newPos |
584 position:newPos |
556 FILE *f; |
589 FILE *f; |
557 int ret; |
590 int ret; |
558 extern errno; |
591 extern errno; |
559 |
592 |
560 if (_INST(filePointer) != nil) { |
593 if (_INST(filePointer) != nil) { |
561 if (_isSmallInteger(newPos)) { |
594 if (_isSmallInteger(newPos)) { |
562 f = (FILE *)MKFD(_INST(filePointer)); |
595 f = (FILE *)MKFD(_INST(filePointer)); |
563 /* |
596 /* |
564 * notice: Smalltalk index starts at 1 |
597 * notice: Smalltalk index starts at 1 |
565 */ |
598 */ |
566 do { |
599 do { |
567 if (_INST(buffered) == true) { |
600 if (_INST(buffered) == true) { |
568 ret = fseek(f, (long) (_intVal(newPos) - 1), SEEK_SET); |
601 ret = fseek(f, (long) (_intVal(newPos) - 1), SEEK_SET); |
569 } else { |
602 } else { |
570 ret = (long) lseek(fileno(f), (long)(_intVal(newPos) - 1), SEEK_SET); |
603 ret = (long) lseek(fileno(f), (long)(_intVal(newPos) - 1), SEEK_SET); |
571 } |
604 } |
572 } while ((ret < 0) && (errno == EINTR)); |
605 } while ((ret < 0) && (errno == EINTR)); |
573 if (ret >= 0) { |
606 if (ret >= 0) { |
574 _INST(position) = newPos; |
607 _INST(position) = newPos; |
575 /* |
608 /* |
576 * just to make certain ... |
609 * just to make certain ... |
577 */ |
610 */ |
578 _INST(hitEOF) = false; |
611 _INST(hitEOF) = false; |
579 RETURN ( self ); |
612 RETURN ( self ); |
580 } |
613 } |
581 ExternalStream_LastErrorNumber = _MKSMALLINT(errno); |
614 _INST(lastErrorNumber) = _MKSMALLINT(errno); |
582 } |
615 } |
583 } |
616 } |
584 %} |
617 %}. |
585 . |
618 lastErrorNumber notNil ifTrue:[^ self ioError]. |
586 filePointer isNil ifTrue:[^ self errorNotOpen]. |
619 filePointer isNil ifTrue:[^ self errorNotOpen]. |
587 ^ self primitiveFailed |
620 ^ self primitiveFailed |
588 ! |
621 ! |
589 |
622 |
590 setToEnd |
623 setToEnd |
594 FILE *f; |
627 FILE *f; |
595 int ret; |
628 int ret; |
596 extern errno; |
629 extern errno; |
597 |
630 |
598 if (_INST(filePointer) != nil) { |
631 if (_INST(filePointer) != nil) { |
599 f = (FILE *)MKFD(_INST(filePointer)); |
632 f = (FILE *)MKFD(_INST(filePointer)); |
600 _INST(position) = nil; |
633 _INST(position) = nil; |
601 do { |
634 do { |
602 if (_INST(buffered) == true) { |
635 if (_INST(buffered) == true) { |
603 ret = fseek(f, 0L, SEEK_END); |
636 ret = fseek(f, 0L, SEEK_END); |
604 } else { |
637 } else { |
605 ret = (long)lseek(fileno(f), 0L, SEEK_END); |
638 ret = (long)lseek(fileno(f), 0L, SEEK_END); |
606 } |
639 } |
607 } while ((ret < 0) && (errno == EINTR)); |
640 } while ((ret < 0) && (errno == EINTR)); |
608 if (ret >= 0) { |
641 if (ret >= 0) { |
609 RETURN ( self ); |
642 RETURN ( self ); |
610 } |
643 } |
611 ExternalStream_LastErrorNumber = _MKSMALLINT(errno); |
644 _INST(lastErrorNumber) = _MKSMALLINT(errno); |
612 } |
645 } |
613 %} |
646 %}. |
614 . |
647 lastErrorNumber notNil ifTrue:[^ self ioError]. |
615 filePointer isNil ifTrue:[^ self errorNotOpen]. |
648 filePointer isNil ifTrue:[^ self errorNotOpen]. |
616 DemoMode ifTrue:[^ self warn:'no save in Demo mode']. |
649 DemoMode ifTrue:[^ self warn:'no save in Demo mode']. |
617 ^ self primitiveFailed |
650 ^ self primitiveFailed |
618 ! ! |
651 ! ! |
619 |
652 |