From a5ee6145038bd04377a96aed133eaa440f14b7d3 Mon Sep 17 00:00:00 2001 From: Ralf Grillenberger Date: Sun, 5 Jun 2011 18:28:00 +0000 Subject: [PATCH] - Add midnight/next day increment - Add date and time commands (functionality limited) Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@3715 --- include/shell.h | 2 + src/dos/dos.cpp | 79 +++++++++++++++++++---------- src/ints/bios.cpp | 42 +++++++++++++++- src/shell/shell.cpp | 17 +++++++ src/shell/shell_cmds.cpp | 104 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 218 insertions(+), 26 deletions(-) diff --git a/include/shell.h b/include/shell.h index c131f9e4..ec7d7d05 100644 --- a/include/shell.h +++ b/include/shell.h @@ -87,6 +87,8 @@ public: void CMD_HELP(char * args); void CMD_CLS(char * args); void CMD_COPY(char * args); + void CMD_DATE(char * args); + void CMD_TIME(char * args); void CMD_DIR(char * args); void CMD_DELETE(char * args); void CMD_ECHO(char * args); diff --git a/src/dos/dos.cpp b/src/dos/dos.cpp index 17503e2c..e05922bf 100644 --- a/src/dos/dos.cpp +++ b/src/dos/dos.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #include "dosbox.h" #include "bios.h" #include "mem.h" @@ -41,6 +40,34 @@ void DOS_SetError(Bit16u code) { dos.errorcode=code; } +const Bit8u DOS_DATE_months[] = { + 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +static void DOS_AddDays(Bitu days) { + dos.date.day += days; + Bit8u monthlimit = DOS_DATE_months[dos.date.month]; + + if(dos.date.day > monthlimit) { + if((dos.date.year %4 == 0) && (dos.date.month==2)) { + // leap year + if(dos.date.day > 29) { + dos.date.month++; + dos.date.day -= 29; + } + } else { + //not leap year + dos.date.month++; + dos.date.day -= monthlimit; + } + if(dos.date.month > 12) { + // year over + dos.date.month = 1; + dos.date.year++; + } + } +} + #define DATA_TRANSFERS_TAKE_CYCLES 1 #ifdef DATA_TRANSFERS_TAKE_CYCLES @@ -373,6 +400,9 @@ static Bitu DOS_21Handler(void) { break; case 0x2a: /* Get System Date */ { + reg_ax=0; // get time + CALLBACK_RunRealInt(0x1a); + if(reg_al) DOS_AddDays(reg_al); int a = (14 - dos.date.month)/12; int y = dos.date.year - a; int m = dos.date.month + 12*a - 2; @@ -385,28 +415,37 @@ static Bitu DOS_21Handler(void) { case 0x2b: /* Set System Date */ if (reg_cx<1980) { reg_al=0xff;break;} if ((reg_dh>12) || (reg_dh==0)) { reg_al=0xff;break;} - if ((reg_dl>31) || (reg_dl==0)) { reg_al=0xff;break;} + if (reg_dl==0) { reg_al=0xff;break;} + if (reg_dl>DOS_DATE_months[reg_dh]) { + if(!((reg_dh==2)&&(reg_cx%4 == 0)&&(reg_dl==29))) // february pass + { reg_al=0xff;break; } + } dos.date.year=reg_cx; dos.date.month=reg_dh; dos.date.day=reg_dl; reg_al=0; break; - case 0x2c: /* Get System Time */ -//TODO Get time through bios calls date is fixed - { -/* Calculate how many miliseconds have passed */ - Bitu ticks=5*(mem_readd(BIOS_TIMER) - time_start); - ticks = ((ticks / 59659u) << 16) + ((ticks % 59659u) << 16) / 59659u; - Bitu seconds=(ticks/100); - reg_ch=(Bit8u)(seconds/3600); - reg_cl=(Bit8u)((seconds % 3600)/60); - reg_dh=(Bit8u)(seconds % 60); - reg_dl=(Bit8u)(ticks % 100); - } + case 0x2c: { /* Get System Time */ + reg_ax=0; // get time + CALLBACK_RunRealInt(0x1a); + if(reg_al) DOS_AddDays(reg_al); + + Bitu time=((Bitu)reg_cx<<16)|reg_dx; + Bitu ticks=(Bitu)(5.49254945 * (double)time); + + reg_dl=(Bit8u)((Bitu)ticks % 100); // 1/100 seconds + ticks/=100; + reg_dh=(Bit8u)((Bitu)ticks % 60); // seconds + ticks/=60; + reg_cl=(Bit8u)((Bitu)ticks % 60); // minutes + ticks/=60; + reg_ch=(Bit8u)((Bitu)ticks % 24); // hours + //Simulate DOS overhead for timing-sensitive games - //Robomaze 2 + //Robomaze 2 overhead(); break; + } case 0x2d: /* Set System Time */ LOG(LOG_DOSMISC,LOG_ERROR)("DOS:Set System Time not supported"); //Check input parameters nonetheless @@ -1188,16 +1227,6 @@ public: dos.version.major=5; dos.version.minor=0; - - /* Setup time and date */ - time_t curtime;struct tm *loctime; - curtime = time (NULL);loctime = localtime (&curtime); - - dos.date.day=(Bit8u)loctime->tm_mday; - dos.date.month=(Bit8u)loctime->tm_mon+1; - dos.date.year=(Bit16u)loctime->tm_year+1900; - Bit32u ticks=(Bit32u)((loctime->tm_hour*3600+loctime->tm_min*60+loctime->tm_sec)*(float)PIT_TICK_RATE/65536.0); - mem_writed(BIOS_TIMER,ticks); } ~DOS(){ for (Bit16u i=0;i +#include /* if mem_systems 0 then size_extended is reported as the real size else @@ -311,7 +313,8 @@ static Bitu INT1A_Handler(void) { case 0x00: /* Get System time */ { Bit32u ticks=mem_readd(BIOS_TIMER); - reg_al=0; /* Midnight never passes :) */ + reg_al=mem_readb(BIOS_24_HOURS_FLAG); + mem_writeb(BIOS_24_HOURS_FLAG,0); // reset the "flag" reg_cx=(Bit16u)(ticks >> 16); reg_dx=(Bit16u)(ticks & 0xffff); break; @@ -371,9 +374,45 @@ static Bitu INT11_Handler(void) { #ifndef DOSBOX_CLOCKSYNC #define DOSBOX_CLOCKSYNC 0 #endif + +static void BIOS_HostTimeSync() { + /* Setup time and date */ + struct timeb timebuffer; + ftime(&timebuffer); + + struct tm *loctime; + loctime = localtime (&timebuffer.time); + + /* + loctime->tm_hour = 23; + loctime->tm_min = 59; + loctime->tm_sec = 45; + loctime->tm_mday = 28; + loctime->tm_mon = 2-1; + loctime->tm_year = 2007 - 1900; + */ + + dos.date.day=(Bit8u)loctime->tm_mday; + dos.date.month=(Bit8u)loctime->tm_mon+1; + dos.date.year=(Bit16u)loctime->tm_year+1900; + + Bit32u ticks=(Bit32u)(((double)( + loctime->tm_hour*3600*1000+ + loctime->tm_min*60*1000+ + loctime->tm_sec*1000+ + timebuffer.millitm))*(((double)PIT_TICK_RATE/65536.0)/1000.0)); + mem_writed(BIOS_TIMER,ticks); +} + static Bitu INT8_Handler(void) { /* Increase the bios tick counter */ Bit32u value = mem_readd(BIOS_TIMER) + 1; + if(value >= 0x1800B0) { + // time wrap at midnight + mem_writeb(BIOS_24_HOURS_FLAG,mem_readb(BIOS_24_HOURS_FLAG)+1); + value=0; + } + #if DOSBOX_CLOCKSYNC static bool check = false; if((value %50)==0) { @@ -1079,6 +1118,7 @@ public: size_extended=IO_Read(0x71); IO_Write(0x70,0x31); size_extended|=(IO_Read(0x71) << 8); + BIOS_HostTimeSync(); } ~BIOS(){ /* abort DAC playing */ diff --git a/src/shell/shell.cpp b/src/shell/shell.cpp index 77a40021..b4384725 100644 --- a/src/shell/shell.cpp +++ b/src/shell/shell.cpp @@ -464,6 +464,23 @@ void SHELL_Init() { MSG_Add("SHELL_CMD_CHDIR_HINT","To change to different drive type \033[31m%c:\033[0m\n"); MSG_Add("SHELL_CMD_CHDIR_HINT_2","directoryname is longer than 8 characters and/or contains spaces.\nTry \033[31mcd %s\033[0m\n"); MSG_Add("SHELL_CMD_CHDIR_HINT_3","You are still on drive Z:, change to a mounted drive with \033[31mC:\033[0m.\n"); + MSG_Add("SHELL_CMD_DATE_HELP","Displays or changes the internal date.\n"); + MSG_Add("SHELL_CMD_DATE_ERROR","The specified date is not correct.\n"); + MSG_Add("SHELL_CMD_DATE_DAYS","3SunMonTueWedThuFriSat"); // "2SoMoDiMiDoFrSa" + MSG_Add("SHELL_CMD_DATE_NOW","Current date: "); + MSG_Add("SHELL_CMD_DATE_SETHLP","Type 'date MM-DD-YYYY' to change.\n"); + MSG_Add("SHELL_CMD_DATE_FORMAT","M/D/Y"); + MSG_Add("SHELL_CMD_DATE_HELP_LONG","DATE [[/T] [/H] [/S] | MM-DD-YYYY]\n"\ + " MM-DD-YYYY: new date to set\n"\ + " /S: Permanently use host time and date as DOS time\n"\ + " /F: Switch back to DOSBox internal time (opposite of /S)\n"\ + " /T: Only display date\n"\ + " /H: Synchronize with host\n"); + MSG_Add("SHELL_CMD_TIME_HELP","Displays the internal time.\n"); + MSG_Add("SHELL_CMD_TIME_NOW","Current time: "); + MSG_Add("SHELL_CMD_TIME_HELP_LONG","TIME [/T] [/H]\n"\ + " /T: Display simple time\n"\ + " /H: Synchronize with host\n"); MSG_Add("SHELL_CMD_MKDIR_ERROR","Unable to make: %s.\n"); MSG_Add("SHELL_CMD_RMDIR_ERROR","Unable to remove: %s.\n"); MSG_Add("SHELL_CMD_DEL_ERROR","Unable to delete: %s.\n"); diff --git a/src/shell/shell_cmds.cpp b/src/shell/shell_cmds.cpp index 19791879..e2af8415 100644 --- a/src/shell/shell_cmds.cpp +++ b/src/shell/shell_cmds.cpp @@ -29,6 +29,7 @@ #include #include #include +#include static SHELL_Cmd cmd_list[]={ { "DIR", 0, &DOS_Shell::CMD_DIR, "SHELL_CMD_DIR_HELP"}, @@ -39,6 +40,7 @@ static SHELL_Cmd cmd_list[]={ { "CHOICE", 1, &DOS_Shell::CMD_CHOICE, "SHELL_CMD_CHOICE_HELP"}, { "CLS", 0, &DOS_Shell::CMD_CLS, "SHELL_CMD_CLS_HELP"}, { "COPY", 0, &DOS_Shell::CMD_COPY, "SHELL_CMD_COPY_HELP"}, +{ "DATE", 0, &DOS_Shell::CMD_DATE, "SHELL_CMD_DATE_HELP"}, { "DEL", 0, &DOS_Shell::CMD_DELETE, "SHELL_CMD_DELETE_HELP"}, { "DELETE", 1, &DOS_Shell::CMD_DELETE, "SHELL_CMD_DELETE_HELP"}, { "ERASE", 1, &DOS_Shell::CMD_DELETE, "SHELL_CMD_DELETE_HELP"}, @@ -61,6 +63,7 @@ static SHELL_Cmd cmd_list[]={ { "SET", 1, &DOS_Shell::CMD_SET, "SHELL_CMD_SET_HELP"}, { "SHIFT", 1, &DOS_Shell::CMD_SHIFT, "SHELL_CMD_SHIFT_HELP"}, { "SUBST", 1, &DOS_Shell::CMD_SUBST, "SHELL_CMD_SUBST_HELP"}, +{ "TIME", 0, &DOS_Shell::CMD_TIME, "SHELL_CMD_TIME_HELP"}, { "TYPE", 0, &DOS_Shell::CMD_TYPE, "SHELL_CMD_TYPE_HELP"}, { "VER", 0, &DOS_Shell::CMD_VER, "SHELL_CMD_VER_HELP"}, {0,0,0,0} @@ -937,6 +940,107 @@ void DOS_Shell::CMD_CALL(char * args){ this->call=false; } +void DOS_Shell::CMD_DATE(char * args) { + HELP("DATE"); + if(ScanCMDBool(args,"h")) { + // synchronize date with host parameter + time_t curtime; + struct tm *loctime; + curtime = time (NULL); + loctime = localtime (&curtime); + + reg_cx = loctime->tm_year+1900; + reg_dh = loctime->tm_mon+1; + reg_dl = loctime->tm_mday; + + reg_ah=0x2b; // set system date + CALLBACK_RunRealInt(0x21); + return; + } + // check if a date was passed in command line + Bitu newday,newmonth,newyear; + if(sscanf(args,"%u-%u-%u",&newmonth,&newday,&newyear)==3) { + reg_cx = newyear; + reg_dh = newmonth; + reg_dl = newday; + + reg_ah=0x2b; // set system date + CALLBACK_RunRealInt(0x21); + if(reg_al==0xff) WriteOut(MSG_Get("SHELL_CMD_DATE_ERROR")); + return; + } + // display the current date + reg_ah=0x2a; // get system date + CALLBACK_RunRealInt(0x21); + + const char* datestring = MSG_Get("SHELL_CMD_DATE_DAYS"); + Bit8u length; + char day[6] = {0}; + if(sscanf(datestring,"%u",&length) && (length<5) && (strlen(datestring)==(length*7+1))) { + // date string appears valid + for(int i = 0; i < length; i++) day[i] = datestring[reg_al*length+1+i]; + } + bool dateonly = ScanCMDBool(args,"t"); + if(!dateonly) WriteOut(MSG_Get("SHELL_CMD_DATE_NOW")); + + const char* formatstring = MSG_Get("SHELL_CMD_DATE_FORMAT"); + if(strlen(formatstring)!=5) return; + char buffer[15] = {0}; + Bitu bufferptr=0; + for(Bitu i = 0; i < 5; i++) { + if(i==1 || i==3) { + buffer[bufferptr] = formatstring[i]; + bufferptr++; + } else { + if(formatstring[i]=='M') bufferptr += sprintf(buffer+bufferptr,"%02u",(Bitu)reg_dh); + if(formatstring[i]=='D') bufferptr += sprintf(buffer+bufferptr,"%02u",(Bitu)reg_dl); + if(formatstring[i]=='Y') bufferptr += sprintf(buffer+bufferptr,"%04u",(Bitu)reg_cx); + } + } + WriteOut("%s %s\n",day, buffer); + if(!dateonly) WriteOut(MSG_Get("SHELL_CMD_DATE_SETHLP")); +}; + +void DOS_Shell::CMD_TIME(char * args) { + HELP("TIME"); + if(ScanCMDBool(args,"h")) { + // synchronize time with host parameter + time_t curtime; + struct tm *loctime; + curtime = time (NULL); + loctime = localtime (&curtime); + + //reg_cx = loctime->; + //reg_dh = loctime->; + //reg_dl = loctime->; + + // reg_ah=0x2d; // set system time TODO + // CALLBACK_RunRealInt(0x21); + + Bit32u ticks=(Bit32u)(((double)(loctime->tm_hour*3600+ + loctime->tm_min*60+ + loctime->tm_sec))*18.206481481); + mem_writed(BIOS_TIMER,ticks); + return; + } + bool timeonly = ScanCMDBool(args,"t"); + + reg_ah=0x2c; // get system time + CALLBACK_RunRealInt(0x21); +/* + reg_dl= // 1/100 seconds + reg_dh= // seconds + reg_cl= // minutes + reg_ch= // hours +*/ + if(timeonly) { + WriteOut("%2u:%02u\n",reg_ch,reg_cl); + } else { + WriteOut(MSG_Get("SHELL_CMD_TIME_NOW")); + WriteOut("%2u:%02u:%02u,%02u\n",reg_ch,reg_cl,reg_dh,reg_dl); + } +}; + void DOS_Shell::CMD_SUBST (char * args) { /* If more that one type can be substed think of something else * E.g. make basedir member dos_drive instead of localdrive