9 other person. No title to or ownership of the software is |
9 other person. No title to or ownership of the software is |
10 hereby transferred. |
10 hereby transferred. |
11 " |
11 " |
12 "{ Package: 'stx:libbasic' }" |
12 "{ Package: 'stx:libbasic' }" |
13 |
13 |
|
14 "{ NameSpace: Smalltalk }" |
|
15 |
14 FileStream subclass:#DirectoryStream |
16 FileStream subclass:#DirectoryStream |
15 instanceVariableNames:'dirPointer readAheadEntry' |
17 instanceVariableNames:'dirPointer readAheadEntry' |
16 classVariableNames:'' |
18 classVariableNames:'' |
17 poolDictionaries:'' |
19 poolDictionaries:'' |
18 category:'Streams-External' |
20 category:'Streams-External' |
19 ! |
21 ! |
20 |
22 |
21 !DirectoryStream primitiveDefinitions! |
23 !DirectoryStream primitiveDefinitions! |
22 %{ |
24 %{ |
23 |
25 #include "stxOSDefs.h" |
24 #define UNIX_LIKE |
|
25 |
26 |
26 #if defined(WIN32) |
27 #if defined(WIN32) |
27 # undef UNIX_LIKE |
28 # undef UNIX_LIKE |
28 #endif |
29 #else |
29 |
30 # if defined(transputer) |
30 #if defined(transputer) |
31 # undef UNIX_LIKE |
31 # undef UNIX_LIKE |
32 # else |
|
33 # define UNIX_LIKE |
|
34 # endif |
32 #endif |
35 #endif |
33 |
36 |
34 #ifdef UNIX_LIKE |
37 #ifdef UNIX_LIKE |
35 # if defined(__GLIBC__) && (__GLIBC__ == 2) |
38 # if defined(__GLIBC__) && (__GLIBC__ == 2) |
36 # if defined(__GLIBC_MINOR__) && (__GLIBC_MINOR__ == 1) |
39 # if defined(__GLIBC_MINOR__) && (__GLIBC_MINOR__ == 1) |
506 ]. |
507 ]. |
507 ^ contents |
508 ^ contents |
508 ! |
509 ! |
509 |
510 |
510 nextLine |
511 nextLine |
511 "return the next filename as a string" |
512 "return the next filename as a string or nil" |
512 |
513 |
513 |prevEntry nextEntry isUnix| |
514 |linkInfo| |
|
515 |
|
516 linkInfo := self nextLinkInfo. |
|
517 linkInfo notNil ifTrue:[^ linkInfo sourcePath]. |
|
518 ^ nil |
|
519 ! |
|
520 |
|
521 nextLinkInfo |
|
522 "return the next FileStatusInfo or nil" |
|
523 |
|
524 |nextResult resultInfo| |
|
525 |
|
526 (hitEOF or:[readAheadEntry isNil]) ifTrue:[ |
|
527 ^ self pastEndRead |
|
528 ]. |
|
529 |
|
530 nextResult := OperatingSystem nextLinkInfoFrom:self dirPointer:dirPointer. |
|
531 nextResult isNil ifTrue:[ |
|
532 hitEOF := true. |
|
533 ]. |
|
534 readAheadEntry notNil ifTrue:[ |
|
535 resultInfo := readAheadEntry. |
|
536 readAheadEntry := nextResult. |
|
537 ^ resultInfo |
|
538 ]. |
|
539 nextResult isNil ifTrue:[ |
|
540 ^ self pastEndRead |
|
541 ]. |
|
542 ^ nextResult |
|
543 ! ! |
|
544 |
|
545 !DirectoryStream protectedMethodsFor:'instance release'! |
|
546 |
|
547 closeFile |
|
548 "low level close of a directoryStream" |
|
549 |
|
550 |dp| |
|
551 |
|
552 dp := dirPointer. |
|
553 dp isNil ifTrue:[ |
|
554 ^ self errorNotOpen. |
|
555 ]. |
|
556 dirPointer := nil. |
514 %{ |
557 %{ |
515 #ifdef HAS_OPENDIR |
558 #ifdef HAS_OPENDIR |
516 DIR *d; |
559 closedir( (DIR *)(__FILEVal(dp)) ); |
517 DIRENT_STRUCT *dp; |
|
518 OBJ dirP; |
|
519 |
|
520 if (__INST(hitEOF) != true && (dirP = __INST(dirPointer)) != nil) { |
|
521 __INST(lastErrorNumber) = nil; |
|
522 d = (DIR *)__FILEVal(dirP); |
|
523 |
|
524 __BEGIN_INTERRUPTABLE__ |
|
525 do { |
|
526 do { |
|
527 __threadErrno = 0; |
|
528 dp = readdir(d); |
|
529 /* |
|
530 * for compatibility with ST-80, |
|
531 * skip entries for '.' and '..'. |
|
532 * If wanted, these must be added synthetically. |
|
533 */ |
|
534 } while (dp && ((strcmp(dp->d_name, ".")==0) || (strcmp(dp->d_name, "..")==0))); |
|
535 } while ((dp == NULL) && (__threadErrno == EINTR)); |
|
536 __END_INTERRUPTABLE__ |
|
537 |
|
538 if (dp != NULL) { |
|
539 nextEntry = __MKSTRING((char *)(dp->d_name)); |
|
540 } else { |
|
541 if (__threadErrno) { |
|
542 __INST(lastErrorNumber) = __mkSmallInteger(__threadErrno); |
|
543 } else { |
|
544 __INST(hitEOF) = true; |
|
545 } |
|
546 } |
|
547 } |
|
548 #else /* no HAS_OPENDIR */ |
|
549 # ifdef WIN32 |
|
550 HANDLE d; |
|
551 WIN32_FIND_DATAW data; |
|
552 OBJ dirP; |
|
553 int rslt; |
|
554 |
|
555 if (__INST(hitEOF) != true && (dirP = __INST(dirPointer)) != nil) { |
|
556 __INST(lastErrorNumber) = nil; |
|
557 d = __HANDLEVal(dirP); |
|
558 |
|
559 do { |
|
560 __threadErrno = 0; |
|
561 rslt = STX_API_NOINT_CALL2( "FindNextFileW", FindNextFileW, d, &data ); |
|
562 } while ((rslt < 0) && (__threadErrno == EINTR)); |
|
563 |
|
564 if (rslt > 0) { |
|
565 nextEntry = __MKU16STRING( data.cFileName ); |
|
566 } else { |
|
567 __INST(hitEOF) = true; |
|
568 } |
|
569 } |
|
570 # endif /* WIN32 */ |
|
571 #endif /* HAS_OPENDIR */ |
|
572 |
|
573 #ifdef unix |
|
574 isUnix = true; |
|
575 #endif |
|
576 |
|
577 %}. |
|
578 lastErrorNumber notNil ifTrue:[^ self ioError]. |
|
579 nextEntry notNil ifTrue:[ |
|
580 isUnix == true ifTrue:[ |
|
581 nextEntry := OperatingSystem decodePath:nextEntry. |
|
582 ] ifFalse:[ |
|
583 nextEntry := nextEntry asSingleByteStringIfPossible. |
|
584 ] |
|
585 ]. |
|
586 prevEntry := readAheadEntry. |
|
587 readAheadEntry := nextEntry. |
|
588 prevEntry isNil ifTrue:[^ self pastEndRead]. |
|
589 ^ prevEntry |
|
590 ! ! |
|
591 |
|
592 !DirectoryStream methodsFor:'closing'! |
|
593 |
|
594 close |
|
595 "close the stream - tell operating system" |
|
596 |
|
597 dirPointer notNil ifTrue:[ |
|
598 Lobby unregister:self. |
|
599 self closeFile. |
|
600 dirPointer := nil |
|
601 ] |
|
602 ! ! |
|
603 |
|
604 !DirectoryStream protectedMethodsFor:'instance release'! |
|
605 |
|
606 closeFile |
|
607 "low level close of a directoryStream" |
|
608 %{ |
|
609 #ifdef HAS_OPENDIR |
|
610 OBJ dp; |
|
611 |
|
612 if ((dp = __INST(dirPointer)) != nil) { |
|
613 __INST(dirPointer) = nil; |
|
614 closedir( (DIR *)(__FILEVal(dp)) ); |
|
615 } |
|
616 #else |
560 #else |
617 # ifdef WIN32 |
561 # ifdef WIN32 |
618 OBJ dp; |
562 FindClose( __HANDLEVal(dp) ); |
619 |
|
620 if ((dp = __INST(dirPointer)) != nil) { |
|
621 __INST(dirPointer) = nil; |
|
622 FindClose( __HANDLEVal(dp) ); |
|
623 } |
|
624 # endif |
563 # endif |
625 #endif |
564 #endif |
626 %} |
565 %} |
627 ! ! |
566 ! ! |
628 |
567 |
629 !DirectoryStream methodsFor:'private'! |
568 !DirectoryStream methodsFor:'private'! |
630 |
569 |
631 openForReading |
570 openForReading |
632 "open the file for readonly" |
571 "open the file for readonly" |
633 |
572 |
634 |ok entry encodedPathName| |
573 |ok encodedPathName error fileSize osPathname osModTime osCrtTime osAccTime osFileAttributes | |
635 |
574 |
636 encodedPathName := OperatingSystem encodePath:pathName. |
575 encodedPathName := OperatingSystem encodePath:pathName. |
637 mode := #readonly. |
576 mode := #readonly. |
|
577 hitEOF := false. |
|
578 |
638 %{ |
579 %{ |
639 #ifdef HAS_OPENDIR |
580 #ifdef HAS_OPENDIR |
640 DIR *d; |
581 DIR *d; |
641 OBJ path, dp; |
582 OBJ path, dp; |
642 |
583 |
649 d = opendir((char *) __stringVal(encodedPathName)); |
590 d = opendir((char *) __stringVal(encodedPathName)); |
650 } while ((d == NULL) && (__threadErrno == EINTR)); |
591 } while ((d == NULL) && (__threadErrno == EINTR)); |
651 __END_INTERRUPTABLE__ |
592 __END_INTERRUPTABLE__ |
652 |
593 |
653 if (d == NULL) { |
594 if (d == NULL) { |
654 __INST(lastErrorNumber) = __mkSmallInteger(__threadErrno); |
595 error = __mkSmallInteger(__threadErrno); |
655 } else { |
596 } else { |
656 dp = __MKEXTERNALADDRESS(d); __INST(dirPointer) = dp; __STORE(self, dp); |
597 dp = __MKEXTERNALADDRESS(d); __INST(dirPointer) = dp; __STORE(self, dp); |
657 ok = true; |
598 ok = true; |
658 } |
599 } |
659 } |
600 } |
660 } |
601 } |
661 #else |
602 #else |
662 # ifdef WIN32 |
603 #ifdef WIN32 |
663 HANDLE d; |
604 HANDLE d; |
664 OBJ path, dp; |
605 OBJ path, dp; |
665 union { |
606 union { |
666 char pattern[MAXPATHLEN]; |
607 char pattern[MAXPATHLEN]; |
667 wchar_t wpattern[MAXPATHLEN]; |
608 wchar_t wpattern[MAXPATHLEN]; |
685 __threadErrno = 0; |
626 __threadErrno = 0; |
686 d = STX_API_NOINT_CALL2( "FindFirstFileA", FindFirstFileA, uP.pattern, &uD.data ); |
627 d = STX_API_NOINT_CALL2( "FindFirstFileA", FindFirstFileA, uP.pattern, &uD.data ); |
687 } while ((d < 0) && (__threadErrno == EINTR)); |
628 } while ((d < 0) && (__threadErrno == EINTR)); |
688 |
629 |
689 if (d == INVALID_HANDLE_VALUE) { |
630 if (d == INVALID_HANDLE_VALUE) { |
690 __INST(lastErrorNumber) = __mkSmallInteger(GetLastError()); |
631 error = __mkSmallInteger(GetLastError()); |
691 } else { |
632 } else { |
692 dp = __MKEXTERNALADDRESS(d); __INST(dirPointer) = dp; __STORE(self, dp); |
633 dp = __MKEXTERNALADDRESS(d); __INST(dirPointer) = dp; __STORE(self, dp); |
693 entry = __MKSTRING( uD.data.cFileName ); |
634 |
|
635 fileSize = __MKLARGEINT64(1, uD.data.nFileSizeLow, uD.data.nFileSizeHigh ); |
|
636 osPathname = __MKSTRING( uD.data.cFileName ); |
|
637 osFileAttributes = __mkSmallInteger( uD.data.dwFileAttributes ); |
|
638 |
|
639 osCrtTime = FileTimeToOsTime(&uD.data.ftCreationTime); |
|
640 osAccTime = FileTimeToOsTime(&uD.data.ftLastAccessTime); |
|
641 osModTime = FileTimeToOsTime(&uD.data.ftLastWriteTime); |
694 ok = true; |
642 ok = true; |
695 } |
643 } |
696 } |
644 } |
697 } |
645 } |
698 else if (__isUnicode16String(path)) { |
646 else if (__isUnicode16String(path)) { |
711 __threadErrno = 0; |
659 __threadErrno = 0; |
712 d = STX_API_NOINT_CALL2( "FindFirstFileW", FindFirstFileW, uP.wpattern, &uD.wdata ); |
660 d = STX_API_NOINT_CALL2( "FindFirstFileW", FindFirstFileW, uP.wpattern, &uD.wdata ); |
713 } while ((d < 0) && (__threadErrno == EINTR)); |
661 } while ((d < 0) && (__threadErrno == EINTR)); |
714 |
662 |
715 if (d == INVALID_HANDLE_VALUE) { |
663 if (d == INVALID_HANDLE_VALUE) { |
716 __INST(lastErrorNumber) = __mkSmallInteger(GetLastError()); |
664 error = __mkSmallInteger(GetLastError()); |
717 } else { |
665 } else { |
718 dp = __MKEXTERNALADDRESS(d); __INST(dirPointer) = dp; __STORE(self, dp); |
666 dp = __MKEXTERNALADDRESS(d); __INST(dirPointer) = dp; __STORE(self, dp); |
719 entry = __MKU16STRING( uD.wdata.cFileName ); |
667 |
|
668 fileSize = __MKLARGEINT64(1, uD.wdata.nFileSizeLow, uD.wdata.nFileSizeHigh ); |
|
669 osPathname = __MKU16STRING( uD.wdata.cFileName ); |
|
670 osFileAttributes = __mkSmallInteger( uD.data.dwFileAttributes ); |
|
671 |
|
672 osCrtTime = FileTimeToOsTime(&uD.wdata.ftCreationTime); |
|
673 osAccTime = FileTimeToOsTime(&uD.wdata.ftLastAccessTime); |
|
674 osModTime = FileTimeToOsTime(&uD.wdata.ftLastWriteTime); |
720 ok = true; |
675 ok = true; |
721 } |
676 } |
722 } |
677 } |
723 } |
678 } |
724 } |
679 } |
725 # endif |
680 #endif |
726 #endif |
681 #endif |
727 %}. |
682 %}. |
728 ok isNil ifTrue:[ |
683 |
729 " |
684 ok == true ifTrue:[ |
730 opendir not avalable - use slower pipe |
|
731 " |
|
732 ^ PipeStream readingFrom:('cd ' , pathName , '; ls -a') |
|
733 ]. |
|
734 |
|
735 (ok == true) ifTrue:[ |
|
736 Lobby register:self. |
685 Lobby register:self. |
737 entry isNil ifTrue:[ |
686 osPathname isNil ifTrue:[ |
738 self nextLine. "read 1st entry into readAheadEntry buffer" |
687 "UNIX: does not automatically provide the first entry" |
|
688 |
|
689 StreamError handle:[:ex | |
|
690 self close. |
|
691 ex reject. |
|
692 ] do:[ |
|
693 readAheadEntry := OperatingSystem nextLinkInfoFrom:self dirPointer:dirPointer. |
|
694 ]. |
739 ] ifFalse:[ |
695 ] ifFalse:[ |
740 readAheadEntry := entry. |
696 "Windows already provides the first entry's info" |
|
697 |
|
698 readAheadEntry := OperatingSystem |
|
699 linkInfoFor:osPathname |
|
700 fileSize:fileSize |
|
701 fileAttributes:osFileAttributes |
|
702 osCrtTime:osCrtTime |
|
703 osAccTime:osAccTime |
|
704 osModTime:osModTime |
741 ]. |
705 ]. |
|
706 |
742 ^ self |
707 ^ self |
743 ]. |
708 ]. |
744 dirPointer notNil ifTrue:[^ self errorAlreadyOpen]. |
709 |
745 lastErrorNumber notNil ifTrue:[^ self openError:lastErrorNumber]. |
710 ok notNil ifTrue:[ |
|
711 dirPointer notNil ifTrue:[^ self errorAlreadyOpen]. |
|
712 ]. |
|
713 error notNil ifTrue:[ |
|
714 ^ self openError:(lastErrorNumber := error). |
|
715 ]. |
746 ^ nil |
716 ^ nil |
747 ! |
717 ! |
748 |
718 |
749 reOpen |
719 reOpen |
750 "USERS WILL NEVER INVOKE THIS METHOD |
720 "USERS WILL NEVER INVOKE THIS METHOD |
781 (DirectoryStream directoryNamed:'/') isEmpty |
751 (DirectoryStream directoryNamed:'/') isEmpty |
782 (DirectoryStream directoryNamed:'/var/tmp') isEmpty |
752 (DirectoryStream directoryNamed:'/var/tmp') isEmpty |
783 " |
753 " |
784 |
754 |
785 "Modified: 18.9.1997 / 18:05:31 / stefan" |
755 "Modified: 18.9.1997 / 18:05:31 / stefan" |
|
756 ! |
|
757 |
|
758 isOpen |
|
759 ^ dirPointer notNil. |
786 ! ! |
760 ! ! |
787 |
761 |
788 !DirectoryStream class methodsFor:'documentation'! |
762 !DirectoryStream class methodsFor:'documentation'! |
789 |
763 |
790 version |
764 version |
791 ^ '$Header: /cvs/stx/stx/libbasic/DirectoryStream.st,v 1.78 2013-01-10 11:43:30 cg Exp $' |
765 ^ '$Header: /cvs/stx/stx/libbasic/DirectoryStream.st,v 1.87 2015-01-15 15:24:41 cg Exp $' |
792 ! |
766 ! |
793 |
767 |
794 version_CVS |
768 version_CVS |
795 ^ '$Header: /cvs/stx/stx/libbasic/DirectoryStream.st,v 1.78 2013-01-10 11:43:30 cg Exp $' |
769 ^ '$Header: /cvs/stx/stx/libbasic/DirectoryStream.st,v 1.87 2015-01-15 15:24:41 cg Exp $' |
796 ! ! |
770 ! ! |
|
771 |