DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/dos/dos_devices.cpp
00001 /*
00002  *  Copyright (C) 2002-2020  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License along
00015  *  with this program; if not, write to the Free Software Foundation, Inc.,
00016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 
00020 #include <string.h>
00021 #include "dosbox.h"
00022 #include "callback.h"
00023 #include "regs.h"
00024 #include "mem.h"
00025 #include "bios.h"
00026 #include "dos_inc.h"
00027 #include "support.h"
00028 #include "parport.h"
00029 #include "drives.h" //Wildcmp
00030 /* Include all the devices */
00031 
00032 #include "dev_con.h"
00033 
00034 
00035 DOS_Device * Devices[DOS_DEVICES] = {NULL};
00036 extern int dos_clipboard_device_access;
00037 extern char * dos_clipboard_device_name;
00038 
00039 class device_NUL : public DOS_Device {
00040 public:
00041         device_NUL() { SetName("NUL"); };
00042         virtual bool Read(Bit8u * data,Bit16u * size) {
00043         (void)data; // UNUSED
00044                 *size = 0; //Return success and no data read. 
00045 //              LOG(LOG_IOCTL,LOG_NORMAL)("%s:READ",GetName());
00046                 return true;
00047         }
00048         virtual bool Write(const Bit8u * data,Bit16u * size) {
00049         (void)data; // UNUSED
00050         (void)size; // UNUSED
00051 //              LOG(LOG_IOCTL,LOG_NORMAL)("%s:WRITE",GetName());
00052                 return true;
00053         }
00054         virtual bool Seek(Bit32u * pos,Bit32u type) {
00055         (void)type;
00056         (void)pos;
00057 //              LOG(LOG_IOCTL,LOG_NORMAL)("%s:SEEK",GetName());
00058                 return true;
00059         }
00060         virtual bool Close() { return true; }
00061         virtual Bit16u GetInformation(void) { return 0x8084; }
00062         virtual bool ReadFromControlChannel(PhysPt bufptr,Bit16u size,Bit16u * retcode) { (void)bufptr; (void)size; (void)retcode; return false; }
00063         virtual bool WriteToControlChannel(PhysPt bufptr,Bit16u size,Bit16u * retcode) { (void)bufptr; (void)size; (void)retcode; return false; }
00064 };
00065 
00066 class device_PRN : public DOS_Device {
00067 public:
00068         device_PRN() {
00069                 SetName("PRN");
00070         }
00071         bool Read(Bit8u * data,Bit16u * size) {
00072         (void)data; // UNUSED
00073         (void)size; // UNUSED
00074                 DOS_SetError(DOSERR_ACCESS_DENIED);
00075                 return false;
00076         }
00077         bool Write(const Bit8u * data,Bit16u * size) {
00078                 for(int i = 0; i < 3; i++) {
00079                         // look up a parallel port
00080                         if(parallelPortObjects[i] != NULL) {
00081                                 // send the data
00082                                 for (Bit16u j=0; j<*size; j++) {
00083                                         if(!parallelPortObjects[i]->Putchar(data[j])) return false;
00084                                 }
00085                                 return true;
00086                         }
00087                 }
00088                 return false;
00089         }
00090         bool Seek(Bit32u * pos,Bit32u type) {
00091         (void)type; // UNUSED
00092                 *pos = 0;
00093                 return true;
00094         }
00095         Bit16u GetInformation(void) {
00096                 return 0x80A0;
00097         }
00098         bool Close() {
00099                 return false;
00100         }
00101 };
00102 
00103 #if defined(WIN32)
00104 bool lastwrite = false;
00105 Bit8u *clipAscii = NULL;
00106 Bit32u clipSize = 0, cPointer = 0, fPointer;
00107 
00108 void Unicode2Ascii(const Bit16u* unicode)
00109         {
00110         int memNeeded = WideCharToMultiByte(dos.loaded_codepage, WC_NO_BEST_FIT_CHARS, (LPCWSTR)unicode, -1, NULL, 0, "\x07", NULL);
00111         if (memNeeded <= 1)                                                                                                                             // Includes trailing null
00112                 return;
00113         if (!(clipAscii = (Bit8u *)malloc(memNeeded)))
00114                 return;
00115         // Untranslated characters will be set to 0x07 (BEL), and later stripped
00116         if (WideCharToMultiByte(dos.loaded_codepage, WC_NO_BEST_FIT_CHARS, (LPCWSTR)unicode, -1, (LPSTR)clipAscii, memNeeded, "\x07", NULL) != memNeeded)
00117                 {                                                                                                                                                       // Can't actually happen of course
00118                 free(clipAscii);
00119                 clipAscii = NULL;
00120                 return;
00121                 }
00122         memNeeded--;                                                                                                                                    // Don't include trailing null
00123         for (int i = 0; i < memNeeded; i++)
00124                 if (clipAscii[i] > 31 || clipAscii[i] == 9 || clipAscii[i] == 10 || clipAscii[i] == 13) // Space and up, or TAB, CR/LF allowed (others make no sense when pasting)
00125                         clipAscii[clipSize++] = clipAscii[i];
00126         return;                                                                                                                                                 // clipAscii dould be downsized, but of no real interest
00127         }       
00128 
00129 bool getClipboard()
00130         {
00131         if (clipAscii)
00132                 {
00133                 free(clipAscii);
00134                 clipAscii = NULL;
00135                 }
00136         clipSize = 0;
00137         if (OpenClipboard(NULL))
00138                 {
00139                 if (HANDLE cbText = GetClipboardData(CF_UNICODETEXT))
00140                         {
00141                         Bit16u *unicode = (Bit16u *)GlobalLock(cbText);
00142                         Unicode2Ascii(unicode);
00143                         GlobalUnlock(cbText);
00144                         }
00145                 CloseClipboard();
00146                 }
00147         return clipSize != 0;
00148         }
00149 
00150 Bit16u cpMap[256] = {
00151         0x0020, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2219, 0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
00152         0x25ba, 0x25c4, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8, 0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc,
00153         0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
00154         0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
00155         0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
00156         0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
00157         0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
00158         0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302,
00159         0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
00160         0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
00161         0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
00162         0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,         // 176 - 223 line/box drawing
00163         0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
00164         0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
00165         0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
00166         0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x0020
00167         };
00168 
00169 
00170 class device_CLIP : public DOS_Device {
00171 private:
00172         char    tmpAscii[20];
00173         char    tmpUnicode[20];
00174         std::string rawdata;                            // the raw data sent to CLIP$...
00175         virtual void CommitData() {
00176                 if (cPointer>0) {
00177                         if (!clipSize)
00178                                 getClipboard();
00179                         if (cPointer>clipSize)
00180                                 cPointer=clipSize;
00181                         if (clipSize) {
00182                                 if (rawdata.capacity() < 100000)
00183                                         rawdata.reserve(100000);
00184                                 std::string temp=std::string((char *)clipAscii).substr(0, cPointer);
00185                                 if (temp[temp.length()-1]!='\n') temp+="\n";
00186                                 rawdata.insert(0, temp);
00187                                 clipSize=0;
00188                         }
00189                         cPointer=0;
00190                 }
00191                 FILE* fh = fopen(tmpAscii, "wb");                       // Append or write to ASCII file
00192                 if (fh)
00193                         {
00194                         fwrite(rawdata.c_str(), rawdata.size(), 1, fh);
00195                         fclose(fh);
00196                         fh = fopen(tmpUnicode, "w+b");                  // The same for Unicode file (it's eventually read)
00197                         if (fh)
00198                                 {
00199                                 fprintf(fh, "\xff\xfe");                                                                                        // It's a Unicode text file
00200                                 for (Bit32u i = 0; i < rawdata.size(); i++)
00201                                         {
00202                                         Bit16u textChar =  (Bit8u)rawdata[i];
00203                                         switch (textChar)
00204                                                 {
00205                                         case 9:                                                                                                                         // Tab
00206                                         case 12:                                                                                                                        // Formfeed
00207                                                 fwrite(&textChar, 1, 2, fh);
00208                                                 break;
00209                                         case 10:                                                                                                                        // Linefeed (combination)
00210                                         case 13:
00211                                                 fwrite("\x0d\x00\x0a\x00", 1, 4, fh);
00212                                                 if (i < rawdata.size() -1 && textChar == 23-rawdata[i+1])
00213                                                         i++;
00214                                                 break;
00215                                         default:
00216                                                 if (textChar >= 32)                                                                                             // Forget about further control characters?
00217                                                         fwrite(cpMap+textChar, 1, 2, fh);
00218                                                 break;
00219                                                 }
00220                                         }
00221                                 }
00222                         }
00223                 if (!fh)
00224                         {
00225                         rawdata.clear();
00226                         return;
00227                         }
00228                 if (OpenClipboard(NULL))
00229                         {
00230                         if (EmptyClipboard())
00231                                 {
00232                                 int bytes = ftell(fh);
00233                                 HGLOBAL hCbData = GlobalAlloc(NULL, bytes);
00234                                 Bit8u* pChData = (Bit8u*)GlobalLock(hCbData);
00235                                 if (pChData)
00236                                         {
00237                                         fseek(fh, 2, SEEK_SET);                                                                                 // Skip Unicode signature
00238                                         fread(pChData, 1, bytes-2, fh);
00239                                         pChData[bytes-2] = 0;
00240                                         pChData[bytes-1] = 0;
00241                                         SetClipboardData(CF_UNICODETEXT, hCbData);
00242                                         GlobalUnlock(hCbData);
00243                                         }
00244                                 }
00245                         CloseClipboard();
00246                         }
00247                 fclose(fh);
00248                 remove(tmpAscii);
00249                 remove(tmpUnicode);
00250                 rawdata.clear();
00251                 return;
00252         }
00253 public:
00254         device_CLIP() {
00255                 SetName(*dos_clipboard_device_name?dos_clipboard_device_name:"CLIP$");
00256                 strcpy(tmpAscii, "#clip$.asc");
00257                 strcpy(tmpUnicode, "#clip$.txt");
00258         }
00259         virtual bool Read(Bit8u * data,Bit16u * size) {
00260                 if(control->SecureMode()||!(dos_clipboard_device_access==2||dos_clipboard_device_access==4)) {
00261                         *size = 0;
00262                         return true;
00263                 }
00264                 lastwrite=false;
00265                 if (!clipSize)                                                                                                                          // If no data, we have to read the Windows CLipboard (clipSize gets reset on device close)
00266                         {
00267                         getClipboard();
00268                         fPointer = 0;
00269                         }
00270                 if (fPointer >= clipSize)
00271                         *size = 0;
00272                 else if (fPointer+*size > clipSize)
00273                         *size = (Bit16u)(clipSize-fPointer);
00274                 if (*size > 0) {
00275                         memmove(data, clipAscii+fPointer, *size);
00276                         fPointer += *size;
00277                 }
00278                 return true;
00279         }
00280         virtual bool Write(const Bit8u * data,Bit16u * size) {
00281                 if(control->SecureMode()||!(dos_clipboard_device_access==3||dos_clipboard_device_access==4)) {
00282                         DOS_SetError(DOSERR_ACCESS_DENIED);
00283                         return false;
00284                 }
00285                 lastwrite=true;
00286         const Bit8u* datasrc = (Bit8u*)data;
00287                 Bit8u * datadst = (Bit8u *) data;
00288 
00289                 int numSpaces = 0;
00290                 for (Bit16u idx = *size; idx; idx--)
00291                         {
00292                         if (*datasrc == ' ')                                                                                                            // Put spaces on hold
00293                                 numSpaces++;
00294                         else
00295                                 {
00296                                 if (numSpaces && *datasrc != 0x0a && *datasrc != 0x0d)                                  // Spaces on hold and not end of line
00297                                         while (numSpaces--)
00298                                                 *(datadst++) = ' ';
00299                                 numSpaces = 0;
00300                                 *(datadst++) = *datasrc;
00301                                 }
00302                         datasrc++;
00303                         }
00304                 while (numSpaces--)
00305                         *(datadst++) = ' ';
00306                 if (Bit16u newsize = (Bit16u)(datadst - data))                                                                  // If data
00307                         {
00308                         if (rawdata.capacity() < 100000)                                                                                        // Prevent repetive size allocations
00309                                 rawdata.reserve(100000);
00310                         rawdata.append((char *)data, newsize);
00311                         }
00312                 return true;
00313         }
00314         virtual bool Seek(Bit32u * pos,Bit32u type) {
00315                 if(control->SecureMode()||!(dos_clipboard_device_access==2||dos_clipboard_device_access==4)) {
00316                         *pos = 0;
00317                         return true;
00318                 }
00319                 lastwrite=false;
00320                 if (clipSize == 0)                                                                                                                              // No data yet
00321                         {
00322                         getClipboard();
00323                         fPointer =0;
00324                         }
00325                 Bit32s newPos;
00326                 switch (type)
00327                         {
00328                 case 0:                                                                                                                                                 // Start of file
00329                         newPos = *pos;
00330                         break;
00331                 case 1:                                                                                                                                                 // Current file position
00332                         newPos = fPointer+*pos;
00333                         break;
00334                 case 2:                                                                                                                                                 // End of file
00335                         newPos = clipSize+*pos;
00336                         break;
00337                 default:
00338                         {
00339                         DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
00340                         return false;
00341                         }
00342                         }
00343                 if (newPos > (Bit32s)clipSize)                                                                                                  // Different from "real" Files
00344                         newPos = clipSize;
00345                 else if (newPos < 0)
00346                         newPos = 0;
00347                 *pos = newPos;
00348                 cPointer = newPos;
00349                 fPointer = newPos;
00350                 return true;
00351         }
00352         virtual bool Close() {
00353                 if(control->SecureMode()||dos_clipboard_device_access<2)
00354                         return false;
00355                 clipSize = 0;                                                                                                                                   // Reset clipboard read
00356                 rawdata.erase(rawdata.find_last_not_of(" \n\r\t")+1);                                                   // Remove trailing white space
00357                 if (!rawdata.size()&&!lastwrite)                                                                                                // Nothing captured/to do
00358                         return false;
00359                 lastwrite=false;
00360                 int len = (int)rawdata.size();
00361                 if (len > 2 && rawdata[len-3] == 0x0c && rawdata[len-2] == 27 && rawdata[len-1] == 64)  // <ESC>@ after last FF?
00362                         rawdata.erase(len-2, 2);
00363                 CommitData();
00364                 return true;
00365         }
00366         Bit16u GetInformation(void) {
00367                 return 0x80E0;
00368         }
00369 };
00370 #endif
00371 
00372 bool DOS_Device::Read(Bit8u * data,Bit16u * size) {
00373         return Devices[devnum]->Read(data,size);
00374 }
00375 
00376 bool DOS_Device::Write(const Bit8u * data,Bit16u * size) {
00377         return Devices[devnum]->Write(data,size);
00378 }
00379 
00380 bool DOS_Device::Seek(Bit32u * pos,Bit32u type) {
00381         return Devices[devnum]->Seek(pos,type);
00382 }
00383 
00384 bool DOS_Device::Close() {
00385         return Devices[devnum]->Close();
00386 }
00387 
00388 Bit16u DOS_Device::GetInformation(void) { 
00389         return Devices[devnum]->GetInformation();
00390 }
00391 
00392 bool DOS_Device::ReadFromControlChannel(PhysPt bufptr,Bit16u size,Bit16u * retcode) { 
00393         return Devices[devnum]->ReadFromControlChannel(bufptr,size,retcode);
00394 }
00395 
00396 bool DOS_Device::WriteToControlChannel(PhysPt bufptr,Bit16u size,Bit16u * retcode) { 
00397         return Devices[devnum]->WriteToControlChannel(bufptr,size,retcode);
00398 }
00399 
00400 DOS_File::DOS_File(const DOS_File& orig) : flags(orig.flags), open(orig.open), attr(orig.attr),
00401 time(orig.time), date(orig.date), refCtr(orig.refCtr), hdrive(orig.hdrive) {
00402         if(orig.name) {
00403                 name=new char [strlen(orig.name) + 1];strcpy(name,orig.name);
00404         }
00405 }
00406 
00407 DOS_File& DOS_File::operator= (const DOS_File& orig) {
00408     if (this != &orig) {
00409         flags = orig.flags;
00410         time = orig.time;
00411         date = orig.date;
00412         attr = orig.attr;
00413         refCtr = orig.refCtr;
00414         open = orig.open;
00415         hdrive = orig.hdrive;
00416         drive = orig.drive;
00417         newtime = orig.newtime;
00418         if (name) {
00419             delete[] name; name = 0;
00420         }
00421         if (orig.name) {
00422             name = new char[strlen(orig.name) + 1]; strcpy(name, orig.name);
00423         }
00424     }
00425     return *this;
00426 }
00427 
00428 Bit8u DOS_FindDevice(char const * name) {
00429         /* should only check for the names before the dot and spacepadded */
00430         char fullname[DOS_PATHLENGTH];Bit8u drive;
00431 //      if(!name || !(*name)) return DOS_DEVICES; //important, but makename does it
00432         if (!DOS_MakeName(name,fullname,&drive)) return DOS_DEVICES;
00433 
00434         char* name_part = strrchr(fullname,'\\');
00435         if(name_part) {
00436                 *name_part++ = 0;
00437                 //Check validity of leading directory.
00438                 if(!Drives[drive]->TestDir(fullname)) return DOS_DEVICES;
00439         } else name_part = fullname;
00440    
00441         char* dot = strrchr(name_part,'.');
00442         if(dot) *dot = 0; //no ext checking
00443 
00444         static char com[5] = { 'C','O','M','1',0 };
00445         static char lpt[5] = { 'L','P','T','1',0 };
00446         // AUX is alias for COM1 and PRN for LPT1
00447         // A bit of a hack. (but less then before).
00448         // no need for casecmp as makename returns uppercase
00449         if (strcmp(name_part, "AUX") == 0) name_part = com;
00450         if (strcmp(name_part, "PRN") == 0) name_part = lpt;
00451 
00452         /* loop through devices */
00453         for(Bit8u index = 0;index < DOS_DEVICES;index++) {
00454                 if (Devices[index]) {
00455                         if (WildFileCmp(name_part,Devices[index]->name)) return index;
00456                 }
00457         }
00458         return DOS_DEVICES;
00459 }
00460 
00461 
00462 void DOS_AddDevice(DOS_Device * adddev) {
00463 //Caller creates the device. We store a pointer to it
00464 //TODO Give the Device a real handler in low memory that responds to calls
00465         if (adddev == NULL) E_Exit("DOS_AddDevice with null ptr");
00466         for(Bitu i = 0; i < DOS_DEVICES;i++) {
00467                 if (Devices[i] == NULL){
00468 //                      LOG_MSG("DOS_AddDevice %s (%p)\n",adddev->name,(void*)adddev);
00469                         Devices[i] = adddev;
00470                         Devices[i]->SetDeviceNumber(i);
00471                         return;
00472                 }
00473         }
00474         E_Exit("DOS:Too many devices added");
00475 }
00476 
00477 void DOS_DelDevice(DOS_Device * dev) {
00478 // We will destroy the device if we find it in our list.
00479 // TODO:The file table is not checked to see the device is opened somewhere!
00480         if (dev == NULL) return E_Exit("DOS_DelDevice with null ptr");
00481         for (Bitu i = 0; i <DOS_DEVICES;i++) {
00482                 if (Devices[i] == dev) { /* NTS: The mainline code deleted by matching names??? Why? */
00483 //                      LOG_MSG("DOS_DelDevice %s (%p)\n",dev->name,(void*)dev);
00484                         delete Devices[i];
00485                         Devices[i] = 0;
00486                         return;
00487                 }
00488         }
00489 
00490         /* hm. unfortunately, too much code in DOSBox assumes that we delete the object.
00491          * prior to this fix, failure to delete caused a memory leak */
00492         LOG_MSG("WARNING: DOS_DelDevice() failed to match device object '%s' (%p). Deleting anyway\n",dev->name,(void*)dev);
00493         delete dev;
00494 }
00495 
00496 void DOS_ShutdownDevices(void) {
00497         for (Bitu i=0;i < DOS_DEVICES;i++) {
00498                 if (Devices[i] != NULL) {
00499 //                      LOG_MSG("DOS: Shutting down device %s (%p)\n",Devices[i]->name,(void*)Devices[i]);
00500                         delete Devices[i];
00501                         Devices[i] = NULL;
00502                 }
00503         }
00504 
00505     /* NTS: CON counts as a device */
00506     if (IS_PC98_ARCH) update_pc98_function_row(0);
00507 }
00508 
00509 // INT 29h emulation needs to keep track of CON
00510 device_CON *DOS_CON = NULL;
00511 
00512 bool ANSI_SYS_installed() {
00513     if (DOS_CON != NULL)
00514         return DOS_CON->ANSI_SYS_installed();
00515 
00516     return false;
00517 }
00518 
00519 void DOS_SetupDevices(void) {
00520         DOS_Device * newdev;
00521         DOS_CON=new device_CON(); newdev=DOS_CON;
00522         DOS_AddDevice(newdev);
00523         DOS_Device * newdev2;
00524         newdev2=new device_NUL();
00525         DOS_AddDevice(newdev2);
00526         DOS_Device * newdev3;
00527         newdev3=new device_PRN();
00528         DOS_AddDevice(newdev3);
00529 #if defined(WIN32)
00530         if (dos_clipboard_device_access) {
00531                 DOS_Device * newdev4;
00532                 newdev4=new device_CLIP();
00533                 DOS_AddDevice(newdev4);
00534         }
00535 #endif
00536 }
00537 
00538 /* PC-98 INT DC CL=0x10 AH=0x00 DL=cjar */
00539 void PC98_INTDC_WriteChar(unsigned char b) {
00540     if (DOS_CON != NULL) {
00541         Bit16u sz = 1;
00542 
00543         DOS_CON->Write(&b,&sz);
00544     }
00545 }
00546 
00547 void INTDC_CL10h_AH03h(Bit16u raw) {
00548     if (DOS_CON != NULL)
00549         DOS_CON->INTDC_CL10h_AH03h(raw);
00550 }
00551 
00552 void INTDC_CL10h_AH04h(void) {
00553     if (DOS_CON != NULL)
00554         DOS_CON->INTDC_CL10h_AH04h();
00555 }
00556 
00557 void INTDC_CL10h_AH05h(void) {
00558     if (DOS_CON != NULL)
00559         DOS_CON->INTDC_CL10h_AH05h();
00560 }
00561 
00562 void INTDC_CL10h_AH06h(Bit16u count) {
00563     if (DOS_CON != NULL)
00564         DOS_CON->INTDC_CL10h_AH06h(count);
00565 }
00566 
00567 void INTDC_CL10h_AH07h(Bit16u count) {
00568     if (DOS_CON != NULL)
00569         DOS_CON->INTDC_CL10h_AH07h(count);
00570 }
00571 
00572 void INTDC_CL10h_AH08h(Bit16u count) {
00573     if (DOS_CON != NULL)
00574         DOS_CON->INTDC_CL10h_AH08h(count);
00575 }
00576 
00577 void INTDC_CL10h_AH09h(Bit16u count) {
00578     if (DOS_CON != NULL)
00579         DOS_CON->INTDC_CL10h_AH09h(count);
00580 }
00581 
00582 Bitu INT29_HANDLER(void) {
00583     if (DOS_CON != NULL) {
00584         unsigned char b = reg_al;
00585         Bit16u sz = 1;
00586 
00587         DOS_CON->Write(&b,&sz);
00588     }
00589 
00590     return CBRET_NONE;
00591 }
00592 
00593 extern bool dos_kernel_disabled;
00594 
00595 // save state support
00596 void POD_Save_DOS_Devices( std::ostream& stream )
00597 {
00598         if (!dos_kernel_disabled) {
00599                 if( strcmp( Devices[2]->GetName(), "CON" ) == 0 )
00600                         Devices[2]->SaveState(stream);
00601         }
00602 }
00603 
00604 void POD_Load_DOS_Devices( std::istream& stream )
00605 {
00606         if (!dos_kernel_disabled) {
00607                 if( strcmp( Devices[2]->GetName(), "CON" ) == 0 )
00608                         Devices[2]->LoadState(stream, false);
00609         }
00610 }