diff --git a/README b/README index 15ff040..93de2b8 100644 --- a/README +++ b/README @@ -220,11 +220,11 @@ CD-ROM: My CD-ROM doesn't work. To enable SDL-support (does not include low-level CD access!): - mount d f:\ -t cdrom -usecd 0 -noioctl To enable ioctl access using digital audio extraction for CD audio - (windows-only, useful for Vista): + (Windows-only, useful for Vista): - mount d f:\ -t cdrom -ioctl_dx - To enable ioctl access using MCI for CD audio (windows-only): + To enable ioctl access using MCI for CD audio (Windows-only): - mount d f:\ -t cdrom -ioctl_mci - To force ioctl-only access (windows-only): + To force ioctl-only access (Windows-only): - mount d f:\ -t cdrom -ioctl_dio To enable low-level aspi-support (win98 with aspi-layer installed): - mount d f:\ -t cdrom -aspi @@ -265,7 +265,7 @@ SOUND: There is no sound. Be sure that the sound is correctly configured in the game. This might be done during the installation or with a setup/setsound utility that accompanies the game. First see if an autodetection option is provided. If - there is none try selecting Soundblaster or Soundblaster 16 with the default + there is none try selecting SoundBlaster or SoundBlaster 16 with the default settings being "address=220 irq=7 dma=1" (sometimes highdma=5). You might also want to select Sound Canvas/SCC/MPU-401/General MIDI/Wave Blaster at "address=330 IRQ=2" as music device. @@ -275,8 +275,8 @@ SOUND: There is no sound. configuration and use some lower fixed cycles value (like cycles=2000). Also assure that your host operating sound does provide sound. In certain cases it might be useful to use a different emulated sound device - like a soundblaster pro (sbtype=sbpro1 in the DOSBox configuration file) or - the gravis ultrasound (gus=true). + like a SoundBlaster Pro (sbtype=sbpro1 in the DOSBox configuration file) or + the Gravis Ultrasound (gus=true). SOUND: What sound hardware does DOSBox presently emulate? @@ -286,21 +286,21 @@ SOUND: What sound hardware does DOSBox presently emulate? digital sound output through the internal speaker. - Creative CMS/Gameblaster The is the first card released by Creative Labs(R). The default - configuration places it on address 220. It is disabled as default. + configuration places it on address 220. It is disabled by default. - Tandy 3 voice The emulation of this sound hardware is complete with the exception of the noise channel. The noise channel is not very well documented and as such is only a best guess as to the sound's accuracy. It is disabled as default. - Tandy DAC - Some games may require turning off sound blaster emulation (sbtype=none) - for better tandy DAC sound support. Don't forget to set the sbtype back to - sb16 if you don't use tandy sound. + Some games may require turning off SoundBlaster emulation (sbtype=none) + for better Tandy DAC sound support. Don't forget to set the sbtype back to + sb16 if you don't use Tandy sound. - Adlib This emulation is almost perfect and includes the Adlib's ability to almost play digitized sound. Placed at address 220 (also on 388). - SoundBlaster 16 / SoundBlaster Pro I & II / SoundBlaster I & II - By default DOSBox provides Soundblaster 16 level 16-bit stereo sound. + By default DOSBox provides SoundBlaster 16 level 16-bit stereo sound. You can select a different SoundBlaster version in the configuration of DOSBox. AWE32 music is not emulated as you can use MPU-401 instead (see below). @@ -311,14 +311,14 @@ SOUND: What sound hardware does DOSBox presently emulate? The emulation of this hardware is nearly complete, though the MIDI capabilities have been left out, since an MPU-401 has been emulated in other code. For Gravis music you also have to install Gravis drivers - inside DOSBox. It is disabled as default. + inside DOSBox. It is disabled by default. - MPU-401 A MIDI passthrough interface is also emulated. This method of sound output will only work when used with external device/emulator. - Every Windows XP/Vista/7 and MAC OS has got a default emulator compatible - with: Sound Canvas/SCC/General Standard/General MIDI/Wave Blaster. - A different device/emulator is needed for Roland LAPC/CM-32L/MT-32 - compatibility. + Every Windows XP/Vista/7 and Mac OS X has got a default emulator + compatible with: Sound Canvas/SCC/General Standard/General MIDI/Wave + Blaster. A different device/emulator is needed for + Roland LAPC/CM-32L/MT-32 compatibility. SOUND: The sound stutters or sounds stretched/weird. @@ -387,7 +387,7 @@ CRASH: The game/application does not run at all/crashes! Look at Section 11: "Troubleshooting". -CRASH: DOSBox crashes on startup!. +CRASH: DOSBox crashes on startup! Look at Section 11: "Troubleshooting". @@ -429,7 +429,7 @@ See Section 13: "The configuration (options) file". To be able to use Command Line Parameters: (Windows) open cmd.exe or command.com or edit the shortcut to dosbox.exe (Linux) use console -(MAC OS X) start terminal.app and navigate to: +(Mac OS X) start terminal.app and navigate to: /applications/dosbox.app/contents/macos/dosbox The options are valid for all operating systems unless noted in the option @@ -482,15 +482,15 @@ dosbox -erasemapper -machine machinetype Setup DOSBox to emulate a specific type of machine. Valid choices are: hercules, cga, ega, pcjr, tandy, svga_s3 (default) as well as - the additional svga chipsets listed in the DOSBox configuration file. - svga_s3 enables vesa emulation as well. - For some special vga effects the machinetype vgaonly can be used, - note that this disables svga capabilities and might be slower due to the + the additional SVGA chipsets listed in the DOSBox configuration file. + svga_s3 enables VESA emulation as well. + For some special VGA effects the machinetype vgaonly can be used, + note that this disables SVGA capabilities and might be slower due to the higher emulation precision. The machinetype affects the video card and the available sound cards. -noconsole (Windows Only) - Start DOSBox without showing DOSBox Status Window (console). + Start DOSBox without showing the DOSBox status window (console). Output will be redirected to stdout.txt and stderr.txt -startmapper @@ -630,7 +630,7 @@ MOUNT -u "Emulated Drive letter" Forces use of the SDL CD-ROM layer. Valid on all systems. -usecd number - Valid on all systems, under windows the -noioctl switch has to be + Valid on all systems, under Windows the -noioctl switch has to be present to make use of the -usecd switch. Enables to select the drive that should be used by SDL. Use this if the wrong or no CD-ROM drive is mounted while using the SDL CD-ROM @@ -882,10 +882,19 @@ LOADFIX -f loadfix -f -RESCAN +RESCAN [Drive:] [-All] Make DOSBox reread the directory structure. Useful if you changed something on a mounted drive outside of DOSBox. (CTRL - F4 does this as well!) + + Drive: + Drive to refresh. + -All + Refresh all drives. + + if both a Drive: and -All are missing, then the current drive will be + refreshed. + MIXER Makes DOSBox display its current volume settings. @@ -1170,8 +1179,8 @@ CTRL-F11 Slow down emulation (Decrease DOSBox Cycles). CTRL-F12 Speed up emulation (Increase DOSBox Cycles)*. ALT-F12 Unlock speed (turbo button/fast forward)**. CTRL-ALT-HOME Restart DOSBox. -F11, ALT-F11 (machine=cga) change tint in NTSC output modes*** -F11 (machine=hercules) cycle through amber, green, white colouring*** +F11, ALT-F11 (machine=cga) change tint in NTSC output modes***. +F11 (machine=hercules) cycle through amber, green, white colouring***. *NOTE: Once you increase your DOSBox cycles beyond your computer CPU resources, it will produce the same effect as slowing down the emulation. @@ -1187,13 +1196,14 @@ F11 (machine=hercules) cycle through amber, green, white colouring*** These are the default keybindings. They can be changed in the keymapper (see Section 7: "KeyMapper"). -In MAC OS you can try using cmd(applekey) together with Ctrl if the key doesn't -work eg. cmd-ctrl-F1, but some keys may still need remapping (in Linux too). +In Mac OS X you can try using cmd(applekey) together with Ctrl (and/or ) Fn, +if the key doesn't work i.e. fn-cmd-ctrl-F1, but some keys may still need +remapping (in Linux too). Saved/recorded files can be found in: (Windows) "Start/WinLogo Menu"->"All Programs"->DOSBox-0.74->Extras (Linux) ~/.dosbox/capture - (MAC OS X) "~/Library/Preferences/capture" + (Mac OS X) "~/Library/Preferences/capture" This can be changed in the DOSBox configuration file. @@ -1231,7 +1241,7 @@ connected, or with a different joystick setting, your new setting will not work properly, or not work at all, until you reset DOSBox's mapperfile. If controller is working properly outside DOSBox, but doesn't calibrate properly -inside DOSBox, try different 'timed' setting in DOSBox's configuration file. +inside DOSBox, try a different 'timed' setting in DOSBox's configuration file. @@ -1239,8 +1249,8 @@ inside DOSBox, try different 'timed' setting in DOSBox's configuration file. 7. KeyMapper: ============= -You start the DOSBox mapper either with CTRL-F1 (see Section 5: "Special Keys") -or -startmapper (see Section 3: "Command Line Parameters"). +Start the DOSBox mapper either with CTRL-F1 (see Section 5: "Special Keys") or +-startmapper (see Section 3: "Command Line Parameters"). You are presented with a virtual keyboard and a virtual joystick. These virtual devices correspond to the keys and events DOSBox will @@ -1296,7 +1306,7 @@ Q3. If you try it out in DOSBox, you will notice that pressing X makes ZX mapped key X. Click "Del". -Examples about remapping the joystick: +Examples of remapping the joystick: You have a joystick attached, it is working fine under DOSBox and you want to play some keyboard-only game with the joystick (it is assumed that the game is controlled by the arrows on the keyboard): @@ -1318,7 +1328,7 @@ Examples about remapping the joystick: If you want to remap anything to your d-pad/hat you will have to change 'joysticktype=auto' to 'joysticktype=fcs' in configuration file. Maybe this - will be improved in the next dosbox version. + will be improved in the next DOSBox version. If you change the default mapping, you can save your changes by clicking on @@ -1333,12 +1343,12 @@ your mapperfile, if it is present in the DOSBox configuration file. =================== To switch to a different keyboard layout, either the entry "keyboardlayout" -in the [dos] section of the DOSBox configuration file can be used, or the -internal DOSBox program keyb.com (Section 4: "Internal Programs"). Both accept +in the [dos] section of the DOSBox configuration file or the internal DOSBox +program keyb.com (Section 4: "Internal Programs") can be used. Both accept DOS conforming language codes (see below), but only by using keyb.com a custom codepage can be specified. -The default keyboardlayout=auto currently works under windows only. The language +The default keyboardlayout=auto currently works under Windows only. The language is chosen according to the OS language, but the keyboard layout is not detected. Layout switching @@ -1411,7 +1421,7 @@ of the nullmodem connection. These are all parameters: * port: - TCP port number. Default: 23 * rxdelay: - how long (milliseconds) to delay received data if the interface is not ready. Increase this value if you encounter - overrun errors in the DOSBox Status Window. Default: 100 + overrun errors in the DOSBox status window. Default: 100 * txdelay: - how long to gather data before sending a packet. Default: 12 (reduces Network overhead) * server: - This nullmodem will be a client connecting to the specified @@ -1517,7 +1527,7 @@ Example: ==================== General tip: - Check messages in DOSBox Status Window. See Section 12: "DOSBox Status Window". + Check messages in the DOSBox status window. See Section 12: "DOSBox Status Window". DOSBox crashes right after starting it: - use different values for the output= entry in your DOSBox @@ -1563,14 +1573,14 @@ The game exits to the DOSBox prompt with some error message: 12. DOSBox Status Window: ========================= -DOSBox's Staus window contains many useful information about your currant -configuration, your actions in DOSBox, errors that happened and more. -Whenever you have any problem with DOSBox check these messages. +DOSBox's status window contains useful information about your current +configuration, your actions in DOSBox, errors which occurred and more. +Check these messages in case you encounter any problems with DOSBox. -To start DOSBox Status Window: - (Windows) Status Window is being started together with main DOSBox window. - (Linux) You may have to start DOSBox from a console to see Status Window. - (MAC OS X) Right click on DOSBox.app, choose "Show Package Contents"-> +To display the DOSBox status window: + (Windows) The status window is being started together with main DOSBox window. + (Linux) You may have to start DOSBox from a console to see the status window. + (Mac OS X) Right click on DOSBox.app, choose "Show Package Contents"-> ->enter "Contents"->enter "MacOS"->run "DOSBox" @@ -1583,7 +1593,7 @@ The configuration file is automatically created the first time you run DOSBox. The file can be found in: (Windows) "Start/WinLogo Menu"->"All Programs"->DOSBox-0.74->Options (Linux) ~/.dosbox/dosbox-0.74.conf - (MAC OS X) "~/Library/Preferences/DOSBox 0.74 Preferences" + (Mac OS X) "~/Library/Preferences/DOSBox 0.74 Preferences" The file is divided into several sections. Each section starts with a [section name] line. The settings are the property=value lines where value can be altered to customize DOSBox. diff --git a/docs/dosbox.1 b/docs/dosbox.1 index cffcb38..c15a1ce 100644 --- a/docs/dosbox.1 +++ b/docs/dosbox.1 @@ -205,7 +205,7 @@ which is located on the local filesystem. Not a mounted drive in .RS .TP .B \-securemode -.RB Switches dosbox " to a more secure mode. In this mode the" +.RB "Switches " dosbox " to a more secure mode. In this mode the" .RI "internal commands " MOUNT ", " IMGMOUNT " and " BOOT " won\'t work." It\'s not possible either to create a new configfile or languagefile in this mode. @@ -216,7 +216,7 @@ either to create a new configfile or languagefile in this mode. The configuration file controls various settings of .BR dosbox ": The amount of emulated memory," the emulated soundcards and many -.RI "more things. It futher allows acces to " AUTOEXEC.BAT . +.RI "more things. It further allows access to " AUTOEXEC.BAT . .LP The language file controls all visible output of the internal commands and the internal dos. @@ -242,11 +242,21 @@ The amount of memory to eat up (in kb). Example \-32, \-64 or \-128 Frees all memory eaten up by loadfix. .RE .TP -.B RESCAN +.B RESCAN [\-All] [Drive:] .LP .RB "Make " dosbox " reread the directory structure. Useful if you changed .RB "something on a mounted drive outside " dosbox ".(CTRL\-F4 does" this as well!) +.RS +.TP +.B \-All +.R Reread directory structure for all drives. +.TP +.B Drive: +.RB "Reread directory structure for drive " Drive: +.RE +.LP +.RB "If both " \-All " and " Drive: " are missing, then the current drive is used. .TP .B IMGMOUNT .LP @@ -335,7 +345,7 @@ gets saved/recorded ! capacity, it will produce the same effect as slowing down the emulation. This maximum will vary from computer to computer, there is no standard. .SH "SYSTEM REQUIREMENTS" -Fast machine. My guess would be pentium\-2 400+ to get decent emulation +Fast machine. My guess would be Pentium\-2 400+ to get decent emulation of games written for an 286 machine. For protected mode games a 1 Ghz machine is recommended and don't expect them to run fast though!! Be sure to read the next section on how to speed diff --git a/include/bios_disk.h b/include/bios_disk.h index b43a79f..f41cd78 100644 --- a/include/bios_disk.h +++ b/include/bios_disk.h @@ -69,6 +69,7 @@ public: }; void updateDPT(void); +void incrementFDD(void); #define MAX_HDD_IMAGES 2 diff --git a/include/callback.h b/include/callback.h index f37395b..2ed9d88 100644 --- a/include/callback.h +++ b/include/callback.h @@ -30,7 +30,7 @@ extern CallBack_Handler CallBack_Handlers[]; enum { CB_RETN,CB_RETF,CB_RETF8,CB_IRET,CB_IRETD,CB_IRET_STI,CB_IRET_EOI_PIC1, CB_IRQ0,CB_IRQ1,CB_IRQ9,CB_IRQ12,CB_IRQ12_RET,CB_IRQ6_PCJR,CB_MOUSE, CB_INT29,CB_INT16,CB_HOOKABLE,CB_TDE_IRET,CB_IPXESR,CB_IPXESR_RET, - CB_INT21 }; + CB_INT21,CB_INT13 }; #define CB_MAX 128 #define CB_SIZE 32 diff --git a/include/pci_bus.h b/include/pci_bus.h index 470114f..adec2d9 100644 --- a/include/pci_bus.h +++ b/include/pci_bus.h @@ -61,16 +61,17 @@ public: PCI_Device* GetSubdevice(Bits subfct); Bit16u NumSubdevices(void) { - if (num_subdevices>PCI_MAX_PCIFUNCTIONS-1) return PCI_MAX_PCIFUNCTIONS-1; - return num_subdevices; + if (num_subdevices>PCI_MAX_PCIFUNCTIONS-1) return (Bit16u)(PCI_MAX_PCIFUNCTIONS-1); + return (Bit16u)num_subdevices; } Bits GetNextSubdeviceNumber(void) { if (num_subdevices>=PCI_MAX_PCIFUNCTIONS-1) return -1; - return num_subdevices+1; + return (Bits)num_subdevices+1; } virtual Bits ParseReadRegister(Bit8u regnum)=0; + virtual bool OverrideReadRegister(Bit8u regnum, Bit8u* rval, Bit8u* rval_mask)=0; virtual Bits ParseWriteRegister(Bit8u regnum,Bit8u value)=0; virtual bool InitializeRegisters(Bit8u registers[256])=0; diff --git a/include/programs.h b/include/programs.h index 455d546..0b85a86 100644 --- a/include/programs.h +++ b/include/programs.h @@ -50,6 +50,7 @@ public: bool FindCommand(unsigned int which,std::string & value); bool FindStringBegin(char const * const begin,std::string & value, bool remove=false); bool FindStringRemain(char const * const name,std::string & value); + bool FindStringRemainBegin(char const * const name,std::string & value); bool GetStringRemain(std::string & value); int GetParameterFromList(const char* const params[], std::vector & output); void FillVector(std::vector & vector); diff --git a/include/vga.h b/include/vga.h index 6359675..82155e7 100644 --- a/include/vga.h +++ b/include/vga.h @@ -166,6 +166,7 @@ typedef struct { } cursor; Drawmode mode; bool vret_triggered; + bool vga_override; } VGA_Draw; typedef struct { @@ -448,6 +449,8 @@ void VGA_SetCGA4Table(Bit8u val0,Bit8u val1,Bit8u val2,Bit8u val3); void VGA_ActivateHardwareCursor(void); void VGA_KillDrawing(void); +void VGA_SetOverride(bool vga_override); + extern VGA_Type vga; /* Support for modular SVGA implementation */ diff --git a/src/cpu/callback.cpp b/src/cpu/callback.cpp index c0475b1..53cc403 100644 --- a/src/cpu/callback.cpp +++ b/src/cpu/callback.cpp @@ -433,7 +433,18 @@ Bitu CALLBACK_SetupExtra(Bitu callback, Bitu type, PhysPt physAddress, bool use_ phys_writeb(physAddress+0x09,(Bit8u)0x59); // pop cx phys_writeb(physAddress+0x0A,(Bit8u)0xCF); //An IRET Instruction return (use_cb?15:11); - + case CB_INT13: + phys_writeb(physAddress+0x00,(Bit8u)0xFB); //STI + if (use_cb) { + phys_writeb(physAddress+0x01,(Bit8u)0xFE); //GRP 4 + phys_writeb(physAddress+0x02,(Bit8u)0x38); //Extra Callback instruction + phys_writew(physAddress+0x03,(Bit16u)callback); //The immediate word + physAddress+=4; + } + phys_writeb(physAddress+0x01,(Bit8u)0xCF); //An IRET Instruction + phys_writew(physAddress+0x02,(Bit16u)0x0ECD); // int 0e + phys_writeb(physAddress+0x04,(Bit8u)0xCF); //An IRET Instruction + return (use_cb?9:5); default: E_Exit("CALLBACK:Setup:Illegal type %d",type); } diff --git a/src/cpu/core_dyn_x86.cpp b/src/cpu/core_dyn_x86.cpp index 656a749..b793e5c 100644 --- a/src/cpu/core_dyn_x86.cpp +++ b/src/cpu/core_dyn_x86.cpp @@ -247,8 +247,8 @@ static void dyn_restoreregister(DynReg * src_reg, DynReg * dst_reg) { { \ __asm__ volatile ( \ "fnsave %0 \n" \ + : "=m" (dyn_dh_fpu.state[0]) \ : \ - : "m" (dyn_dh_fpu.state[0]) \ : "memory" \ ); \ dyn_dh_fpu.state_used=false; \ @@ -303,7 +303,10 @@ run_block: } #endif if (!GETFLAG(TF)) { - if (GETFLAG(IF) && PIC_IRQCheck) return CBRET_NONE; + if (GETFLAG(IF) && PIC_IRQCheck) { + if (dyn_dh_fpu.state_used) DH_FPU_SAVE_REINIT + return CBRET_NONE; + } goto restart_core; } cpudecoder=CPU_Core_Dyn_X86_Trap_Run; @@ -450,8 +453,8 @@ void CPU_Core_Dyn_X86_Init(void) { "finit \n" "fsave %0 \n" "fstcw %1 \n" + : "=m" (dyn_dh_fpu.state[0]), "=m" (dyn_dh_fpu.host_cw) : - : "m" (dyn_dh_fpu.state[0]), "m" (dyn_dh_fpu.host_cw) : "memory" ); #endif @@ -468,8 +471,62 @@ void CPU_Core_Dyn_X86_Cache_Close(void) { cache_close(); } +void CPU_Core_Dyn_X86_Cache_Reset(void) { + cache_reset(); +} + void CPU_Core_Dyn_X86_SetFPUMode(bool dh_fpu) { dyn_dh_fpu.dh_fpu_enabled=dh_fpu; } +Bit32u fpu_state[32]; + +void CPU_Core_Dyn_X86_SaveDHFPUState(void) { + if (dyn_dh_fpu.dh_fpu_enabled) { + if (dyn_dh_fpu.state_used!=0) { +#if defined (_MSC_VER) + __asm { + __asm fsave fpu_state[0] + __asm finit + } +#else + __asm__ volatile ( + "fsave %0 \n" + "finit \n" + : "=m" (fpu_state[0]) + : + : "memory" + ); +#endif + } + } +} + +void CPU_Core_Dyn_X86_RestoreDHFPUState(void) { + if (dyn_dh_fpu.dh_fpu_enabled) { + if (dyn_dh_fpu.state_used!=0) { +#if defined (_MSC_VER) + __asm { + __asm frstor fpu_state[0] + } +#else + __asm__ volatile ( + "frstor %0 \n" + : + : "m" (fpu_state[0]) + : + ); +#endif + } + } +} + +#else + +void CPU_Core_Dyn_X86_SaveDHFPUState(void) { +} + +void CPU_Core_Dyn_X86_RestoreDHFPUState(void) { +} + #endif diff --git a/src/cpu/core_dyn_x86/cache.h b/src/cpu/core_dyn_x86/cache.h index fe5aeaa..81b11f0 100644 --- a/src/cpu/core_dyn_x86/cache.h +++ b/src/cpu/core_dyn_x86/cache.h @@ -569,3 +569,75 @@ static void cache_close(void) { cache_code_link_blocks = NULL; cache_initialized = false; */ } + +static void cache_reset(void) { + if (cache_initialized) { + for (;;) { + if (cache.used_pages) { + CodePageHandler * cpage=cache.used_pages; + CodePageHandler * npage=cache.used_pages->next; + cpage->ClearRelease(); + delete cpage; + cache.used_pages=npage; + } else break; + } + + if (cache_blocks == NULL) { + cache_blocks=(CacheBlock*)malloc(CACHE_BLOCKS*sizeof(CacheBlock)); + if(!cache_blocks) E_Exit("Allocating cache_blocks has failed"); + } + memset(cache_blocks,0,sizeof(CacheBlock)*CACHE_BLOCKS); + cache.block.free=&cache_blocks[0]; + for (Bits i=0;icache.start=&cache_code[0]; + block->cache.size=CACHE_TOTAL; + block->cache.next=0; //Last block in the list + + /* Setup the default blocks for block linkage returns */ + cache.pos=&cache_code_link_blocks[0]; + link_blocks[0].cache.start=cache.pos; + gen_return(BR_Link1); + cache.pos=&cache_code_link_blocks[32]; + link_blocks[1].cache.start=cache.pos; + gen_return(BR_Link2); + cache.free_pages=0; + cache.last_page=0; + cache.used_pages=0; + /* Setup the code pages */ + for (Bitu i=0;inext=cache.free_pages; + cache.free_pages=newpage; + } + } +} diff --git a/src/cpu/core_dyn_x86/decoder.h b/src/cpu/core_dyn_x86/decoder.h index 7e73486..a6f826e 100644 --- a/src/cpu/core_dyn_x86/decoder.h +++ b/src/cpu/core_dyn_x86/decoder.h @@ -2677,7 +2677,7 @@ restart_prefix: goto illegalopcode; } } - // link to next block because the maximal number of opcodes has been reached + // link to next block because the maximum number of opcodes has been reached dyn_set_eip_end(); dyn_reduce_cycles(); dyn_save_critical_regs(); diff --git a/src/cpu/core_dynrec.cpp b/src/cpu/core_dynrec.cpp index b20900e..43957c5 100644 --- a/src/cpu/core_dynrec.cpp +++ b/src/cpu/core_dynrec.cpp @@ -246,7 +246,7 @@ run_block: // the block was exited due to a non-predictable control flow // modifying instruction (like ret) or some nontrivial cpu state // changing instruction (for example switch to/from pmode), - // or the maximal number of instructions to translate was reached + // or the maximum number of instructions to translate was reached #if C_HEAVY_DEBUG if (DEBUG_HeavyIsBreakpoint()) return debugCallback; #endif diff --git a/src/cpu/core_dynrec/cache.h b/src/cpu/core_dynrec/cache.h index fd742c7..3db4506 100644 --- a/src/cpu/core_dynrec/cache.h +++ b/src/cpu/core_dynrec/cache.h @@ -53,7 +53,7 @@ public: CacheBlockDynRec * to; // this block can transfer control to the to-block CacheBlockDynRec * next; CacheBlockDynRec * from; // the from-block can transfer control to this block - } link[2]; // maximal two links (conditional jumps) + } link[2]; // maximum two links (conditional jumps) CacheBlockDynRec * crossblock; }; diff --git a/src/cpu/core_dynrec/decoder.h b/src/cpu/core_dynrec/decoder.h index 383ef5c..0328a89 100644 --- a/src/cpu/core_dynrec/decoder.h +++ b/src/cpu/core_dynrec/decoder.h @@ -26,7 +26,7 @@ /* The function CreateCacheBlock translates the instruction stream - until either an unhandled instruction is found, the maximal + until either an unhandled instruction is found, the maximum number of translated instructions is reached or some critical instruction is encountered. */ @@ -586,7 +586,7 @@ restart_prefix: goto illegalopcode; } } - // link to next block because the maximal number of opcodes has been reached + // link to next block because the maximum number of opcodes has been reached dyn_set_eip_end(); dyn_reduce_cycles(); gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlockDynRec,cache.start)); diff --git a/src/cpu/core_full/load.h b/src/cpu/core_full/load.h index 664a0a6..aec2b3f 100644 --- a/src/cpu/core_full/load.h +++ b/src/cpu/core_full/load.h @@ -502,7 +502,7 @@ l_M_Ed: continue; case D_RDTSC: { if (CPU_ArchitectureType>32); reg_eax=(Bit32u)(tsc&0xffffffff); break; diff --git a/src/cpu/core_normal/prefix_0f.h b/src/cpu/core_normal/prefix_0f.h index 1be0053..6878e1e 100644 --- a/src/cpu/core_normal/prefix_0f.h +++ b/src/cpu/core_normal/prefix_0f.h @@ -228,7 +228,8 @@ CASE_0F_B(0x31) /* RDTSC */ { if (CPU_ArchitectureType>32); reg_eax=(Bit32u)(tsc&0xffffffff); } diff --git a/src/cpu/cpu.cpp b/src/cpu/cpu.cpp index e70a807..c867f40 100644 --- a/src/cpu/cpu.cpp +++ b/src/cpu/cpu.cpp @@ -19,6 +19,7 @@ #include #include +#include #include "dosbox.h" #include "cpu.h" #ifdef HW_RVL diff --git a/src/cpu/paging.cpp b/src/cpu/paging.cpp index 1b415d7..aed7eed 100644 --- a/src/cpu/paging.cpp +++ b/src/cpu/paging.cpp @@ -849,7 +849,7 @@ void PAGING_SetDirBase(Bitu cr3) { } void PAGING_Enable(bool enabled) { - /* If paging is disable we work from a default paging table */ + /* If paging is disabled, we work from a default paging table */ if (paging.enabled==enabled) return; paging.enabled=enabled; if (enabled) { diff --git a/src/debug/debug.cpp b/src/debug/debug.cpp index d7e27a5..2b6fa48 100644 --- a/src/debug/debug.cpp +++ b/src/debug/debug.cpp @@ -402,7 +402,7 @@ void CBreakpoint::ActivateBreakpoints(PhysPt adr, bool activate) CBreakpoint* bp; for(i=BPoints.begin(); i != BPoints.end(); i++) { bp = (*i); - // Do not activate, when bp is an actual adress + // Do not activate, when bp is an actual address if (activate && (bp->GetType()==BKPNT_PHYSICAL) && (bp->GetLocation()==adr)) { // Do not activate :) continue; @@ -412,7 +412,7 @@ void CBreakpoint::ActivateBreakpoints(PhysPt adr, bool activate) }; bool CBreakpoint::CheckBreakpoint(Bitu seg, Bitu off) -// Checks if breakpoint is valid an should stop execution +// Checks if breakpoint is valid and should stop execution { if ((ignoreAddressOnce!=0) && (GetAddress(seg,off)==ignoreAddressOnce)) { ignoreAddressOnce = 0; @@ -476,7 +476,7 @@ bool CBreakpoint::CheckBreakpoint(Bitu seg, Bitu off) }; bool CBreakpoint::CheckIntBreakpoint(PhysPt adr, Bit8u intNr, Bit16u ahValue) -// Checks if interrupt breakpoint is valid an should stop execution +// Checks if interrupt breakpoint is valid and should stop execution { if ((ignoreAddressOnce!=0) && (adr==ignoreAddressOnce)) { ignoreAddressOnce = 0; @@ -491,7 +491,7 @@ bool CBreakpoint::CheckIntBreakpoint(PhysPt adr, Bit8u intNr, Bit16u ahValue) bp = (*i); if ((bp->GetType()==BKPNT_INTERRUPT) && bp->IsActive() && (bp->GetIntNr()==intNr)) { if ((bp->GetValue()==BPINT_ALL) || (bp->GetValue()==ahValue)) { - // Ignoie it once ? + // Ignore it once ? if (ignoreOnce==bp) { ignoreOnce=0; bp->Activate(true); @@ -681,7 +681,7 @@ static void DrawData(void) { Bit32u address; /* Data win */ for (int y=0; y<8; y++) { - // Adress + // Address if (add<0x10000) mvwprintw (dbg.win_data,1+y,0,"%04X:%04X ",dataSeg,add); else mvwprintw (dbg.win_data,1+y,0,"%04X:%08X ",dataSeg,add); for (int x=0; x<16; x++) { @@ -1402,7 +1402,7 @@ char* AnalyzeInstruction(char* inst, bool saveSelector) { // Variable found ? CDebugVar* var = CDebugVar::FindVar(address); if (var) { - // Replace occurance + // Replace occurence char* pos1 = strchr(inst,'['); char* pos2 = strchr(inst,']'); if (pos1 && pos2) { @@ -2424,7 +2424,7 @@ void DEBUG_HeavyWriteLogInstruction(void) { out << hex << noshowbase << setfill('0') << uppercase; Bit32u startLog = logCount; do { - // Write Intructions + // Write Instructions TLogInst & inst = logInst[startLog]; out << setw(4) << inst.s_cs << ":" << setw(8) << inst.eip << " " << inst.dline << " " << inst.res << " EAX:" << setw(8)<< inst.eax diff --git a/src/debug/debug_disasm.cpp b/src/debug/debug_disasm.cpp index 626ca56..c9d41e0 100644 --- a/src/debug/debug_disasm.cpp +++ b/src/debug/debug_disasm.cpp @@ -283,8 +283,10 @@ static char const *second[] = { 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, + 0, "rdtsc", 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, /* 4 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -947,7 +949,9 @@ static void percent(char type, char subtype) break; case '2': /* old [pop cs]! now indexes */ - ua_str(second[getbyte()]); /* instructions in 386/486 */ + c = getbyte(); + wordop = c & 1; + ua_str(second[c]); /* instructions in 386/486 */ break; case 'g': /* modrm group `subtype' (0--7) */ diff --git a/src/debug/debug_gui.cpp b/src/debug/debug_gui.cpp index 8a50ee6..055e5fe 100644 --- a/src/debug/debug_gui.cpp +++ b/src/debug/debug_gui.cpp @@ -161,7 +161,7 @@ static void DrawBars(void) { static void MakeSubWindows(void) { - /* The Std output win should go in bottem */ + /* The Std output win should go at the bottom */ /* Make all the subwindows */ int win_main_maxy, win_main_maxx; getmaxyx(dbg.win_main,win_main_maxy,win_main_maxx); int outy=1; //Match values with above diff --git a/src/dos/dev_con.h b/src/dos/dev_con.h index 936bfef..813aa6a 100644 --- a/src/dos/dev_con.h +++ b/src/dos/dev_con.h @@ -37,7 +37,7 @@ public: private: Bit8u readcache; Bit8u lastwrite; - struct ansi { /* should create a constructor which fills them with the appriorate values */ + struct ansi { /* should create a constructor, which would fill them with the appropriate values */ bool esc; bool sci; bool enabled; @@ -128,7 +128,7 @@ bool device_CON::Write(Bit8u * data,Bit16u * size) { count++; continue; } else { - /* Some sort of "hack" now that \n doesn't set col to 0 (int10_char.cpp old chessgame) */ + /* Some sort of "hack" now that '\n' doesn't set col to 0 (int10_char.cpp old chessgame) */ if((data[count] == '\n') && (lastwrite != '\r')) INT10_TeletypeOutputAttr('\r',ansi.attr,ansi.enabled); /* pass attribute only if ansi is enabled */ INT10_TeletypeOutputAttr(data[count],ansi.attr,ansi.enabled); diff --git a/src/dos/dos.cpp b/src/dos/dos.cpp index 984ed44..2eeeb01 100644 --- a/src/dos/dos.cpp +++ b/src/dos/dos.cpp @@ -220,6 +220,7 @@ static Bitu DOS_21Handler(void) { Bit8u free=mem_readb(data); Bit8u read=0;Bit8u c;Bit16u n=1; if (!free) break; + free--; for(;;) { DOS_ReadFile(STDIN,&c,&n); if (c == 8) { // Backspace @@ -232,7 +233,7 @@ static Bitu DOS_21Handler(void) { } continue; } - if (read >= free) { // Keyboard buffer full + if (read == free && c != 13) { // Keyboard buffer full Bit8u bell = 7; DOS_WriteFile(STDOUT, &bell, &n); continue; diff --git a/src/dos/dos_devices.cpp b/src/dos/dos_devices.cpp index 1ebf5bf..b2ed2ee 100644 --- a/src/dos/dos_devices.cpp +++ b/src/dos/dos_devices.cpp @@ -97,6 +97,7 @@ DOS_File::DOS_File(const DOS_File& orig) { attr=orig.attr; refCtr=orig.refCtr; open=orig.open; + hdrive=orig.hdrive; name=0; if(orig.name) { name=new char [strlen(orig.name) + 1];strcpy(name,orig.name); @@ -110,6 +111,7 @@ DOS_File & DOS_File::operator= (const DOS_File & orig) { attr=orig.attr; refCtr=orig.refCtr; open=orig.open; + hdrive=orig.hdrive; if(name) { delete [] name; name=0; } diff --git a/src/dos/dos_execute.cpp b/src/dos/dos_execute.cpp index f51a15b..2cc5c17 100644 --- a/src/dos/dos_execute.cpp +++ b/src/dos/dos_execute.cpp @@ -93,8 +93,13 @@ void DOS_UpdatePSPName(void) { DOS_MCB mcb(dos.psp()-1); static char name[9]; mcb.GetFileName(name); + name[8] = 0; if (!strlen(name)) strcpy(name,"DOSBOX"); - RunningProgram=name; + for(Bitu i = 0;i < 8;i++) { //Don't put garbage in the title bar. Mac OS X doesn't like it + if (name[i] == 0) break; + if ( !isprint(*reinterpret_cast(&name[i])) ) name[i] = '?'; + } + RunningProgram = name; GFX_SetTitle(-1,-1,false); } diff --git a/src/dos/dos_files.cpp b/src/dos/dos_files.cpp index 91cbc71..dc2962c 100644 --- a/src/dos/dos_files.cpp +++ b/src/dos/dos_files.cpp @@ -299,7 +299,7 @@ bool DOS_Rename(char const * const oldname,char const * const newname) { } if (Drives[drivenew]->Rename(fullold,fullnew)) return true; - /* If it still fails. which error should we give ? PATH NOT FOUND or EACCESS */ + /* If it still fails, which error should we give ? PATH NOT FOUND or EACCESS */ LOG(LOG_FILES,LOG_NORMAL)("Rename fails for %s to %s, no proper errorcode returned.",oldname,newname); DOS_SetError(DOSERR_FILE_NOT_FOUND); return false; @@ -924,7 +924,10 @@ bool DOS_FCBCreate(Bit16u seg,Bit16u offset) { DOS_FCB fcb(seg,offset); char shortname[DOS_FCBNAME];Bit16u handle; fcb.GetName(shortname); - if (!DOS_CreateFile(shortname,DOS_ATTR_ARCHIVE,&handle)) return false; + Bit8u attr = DOS_ATTR_ARCHIVE; + fcb.GetAttr(attr); + if (!attr) attr = DOS_ATTR_ARCHIVE; //Better safe than sorry + if (!DOS_CreateFile(shortname,attr,&handle)) return false; fcb.FileOpen((Bit8u)handle); return true; } @@ -1164,10 +1167,11 @@ bool DOS_FCBDeleteFile(Bit16u seg,Bit16u offset){ * stored. This can not be the tempdta as that one is used by fcbfindfirst */ RealPt old_dta=dos.dta();dos.dta(dos.tables.tempdta_fcbdelete); - DOS_FCB fcb(RealSeg(dos.dta()),RealOff(dos.dta())); + RealPt new_dta=dos.dta(); bool nextfile = false; bool return_value = false; nextfile = DOS_FCBFindFirst(seg,offset); + DOS_FCB fcb(RealSeg(new_dta),RealOff(new_dta)); while(nextfile) { char shortname[DOS_FCBNAME] = { 0 }; fcb.GetName(shortname); diff --git a/src/dos/dos_ioctl.cpp b/src/dos/dos_ioctl.cpp index 3b54718..0274484 100644 --- a/src/dos/dos_ioctl.cpp +++ b/src/dos/dos_ioctl.cpp @@ -40,7 +40,7 @@ bool DOS_IOCTL(void) { } else if (reg_al<0x12) { /* those use a diskdrive except 0x0b */ if (reg_al!=0x0b) { drive=reg_bl;if (!drive) drive = DOS_GetDefaultDrive();else drive--; - if( !(( drive < DOS_DRIVES ) && Drives[drive]) ) { + if( (drive >= 2) && !(( drive < DOS_DRIVES ) && Drives[drive]) ) { DOS_SetError(DOSERR_INVALID_DRIVE); return false; } @@ -133,7 +133,7 @@ bool DOS_IOCTL(void) { } return true; case 0x09: /* Check if block device remote */ - if (Drives[drive]->isRemote()) { + if ((drive >= 2) && Drives[drive]->isRemote()) { reg_dx=0x1000; // device is remote // undocumented bits always clear } else { @@ -151,7 +151,7 @@ bool DOS_IOCTL(void) { return true; case 0x0D: /* Generic block device request */ { - if (Drives[drive]->isRemovable()) { + if ((drive < 2) || Drives[drive]->isRemovable()) { DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID); return false; } @@ -202,11 +202,14 @@ bool DOS_IOCTL(void) { return true; } case 0x0E: /* Get Logical Drive Map */ - if (Drives[drive]->isRemovable()) { + if (drive < 2) { + if (Drives[drive]) reg_al=drive+1; + else reg_al=1; + } else if (Drives[drive]->isRemovable()) { DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID); return false; - } - reg_al = 0; /* Only 1 logical drive assigned */ + } else reg_al=0; /* Only 1 logical drive assigned */ + reg_ah=0x07; return true; default: LOG(LOG_DOSMISC,LOG_ERROR)("DOS:IOCTL Call %2X unhandled",reg_al); diff --git a/src/dos/dos_programs.cpp b/src/dos/dos_programs.cpp index 62f326c..cc3ed1e 100644 --- a/src/dos/dos_programs.cpp +++ b/src/dos/dos_programs.cpp @@ -48,6 +48,7 @@ Bitu DEBUG_EnableDebugger(void); #endif void MSCDEX_SetCDInterface(int intNr, int forceCD); +static Bitu ZDRIVE_NUM = 25; #ifdef HW_RVL // Mounts a folder as a harddrive before starting the shell @@ -121,23 +122,51 @@ int MountDOSBoxDir(char DriveLetter, const char *path) { class MOUNT : public Program { public: - void Run(void) - { + void ListMounts(void) { + char name[DOS_NAMELENGTH_ASCII];Bit32u size;Bit16u date;Bit16u time;Bit8u attr; + /* Command uses dta so set it to our internal dta */ + RealPt save_dta = dos.dta(); + dos.dta(dos.tables.tempdta); + DOS_DTA dta(dos.dta()); + + WriteOut(MSG_Get("PROGRAM_MOUNT_STATUS_1")); + WriteOut(MSG_Get("PROGRAM_MOUNT_STATUS_FORMAT"),"Drive","Type","Label"); + for(int p = 0;p < 8;p++) WriteOut("----------"); + + for (int d = 0;d < DOS_DRIVES;d++) { + if (!Drives[d]) continue; + + char root[4] = {'A'+d,':','\\',0}; + bool ret = DOS_FindFirst(root,DOS_ATTR_VOLUME); + if (ret) { + dta.GetResult(name,size,date,time,attr); + DOS_FindNext(); //Mark entry as invalid + } else name[0] = 0; + + /* Change 8.3 to 11.0 */ + char* dot = strchr(name,'.'); + if(dot && (dot - name == 8) ) { + name[8] = name[9];name[9] = name[10];name[10] = name[11];name[11] = 0; + } + + root[1] = 0; //This way, the format string can be reused. + WriteOut(MSG_Get("PROGRAM_MOUNT_STATUS_FORMAT"),root, Drives[d]->GetInfo(),name); + } + dos.dta(save_dta); + } + + void Run(void) { DOS_Drive * newdrive;char drive; std::string label; std::string umount; + std::string newz; //Hack To allow long commandlines ChangeToLongCmd(); /* Parse the command line */ /* if the command line is empty show current mounts */ if (!cmd->GetCount()) { - WriteOut(MSG_Get("PROGRAM_MOUNT_STATUS_1")); - for (int d=0;dGetInfo()); - } - } + ListMounts(); return; } @@ -152,12 +181,12 @@ public: if (cmd->FindString("-u",umount,false)) { umount[0] = toupper(umount[0]); int i_drive = umount[0]-'A'; - if(i_drive < DOS_DRIVES && i_drive >= 0 && Drives[i_drive]) { + if (i_drive < DOS_DRIVES && i_drive >= 0 && Drives[i_drive]) { switch (DriveManager::UnmountDrive(i_drive)) { case 0: Drives[i_drive] = 0; if(i_drive == DOS_GetDefaultDrive()) - DOS_SetDrive(toupper('Z') - 'A'); + DOS_SetDrive(ZDRIVE_NUM); WriteOut(MSG_Get("PROGRAM_MOUNT_UMOUNT_SUCCESS"),umount[0]); break; case 1: @@ -172,8 +201,46 @@ public: } return; } - - // Show list of cdroms + + /* Check for moving Z: */ + /* Only allowing moving it once. It is merely a convenience added for the wine team */ + if (ZDRIVE_NUM == 25 && cmd->FindString("-z", newz,false)) { + newz[0] = toupper(newz[0]); + int i_newz = newz[0] - 'A'; + if (i_newz >= 0 && i_newz < DOS_DRIVES-1 && !Drives[i_newz]) { + ZDRIVE_NUM = i_newz; + /* remap drives */ + Drives[i_newz] = Drives[25]; + Drives[25] = 0; + DOS_Shell *fs = static_cast(first_shell); //dynamic ? + /* Update environment */ + std::string line = ""; + char ppp[2] = {newz[0],0}; + std::string tempenv = ppp; tempenv += ":\\"; + if (fs->GetEnvStr("PATH",line)){ + std::string::size_type idx = line.find('='); + std::string value = line.substr(idx +1 , std::string::npos); + while ( (idx = value.find("Z:\\")) != std::string::npos || + (idx = value.find("z:\\")) != std::string::npos ) + value.replace(idx,3,tempenv); + line = value; + } + if (!line.size()) line = tempenv; + fs->SetEnv("PATH",line.c_str()); + tempenv += "COMMAND.COM"; + fs->SetEnv("COMSPEC",tempenv.c_str()); + + /* Update batch file if running from Z: (very likely: autoexec) */ + if(fs->bf) { + std::string &name = fs->bf->filename; + if(name.length() >2 && name[0] == 'Z' && name[1] == ':') name[0] = newz[0]; + } + /* Change the active drive */ + if (DOS_GetDefaultDrive() == 25) DOS_SetDrive(i_newz); + } + return; + } + /* Show list of cdroms */ if (cmd->FindExist("-cd",false)) { int num = SDL_CDNumDrives(); WriteOut(MSG_Get("PROGRAM_MOUNT_CDROMS_FOUND"),num); @@ -393,6 +460,7 @@ public: label = drive; label += "_FLOPPY"; newdrive->dirCache.SetLabel(label.c_str(),iscdrom,true); } + if(type == "floppy") incrementFDD(); return; showusage: #if defined (WIN32) || defined(OS2) @@ -982,11 +1050,29 @@ public: void RESCAN::Run(void) { - // Get current drive + bool all = false; + Bit8u drive = DOS_GetDefaultDrive(); - if (Drives[drive]) { - Drives[drive]->EmptyCache(); + + if(cmd->FindCommand(1,temp_line)) { + //-A -All /A /All + if(temp_line.size() >= 2 && (temp_line[0] == '-' ||temp_line[0] =='/')&& (temp_line[1] == 'a' || temp_line[1] =='A') ) all = true; + else if(temp_line.size() == 2 && temp_line[1] == ':') { + lowcase(temp_line); + drive = temp_line[0] - 'a'; + } + } + // Get current drive + if (all) { + for(Bitu i =0; iEmptyCache(); + } WriteOut(MSG_Get("PROGRAM_RESCAN_SUCCESS")); + } else { + if (drive < DOS_DRIVES && Drives[drive]) { + Drives[drive]->EmptyCache(); + WriteOut(MSG_Get("PROGRAM_RESCAN_SUCCESS")); + } } } @@ -1423,8 +1509,9 @@ void DOS_SetupPrograms(void) { /*Add Messages */ MSG_Add("PROGRAM_MOUNT_CDROMS_FOUND","CDROMs found: %d\n"); + MSG_Add("PROGRAM_MOUNT_STATUS_FORMAT","%-5s %-58s %-12s\n"); MSG_Add("PROGRAM_MOUNT_STATUS_2","Drive %c is mounted as %s\n"); - MSG_Add("PROGRAM_MOUNT_STATUS_1","Current mounted drives are:\n"); + MSG_Add("PROGRAM_MOUNT_STATUS_1","The currently mounted drives are:\n"); MSG_Add("PROGRAM_MOUNT_ERROR_1","Directory %s doesn't exist.\n"); MSG_Add("PROGRAM_MOUNT_ERROR_2","%s isn't a directory\n"); MSG_Add("PROGRAM_MOUNT_ILL_TYPE","Illegal type %s\n"); diff --git a/src/dos/drive_cache.cpp b/src/dos/drive_cache.cpp index 7f8d021..5d59392 100644 --- a/src/dos/drive_cache.cpp +++ b/src/dos/drive_cache.cpp @@ -192,7 +192,7 @@ char* DOS_Drive_Cache::GetExpandName(const char* path) { if((len > 1) && (work[len-1] == CROSS_FILESPLIT )) { #endif #ifndef HW_RVL - work[len-1] = 0; // Remove trailing slashes except when in root + work[len-1] = 0; // Remove trailing slashes except when in root #endif } } @@ -378,6 +378,60 @@ bool DOS_Drive_Cache::RemoveTrailingDot(char* shortname) { return false; } +#define WINE_DRIVE_SUPPORT 1 +#if WINE_DRIVE_SUPPORT +//Changes to interact with WINE by supporting their namemangling. +//The code is rather slow, because orglist is unordered, so it needs to be avoided if possible. +//Hence the tests in GetLongFileName + + +// From the Wine project +static Bits wine_hash_short_file_name( char* name, char* buffer ) +{ + static const char hash_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"; + static const char invalid_chars[] = { '*','?','<','>','|','"','+','=',',',';','[',']',' ','\345','~','.',0 }; + char* p; + char* ext; + char* end = name + strlen(name); + char* dst; + unsigned short hash; + int i; + + // Compute the hash code of the file name + for (p = name, hash = 0xbeef; p < end - 1; p++) + hash = (hash<<3) ^ (hash>>5) ^ tolower(*p) ^ (tolower(p[1]) << 8); + hash = (hash<<3) ^ (hash>>5) ^ tolower(*p); // Last character + + + // Find last dot for start of the extension + for (p = name + 1, ext = NULL; p < end - 1; p++) if (*p == '.') ext = p; + + // Copy first 4 chars, replacing invalid chars with '_' + for (i = 4, p = name, dst = buffer; i > 0; i--, p++) + { + if (p == end || p == ext) break; + *dst++ = (*p < 0 || strchr( invalid_chars, *p ) != NULL) ? '_' : toupper(*p); + } + // Pad to 5 chars with '~' + while (i-- >= 0) *dst++ = '~'; + + // Insert hash code converted to 3 ASCII chars + *dst++ = hash_chars[(hash >> 10) & 0x1f]; + *dst++ = hash_chars[(hash >> 5) & 0x1f]; + *dst++ = hash_chars[hash & 0x1f]; + + // Copy the first 3 chars of the extension (if any) + if (ext) + { + *dst++ = '.'; + for (i = 3, ext++; (i > 0) && ext < end; i--, ext++) + *dst++ = (*ext < 0 || strchr( invalid_chars, *ext ) != NULL) ? '_' : toupper(*ext); + } + + return dst - buffer; +} +#endif + Bits DOS_Drive_Cache::GetLongName(CFileInfo* curDir, char* shortName) { std::vector::size_type filelist_size = curDir->fileList.size(); if (GCC_UNLIKELY(filelist_size<=0)) return -1; @@ -398,6 +452,21 @@ Bits DOS_Drive_Cache::GetLongName(CFileInfo* curDir, char* shortName) { return mid; }; } +#ifdef WINE_DRIVE_SUPPORT + if (strlen(shortName) < 8 || shortName[4] != '~' || shortName[5] == '.' || shortName[6] == '.' || shortName[7] == '.') return -1; // not available + // else it's most likely a Wine style short name ABCD~###, # = not dot (length at least 8) + // The above test is rather strict as the following loop can be really slow if filelist_size is large. + char buff[CROSS_LEN]; + for (Bitu i = 0; i < filelist_size; i++) { + res = wine_hash_short_file_name(curDir->fileList[i]->orgname,buff); + buff[res] = 0; + if (!strcmp(shortName,buff)) { + // Found + strcpy(shortName,curDir->fileList[i]->orgname); + return (Bits)i; + } + } +#endif // not available return -1; } diff --git a/src/dos/drive_virtual.cpp b/src/dos/drive_virtual.cpp index a054648..835a309 100644 --- a/src/dos/drive_virtual.cpp +++ b/src/dos/drive_virtual.cpp @@ -101,7 +101,7 @@ bool Virtual_File::Read(Bit8u * data,Bit16u * size) { } bool Virtual_File::Write(Bit8u * data,Bit16u * size){ -/* Not really writeable */ + /* Not really writable */ return false; } diff --git a/src/dosbox.cpp b/src/dosbox.cpp index b5a1981..94008f6 100644 --- a/src/dosbox.cpp +++ b/src/dosbox.cpp @@ -506,6 +506,7 @@ void DOSBOX_Init(void) { Pstring = secprop->Add_string("midiconfig",Property::Changeable::WhenIdle,""); Pstring->Set_help("Special configuration options for the device driver. This is usually the id of the device you want to use.\n" + " or in the case of coreaudio, you can specify a soundfont here.\n" " When using a Roland MT-32 rev. 0 as midi output device, some games may require a delay in order to prevent 'buffer overflow' issues.\n" " In that case, add 'delaysysex', for example: midiconfig=2 delaysysex\n" " See the README/Manual for more details."); @@ -733,8 +734,8 @@ void DOSBOX_Init(void) { "You can put your MOUNT lines here.\n" ); MSG_Add("CONFIGFILE_INTRO", - "# This is the configurationfile for DOSBox %s. (Please use the latest version of DOSBox)\n" - "# Lines starting with a # are commentlines and are ignored by DOSBox.\n" + "# This is the configuration file for DOSBox %s. (Please use the latest version of DOSBox)\n" + "# Lines starting with a # are comment lines and are ignored by DOSBox.\n" "# They are used to (briefly) document the effect of each option.\n"); MSG_Add("CONFIG_SUGGESTED_VALUES", "Possible values"); diff --git a/src/gui/midi_coreaudio.h b/src/gui/midi_coreaudio.h index bcd757a..41a8caa 100644 --- a/src/gui/midi_coreaudio.h +++ b/src/gui/midi_coreaudio.h @@ -32,6 +32,7 @@ class MidiHandler_coreaudio : public MidiHandler { private: AUGraph m_auGraph; AudioUnit m_synth; + const char *soundfont; public: MidiHandler_coreaudio() : m_auGraph(0), m_synth(0) {} const char * GetName(void) { return "coreaudio"; } @@ -71,6 +72,22 @@ public: // Get the music device from the graph. RequireNoErr(AUGraphGetNodeInfo(m_auGraph, synthNode, NULL, NULL, NULL, &m_synth)); + // Optionally load a soundfont + if (conf && conf[0]) { + soundfont = conf; + FSRef soundfontRef; + RequireNoErr(FSPathMakeRef((const UInt8*)soundfont, &soundfontRef, NULL)); + RequireNoErr(AudioUnitSetProperty( + m_synth, + kMusicDeviceProperty_SoundBankFSRef, + kAudioUnitScope_Global, + 0, + &soundfontRef, + sizeof(soundfontRef) + )); + LOG_MSG("MIDI:coreaudio: loaded soundfont: %s",soundfont); + } + // Finally: Start the graph! RequireNoErr(AUGraphStart(m_auGraph)); diff --git a/src/gui/sdl_mapper.cpp b/src/gui/sdl_mapper.cpp index 2110a36..8e685bf 100644 --- a/src/gui/sdl_mapper.cpp +++ b/src/gui/sdl_mapper.cpp @@ -2107,7 +2107,7 @@ static void CreateDefaultBinds(void) { } void MAPPER_AddHandler(MAPPER_Handler * handler,MapKeys key,Bitu mods,char const * const eventname,char const * const buttonname) { - //Check if it allready exists=> if so return. + //Check if it already exists=> if so return. for(CHandlerEventVector_it it=handlergroup.begin();it!=handlergroup.end();it++) if(strcmp((*it)->buttonname,buttonname) == 0) return; diff --git a/src/gui/sdlmain.cpp b/src/gui/sdlmain.cpp index 555c15d..ab0e5d6 100644 --- a/src/gui/sdlmain.cpp +++ b/src/gui/sdlmain.cpp @@ -174,6 +174,8 @@ struct SDL_Block { } window; Bit8u bpp; bool fullscreen; + bool lazy_fullscreen; + bool lazy_fullscreen_req; bool doublebuf; SCREEN_TYPES type; SCREEN_TYPES want_type; @@ -247,6 +249,12 @@ void GFX_SetTitle(Bit32s cycles,Bits frameskip,bool paused){ SDL_WM_SetCaption(title,VERSION); } +static void KillSwitch(bool pressed) { + if (!pressed) + return; + throw 1; +} + static void PauseDOSBox(bool pressed) { if (!pressed) return; @@ -263,15 +271,22 @@ static void PauseDOSBox(bool pressed) { SDL_WaitEvent(&event); // since we're not polling, cpu usage drops to 0. switch (event.type) { - case SDL_QUIT: throw(0); break; + case SDL_QUIT: KillSwitch(true); break; case SDL_KEYDOWN: // Must use Pause/Break Key to resume. case SDL_KEYUP: - if(event.key.keysym.sym==SDLK_PAUSE) { + if(event.key.keysym.sym == SDLK_PAUSE) { - paused=false; + paused = false; GFX_SetTitle(-1,-1,false); break; } +#if defined (MACOSX) + if (event.key.keysym.sym == SDLK_q && (event.key.keysym.mod == KMOD_RMETA || event.key.keysym.mod == KMOD_LMETA) ) { + /* On macs, all aps exit when pressing cmd-q */ + KillSwitch(true); + break; + } +#endif } } } @@ -356,6 +371,16 @@ void GFX_ResetScreen(void) { CPU_Reset_AutoAdjust(); } +void GFX_ForceFullscreenExit(void) { + if (sdl.desktop.lazy_fullscreen) { +// sdl.desktop.lazy_fullscreen_req=true; + LOG_MSG("GFX LF: invalid screen change"); + } else { + sdl.desktop.fullscreen=false; + GFX_ResetScreen(); + } +} + static int int_log2 (int val) { int log = 0; while ((val >>= 1) != 0) @@ -408,6 +433,16 @@ static SDL_Surface * GFX_SetupSurfaceScaled(Bit32u sdl_flags, Bit32u bpp) { } } +void GFX_TearDown(void) { + if (sdl.updating) + GFX_EndUpdate( 0 ); + + if (sdl.blit.surface) { + SDL_FreeSurface(sdl.blit.surface); + sdl.blit.surface=0; + } +} + Bitu GFX_SetSize(Bitu width,Bitu height,Bitu flags,double scalex,double scaley,GFX_CallBack_t callback) { if (sdl.updating) GFX_EndUpdate( 0 ); @@ -673,6 +708,18 @@ void GFX_CaptureMouse(void) { mouselocked=sdl.mouse.locked; } +void GFX_UpdateSDLCaptureState(void) { + if (sdl.mouse.locked) { + SDL_WM_GrabInput(SDL_GRAB_ON); + SDL_ShowCursor(SDL_DISABLE); + } else { + SDL_WM_GrabInput(SDL_GRAB_OFF); + if (sdl.mouse.autoenable || !sdl.mouse.autolock) SDL_ShowCursor(SDL_ENABLE); + } + CPU_Reset_AutoAdjust(); + GFX_SetTitle(-1,-1,false); +} + bool mouselocked; //Global variable for mapper static void CaptureMouse(bool pressed) { if (!pressed) @@ -680,12 +727,40 @@ static void CaptureMouse(bool pressed) { GFX_CaptureMouse(); } +#if defined (WIN32) +STICKYKEYS stick_keys = {sizeof(STICKYKEYS), 0}; +void sticky_keys(bool restore){ + static bool inited = false; + if (!inited){ + inited = true; + SystemParametersInfo(SPI_GETSTICKYKEYS, sizeof(STICKYKEYS), &stick_keys, 0); + } + if (restore) { + SystemParametersInfo(SPI_SETSTICKYKEYS, sizeof(STICKYKEYS), &stick_keys, 0); + return; + } + //Get current sticky keys layout: + STICKYKEYS s = {sizeof(STICKYKEYS), 0}; + SystemParametersInfo(SPI_GETSTICKYKEYS, sizeof(STICKYKEYS), &s, 0); + if ( !(s.dwFlags & SKF_STICKYKEYSON)) { //Not on already + s.dwFlags &= ~SKF_HOTKEYACTIVE; + SystemParametersInfo(SPI_SETSTICKYKEYS, sizeof(STICKYKEYS), &s, 0); + } +} +#endif + void GFX_SwitchFullScreen(void) { sdl.desktop.fullscreen=!sdl.desktop.fullscreen; if (sdl.desktop.fullscreen) { if (!sdl.mouse.locked) GFX_CaptureMouse(); +#if defined (WIN32) + sticky_keys(false); //disable sticky keys in fullscreen mode +#endif } else { if (sdl.mouse.locked) GFX_CaptureMouse(); +#if defined (WIN32) + sticky_keys(true); //restore sticky keys to default state in windowed mode. +#endif } GFX_ResetScreen(); } @@ -693,7 +768,32 @@ void GFX_SwitchFullScreen(void) { static void SwitchFullScreen(bool pressed) { if (!pressed) return; - GFX_SwitchFullScreen(); + + if (sdl.desktop.lazy_fullscreen) { +// sdl.desktop.lazy_fullscreen_req=true; + LOG_MSG("GFX LF: fullscreen switching not supported"); + } else { + GFX_SwitchFullScreen(); + } +} + +void GFX_SwitchLazyFullscreen(bool lazy) { + sdl.desktop.lazy_fullscreen=lazy; + sdl.desktop.lazy_fullscreen_req=false; +} + +void GFX_SwitchFullscreenNoReset(void) { + sdl.desktop.fullscreen=!sdl.desktop.fullscreen; +} + +bool GFX_LazyFullscreenRequested(void) { + if (sdl.desktop.lazy_fullscreen) return sdl.desktop.lazy_fullscreen_req; + return false; +} + +void GFX_RestoreMode(void) { + GFX_SetSize(sdl.draw.width,sdl.draw.height,sdl.draw.flags,sdl.draw.scalex,sdl.draw.scaley,sdl.draw.callback); + GFX_UpdateSDLCaptureState(); } @@ -907,11 +1007,6 @@ static void GUI_ShutDown(Section * /*sec*/) { if (sdl.desktop.fullscreen) GFX_SwitchFullScreen(); } -static void KillSwitch(bool pressed) { - if (!pressed) - return; - throw 1; -} static void SetPriority(PRIORITY_LEVELS level) { @@ -1010,6 +1105,9 @@ static void GUI_StartUp(Section * sec) { SDL_WM_SetIcon(logos,NULL); #endif + sdl.desktop.lazy_fullscreen=false; + sdl.desktop.lazy_fullscreen_req=false; + sdl.desktop.fullscreen=section->Get_bool("fullscreen"); sdl.wait_on_error=section->Get_bool("waitonerror"); @@ -1186,7 +1284,7 @@ static void GUI_StartUp(Section * sec) { //#endif /* Please leave the Splash screen stuff in working order in DOSBox. We spend a lot of time making DOSBox. */ -/* +#ifndef HW_RVL SDL_Surface* splash_surf = SDL_CreateRGBSurface(SDL_SWSURFACE, 640, 400, 32, rmask, gmask, bmask, 0); if (splash_surf) { SDL_FillRect(splash_surf, NULL, SDL_MapRGB(splash_surf->format, 0, 0, 0)); @@ -1246,7 +1344,7 @@ static void GUI_StartUp(Section * sec) { delete [] tmpbufp; } -*/ +#endif /* Get some Event handlers */ MAPPER_AddHandler(KillSwitch,MK_f9,MMOD1,"shutdown","ShutDown"); MAPPER_AddHandler(CaptureMouse,MK_f10,MMOD1,"capmouse","Cap Mouse"); @@ -1327,6 +1425,10 @@ void GFX_LosingFocus(void) { MAPPER_LosingFocus(); } +bool GFX_IsFullscreen(void) { + return sdl.desktop.fullscreen; +} + void GFX_Events() { #ifdef HW_RVL // check for home button @@ -1363,8 +1465,7 @@ void GFX_Events() { #ifdef WIN32 if (sdl.desktop.fullscreen) { VGA_KillDrawing(); - sdl.desktop.fullscreen=false; - GFX_ResetScreen(); + GFX_ForceFullscreenExit(); } #endif GFX_CaptureMouse(); @@ -1446,6 +1547,15 @@ void GFX_Events() { if (event.key.keysym.sym==SDLK_RALT) sdl.raltstate = event.key.type; if (((event.key.keysym.sym==SDLK_TAB)) && ((sdl.laltstate==SDL_KEYDOWN) || (sdl.raltstate==SDL_KEYDOWN))) break; +#endif +#if defined (MACOSX) + case SDL_KEYDOWN: + case SDL_KEYUP: + /* On macs CMD-Q is the default key to close an application */ + if (event.key.keysym.sym == SDLK_q && (event.key.keysym.mod == KMOD_RMETA || event.key.keysym.mod == KMOD_LMETA) ) { + KillSwitch(true); + break; + } #endif default: void MAPPER_CheckEvent(SDL_Event * event); @@ -1755,7 +1865,7 @@ int main(int argc, char* argv[]) { if(control->cmdline->FindExist("-resetconf")) eraseconfigfile(); if(control->cmdline->FindExist("-erasemapper")) erasemapperfile(); if(control->cmdline->FindExist("-resetmapper")) erasemapperfile(); - + /* Can't disable the console with debugger enabled */ #if defined(WIN32) && !(C_DEBUG) if (control->cmdline->FindExist("-noconsole")) { @@ -1933,7 +2043,7 @@ int main(int argc, char* argv[]) { Section_prop * sdl_sec=static_cast(control->GetSection("sdl")); if (control->cmdline->FindExist("-fullscreen") || sdl_sec->Get_bool("fullscreen")) { - if(!sdl.desktop.fullscreen) { //only switch if not allready in fullscreen + if(!sdl.desktop.fullscreen) { //only switch if not already in fullscreen GFX_SwitchFullScreen(); } } @@ -1957,6 +2067,9 @@ int main(int argc, char* argv[]) { control->StartUp(); /* Shutdown everything */ } catch (char * error) { +#if defined (WIN32) + sticky_keys(true); +#endif GFX_ShowMsg("Exit to error: %s",error); fflush(NULL); if(sdl.wait_on_error) { @@ -1975,11 +2088,17 @@ int main(int argc, char* argv[]) { ;//nothing pressed killswitch } catch(...){ +#if defined (WIN32) + sticky_keys(true); +#endif //Force visible mouse to end user. Somehow this sometimes doesn't happen SDL_WM_GrabInput(SDL_GRAB_OFF); SDL_ShowCursor(SDL_ENABLE); throw;//dunno what happened. rethrow for sdl to catch } +#if defined (WIN32) + sticky_keys(true); //Might not be needed if the shutdown function switches to windowed mode, but it doesn't hurt +#endif //Force visible mouse to end user. Somehow this sometimes doesn't happen SDL_WM_GrabInput(SDL_GRAB_OFF); SDL_ShowCursor(SDL_ENABLE); diff --git a/src/hardware/hardware.cpp b/src/hardware/hardware.cpp index 257caf2..4addbfd 100644 --- a/src/hardware/hardware.cpp +++ b/src/hardware/hardware.cpp @@ -323,7 +323,7 @@ void CAPTURE_AddImage(Bitu width, Bitu height, Bitu bpp, Bitu pitch, Bitu flags, /* Open the actual file */ FILE * fp=OpenCaptureFile("Screenshot",".png"); if (!fp) goto skip_shot; - /* First try to alloacte the png structures */ + /* First try to allocate the png structures */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL, NULL); if (!png_ptr) goto skip_shot; info_ptr = png_create_info_struct(png_ptr); @@ -359,7 +359,23 @@ void CAPTURE_AddImage(Bitu width, Bitu height, Bitu bpp, Bitu pitch, Bitu flags, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); } +#ifdef PNG_TEXT_SUPPORTED + int fields = 1; + png_text text[1]; + const char* text_s = "DOSBox " VERSION; + size_t strl = strlen(text_s); + char* ptext_s = new char[strl + 1]; + strcpy(ptext_s, text_s); + char software[9] = { 'S','o','f','t','w','a','r','e',0}; + text[0].compression = PNG_TEXT_COMPRESSION_NONE; + text[0].key = software; + text[0].text = ptext_s; + png_set_text(png_ptr, info_ptr, text, fields); +#endif png_write_info(png_ptr, info_ptr); +#ifdef PNG_TEXT_SUPPORTED + delete [] ptext_s; +#endif for (i=0;i=0) && (parsed_regnum<256)) return pci_cfg_data[dev->PCIId()][dev->PCISubfunction()][parsed_regnum]; + Bit8u newval, mask; + if (dev->OverrideReadRegister(regnum, &newval, &mask)) { + Bit8u oldval=pci_cfg_data[dev->PCIId()][dev->PCISubfunction()][regnum] & (~mask); + return oldval | (newval & mask); + } + return 0xff; } diff --git a/src/hardware/sblaster.cpp b/src/hardware/sblaster.cpp index f43ee08..cd36cfb 100644 --- a/src/hardware/sblaster.cpp +++ b/src/hardware/sblaster.cpp @@ -871,6 +871,11 @@ static void DSP_DoCommand(void) { case 0x76: /* 074h : Single Cycle 3-bit(2.6bit) ADPCM */ DSP_PrepareDMA_Old(DSP_DMA_3,false,false); break; + case 0x7d: /* Auto Init 4-bit ADPCM Reference */ + DSP_SB2_ABOVE; + sb.adpcm.haveref=true; + DSP_PrepareDMA_Old(DSP_DMA_4,true,false); + break; case 0x17: /* 017h : Single Cycle 2-bit ADPCM Reference*/ sb.adpcm.haveref=true; case 0x16: /* 074h : Single Cycle 2-bit ADPCM */ @@ -996,7 +1001,7 @@ static void DSP_DoCommand(void) { DSP_SB2_ABOVE; LOG(LOG_SB,LOG_ERROR)("DSP:Unimplemented MIDI UART command %2X",sb.dsp.cmd); break; - case 0x7d: case 0x7f: case 0x1f: + case 0x7f: case 0x1f: DSP_SB2_ABOVE; LOG(LOG_SB,LOG_ERROR)("DSP:Unimplemented auto-init DMA ADPCM command %2X",sb.dsp.cmd); break; @@ -1158,10 +1163,15 @@ static void CTMIXER_Write(Bit8u val) { break; case 0x08: /* CDA Volume (SB2 Only) */ SETPROVOL(sb.mixer.cda,(val&0xf)|(val<<4)); + CTMIXER_UpdateVolumes(); break; case 0x0a: /* Mic Level (SBPRO) or DAC Volume (SB2): 2-bit, 3-bit on SB16 */ - if (sb.type==SBT_2) sb.mixer.dac[0]=sb.mixer.dac[1]=((val & 0x6) << 2)|3; - else sb.mixer.mic=((val & 0x7) << 2)|(sb.type==SBT_16?1:3); + if (sb.type==SBT_2) { + sb.mixer.dac[0]=sb.mixer.dac[1]=((val & 0x6) << 2)|3; + CTMIXER_UpdateVolumes(); + } else { + sb.mixer.mic=((val & 0x7) << 2)|(sb.type==SBT_16?1:3); + } break; case 0x0e: /* Output/Stereo Select */ sb.mixer.stereo=(val & 0x2) > 0; @@ -1179,6 +1189,7 @@ static void CTMIXER_Write(Bit8u val) { break; case 0x28: /* CD Audio Volume (SBPRO) */ SETPROVOL(sb.mixer.cda,val); + CTMIXER_UpdateVolumes(); break; case 0x2e: /* Line-in Volume (SBPRO) */ SETPROVOL(sb.mixer.lin,val); diff --git a/src/hardware/serialport/libserial.cpp b/src/hardware/serialport/libserial.cpp index e7631b1..138a0b6 100644 --- a/src/hardware/serialport/libserial.cpp +++ b/src/hardware/serialport/libserial.cpp @@ -197,7 +197,7 @@ int SERIAL_getextchar(COMPORT port) { char chRead; int retval = 0; - // receive a byte; TODO communicate faliure + // receive a byte; TODO communicate failure if (ReadFile (port->porthandle, &chRead, 1, &dwRead, NULL)) { if (dwRead) { // check for errors @@ -580,7 +580,7 @@ int SERIAL_getextchar(COMPORT port) { char chRead; int retval = 0; - // receive a byte; TODO communicate faliure + // receive a byte; TODO communicate failure if (DosRead(port->porthandle, &chRead, 1, &dwRead) == NO_ERROR) { if (dwRead) { // check for errors; will OS/2 clear the error on reading its data? diff --git a/src/hardware/serialport/nullmodem.cpp b/src/hardware/serialport/nullmodem.cpp index 9ecfbff..a3c1ace 100644 --- a/src/hardware/serialport/nullmodem.cpp +++ b/src/hardware/serialport/nullmodem.cpp @@ -52,87 +52,59 @@ CNullModem::CNullModem(Bitu id, CommandLine* cmd):CSerial (id, cmd) { // 1) when it is client connect to the server not immediately but // as soon as a modem-aware application is started (DTR is switched on). // 2) only receive data when DTR is on. - if(getBituSubstring("usedtr:", &bool_temp, cmd)) { - if(bool_temp==1) { + if (getBituSubstring("usedtr:", &bool_temp, cmd)) { + if (bool_temp==1) { dtrrespect=true; transparent=true; + DTR_delta=false; // connect immediately when DTR is already 1 } } // transparent: don't add additional handshake control. - if(getBituSubstring("transparent:", &bool_temp, cmd)) { - if(bool_temp==1) transparent=true; + if (getBituSubstring("transparent:", &bool_temp, cmd)) { + if (bool_temp==1) transparent=true; else transparent=false; } // telnet: interpret telnet commands. - if(getBituSubstring("telnet:", &bool_temp, cmd)) { - if(bool_temp==1) { + if (getBituSubstring("telnet:", &bool_temp, cmd)) { + if (bool_temp==1) { transparent=true; telnet=true; } } // rxdelay: How many milliseconds to wait before causing an // overflow when the application is unresponsive. - if(getBituSubstring("rxdelay:", &rx_retry_max, cmd)) { - if(!(rx_retry_max<=10000)) { + if (getBituSubstring("rxdelay:", &rx_retry_max, cmd)) { + if (!(rx_retry_max<=10000)) { rx_retry_max=50; } } // txdelay: How many milliseconds to wait before sending data. // This reduces network overhead quite a lot. - if(getBituSubstring("txdelay:", &tx_gather, cmd)) { - if(!(tx_gather<=500)) { + if (getBituSubstring("txdelay:", &tx_gather, cmd)) { + if (!(tx_gather<=500)) { tx_gather=12; } } // port is for both server and client - if(getBituSubstring("port:", &temptcpport, cmd)) { - if(!(temptcpport>0&&temptcpport<65536)) { + if (getBituSubstring("port:", &temptcpport, cmd)) { + if (!(temptcpport>0&&temptcpport<65536)) { temptcpport=23; } } - // socket inheritance - if(getBituSubstring("inhsocket:", &bool_temp, cmd)) { + // socket inheritance (client-alike) + if (getBituSubstring("inhsocket:", &bool_temp, cmd)) { #ifdef NATIVESOCKETS - if(Netwrapper_GetCapabilities()&NETWRAPPER_TCP_NATIVESOCKET) { - if(bool_temp==1) { + if (Netwrapper_GetCapabilities()&NETWRAPPER_TCP_NATIVESOCKET) { + if (bool_temp==1) { int sock; if (control->cmdline->FindInt("-socket",sock,true)) { dtrrespect=false; transparent=true; - // custom connect - Bit8u peernamebuf[16]; - LOG_MSG("inheritance port: %d",sock); - clientsocket = new TCPClientSocket(sock); - if(!clientsocket->isopen) { - LOG_MSG("Serial%d: Connection failed.",COMNUMBER); -#if SERIAL_DEBUG - log_ser(dbg_aux,"Nullmodem: Connection failed."); -#endif - delete clientsocket; - clientsocket=0; + LOG_MSG("Inheritance socket handle: %d",sock); + if (!ClientConnect(new TCPClientSocket(sock))) return; - } - clientsocket->SetSendBufferSize(256); - clientsocket->GetRemoteAddressString(peernamebuf); - // transmit the line status - if(!transparent) setRTSDTR(getRTS(), getDTR()); - - LOG_MSG("Serial%d: Connected to %s",COMNUMBER,peernamebuf); -#if SERIAL_DEBUG - log_ser(dbg_aux,"Nullmodem: Connected to %s",peernamebuf); -#endif - setEvent(SERIAL_POLLING_EVENT, 1); - - CSerial::Init_Registers (); - InstallationSuccessful = true; - - setCTS(true); - setDSR(true); - setRI (false); - setCD (true); - return; } else { - LOG_MSG("Serial%d: -socket start parameter missing.",COMNUMBER); + LOG_MSG("Serial%d: -socket parameter missing.",COMNUMBER); return; } } @@ -144,47 +116,44 @@ CNullModem::CNullModem(Bitu id, CommandLine* cmd):CSerial (id, cmd) { #else LOG_MSG("Serial%d: socket inheritance not available.", COMNUMBER); #endif - } - std::string tmpstring; - if(cmd->FindStringBegin("server:",tmpstring,false)) { - // we are a client - const char* hostnamechar=tmpstring.c_str(); - size_t hostlen=strlen(hostnamechar)+1; - if(hostlen>sizeof(hostnamebuffer)) { - hostlen=sizeof(hostnamebuffer); - hostnamebuffer[sizeof(hostnamebuffer)-1]=0; - } - memcpy(hostnamebuffer,hostnamechar,hostlen); - clientport=(Bit16u)temptcpport; - if(dtrrespect) { - // we connect as soon as DTR is switched on - setEvent(SERIAL_NULLMODEM_DTR_EVENT, 50); - LOG_MSG("Serial%d: Waiting for DTR...",COMNUMBER); - } else ClientConnect(); } else { - // we are a server - serverport = (Bit16u)temptcpport; - serversocket = new TCPServerSocket(serverport); - if(!serversocket->isopen) return; - LOG_MSG("Serial%d: Nullmodem server waiting for connection on port %d...", - COMNUMBER,serverport); - setEvent(SERIAL_SERVER_POLLING_EVENT, 50); + // normal server/client + std::string tmpstring; + if (cmd->FindStringBegin("server:",tmpstring,false)) { + // we are a client + const char* hostnamechar=tmpstring.c_str(); + size_t hostlen=strlen(hostnamechar)+1; + if (hostlen>sizeof(hostnamebuffer)) { + hostlen=sizeof(hostnamebuffer); + hostnamebuffer[sizeof(hostnamebuffer)-1]=0; + } + memcpy(hostnamebuffer,hostnamechar,hostlen); + clientport=(Bit16u)temptcpport; + if (dtrrespect) { + // we connect as soon as DTR is switched on + setEvent(SERIAL_NULLMODEM_DTR_EVENT, 50); + LOG_MSG("Serial%d: Waiting for DTR...",COMNUMBER); + } else if (!ClientConnect( + new TCPClientSocket((char*)hostnamebuffer,(Bit16u)clientport))) + return; + } else { + // we are a server + serverport = (Bit16u)temptcpport; + if (!ServerListen()) return; + } } - - // .... - - CSerial::Init_Registers (); + CSerial::Init_Registers(); InstallationSuccessful = true; setCTS(dtrrespect||transparent); setDSR(dtrrespect||transparent); - setRI (false); - setCD (dtrrespect); + setRI(false); + setCD(clientsocket > 0); // CD on if connection established } -CNullModem::~CNullModem () { - if(serversocket) delete serversocket; - if(clientsocket) delete clientsocket; +CNullModem::~CNullModem() { + if (serversocket) delete serversocket; + if (clientsocket) delete clientsocket; // remove events for(Bit16u i = SERIAL_BASE_EVENT_COUNT+1; i <= SERIAL_NULLMODEM_EVENT_COUNT; i++) { @@ -193,9 +162,8 @@ CNullModem::~CNullModem () { } void CNullModem::WriteChar(Bit8u data) { - - if(clientsocket)clientsocket->SendByteBuffered(data); - if(!tx_block) { + if (clientsocket)clientsocket->SendByteBuffered(data); + if (!tx_block) { //LOG_MSG("setevreduct"); setEvent(SERIAL_TX_REDUCTION, (float)tx_gather); tx_block=true; @@ -203,37 +171,75 @@ void CNullModem::WriteChar(Bit8u data) { } Bits CNullModem::readChar() { - Bits rxchar = clientsocket->GetcharNonBlock(); - if(telnet && rxchar>=0) return TelnetEmulation((Bit8u)rxchar); - else if(rxchar==0xff && !transparent) {// escape char + if (telnet && rxchar>=0) return TelnetEmulation((Bit8u)rxchar); + else if (rxchar==0xff && !transparent) {// escape char // get the next char Bits rxchar = clientsocket->GetcharNonBlock(); - if(rxchar==0xff) return rxchar; // 0xff 0xff -> 0xff was meant + if (rxchar==0xff) return rxchar; // 0xff 0xff -> 0xff was meant rxchar&0x1? setCTS(true) : setCTS(false); rxchar&0x2? setDSR(true) : setDSR(false); - if(rxchar&0x4) receiveByteEx(0x0,0x10); + if (rxchar&0x4) receiveByteEx(0x0,0x10); return -1; // no "payload" received } else return rxchar; } -void CNullModem::ClientConnect(){ +bool CNullModem::ClientConnect(TCPClientSocket* newsocket) { Bit8u peernamebuf[16]; - clientsocket = new TCPClientSocket((char*)hostnamebuffer, - (Bit16u)clientport); - if(!clientsocket->isopen) { - LOG_MSG("Serial%d: Connection failed.",idnumber+1); + clientsocket = newsocket; + + if (!clientsocket->isopen) { + LOG_MSG("Serial%d: Connection failed.",COMNUMBER); delete clientsocket; clientsocket=0; - return; + setCD(false); + return false; } clientsocket->SetSendBufferSize(256); clientsocket->GetRemoteAddressString(peernamebuf); // transmit the line status - if(!transparent) setRTSDTR(getRTS(), getDTR()); + if (!transparent) setRTSDTR(getRTS(), getDTR()); rx_state=N_RX_IDLE; - LOG_MSG("Serial%d: Connected to %s",idnumber+1,peernamebuf); + LOG_MSG("Serial%d: Connected to %s",COMNUMBER,peernamebuf); setEvent(SERIAL_POLLING_EVENT, 1); + setCD(true); + return true; +} + +bool CNullModem::ServerListen() { + // Start the server listen port. + serversocket = new TCPServerSocket(serverport); + if (!serversocket->isopen) return false; + LOG_MSG("Serial%d: Nullmodem server waiting for connection on port %d...", + COMNUMBER,serverport); + setEvent(SERIAL_SERVER_POLLING_EVENT, 50); + setCD(false); + return true; +} + +bool CNullModem::ServerConnect() { + // check if a connection is available. + clientsocket=serversocket->Accept(); + if (!clientsocket) return false; + + Bit8u peeripbuf[16]; + clientsocket->GetRemoteAddressString(peeripbuf); + LOG_MSG("Serial%d: A client (%s) has connected.",COMNUMBER,peeripbuf); +#if SERIAL_DEBUG + log_ser(dbg_aux,"Nullmodem: A client (%s) has connected.", peeripbuf); +#endif + clientsocket->SetSendBufferSize(256); + rx_state=N_RX_IDLE; + setEvent(SERIAL_POLLING_EVENT, 1); + + // we don't accept further connections + delete serversocket; + serversocket=0; + + // transmit the line status + setRTSDTR(getRTS(), getDTR()); + if (transparent) setCD(true); + return true; } void CNullModem::Disconnect() { @@ -245,11 +251,16 @@ void CNullModem::Disconnect() { clientsocket=0; setDSR(false); setCTS(false); - if(serverport) { + setCD(false); + + if (serverport) { serversocket = new TCPServerSocket(serverport); - if(serversocket->isopen) + if (serversocket->isopen) setEvent(SERIAL_SERVER_POLLING_EVENT, 50); else delete serversocket; + } else if (dtrrespect) { + setEvent(SERIAL_NULLMODEM_DTR_EVENT,50); + DTR_delta = getDTR(); // try to reconnect the next time DTR is set } } @@ -264,8 +275,8 @@ void CNullModem::handleUpperEvent(Bit16u type) { updateMSR(); switch(rx_state) { case N_RX_IDLE: - if(CanReceiveByte()) { - if(doReceive()) { + if (CanReceiveByte()) { + if (doReceive()) { // a byte was received rx_state=N_RX_WAIT; setEvent(SERIAL_RX_EVENT, bytetime*0.9f); @@ -281,13 +292,13 @@ void CNullModem::handleUpperEvent(Bit16u type) { break; case N_RX_BLOCKED: // one timeout tick - if(!CanReceiveByte()) { + if (!CanReceiveByte()) { rx_retry++; - if(rx_retry>=rx_retry_max) { + if (rx_retry>=rx_retry_max) { // it has timed out: rx_retry=0; removeEvent(SERIAL_RX_EVENT); - if(doReceive()) { + if (doReceive()) { // read away everything while(doReceive()); rx_state=N_RX_WAIT; @@ -304,7 +315,7 @@ void CNullModem::handleUpperEvent(Bit16u type) { // good: we can receive again removeEvent(SERIAL_RX_EVENT); rx_retry=0; - if(doReceive()) { + if (doReceive()) { rx_state=N_RX_FASTWAIT; setEvent(SERIAL_RX_EVENT, bytetime*0.65f); } else { @@ -329,11 +340,11 @@ void CNullModem::handleUpperEvent(Bit16u type) { case N_RX_BLOCKED: // try to receive case N_RX_WAIT: case N_RX_FASTWAIT: - if(CanReceiveByte()) { + if (CanReceiveByte()) { // just works or unblocked - if(doReceive()) { + if (doReceive()) { rx_retry=0; // not waiting anymore - if(rx_state==N_RX_WAIT) setEvent(SERIAL_RX_EVENT, bytetime*0.9f); + if (rx_state==N_RX_WAIT) setEvent(SERIAL_RX_EVENT, bytetime*0.9f); else { // maybe unblocked rx_state=N_RX_FASTWAIT; @@ -347,7 +358,7 @@ void CNullModem::handleUpperEvent(Bit16u type) { } else { // blocking now or still blocked #if SERIAL_DEBUG - if(rx_state==N_RX_BLOCKED) + if (rx_state==N_RX_BLOCKED) log_ser(dbg_aux,"Nullmodem: rx still blocked (retry=%d)",rx_retry); else log_ser(dbg_aux,"Nullmodem: block on continued rx (retry=%d).",rx_retry); #endif @@ -361,8 +372,8 @@ void CNullModem::handleUpperEvent(Bit16u type) { } case SERIAL_TX_EVENT: { // Maybe echo cirquit works a bit better this way - if(rx_state==N_RX_IDLE && CanReceiveByte() && clientsocket) { - if(doReceive()) { + if (rx_state==N_RX_IDLE && CanReceiveByte() && clientsocket) { + if (doReceive()) { // a byte was received rx_state=N_RX_WAIT; setEvent(SERIAL_RX_EVENT, bytetime*0.9f); @@ -380,25 +391,7 @@ void CNullModem::handleUpperEvent(Bit16u type) { case SERIAL_SERVER_POLLING_EVENT: { // As long as nothing is connected to our server poll the // connection. - clientsocket=serversocket->Accept(); - if(clientsocket) { - Bit8u peeripbuf[16]; - clientsocket->GetRemoteAddressString(peeripbuf); - LOG_MSG("Serial%d: A client (%s) has connected.",COMNUMBER,peeripbuf); -#if SERIAL_DEBUG - log_ser(dbg_aux,"Nullmodem: A client (%s) has connected.", peeripbuf); -#endif// new socket found... - clientsocket->SetSendBufferSize(256); - rx_state=N_RX_IDLE; - setEvent(SERIAL_POLLING_EVENT, 1); - - // we don't accept further connections - delete serversocket; - serversocket=0; - - // transmit the line status - setRTSDTR(getRTS(), getDTR()); - } else { + if (!ServerConnect()) { // continue looking setEvent(SERIAL_SERVER_POLLING_EVENT, 50); } @@ -406,13 +399,19 @@ void CNullModem::handleUpperEvent(Bit16u type) { } case SERIAL_TX_REDUCTION: { // Flush the data in the transmitting buffer. - if(clientsocket) clientsocket->FlushBuffer(); + if (clientsocket) clientsocket->FlushBuffer(); tx_block=false; break; } case SERIAL_NULLMODEM_DTR_EVENT: { - if(getDTR()) ClientConnect(); - else setEvent(SERIAL_NULLMODEM_DTR_EVENT,50); + if ((!DTR_delta) && getDTR()) { + // DTR went positive. Try to connect. + if (ClientConnect(new TCPClientSocket((char*)hostnamebuffer, + (Bit16u)clientport))) + break; // no more DTR wait event when connected + } + DTR_delta = getDTR(); + setEvent(SERIAL_NULLMODEM_DTR_EVENT,50); break; } } @@ -432,11 +431,11 @@ void CNullModem::updateMSR () { bool CNullModem::doReceive () { Bits rxchar = readChar(); - if(rxchar>=0) { + if (rxchar>=0) { receiveByteEx((Bit8u)rxchar,0); return true; } - else if(rxchar==-2) { + else if (rxchar==-2) { Disconnect(); } return false; @@ -444,7 +443,7 @@ bool CNullModem::doReceive () { void CNullModem::transmitByte (Bit8u val, bool first) { // transmit it later in THR_Event - if(first) setEvent(SERIAL_THR_EVENT, bytetime/8); + if (first) setEvent(SERIAL_THR_EVENT, bytetime/8); else setEvent(SERIAL_TX_EVENT, bytetime); // disable 0xff escaping when transparent mode is enabled @@ -455,73 +454,73 @@ void CNullModem::transmitByte (Bit8u val, bool first) { Bits CNullModem::TelnetEmulation(Bit8u data) { Bit8u response[3]; - if(telClient.inIAC) { - if(telClient.recCommand) { - if((data != 0) && (data != 1) && (data != 3)) { + if (telClient.inIAC) { + if (telClient.recCommand) { + if ((data != 0) && (data != 1) && (data != 3)) { LOG_MSG("Serial%d: Unrecognized telnet option %d",COMNUMBER, data); - if(telClient.command>250) { + if (telClient.command>250) { /* Reject anything we don't recognize */ response[0]=0xff; response[1]=252; response[2]=data; /* We won't do crap! */ - if(clientsocket) clientsocket->SendArray(response, 3); + if (clientsocket) clientsocket->SendArray(response, 3); } } switch(telClient.command) { case 251: /* Will */ - if(data == 0) telClient.binary[TEL_SERVER] = true; - if(data == 1) telClient.echo[TEL_SERVER] = true; - if(data == 3) telClient.supressGA[TEL_SERVER] = true; + if (data == 0) telClient.binary[TEL_SERVER] = true; + if (data == 1) telClient.echo[TEL_SERVER] = true; + if (data == 3) telClient.supressGA[TEL_SERVER] = true; break; case 252: /* Won't */ - if(data == 0) telClient.binary[TEL_SERVER] = false; - if(data == 1) telClient.echo[TEL_SERVER] = false; - if(data == 3) telClient.supressGA[TEL_SERVER] = false; + if (data == 0) telClient.binary[TEL_SERVER] = false; + if (data == 1) telClient.echo[TEL_SERVER] = false; + if (data == 3) telClient.supressGA[TEL_SERVER] = false; break; case 253: /* Do */ - if(data == 0) { + if (data == 0) { telClient.binary[TEL_CLIENT] = true; response[0]=0xff; response[1]=251; response[2]=0; /* Will do binary transfer */ - if(clientsocket) clientsocket->SendArray(response, 3); + if (clientsocket) clientsocket->SendArray(response, 3); } - if(data == 1) { + if (data == 1) { telClient.echo[TEL_CLIENT] = false; response[0]=0xff; response[1]=252; response[2]=1; /* Won't echo (too lazy) */ - if(clientsocket) clientsocket->SendArray(response, 3); + if (clientsocket) clientsocket->SendArray(response, 3); } - if(data == 3) { + if (data == 3) { telClient.supressGA[TEL_CLIENT] = true; response[0]=0xff; response[1]=251; response[2]=3; /* Will Suppress GA */ - if(clientsocket) clientsocket->SendArray(response, 3); + if (clientsocket) clientsocket->SendArray(response, 3); } break; case 254: /* Don't */ - if(data == 0) { + if (data == 0) { telClient.binary[TEL_CLIENT] = false; response[0]=0xff; response[1]=252; response[2]=0; /* Won't do binary transfer */ - if(clientsocket) clientsocket->SendArray(response, 3); + if (clientsocket) clientsocket->SendArray(response, 3); } - if(data == 1) { + if (data == 1) { telClient.echo[TEL_CLIENT] = false; response[0]=0xff; response[1]=252; response[2]=1; /* Won't echo (fine by me) */ - if(clientsocket) clientsocket->SendArray(response, 3); + if (clientsocket) clientsocket->SendArray(response, 3); } - if(data == 3) { + if (data == 3) { telClient.supressGA[TEL_CLIENT] = true; response[0]=0xff; response[1]=251; response[2]=3; /* Will Suppress GA (too lazy) */ - if(clientsocket) clientsocket->SendArray(response, 3); + if (clientsocket) clientsocket->SendArray(response, 3); } break; default: @@ -532,7 +531,7 @@ Bits CNullModem::TelnetEmulation(Bit8u data) { telClient.recCommand = false; return -1; //continue; } else { - if(data==249) { + if (data==249) { /* Go Ahead received */ telClient.inIAC = false; return -1; //continue; @@ -540,7 +539,7 @@ Bits CNullModem::TelnetEmulation(Bit8u data) { telClient.command = data; telClient.recCommand = true; - if((telClient.binary[TEL_SERVER]) && (data == 0xff)) { + if ((telClient.binary[TEL_SERVER]) && (data == 0xff)) { /* Binary data with value of 255 */ telClient.inIAC = false; telClient.recCommand = false; @@ -548,7 +547,7 @@ Bits CNullModem::TelnetEmulation(Bit8u data) { } } } else { - if(data == 0xff) { + if (data == 0xff) { telClient.inIAC = true; return -1; } @@ -570,14 +569,14 @@ void CNullModem::setBreak (bool /*value*/) { /* updateModemControlLines(mcr) sets DTR and RTS. **/ /*****************************************************************************/ void CNullModem::setRTSDTR(bool xrts, bool xdtr) { - if(!transparent) { + if (!transparent) { Bit8u control[2]; control[0]=0xff; control[1]=0x0; - if(xrts) control[1]|=1; - if(xdtr) control[1]|=2; - if(LCR&LCR_BREAK_MASK) control[1]|=4; - if(clientsocket) clientsocket->SendArray(control, 2); + if (xrts) control[1]|=1; + if (xdtr) control[1]|=2; + if (LCR&LCR_BREAK_MASK) control[1]|=4; + if (clientsocket) clientsocket->SendArray(control, 2); } } void CNullModem::setRTS(bool val) { diff --git a/src/hardware/serialport/nullmodem.h b/src/hardware/serialport/nullmodem.h index d8510a8..afa41ac 100644 --- a/src/hardware/serialport/nullmodem.h +++ b/src/hardware/serialport/nullmodem.h @@ -35,16 +35,8 @@ class CNullModem : public CSerial { public: - TCPServerSocket* serversocket; - TCPClientSocket* clientsocket; - CNullModem(Bitu id, CommandLine* cmd); ~CNullModem(); - bool receiveblock; // It's not a block of data it rather blocks - Bit16u serverport; // we are a server if this is nonzero - Bit16u clientport; - - Bit8u hostnamebuffer[128]; // the name passed to us by the user void updatePortConfig(Bit16u divider, Bit8u lcr); void updateMSR(); @@ -56,6 +48,16 @@ public: void setDTR(bool val); void handleUpperEvent(Bit16u type); +private: + TCPServerSocket* serversocket; + TCPClientSocket* clientsocket; + + bool receiveblock; // It's not a block of data it rather blocks + Bit16u serverport; // we are a server if this is nonzero + Bit16u clientport; + + Bit8u hostnamebuffer[128]; // the name passed to us by the user + Bitu rx_state; #define N_RX_IDLE 0 #define N_RX_WAIT 1 @@ -64,11 +66,17 @@ public: #define N_RX_DISC 4 bool doReceive(); - void ClientConnect(); + bool ClientConnect(TCPClientSocket* newsocket); + bool ServerListen(); + bool ServerConnect(); void Disconnect(); Bits readChar(); void WriteChar(Bit8u data); + bool DTR_delta; // with dtrrespect, we try to establish a connection + // whenever DTR switches to 1. This variable is + // used to remember the old state. + bool tx_block; // true while the SERIAL_TX_REDUCTION event // is pending diff --git a/src/hardware/serialport/serialport.cpp b/src/hardware/serialport/serialport.cpp index 2788029..d3b0911 100644 --- a/src/hardware/serialport/serialport.cpp +++ b/src/hardware/serialport/serialport.cpp @@ -223,7 +223,8 @@ void CSerial::changeLineProperties() { else bitlen = (1000.0f/115200.0f)*(float)baud_divider; bytetime=bitlen*(float)(1+5+1); // startbit + minimum length + stopbit bytetime+= bitlen*(float)(LCR&0x3); // databits - if(LCR&0x4) bytetime+=bitlen; // stopbit + if(LCR&0x4) bytetime+=bitlen; // 2nd stopbit + if(LCR&0x8) bytetime+=bitlen; // parity #if SERIAL_DEBUG const char* const dbgtext[]={"none","odd","none","even","none","mark","none","space"}; diff --git a/src/hardware/vga_draw.cpp b/src/hardware/vga_draw.cpp index c63b843..2c2debe 100644 --- a/src/hardware/vga_draw.cpp +++ b/src/hardware/vga_draw.cpp @@ -77,20 +77,20 @@ static Bitu temp[643]={0}; static Bit8u * VGA_Draw_CGA16_Line(Bitu vidstart, Bitu line) { const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift); - const Bit8u *reader = base + vidstart; +#define CGA16_READER(OFF) (base[(vidstart +(OFF))& (8*1024 -1)]) Bit32u * draw=(Bit32u *)TempLine; //Generate a temporary bitline to calculate the avarage //over bit-2 bit-1 bit bit+1. //Combine this number with the current colour to get - //an unigue index in the pallete. Or it with bit 7 as they are stored + //an unique index in the pallette. Or it with bit 7 as they are stored //in the upperpart to keep them from interfering the regular cga stuff for(Bitu x = 0; x < 640; x++) - temp[x+2] = (( reader[(x>>3)] >> (7-(x&7)) )&1) << 4; + temp[x+2] = (( CGA16_READER(x>>3)>> (7-(x&7)) )&1) << 4; //shift 4 as that is for the index. Bitu i = 0,temp1,temp2,temp3,temp4; for (Bitu x=0;x>= 4; @@ -113,6 +113,7 @@ static Bit8u * VGA_Draw_CGA16_Line(Bitu vidstart, Bitu line) { ((temp4|val2) <<24); } return TempLine; +#undef CGA16_READER } static Bit8u * VGA_Draw_4BPP_Line(Bitu vidstart, Bitu line) { @@ -824,7 +825,7 @@ static void VGA_VerticalTimer(Bitu /*val*/) { break; } //Check if we can actually render, else skip the rest (frameskip) - if (!RENDER_StartUpdate()) + if (vga.draw.vga_override || !RENDER_StartUpdate()) return; vga.draw.address_line = vga.config.hlines_skip; @@ -1556,7 +1557,9 @@ void VGA_SetupDrawing(Bitu /*val*/) { LOG(LOG_VGA,LOG_NORMAL)("%s width, %s height aspect %f", doublewidth ? "double":"normal",doubleheight ? "double":"normal",aspect_ratio); #endif - RENDER_SetSize(width,height,bpp,(float)fps,aspect_ratio,doublewidth,doubleheight); + if (!vga.draw.vga_override) + RENDER_SetSize(width, height, bpp, (float)fps, aspect_ratio, + doublewidth, doubleheight); } } @@ -1566,5 +1569,19 @@ void VGA_KillDrawing(void) { PIC_RemoveEvents(VGA_DrawEGASingleLine); vga.draw.parts_left = 0; vga.draw.lines_done = ~0; - RENDER_EndUpdate(true); + if (!vga.draw.vga_override) RENDER_EndUpdate(true); +} + +void VGA_SetOverride(bool vga_override) { + if (vga.draw.vga_override!=vga_override) { + + if (vga_override) { + VGA_KillDrawing(); + vga.draw.vga_override=true; + } else { + vga.draw.vga_override=false; + vga.draw.width=0; // change it so the output window gets updated + VGA_SetupDrawing(0); + } + } } diff --git a/src/hardware/vga_memory.cpp b/src/hardware/vga_memory.cpp index 67adbd1..08e496c 100644 --- a/src/hardware/vga_memory.cpp +++ b/src/hardware/vga_memory.cpp @@ -700,6 +700,7 @@ public: // |PFLAG_NOCODE; } HostPt GetHostReadPt(Bitu phys_page) { + // Odd banks are limited to 16kB and repeated if (vga.tandy.mem_bank & 1) phys_page&=0x03; else @@ -719,9 +720,9 @@ public: } HostPt GetHostReadPt(Bitu phys_page) { phys_page-=0xb8; - //test for a unaliged bank, then replicate 2x16kb - if (vga.tandy.mem_bank & 1) - phys_page&=0x03; + // The 16kB map area is repeated in the 32kB range + // On CGA CPU A14 is not decoded so it repeats there too + phys_page&=0x03; return vga.tandy.mem_base + (phys_page * 4096); } HostPt GetHostWritePt(Bitu phys_page) { diff --git a/src/hardware/vga_other.cpp b/src/hardware/vga_other.cpp index a5b3856..b6c56d0 100644 --- a/src/hardware/vga_other.cpp +++ b/src/hardware/vga_other.cpp @@ -83,7 +83,9 @@ static void write_crtc_data_other(Bitu /*port*/,Bitu val,Bitu /*iolen*/) { vga.draw.cursor.eline = (Bit8u)(val&0x1f); break; case 0x0C: /* Start Address High Register */ - vga.config.display_start=(vga.config.display_start & 0x00FF) | (val << 8); + // Bit 12 (depending on video mode) and 13 are actually masked too, + // but so far no need to implement it. + vga.config.display_start=(vga.config.display_start & 0x00FF) | ((val&0x3F) << 8); break; case 0x0D: /* Start Address Low Register */ vga.config.display_start=(vga.config.display_start & 0xFF00) | val; @@ -491,10 +493,18 @@ static void write_tandy(Bitu port,Bitu val,Bitu /*iolen*/) { write_tandy_reg((Bit8u)val); break; case 0x3df: + // CRT/processor page register + // See the comments on the PCJr version of this register. + // A difference to it is: + // Bit 3-5: Processor page CPU_PG + // The remapped range is 32kB instead of 16. Therefore CPU_PG bit 0 + // appears to be ORed with CPU A14 (to preserve some sort of + // backwards compatibility?), resulting in odd pages being mapped + // as 2x16kB. Implemeted in vga_memory.cpp Tandy handler. + vga.tandy.line_mask = (Bit8u)(val >> 6); vga.tandy.draw_bank = val & ((vga.tandy.line_mask&2) ? 0x6 : 0x7); - if(vga.tandy.line_mask==3) vga.tandy.draw_bank &= ~1; // LSB unused in 32k modes - vga.tandy.mem_bank = (val >> 3) & ((vga.tandy.line_mask&2) ? 0x6 : 0x7); + vga.tandy.mem_bank = (val >> 3) & 7; TandyCheckLineMask(); VGA_SetupHandlers(); break; @@ -514,9 +524,38 @@ static void write_pcjr(Bitu port,Bitu val,Bitu /*iolen*/) { vga.tandy.pcjr_flipflop=!vga.tandy.pcjr_flipflop; break; case 0x3df: + // CRT/processor page register + + // Bit 0-2: CRT page PG0-2 + // In one- and two bank modes, bit 0-2 select the 16kB memory + // area of system RAM that is displayed on the screen. + // In 4-banked modes, bit 1-2 select the 32kB memory area. + // Bit 2 only has effect when the PCJR upgrade to 128k is installed. + + // Bit 3-5: Processor page CPU_PG + // Selects the 16kB area of system RAM that is mapped to + // the B8000h IBM PC video memory window. Since A14-A16 of the + // processor are unconditionally replaced with these bits when + // B8000h is accessed, the 16kB area is mapped to the 32kB + // range twice in a row. (Scuba Venture writes across the boundary) + + // Bit 6-7: Video Address mode + // 0: CRTC addresses A0-12 directly, accessing 8k characters + // (+8k attributes). Used in text modes (one bank). + // PG0-2 in effect. 16k range. + // 1: CRTC A12 is replaced with CRTC RA0 (see max_scanline). + // This results in the even/odd scanline two bank system. + // PG0-2 in effect. 16k range. + // 2: Documented as unused. CRTC addresses A0-12, PG0 is replaced + // with RA1. Looks like nonsense. + // PG1-2 in effect. 32k range which cannot be used completely. + // 3: CRTC A12 is replaced with CRTC RA0, PG0 is replaced with + // CRTC RA1. This results in the 4-bank mode. + // PG1-2 in effect. 32k range. + vga.tandy.line_mask = (Bit8u)(val >> 6); vga.tandy.draw_bank = val & ((vga.tandy.line_mask&2) ? 0x6 : 0x7); - vga.tandy.mem_bank = (val >> 3) & ((vga.tandy.line_mask&2) ? 0x6 : 0x7); + vga.tandy.mem_bank = (val >> 3) & 7; vga.tandy.draw_base = &MemBase[vga.tandy.draw_bank * 16 * 1024]; vga.tandy.mem_base = &MemBase[vga.tandy.mem_bank * 16 * 1024]; TandyCheckLineMask(); @@ -674,6 +713,9 @@ void VGA_SetupOther(void) { write_pcjr( 0x3df, 0x7 | (0x7 << 3), 0 ); IO_RegisterWriteHandler(0x3da,write_pcjr,IO_MB); IO_RegisterWriteHandler(0x3df,write_pcjr,IO_MB); + // additional CRTC access documented + IO_RegisterWriteHandler(0x3d0,write_crtc_index_other,IO_MB); + IO_RegisterWriteHandler(0x3d1,write_crtc_data_other,IO_MB); } if (machine==MCH_HERC) { Bitu base=0x3b0; diff --git a/src/hardware/vga_s3.cpp b/src/hardware/vga_s3.cpp index 63eddbd..01ffff0 100644 --- a/src/hardware/vga_s3.cpp +++ b/src/hardware/vga_s3.cpp @@ -341,7 +341,7 @@ void SVGA_S3_WriteCRTC(Bitu reg,Bitu val,Bitu iolen) { vga.svga.bank_write = vga.svga.bank_read; VGA_SetupHandlers(); break; - case 0x6b: // BIOS scratchpad: LFB adress + case 0x6b: // BIOS scratchpad: LFB address vga.s3.reg_6b=(Bit8u)val; break; default: diff --git a/src/ints/bios.cpp b/src/ints/bios.cpp index 22219d5..804c07a 100644 --- a/src/ints/bios.cpp +++ b/src/ints/bios.cpp @@ -38,7 +38,6 @@ #include #endif - /* if mem_systems 0 then size_extended is reported as the real size else * zero is reported. ems and xms can increase or decrease the other_memsystems * counter using the BIOS_ZeroExtendedSize call */ @@ -850,6 +849,7 @@ static Bitu INT15_Handler(void) { CALLBACK_Idle(); } CALLBACK_SCF(false); + break; } case 0x87: /* Copy extended memory */ { diff --git a/src/ints/bios_disk.cpp b/src/ints/bios_disk.cpp index a298256..ef0cdae 100644 --- a/src/ints/bios_disk.cpp +++ b/src/ints/bios_disk.cpp @@ -85,13 +85,26 @@ void updateDPT(void) { } } +void incrementFDD(void) { + Bit16u equipment=mem_readw(BIOS_CONFIGURATION); + if(equipment&1) { + Bitu numofdisks = (equipment>>6)&3; + numofdisks++; + if(numofdisks > 1) numofdisks=1;//max 2 floppies at the moment + equipment&=~0x00C0; + equipment|=(numofdisks<<6); + } else equipment|=1; + mem_writew(BIOS_CONFIGURATION,equipment); + CMOS_SetRegister(0x14, (Bit8u)(equipment&0xff)); +} + void swapInDisks(void) { bool allNull = true; Bits diskcount = 0; Bits swapPos = swapPosition; int i; - /* Check to make sure there's atleast one setup image */ + /* Check to make sure that there is at least one setup image */ for(i=0;i>6)&3; - numofdisks++; - if(numofdisks > 1) numofdisks=1;//max 2 floppies at the moment - equipment&=~0x00C0; - equipment|=(numofdisks<<6); - } else equipment|=1; - mem_writew(BIOS_CONFIGURATION,equipment); - CMOS_SetRegister(0x14, (Bit8u)(equipment&0xff)); + incrementFDD(); } } } @@ -329,12 +333,14 @@ static Bitu INT13_DiskHandler(void) { if ((machine==MCH_CGA) || (machine==MCH_PCJR)) { /* those bioses call floppy drive reset for invalid drive values */ if (((imageDiskList[0]) && (imageDiskList[0]->active)) || ((imageDiskList[1]) && (imageDiskList[1]->active))) { + if (reg_dl<0x80) reg_ip++; last_status = 0x00; CALLBACK_SCF(false); } } return CBRET_NONE; } + if (reg_dl<0x80) reg_ip++; last_status = 0x00; CALLBACK_SCF(false); } @@ -496,7 +502,7 @@ static Bitu INT13_DiskHandler(void) { void BIOS_SetupDisks(void) { /* TODO Start the time correctly */ call_int13=CALLBACK_Allocate(); - CALLBACK_Setup(call_int13,&INT13_DiskHandler,CB_IRET,"Int 13 Bios disk"); + CALLBACK_Setup(call_int13,&INT13_DiskHandler,CB_INT13,"Int 13 Bios disk"); RealSetVec(0x13,CALLBACK_RealPointer(call_int13)); int i; for(i=0;i<4;i++) { diff --git a/src/ints/bios_keyboard.cpp b/src/ints/bios_keyboard.cpp index 146668e..1e263d9 100644 --- a/src/ints/bios_keyboard.cpp +++ b/src/ints/bios_keyboard.cpp @@ -382,7 +382,7 @@ static Bitu IRQ1_Handler(void) { add_key(scan_to_scanascii[scancode].normal+0x5000); } else if (flags1 &0x04) { add_key((scan_to_scanascii[scancode].control&0xff00)|0xe0); - } else if( ((flags1 &0x3) != 0) || ((flags1 &0x20) != 0) ) { + } else if( ((flags1 &0x3) != 0) || ((flags1 &0x20) != 0) ) { //Due to |0xe0 results are identical. add_key((scan_to_scanascii[scancode].shift&0xff00)|0xe0); } else add_key((scan_to_scanascii[scancode].normal&0xff00)|0xe0); break; @@ -393,7 +393,7 @@ static Bitu IRQ1_Handler(void) { mem_writeb(BIOS_KEYBOARD_TOKEN,token); } else if (flags1 &0x04) { add_key(scan_to_scanascii[scancode].control); - } else if( ((flags1 &0x3) != 0) || ((flags1 &0x20) != 0) ) { + } else if( ((flags1 &0x3) != 0) ^ ((flags1 &0x20) != 0) ) { //Xor shift and numlock (both means off) add_key(scan_to_scanascii[scancode].shift); } else add_key(scan_to_scanascii[scancode].normal); break; @@ -546,7 +546,7 @@ static Bitu INT16_Handler(void) { reg_ax=temp; } break; - case 0x02: /* GET SHIFT FlAGS */ + case 0x02: /* GET SHIFT FLAGS */ reg_al=mem_readb(BIOS_KEYBOARD_FLAGS1); break; case 0x03: /* SET TYPEMATIC RATE AND DELAY */ @@ -594,7 +594,7 @@ static void InitBiosSegment(void) { mem_writew(BIOS_KEYBOARD_BUFFER_HEAD,0x1e); mem_writew(BIOS_KEYBOARD_BUFFER_TAIL,0x1e); Bit8u flag1 = 0; - Bit8u leds = 16; /* Ack recieved */ + Bit8u leds = 16; /* Ack received */ #if SDL_VERSION_ATLEAST(1, 2, 14) //Nothing, mapper handles all. diff --git a/src/ints/ems.cpp b/src/ints/ems.cpp index fc43193..a941f8b 100644 --- a/src/ints/ems.cpp +++ b/src/ints/ems.cpp @@ -489,7 +489,7 @@ static Bit8u EMM_PartialPageMapping(void) { mem_writew(data,segment);data+=2; MEM_BlockWrite(data,&emm_mappings[page],sizeof(EMM_Mapping)); data+=sizeof(EMM_Mapping); - } else if (((segment>=EMM_PAGEFRAME-0x1000) && (segment=0xa000) && (segment<0xb000))) { + } else if ((ems_type==1) || (ems_type==3) || ((segment>=EMM_PAGEFRAME-0x1000) && (segment=0xa000) && (segment<0xb000))) { mem_writew(data,segment);data+=2; MEM_BlockWrite(data,&emm_segmentmappings[segment>>10],sizeof(EMM_Mapping)); data+=sizeof(EMM_Mapping); @@ -506,7 +506,7 @@ static Bit8u EMM_PartialPageMapping(void) { if ((segment>=EMM_PAGEFRAME) && (segment>4); MEM_BlockRead(data,&emm_mappings[page],sizeof(EMM_Mapping)); - } else if (((segment>=EMM_PAGEFRAME-0x1000) && (segment=0xa000) && (segment<0xb000))) { + } else if ((ems_type==1) || (ems_type==3) || ((segment>=EMM_PAGEFRAME-0x1000) && (segment=0xa000) && (segment<0xb000))) { MEM_BlockRead(data,&emm_segmentmappings[segment>>10],sizeof(EMM_Mapping)); } else { return EMM_ILL_PHYS; @@ -1079,7 +1079,7 @@ static Bitu V86_Monitor() { reg_esp+=6; // skip ip of CALL and error code of EXCEPTION 0x0d - /* Get adress of faulting instruction */ + /* Get address of faulting instruction */ Bit16u v86_cs=mem_readw(SegPhys(ss)+((reg_esp+4) & cpu.stack.mask)); Bit16u v86_ip=mem_readw(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask)); Bit8u v86_opcode=mem_readb((v86_cs<<4)+v86_ip); diff --git a/src/ints/int10.cpp b/src/ints/int10.cpp index f60f3a2..679fd15 100644 --- a/src/ints/int10.cpp +++ b/src/ints/int10.cpp @@ -375,7 +375,7 @@ graphics_chars: reg_al=0x12; break; } - case 0x32: /* Video adressing */ + case 0x32: /* Video addressing */ if (!IS_VGA_ARCH) break; LOG(LOG_INT10,LOG_ERROR)("Function 12:Call %2X not handled",reg_bl); if (svgaCard==SVGA_TsengET4K) reg_al&=1; diff --git a/src/ints/int10_memory.cpp b/src/ints/int10_memory.cpp index efe3d3f..5b6d9b8 100644 --- a/src/ints/int10_memory.cpp +++ b/src/ints/int10_memory.cpp @@ -49,7 +49,7 @@ void INT10_LoadFont(PhysPt font,bool reload,Bitu count,Bitu offset,Bitu map,Bitu PhysPt ftwhere=PhysMake(0xa000,map_offset[map & 0x7]+(Bit16u)(offset*32)); IO_Write(0x3c4,0x2);IO_Write(0x3c5,0x4); //Enable plane 2 IO_Write(0x3ce,0x6);Bitu old_6=IO_Read(0x3cf); - IO_Write(0x3cf,0x0); //Disable odd/even and a0000 adressing + IO_Write(0x3cf,0x0); //Disable odd/even and a0000 addressing for (Bitu i=0;imode <= 3) diff --git a/src/ints/mouse.cpp b/src/ints/mouse.cpp index 8e6f30f..357c777 100644 --- a/src/ints/mouse.cpp +++ b/src/ints/mouse.cpp @@ -50,8 +50,8 @@ struct button_event { #define QUEUE_SIZE 32 #define MOUSE_BUTTONS 3 #define MOUSE_IRQ 12 -#define POS_X ((Bit16s)(mouse.x) & mouse.granMask) -#define POS_Y (Bit16s)(mouse.y) +#define POS_X (static_cast(mouse.x) & mouse.gran_x) +#define POS_Y (static_cast(mouse.y) & mouse.gran_y) #define CURSORX 16 #define CURSORY 16 @@ -125,7 +125,7 @@ static struct { bool timer_in_progress; bool in_UIR; Bit8u mode; - Bit16s granMask; + Bit16s gran_x,gran_y; } mouse; bool Mouse_SetPS2State(bool use) { @@ -255,6 +255,7 @@ void DrawCursorText() { // Save Background mouse.backposx = POS_X>>3; mouse.backposy = POS_Y>>3; + if (mouse.mode < 2) mouse.backposx >>= 1; //use current page (CV program) Bit8u page = real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); @@ -582,43 +583,48 @@ static void Mouse_ResetHardware(void){ //Does way to much. Many things should be moved to mouse reset one day void Mouse_NewVideoMode(void) { - mouse.inhibit_draw=false; + mouse.inhibit_draw = false; /* Get the correct resolution from the current video mode */ - Bit8u mode=mem_readb(BIOS_VIDEO_MODE); + Bit8u mode = mem_readb(BIOS_VIDEO_MODE); if(mode == mouse.mode) {LOG(LOG_MOUSE,LOG_NORMAL)("New video is the same as the old"); /*return;*/} + mouse.gran_x = (Bit16s)0xffff; + mouse.gran_y = (Bit16s)0xffff; switch (mode) { case 0x00: case 0x01: case 0x02: - case 0x03: { - Bitu rows=real_readb(BIOSMEM_SEG,BIOSMEM_NB_ROWS); - if ((rows==0) || (rows>250)) rows=25-1; - mouse.max_y=8*(rows+1)-1; + case 0x03: + case 0x07: { + mouse.gran_x = (mode<2)?0xfff0:0xfff8; + mouse.gran_y = (Bit16s)0xfff8; + Bitu rows = real_readb(BIOSMEM_SEG,BIOSMEM_NB_ROWS); + if ((rows == 0) || (rows > 250)) rows = 25 - 1; + mouse.max_y = 8*(rows+1) - 1; break; } case 0x04: case 0x05: case 0x06: - case 0x07: case 0x08: case 0x09: case 0x0a: case 0x0d: case 0x0e: case 0x13: - mouse.max_y=199; + if (mode == 0x0d || mode == 0x13) mouse.gran_x = (Bit16s)0xfffe; + mouse.max_y = 199; break; case 0x0f: case 0x10: - mouse.max_y=349; + mouse.max_y = 349; break; case 0x11: case 0x12: - mouse.max_y=479; + mouse.max_y = 479; break; default: LOG(LOG_MOUSE,LOG_ERROR)("Unhandled videomode %X on reset",mode); - mouse.inhibit_draw=true; + mouse.inhibit_draw = true; return; } mouse.mode = mode; @@ -626,7 +632,6 @@ void Mouse_NewVideoMode(void) { mouse.max_x = 639; mouse.min_x = 0; mouse.min_y = 0; - mouse.granMask = (mode == 0x0d || mode == 0x13) ? 0xfffe : 0xffff; mouse.events = 0; mouse.timer_in_progress = false; @@ -1007,7 +1012,7 @@ static Bitu INT74_Handler(void) { } else if (useps2callback) { CPU_Push16(RealSeg(CALLBACK_RealPointer(int74_ret_callback))); CPU_Push16(RealOff(CALLBACK_RealPointer(int74_ret_callback))); - DoPS2Callback(mouse.event_queue[mouse.events].buttons, POS_X, POS_Y); + DoPS2Callback(mouse.event_queue[mouse.events].buttons, static_cast(mouse.x), static_cast(mouse.y)); } else { SegSet16(cs, RealSeg(CALLBACK_RealPointer(int74_ret_callback))); reg_ip = RealOff(CALLBACK_RealPointer(int74_ret_callback)); diff --git a/src/ints/xms.cpp b/src/ints/xms.cpp index cb11770..3a5209c 100644 --- a/src/ints/xms.cpp +++ b/src/ints/xms.cpp @@ -19,6 +19,7 @@ #include #include +#include #include "dosbox.h" #include "callback.h" #include "mem.h" diff --git a/src/misc/messages.cpp b/src/misc/messages.cpp index e843df7..b36cb57 100644 --- a/src/misc/messages.cpp +++ b/src/misc/messages.cpp @@ -98,7 +98,7 @@ static void LoadMessageFile(const char * fname) { strcpy(name,linein+1); /* End of string marker */ } else if (linein[0]=='.') { - /* Replace/Add the string to the internal langaugefile */ + /* Replace/Add the string to the internal languagefile */ /* Remove last newline (marker is \n.\n) */ size_t ll = strlen(string); if(ll && string[ll - 1] == '\n') string[ll - 1] = 0; //Second if should not be needed, but better be safe. diff --git a/src/misc/programs.cpp b/src/misc/programs.cpp index da32ac4..0964755 100644 --- a/src/misc/programs.cpp +++ b/src/misc/programs.cpp @@ -128,6 +128,7 @@ void Program::ChangeToLongCmd() { full_arguments.assign(""); //Clear so it gets even more save } +static char last_written_character = 0;//For 0xA to OxD 0xA expansion void Program::WriteOut(const char * format,...) { char buf[2048]; va_list msg; @@ -139,10 +140,10 @@ void Program::WriteOut(const char * format,...) { Bit16u size = (Bit16u)strlen(buf); for(Bit16u i = 0; i < size;i++) { Bit8u out;Bit16u s=1; - if (buf[i] == 0xA && i > 0 && buf[i-1] !=0xD) { + if (buf[i] == 0xA && last_written_character != 0xD) { out = 0xD;DOS_WriteFile(STDOUT,&out,&s); } - out = buf[i]; + last_written_character = out = buf[i]; DOS_WriteFile(STDOUT,&out,&s); } @@ -154,10 +155,10 @@ void Program::WriteOut_NoParsing(const char * format) { char const* buf = format; for(Bit16u i = 0; i < size;i++) { Bit8u out;Bit16u s=1; - if (buf[i] == 0xA && i > 0 && buf[i-1] !=0xD) { + if (buf[i] == 0xA && last_written_character != 0xD) { out = 0xD;DOS_WriteFile(STDOUT,&out,&s); } - out = buf[i]; + last_written_character = out = buf[i]; DOS_WriteFile(STDOUT,&out,&s); } diff --git a/src/misc/setup.cpp b/src/misc/setup.cpp index 5bd21e0..0703f9b 100644 --- a/src/misc/setup.cpp +++ b/src/misc/setup.cpp @@ -955,6 +955,39 @@ bool CommandLine::FindStringRemain(char const * const name,std::string & value) return true; } +/* Only used for parsing command.com /C + * Allowing /C dir and /Cdir + * Restoring quotes back into the commands so command /C mount d "/tmp/a b" works as intended + */ +bool CommandLine::FindStringRemainBegin(char const * const name,std::string & value) { + cmd_it it;value=""; + if (!FindEntry(name,it)) { + size_t len = strlen(name); + for (it=cmds.begin();it!=cmds.end();it++) { + if (strncasecmp(name,(*it).c_str(),len)==0) { + std::string temp = ((*it).c_str() + len); + //Restore quotes for correct parsing in later stages + if(temp.find(" ") != std::string::npos) + value = std::string("\"") + temp + std::string("\""); + else + value = temp; + break; + } + } + if( it == cmds.end()) return false; + } + it++; + for (;it!=cmds.end();it++) { + value += " "; + std::string temp = (*it); + if(temp.find(" ") != std::string::npos) + value += std::string("\"") + temp + std::string("\""); + else + value += temp; + } + return true; +} + bool CommandLine::GetStringRemain(std::string & value) { if(!cmds.size()) return false; diff --git a/src/shell/shell.cpp b/src/shell/shell.cpp index 021c58b..3dd09a5 100644 --- a/src/shell/shell.cpp +++ b/src/shell/shell.cpp @@ -52,14 +52,14 @@ typedef std::list::iterator auto_it; void VFILE_Remove(const char *name); void AutoexecObject::Install(const std::string &in) { - if(GCC_UNLIKELY(installed)) E_Exit("autoexec: allready created %s",buf.c_str()); + if(GCC_UNLIKELY(installed)) E_Exit("autoexec: already created %s",buf.c_str()); installed = true; buf = in; autoexec_strings.push_back(buf); this->CreateAutoexec(); //autoexec.bat is normally created AUTOEXEC_Init. - //But if we are allready running (first_shell) + //But if we are already running (first_shell) //we have to update the envirionment to display changes if(first_shell) { @@ -80,7 +80,7 @@ void AutoexecObject::Install(const std::string &in) { } void AutoexecObject::InstallBefore(const std::string &in) { - if(GCC_UNLIKELY(installed)) E_Exit("autoexec: allready created %s",buf.c_str()); + if(GCC_UNLIKELY(installed)) E_Exit("autoexec: already created %s",buf.c_str()); installed = true; buf = in; autoexec_strings.push_front(buf); @@ -288,7 +288,7 @@ void DOS_Shell::RunInternal(void) void DOS_Shell::Run(void) { char input_line[CMD_MAXLINE] = {0}; std::string line; - if (cmd->FindStringRemain("/C",line)) { + if (cmd->FindStringRemainBegin("/C",line)) { strcpy(input_line,line.c_str()); char* sep = strpbrk(input_line,"\r\n"); //GTA installer if (sep) *sep = 0; diff --git a/src/shell/shell_cmds.cpp b/src/shell/shell_cmds.cpp index ab36a59..2bb31fa 100644 --- a/src/shell/shell_cmds.cpp +++ b/src/shell/shell_cmds.cpp @@ -123,11 +123,12 @@ void DOS_Shell::DoCommand(char * line) { char cmd_buffer[CMD_MAXLINE]; char * cmd_write=cmd_buffer; while (*line) { - if (*line==32) break; - if (*line=='/') break; - if (*line=='\t') break; - if (*line=='=') break; - if ((*line=='.') ||(*line =='\\')) { //allow stuff like cd.. and dir.exe cd\kees + if (*line == 32) break; + if (*line == '/') break; + if (*line == '\t') break; + if (*line == '=') break; +// if (*line == ':') break; //This breaks drive switching as that is handled at a later stage. + if ((*line == '.') ||(*line == '\\')) { //allow stuff like cd.. and dir.exe cd\kees *cmd_write=0; Bit32u cmd_index=0; while (cmd_list[cmd_index].name) { @@ -287,7 +288,7 @@ void DOS_Shell::CMD_ECHO(char * args){ args++;//skip first character. either a slash or dot or space size_t len = strlen(args); //TODO check input of else ook nodig is. if(len && args[len - 1] == '\r') { - LOG(LOG_MISC,LOG_WARN)("Hu ? carriage return allready present. Is this possible?"); + LOG(LOG_MISC,LOG_WARN)("Hu ? carriage return already present. Is this possible?"); WriteOut("%s\n",args); } else WriteOut("%s\r\n",args); } @@ -573,6 +574,7 @@ void DOS_Shell::CMD_COPY(char * args) { while(ScanCMDBool(args,"A")) ; ScanCMDBool(args,"Y"); ScanCMDBool(args,"-Y"); + ScanCMDBool(args,"V"); char * rem=ScanCMDRemain(args); if (rem) { diff --git a/src/shell/shell_misc.cpp b/src/shell/shell_misc.cpp index dde11a3..5b1d5c8 100644 --- a/src/shell/shell_misc.cpp +++ b/src/shell/shell_misc.cpp @@ -56,7 +56,7 @@ void DOS_Shell::InputCommand(char * line) { Bit16u dummy; DOS_CloseFile(input_handle); DOS_OpenFile("con",2,&dummy); - LOG(LOG_MISC,LOG_ERROR)("Reopening the input handle.This is a bug!"); + LOG(LOG_MISC,LOG_ERROR)("Reopening the input handle. This is a bug!"); } if (!n) { size=0; //Kill the while loop @@ -174,6 +174,24 @@ void DOS_Shell::InputCommand(char * line) { size++; } break; + case 15: /* Shift-Tab */ + if (l_completion.size()) { + if (it_completion == l_completion.begin()) it_completion = l_completion.end (); + it_completion--; + + if (it_completion->length()) { + for (;str_index > completion_index; str_index--) { + // removes all characters + outc(8); outc(' '); outc(8); + } + + strcpy(&line[completion_index], it_completion->c_str()); + len = (Bit16u)it_completion->length(); + str_len = str_index = completion_index + len; + size = CMD_MAXLINE - str_index - 2; + DOS_WriteFile(STDOUT, (Bit8u *)it_completion->c_str(), &len); + } + } default: break; } @@ -281,7 +299,7 @@ void DOS_Shell::InputCommand(char * line) { } res=DOS_FindNext(); } - /* Add excutable list to front of completion list. */ + /* Add executable list to front of completion list. */ std::copy(executable.begin(),executable.end(),std::front_inserter(l_completion)); it_completion = l_completion.begin(); dos.dta(save_dta);