Detecting system's codepage (DOS)

DOS specific questions.
Post Reply
Fox
Posts: 353
Joined: Aug 08, 2006 13:39
Location: Lille, France
Contact:

Detecting system's codepage (DOS)

Post by Fox »

Hi all!

I am still working on my FoxCalc tool (remember? That mouse-driven DOS calculator :-) ).
I used some ASCII symbols on the calculator's buttons, and I got reported a problem I haven't thought about... For example, I use the Square root symbol, which changes on some other codepage than the default US CP437 :(

So far, I have two solution:
1. Using only ASCII chars < 127 on my buttons :(
2. Detecting the system's CP, then IF CP = 437 then using nice symbols ELSE using ASCII < 127.
3. Loading a custom charset before running the program, then restoring the previous at exit.

Obviously, I would like to use the second one, as the first is ugly, and the third is scaring me. Is there any way under FreeBASIC to detect the system's (DOS) current codepage?
jevans4949
Posts: 1186
Joined: May 08, 2006 21:58
Location: Crewe, England

Post by jevans4949 »

If you are running a "Command Prompt" screen under Windows, we discussed how to do this in the latter half of the following topic:
http://www.freebasic.net/forum/viewtopi ... t=codepage

Under raw DOS, there is probably an interrupt function that does it, but I can't locate it at present.
DrV
Site Admin
Posts: 2116
Joined: May 27, 2005 18:39
Location: Midwestern USA
Contact:

Post by DrV »

http://www.ctyme.com/intr/rb-3167.htm

Code: Select all

#include "dos/dpmi.bi"

function GetCurrentCodePage() as ushort
	const CF = 1
	dim regs as __dpmi_regs
	regs.x.ax = &h6601
	if __dpmi_int(&h21, @regs) = 0 and (regs.x.flags and CF) = 0 then
		return regs.x.bx
	else
		return 0
	end if
end function

print "Current code page: " & GetCurrentCodePage()
Fox
Posts: 353
Joined: Aug 08, 2006 13:39
Location: Lille, France
Contact:

Post by Fox »

DrV wrote:

Code: Select all

#include "dos/dpmi.bi"

function GetCurrentCodePage() as ushort
	const CF = 1
	dim regs as __dpmi_regs
	regs.x.ax = &h6601
	if __dpmi_int(&h21, @regs) = 0 and (regs.x.flags and CF) = 0 then
		return regs.x.bx
	else
		return 0
	end if
end function

print "Current code page: " & GetCurrentCodePage()
WOOW....
Has it to be THAT complicated???

I will try that function when back at home.
Thank you DrV :-)
anonymous1337
Posts: 5494
Joined: Sep 12, 2005 20:06
Location: California

Post by anonymous1337 »

HOMG 10 lines, I'm going to die!

Basically, get a register or something. Check some screen flag. Return the screen flag result, or something.

>.>;; Not sooo complicated, but not like I get it either.
DrV
Site Admin
Posts: 2116
Joined: May 27, 2005 18:39
Location: Midwestern USA
Contact:

Post by DrV »

It could probably be a little shorter if you replaced the __dpmi_int call with intdos or something like that, but I can't remember exactly how those work without looking them up. :) It all goes the same place in the end anyway...
jevans4949
Posts: 1186
Joined: May 08, 2006 21:58
Location: Crewe, England

Post by jevans4949 »

DrV's reply matched that in a weighty tome I have here.

To change the codepage, set AX to &h6602 and BX to the required codepage number.

At least, according to the book ... my DOS machine is currently mothballed.
MichaelW
Posts: 3500
Joined: May 16, 2006 22:34
Location: USA

Post by MichaelW »

The information in the Microsoft MS-DOS references for versions 5 and 6 for function 6601h and 6602h differs from that in the Interrupt List. For function 6601h, “system code page” is followed by “(the code page specified at startup)”, implying that it cannot be changed. For function 6602h, BX specifies the “code page to set”, and there is no mention of a value passed in DX. Also, in the comments there is a warning that “the selected code page must be compatible with the country code specified in CONFIG.SYS”.
jevans4949
Posts: 1186
Joined: May 08, 2006 21:58
Location: Crewe, England

Post by jevans4949 »

OK, "The Revolutionary Guide to Assembler, (c) 1993 by 4 Russian guys, goes on to state:

Output:
CF = 0 function is successful
if AL = 01h
BX = active code page
DX = default code page
CF = 1 error code
Comments:
MS DOS, via the function COUNTRY.SYS, supplies a new code page if AL = 02h, but the device must be prepared for this by the directive DEVICE in CONFIG.SYS and NLSFUNC and MODE CP PREPARE commands in AUTOEXEC.BAT
Fox
Posts: 353
Joined: Aug 08, 2006 13:39
Location: Lille, France
Contact:

Post by Fox »

DrV wrote:It could probably be a little shorter if you replaced the __dpmi_int call with intdos or something like that, but I can't remember exactly how those work without looking them up. :)
I tested it a minute ago, and it seems to work just okay ;-)
Fox
Posts: 353
Joined: Aug 08, 2006 13:39
Location: Lille, France
Contact:

Post by Fox »

I have just upgraded FBC to the latest v0.17 and... the GetCurrentCodepage Function doesn't work anymore :(
FBC v0.17b wrote:Return regs.x.bx
Error 25: Invalid data types
I am using the parameter "-lang qb" (don't know if it has any importance)

DrV - Could you please let me know what should be changed in your magic function to make it working again?
cha0s
Site Admin
Posts: 5319
Joined: May 27, 2005 6:42
Location: USA
Contact:

Post by cha0s »

QB didn't have "return" except with GOSUB.

Hail QB!

edit: just do "function = regs.x.bx" (Also not in QB, but nothing like GOSUB to ruin it) or, "GetCurrentCodePage = regs.x.bx", the "real" QB way.
Fox
Posts: 353
Joined: Aug 08, 2006 13:39
Location: Lille, France
Contact:

Post by Fox »

Right - The problem was there.
I modified my whole program to be compatible with v0.17 without using the "-lang qb" switch, then the GetCurrentCodepage function worked again :)

Thank you!
rugxulo
Posts: 219
Joined: Jun 30, 2006 5:31
Location: Usono (aka, USA)
Contact:

Re: Detecting system's codepage (DOS)

Post by rugxulo »

I have not used FB a lot (and barely know anything in general anyways), hence my slow reply here:

int 21h, 6601h is only for "system" code page (used by CHCP), not the "display"-ed one. (They don't have to match, although ideally they maybe would, if everything were fully supported).

Long story short, it appears that "DOS" splits up everything into various pieces that are meant to (usually) work together: COUNTRY.SYS, DISPLAY.SYS, PRINTER.SYS, NLSFUNC.EXE, KEYB.EXE, KEYB*.SYS, MODE.COM, EGA*.CPI, GRAFTABL, CHCP (internal shell built-in).

COUNTRY and NLSFUNC go together for the collate tables, y/n replies, and date/time/currency info.
KEYB.EXE and KEYB*.SYS files are for the keyboard layouts (usually tied to specific code pages).
EGA*.CPI and DISPLAY are for loading, preparing, and selecting displayed EGA/VGA code pages (glyphs).
GRAFTABL is for old (CGA?) machines that had to use graphics mode for extended 8-bit chars.

However, most DOSes (e.g. MS-DOS and DR-DOS) have fairly limited support for worldwide languages. Henrique Peron (FreeDOS) has done a much more exhaustive job at supporting a lot of stuff. At least, IIRC, none of the others even fully support Latin-1/2/3/4 properly (which truly correspond to cp819, cp912, cp913, cp914 ... I think). Well, even FreeDOS doesn't have a one-to-one set of official *.CPI files (yet) for those, so you're stuck with the "same glyphs but different encodings" cp850, cp852, cp853, etc (or use third-party, e.g. Kosta Kostis' ISOLATIN.CPI).

Ideally you should check if DISPLAY is loaded before trying to guess the "displayed" code page. But IIRC DR-DOS didn't properly identify itself. Also, for example, MS-DOS has an (almost empty?) stub for cp853 in some printer file, but presumably your printer would already have to support it. DR-DOS has display cp853 but undocumented (and lowercase 'j^' is incorrectly used and missing). FreeDOS does have display cp853 and KEYB support, but for "real" Latin-3 you need cp913 (also in OS/2??), which can be gotten in Kosta Kostis' ISOLATIN.CPI.

FreeDOS hasn't fully implemented DISPLAY yet, so for now it's only a loadable .EXE TSR, not a driver. Hence by design it doesn't support the proper IOCTL function int 21h, 440Ch 6Ah as used by MS-DOS and DR-DOS. It only supports the unofficial (MS-DOS only!) int 2Fh, 0AD02h call. (Note that WinXP etc. don't support any of these DOS calls, sadly, no big surprise.)

Here is a C (DJGPP) snippet that I donated to Dos2unix a few years ago, perhaps it will be more explanatory:

N.B. This should return the same result as "mode con cp /status".

Code: Select all

unsigned short query_con_codepage(void) {
   __dpmi_regs regs;

   unsigned short param_block[2] = { 0, 437 };

   regs.d.eax = 0x440C;                /* GENERIC IO FOR HANDLES */
   regs.d.ebx = 1;                     /* STDOUT */
   regs.d.ecx = 0x036A;                /* 3 = CON, 0x6A = QUERY SELECTED CP */
   regs.x.ds = __tb >> 4;              /* using transfer buffer for low mem. */
   regs.x.dx = __tb & 0x0F;            /* (suggested by DJGPP FAQ, hi Eli!) */
   regs.x.flags |= 1;                  /* preset carry for potential failure */
   __dpmi_int (0x21, &regs);

   if (!(regs.x.flags & 1))            /* if succeed (carry flag not set) */
     dosmemget( __tb, 4, param_block);
   else {                              /* (undocumented method) */
     regs.x.ax = 0xAD02;               /* 440C -> MS-DOS or DR-DOS only */
     regs.x.bx = 0xFFFE;               /* AD02 -> MS-DOS or FreeDOS only */
     regs.x.flags |= 1;
     __dpmi_int(0x2F, &regs);

     if ((!(regs.x.flags & 1)) && (regs.x.bx < 0xFFFE))
       param_block[1] = regs.x.bx;
   }

   return param_block[1];
Post Reply