902 " |
902 " |
903 ! ! |
903 ! ! |
904 |
904 |
905 !FileStream methodsFor:'positioning'! |
905 !FileStream methodsFor:'positioning'! |
906 |
906 |
907 position0Based |
907 position |
908 "return the read/write position in the file" |
908 "return the read/write position in the file" |
909 |
909 |
910 %{ |
910 %{ |
911 |
911 |
912 HFILE f; |
912 HFILE f; |
913 off_t currentPosition; |
913 off_t currentPosition; |
914 |
914 |
915 if (__INST(handle) != nil) { |
915 if (__INST(handle) != nil) { |
916 do { |
916 do { |
917 f = __FILEVal(__INST(handle)); |
917 f = __FILEVal(__INST(handle)); |
918 #ifdef WIN32 |
918 #ifdef WIN32 |
919 __threadErrno = 0; |
919 __threadErrno = 0; |
920 if (__INST(buffered) == true) { |
920 if (__INST(buffered) == true) { |
921 # if 0 |
921 # if 0 |
922 currentPosition = STX_C_CALL1( "ftell", ftell, f); |
922 currentPosition = STX_C_CALL1( "ftell", ftell, f); |
923 # else |
923 # else |
924 currentPosition = ftell(f); |
924 currentPosition = ftell(f); |
925 # endif |
925 # endif |
926 } else { |
926 } else { |
927 OBJ rA = __INST(readAhead); |
927 OBJ rA = __INST(readAhead); |
928 off_t offs = 0; |
928 off_t offs = 0; |
929 |
929 |
930 if (rA != nil) { |
930 if (rA != nil) { |
931 __INST(readAhead) = nil; |
931 __INST(readAhead) = nil; |
932 offs = -1; |
932 offs = -1; |
933 } |
933 } |
934 # if 0 |
934 # if 0 |
935 currentPosition = STX_C_CALL3( "lseek", lseek, fileno(f), offs, SEEK_CUR); |
935 currentPosition = STX_C_CALL3( "lseek", lseek, fileno(f), offs, SEEK_CUR); |
936 # else |
936 # else |
937 currentPosition = lseek(fileno(f), offs, SEEK_CUR); |
937 currentPosition = lseek(fileno(f), offs, SEEK_CUR); |
938 # endif |
938 # endif |
939 } |
939 } |
940 #else /* !WIN32 */ |
940 #else /* !WIN32 */ |
941 if (__INST(buffered) == true) { |
941 if (__INST(buffered) == true) { |
942 #ifdef _LFS_LARGEFILE |
942 #ifdef _LFS_LARGEFILE |
943 currentPosition = ftello(f); |
943 currentPosition = ftello(f); |
944 #else |
944 #else |
945 currentPosition = ftell(f); |
945 currentPosition = ftell(f); |
946 #endif /* ! _LFS_LARGEFILE */ |
946 #endif /* ! _LFS_LARGEFILE */ |
947 } else { |
947 } else { |
948 currentPosition = lseek(fileno(f), (off_t)0, SEEK_CUR); |
948 currentPosition = lseek(fileno(f), (off_t)0, SEEK_CUR); |
949 } |
949 } |
950 #endif /* !WIN32 */ |
950 #endif /* !WIN32 */ |
951 } while ((currentPosition < 0) && (__threadErrno == EINTR)); |
951 } while ((currentPosition < 0) && (__threadErrno == EINTR)); |
952 |
952 |
953 if (currentPosition >= 0) { |
953 if (currentPosition >= 0) { |
954 OBJ rslt; |
954 OBJ rslt; |
955 |
955 |
956 if (sizeof(currentPosition) == 8) { |
956 if (sizeof(currentPosition) == 8) { |
957 rslt = __MKINT64 (¤tPosition); |
957 rslt = __MKINT64 (¤tPosition); |
958 } else { |
958 } else { |
959 rslt = __MKINT(currentPosition); |
959 rslt = __MKINT(currentPosition); |
960 } |
960 } |
961 RETURN ( rslt ); |
961 RETURN ( rslt ); |
962 } |
962 } |
963 __INST(lastErrorNumber) = __mkSmallInteger(__threadErrno); |
963 __INST(lastErrorNumber) = __mkSmallInteger(__threadErrno); |
964 } |
964 } |
965 %}. |
965 %}. |
966 lastErrorNumber notNil ifTrue:[^ self ioError]. |
966 lastErrorNumber notNil ifTrue:[^ self ioError]. |
967 handle isNil ifTrue:[^ self errorNotOpen]. |
967 handle isNil ifTrue:[^ self errorNotOpen]. |
968 ^ self primitiveFailed |
968 ^ self primitiveFailed |
969 ! |
969 ! |
970 |
970 |
971 position0Based:newPos |
971 position:newPos |
972 "set the read/write position in the file" |
972 "set the read/write position in the file" |
973 |
973 |
974 |rslt| |
974 |rslt| |
975 %{ |
975 %{ |
976 |
976 |
977 HFILE f; |
977 HFILE f; |
978 long ret; |
978 long ret; |
979 OBJ fp; |
979 OBJ fp; |
980 |
980 |
981 if ((__INST(canPosition) != false) || (newPos == __mkSmallInteger(0))) { |
981 if ((__INST(canPosition) != false) || (newPos == __mkSmallInteger(0))) { |
982 if ((fp = __INST(handle)) != nil) { |
982 if ((fp = __INST(handle)) != nil) { |
983 |
983 |
984 #if defined(_LFS_LARGE_FILE) && !defined(WIN32) |
984 #if defined(_LFS_LARGE_FILE) && !defined(WIN32) |
985 # define FSEEK fseeko |
985 # define FSEEK fseeko |
986 off_t nP; |
986 off_t nP; |
987 #else |
987 #else |
988 #define FSEEK fseek |
988 #define FSEEK fseek |
989 long nP; |
989 long nP; |
990 #endif |
990 #endif |
991 |
991 |
992 if (__isSmallInteger(newPos)) { |
992 if (__isSmallInteger(newPos)) { |
993 nP = __intVal(newPos); |
993 nP = __intVal(newPos); |
994 if (nP < 0) { |
994 if (nP < 0) { |
995 __INST(lastErrorNumber) = __mkSmallInteger(EINVAL); |
995 __INST(lastErrorNumber) = __mkSmallInteger(EINVAL); |
996 goto getOutOfHere; |
996 goto getOutOfHere; |
997 } |
997 } |
998 } else { |
998 } else { |
999 nP = __signedLongIntVal(newPos); |
999 nP = __signedLongIntVal(newPos); |
1000 if (nP < 0) { |
1000 if (nP < 0) { |
1001 __INST(lastErrorNumber) = __mkSmallInteger(EINVAL); |
1001 __INST(lastErrorNumber) = __mkSmallInteger(EINVAL); |
1002 goto getOutOfHere; |
1002 goto getOutOfHere; |
1003 } |
1003 } |
1004 if (nP == 0) { |
1004 if (nP == 0) { |
1005 if (sizeof(nP) == 8) { |
1005 if (sizeof(nP) == 8) { |
1006 if (__signedLong64IntVal(newPos, &nP) == 0 || nP < 0) { |
1006 if (__signedLong64IntVal(newPos, &nP) == 0 || nP < 0) { |
1007 __INST(lastErrorNumber) = __mkSmallInteger(EINVAL); |
1007 __INST(lastErrorNumber) = __mkSmallInteger(EINVAL); |
1008 goto getOutOfHere; |
1008 goto getOutOfHere; |
1009 } |
1009 } |
1010 } else { |
1010 } else { |
1011 __INST(lastErrorNumber) = __mkSmallInteger(EINVAL); |
1011 __INST(lastErrorNumber) = __mkSmallInteger(EINVAL); |
1012 goto getOutOfHere; |
1012 goto getOutOfHere; |
1013 } |
1013 } |
1014 } |
1014 } |
1015 } |
1015 } |
1016 |
1016 |
1017 f = __FILEVal(fp); |
1017 f = __FILEVal(fp); |
1018 |
1018 |
1019 do { |
1019 do { |
1020 #if defined(DO_WRAP_CALL_FSEEK) |
1020 #if defined(DO_WRAP_CALL_FSEEK) |
1021 __threadErrno = 0; |
1021 __threadErrno = 0; |
1022 if (__INST(buffered) == true) { |
1022 if (__INST(buffered) == true) { |
1023 ret = STX_C_CALL3( "fseek", fseek, f, nP, SEEK_SET); |
1023 ret = STX_C_CALL3( "fseek", fseek, f, nP, SEEK_SET); |
1024 } else { |
1024 } else { |
1025 __INST(readAhead) = nil; |
1025 __INST(readAhead) = nil; |
1026 ret = STX_C_CALL3( "lseek", lseek, fileno(f), nP, SEEK_SET); |
1026 ret = STX_C_CALL3( "lseek", lseek, fileno(f), nP, SEEK_SET); |
1027 } |
1027 } |
1028 #else |
1028 #else |
1029 if (__INST(buffered) == true) { |
1029 if (__INST(buffered) == true) { |
1030 ret = FSEEK(f, nP, SEEK_SET); |
1030 ret = FSEEK(f, nP, SEEK_SET); |
1031 } else { |
1031 } else { |
1032 ret = lseek(fileno(f), nP, SEEK_SET); |
1032 ret = lseek(fileno(f), nP, SEEK_SET); |
1033 } |
1033 } |
1034 __threadErrno = errno; |
1034 __threadErrno = errno; |
1035 #endif |
1035 #endif |
1036 } while ((ret < 0) && (__threadErrno == EINTR)); |
1036 } while ((ret < 0) && (__threadErrno == EINTR)); |
1037 if (ret >= 0) { |
1037 if (ret >= 0) { |
1038 __INST(position) = newPos; __STORE(self, newPos); |
1038 __INST(position) = newPos; __STORE(self, newPos); |
1039 /* |
1039 /* |
1040 * just to make certain ... |
1040 * just to make certain ... |
1041 */ |
1041 */ |
1042 __INST(hitEOF) = false; |
1042 __INST(hitEOF) = false; |
1043 RETURN ( self ); |
1043 RETURN ( self ); |
1044 } |
1044 } |
1045 __INST(lastErrorNumber) = __mkSmallInteger(__threadErrno); |
1045 __INST(lastErrorNumber) = __mkSmallInteger(__threadErrno); |
1046 } |
1046 } |
1047 } |
1047 } |
1048 getOutOfHere: ; |
1048 getOutOfHere: ; |
1049 #undef FSEEK |
1049 #undef FSEEK |
1050 %}. |
1050 %}. |
1051 canPosition == false ifTrue:[ |
1051 canPosition == false ifTrue:[ |
1052 "/ position by rewinding & re-reading everything up-to |
1052 "/ position by rewinding & re-reading everything up-to |
1053 "/ that point. |
1053 "/ that point. |
1054 ^ self slowPosition0Based:newPos |
1054 ^ self slowPosition:newPos |
1055 ]. |
1055 ]. |
1056 lastErrorNumber notNil ifTrue:[ |
1056 lastErrorNumber notNil ifTrue:[ |
1057 (OperatingSystem errorSymbolForNumber:lastErrorNumber) == #EINVAL ifTrue:[ |
1057 (OperatingSystem errorSymbolForNumber:lastErrorNumber) == #EINVAL ifTrue:[ |
1058 "/ invalid position |
1058 "/ invalid position |
1059 ^ self positionError |
1059 ^ self positionError |
1060 ]. |
1060 ]. |
1061 "/ assume I/O error |
1061 "/ assume I/O error |
1062 ^ self ioError |
1062 ^ self ioError |
1063 ]. |
1063 ]. |
1064 handle isNil ifTrue:[^ self errorNotOpen]. |
1064 handle isNil ifTrue:[^ self errorNotOpen]. |
1065 |
1065 |
1066 rslt := self positionFile:handle position:newPos. |
1066 rslt := self positionFile:handle position:newPos. |
1067 rslt >= 0 ifTrue:[ |
1067 rslt >= 0 ifTrue:[ |
1068 position := newPos. |
1068 position := newPos. |
1069 ] ifFalse:[ |
1069 ] ifFalse:[ |
1070 hitEOF := true. |
1070 hitEOF := true. |
1071 ] |
1071 ] |
1072 ! |
1072 ! |
1073 |
1073 |
1074 reset |
1074 reset |
1075 "additionaly to setting the position to the beginning of the file, |
1075 "additionaly to setting the position to the beginning of the file, |
1130 lastErrorNumber notNil ifTrue:[^ self ioError]. |
1130 lastErrorNumber notNil ifTrue:[^ self ioError]. |
1131 handle isNil ifTrue:[^ self errorNotOpen]. |
1131 handle isNil ifTrue:[^ self errorNotOpen]. |
1132 ^ self primitiveFailed |
1132 ^ self primitiveFailed |
1133 ! |
1133 ! |
1134 |
1134 |
1135 slowPosition0Based:newPos |
|
1136 "position the file by re-reading everything up-to newPos. |
|
1137 The effect is the same as that of #position:, but its much slower. |
|
1138 This is required to reposition nonPositionable streams, such |
|
1139 as tape-streams or variable-record-RMS files under VMS. |
|
1140 Caveat: |
|
1141 This should really be done transparently by the stdio library." |
|
1142 |
|
1143 |buffer amount pos0Based| |
|
1144 |
|
1145 self isReadable ifFalse:[ |
|
1146 "/ sorry |
|
1147 ^ self positionError |
|
1148 ]. |
|
1149 |
|
1150 buffer := ByteArray new:8*1024. |
|
1151 |
|
1152 (position isNil "/ i.e. unknown |
|
1153 or:[newPos < (pos0Based := self position0Based)]) ifTrue:[ |
|
1154 self reset. |
|
1155 pos0Based := self position0Based. |
|
1156 ]. |
|
1157 [pos0Based < newPos] whileTrue:[ |
|
1158 amount := (buffer size) min:(newPos-pos0Based). |
|
1159 (self nextBytes:amount into:buffer startingAt:1) ~~ amount ifTrue:[ |
|
1160 ^ self positionError |
|
1161 ]. |
|
1162 pos0Based := self position0Based. |
|
1163 ]. |
|
1164 "/ ('FileStream [info]: slow position - please convert ''' , pathName printString , ''' to streamLF format') infoPrintCR. |
|
1165 ! |
|
1166 |
|
1167 slowPosition:newPos |
1135 slowPosition:newPos |
1168 "position the file by re-reading everything up-to newPos. |
1136 "position the file by re-reading everything up-to newPos. |
1169 The effect is the same as that of #position:, but its much slower. |
1137 The effect is the same as that of #position:, but its much slower. |
1170 This is required to reposition nonPositionable streams, such |
1138 This is required to reposition nonPositionable streams, such |
1171 as tape-streams or variable-record-RMS files under VMS. |
1139 as tape-streams or variable-record-RMS files under VMS. |
1172 Caveat: |
1140 Caveat: |
1173 This should really be done transparently by the stdio library." |
1141 This should really be done transparently by the stdio library." |
1174 |
1142 |
1175 ^ self slowPosition0Based:newPos |
1143 |buffer amount pos0Based| |
|
1144 |
|
1145 self isReadable ifFalse:[ |
|
1146 "/ sorry |
|
1147 ^ self positionError |
|
1148 ]. |
|
1149 |
|
1150 buffer := ByteArray new:8*1024. |
|
1151 |
|
1152 (position isNil "/ i.e. unknown |
|
1153 or:[newPos < (pos0Based := self position)]) ifTrue:[ |
|
1154 self reset. |
|
1155 pos0Based := self position. |
|
1156 ]. |
|
1157 [pos0Based < newPos] whileTrue:[ |
|
1158 amount := (buffer size) min:(newPos-pos0Based). |
|
1159 (self nextBytes:amount into:buffer startingAt:1) ~~ amount ifTrue:[ |
|
1160 ^ self positionError |
|
1161 ]. |
|
1162 pos0Based := self position. |
|
1163 ]. |
|
1164 "/ ('FileStream [info]: slow position - please convert ''' , pathName printString , ''' to streamLF format') infoPrintCR. |
1176 ! ! |
1165 ! ! |
1177 |
1166 |
1178 !FileStream methodsFor:'printing & storing'! |
1167 !FileStream methodsFor:'printing & storing'! |
1179 |
1168 |
1180 printOn:aStream |
1169 printOn:aStream |