@@ -176,16 +176,17 @@ private void FillDispatchTable() {
176176 AddAction ( 0x47 , ( ) => GetCurrentDirectory ( true ) ) ;
177177 AddAction ( 0x48 , ( ) => AllocateMemoryBlock ( true ) ) ;
178178 AddAction ( 0x49 , ( ) => FreeMemoryBlock ( true ) ) ;
179- AddAction ( 0x50 , ( ) => SetCurrentPsp ( ) ) ;
180179 AddAction ( 0x4A , ( ) => ModifyMemoryBlock ( true ) ) ;
181180 AddAction ( 0x4B , ( ) => LoadAndOrExecute ( true ) ) ;
182181 AddAction ( 0x4C , QuitWithExitCode ) ;
183182 AddAction ( 0x4D , GetReturnCode ) ;
184183 AddAction ( 0x4E , ( ) => FindFirstMatchingFile ( true ) ) ;
185184 AddAction ( 0x4F , ( ) => FindNextMatchingFile ( true ) ) ;
185+ AddAction ( 0x50 , ( ) => SetCurrentPsp ( ) ) ;
186186 AddAction ( 0x51 , GetPspAddress ) ;
187187 AddAction ( 0x52 , GetListOfLists ) ;
188188 AddAction ( 0x55 , CreateChildPsp ) ;
189+ AddAction ( 0x57 , ( ) => GetSetFileDateAndTime ( true ) ) ;
189190 AddAction ( 0x58 , ( ) => AllocationStrategyOrUpperMemoryLinkState ( true ) ) ;
190191 AddAction ( 0x62 , GetPspAddress ) ;
191192 AddAction ( 0x63 , GetLeadByteTable ) ;
@@ -1951,6 +1952,78 @@ public void GetSetFileAttributes(bool calledFromVm) {
19511952 }
19521953 }
19531954
1955+ /// <summary>
1956+ /// Gets (AL: 0) or sets (AL: 1) file attributes for the file identified via its file path at DS:DX.
1957+ /// TODO: The Set File Attributes operation is not implemented.
1958+ /// </summary>
1959+ /// <returns>
1960+ /// CF is cleared on success. <br/>
1961+ /// CF is set on error. Possible error code in AX: 0x2 (File not found). <br/>
1962+ /// TODO: Always returns that the file is read / write in Get File Attributes mode.
1963+ /// </returns>
1964+ /// <exception cref="UnhandledOperationException">When the operation in the AL Register is not supported.</exception>
1965+ /// <param name="calledFromVm">Whether this was called from internal emulator code.</param>
1966+ public void GetSetFileDateAndTime ( bool calledFromVm ) {
1967+ byte op = State . AL ;
1968+ string dosFileName = _dosStringDecoder . GetZeroTerminatedStringAtDsDx ( ) ;
1969+ string ? fileName = _dosFileManager . TryGetFullHostPathFromDos ( dosFileName ) ;
1970+ if ( ! File . Exists ( fileName ) ) {
1971+ LogDosError ( calledFromVm ) ;
1972+ SetCarryFlag ( true , calledFromVm ) ;
1973+ // invalid handle
1974+ State . AX = 0x6 ;
1975+ return ;
1976+ }
1977+ switch ( op ) {
1978+ case 0 : {
1979+ if ( LoggerService . IsEnabled ( LogEventLevel . Verbose ) ) {
1980+ LoggerService . Verbose ( "GET FILE DATETIME {FileName}" , fileName ) ;
1981+ }
1982+ DateTime dateTime = File . GetLastAccessTime ( fileName ) ;
1983+ State . CX = DosFileManager . ToDosTime ( dateTime ) ;
1984+ State . DX = DosFileManager . ToDosDate ( dateTime ) ;
1985+ SetCarryFlag ( false , calledFromVm ) ;
1986+ break ;
1987+ }
1988+ case 1 : {
1989+ ushort dosFileTime = State . CX ;
1990+ ushort dosFileDate = State . DX ;
1991+ if ( LoggerService . IsEnabled ( LogEventLevel . Verbose ) ) {
1992+ LoggerService . Verbose ( "SET FILE DATETIME {FileName}, {FileTime}, {FileDate}" ,
1993+ fileName , dosFileDate , dosFileTime ) ;
1994+ }
1995+ DateTime fileDateTime = DateTimeFormDosDateAndTime ( dosFileTime , dosFileDate ) ;
1996+ File . SetLastAccessTime ( fileName , fileDateTime ) ;
1997+ SetCarryFlag ( false , calledFromVm ) ;
1998+ break ;
1999+ }
2000+ default : {
2001+ // throw new UnhandledOperationException(State, "getSetFileDateTime operation unhandled: " + op);
2002+ SetCarryFlag ( true , calledFromVm ) ;
2003+ // function number invalid
2004+ State . AX = 0x1 ;
2005+ break ;
2006+ }
2007+ }
2008+ }
2009+
2010+ /// <summary>
2011+ /// Converts DOS Date and Time to DateTime
2012+ /// DOS date format: bits 15-9=year-1980, bits 8-5=month, bits 4-0=day.
2013+ /// DOS time format: bits 15-11=hour, bits 10-5=minute, bits 4-0=seconds/2.
2014+ /// </summary>
2015+ public static DateTime DateTimeFormDosDateAndTime ( ushort dosDate , ushort dosTime ) {
2016+ int day = ( dosDate >> 0 ) & 0b11111 ;
2017+ int month = ( dosDate >> 5 ) & 0b1111 ;
2018+ int year = ( dosDate >> 9 ) & 0b1111111 + 1980 ;
2019+
2020+ int seconds = ( dosTime >> 0 ) & 0b11111 * 2 ;
2021+ int minutes = ( dosTime >> 5 ) & 0b111111 ;
2022+ int hours = ( dosTime >> 11 ) & 0b11111 ;
2023+
2024+ return new DateTime ( year , month , day , hours , minutes , seconds ) ;
2025+ }
2026+
19542027 /// <summary>
19552028 /// Gets the FCB linear address from DS:DX.
19562029 /// </summary>
0 commit comments