Move int21 country information handling to winedos.

Improve country information handling.
Move collate table to upper memory.
This commit is contained in:
Jukka Heinonen 2002-12-10 19:58:39 +00:00 committed by Alexandre Julliard
parent 647c1a33c8
commit be1c6deb18
4 changed files with 372 additions and 185 deletions

View file

@ -44,6 +44,330 @@ extern void WINAPI INT_Int21Handler( CONTEXT86 *context );
WINE_DEFAULT_DEBUG_CHANNEL(int21);
#include "pshpack1.h"
/*
* Structure for DOS data that can be accessed directly from applications.
* Real and protected mode pointers will be returned to this structure so
* the structure must be correctly packed.
*/
typedef struct _INT21_HEAP {
WORD uppercase_size; /* Size of the following table in bytes */
BYTE uppercase_table[128]; /* Uppercase equivalents of chars from 0x80 to 0xff. */
WORD lowercase_size; /* Size of the following table in bytes */
BYTE lowercase_table[256]; /* Lowercase equivalents of chars from 0x00 to 0xff. */
WORD collating_size; /* Size of the following table in bytes */
BYTE collating_table[256]; /* Values used to sort characters from 0x00 to 0xff. */
WORD filename_size; /* Size of the following filename data in bytes */
BYTE filename_reserved1; /* 0x01 for MS-DOS 3.30-6.00 */
BYTE filename_lowest; /* Lowest permissible character value for filename */
BYTE filename_highest; /* Highest permissible character value for filename */
BYTE filename_reserved2; /* 0x00 for MS-DOS 3.30-6.00 */
BYTE filename_exclude_first; /* First illegal character in permissible range */
BYTE filename_exclude_last; /* Last illegal character in permissible range */
BYTE filename_reserved3; /* 0x02 for MS-DOS 3.30-6.00 */
BYTE filename_illegal_size; /* Number of terminators in the following table */
BYTE filename_illegal_table[16]; /* Characters which terminate a filename */
WORD dbcs_size; /* Number of valid ranges in the following table */
BYTE dbcs_table[16]; /* Start/end bytes for N ranges and 00/00 as terminator */
BYTE misc_indos; /* Interrupt 21 nesting flag */
} INT21_HEAP;
#include "poppack.h"
/***********************************************************************
* INT21_GetSystemCountryCode
*
* Return DOS country code for default system locale.
*/
static WORD INT21_GetSystemCountryCode()
{
/*
* FIXME: Determine country code. We should probably use
* DOSCONF structure for that.
*/
return GetSystemDefaultLangID();
}
/***********************************************************************
* INT21_FillCountryInformation
*
* Fill 34-byte buffer with country information data using
* default system locale.
*/
static void INT21_FillCountryInformation( BYTE *buffer )
{
/* 00 - WORD: date format
* 00 = mm/dd/yy
* 01 = dd/mm/yy
* 02 = yy/mm/dd
*/
*(WORD*)(buffer + 0) = 0; /* FIXME: Get from locale */
/* 02 - BYTE[5]: ASCIIZ currency symbol string */
buffer[2] = '$'; /* FIXME: Get from locale */
buffer[3] = 0;
/* 07 - BYTE[2]: ASCIIZ thousands separator */
buffer[7] = 0; /* FIXME: Get from locale */
buffer[8] = 0;
/* 09 - BYTE[2]: ASCIIZ decimal separator */
buffer[9] = '.'; /* FIXME: Get from locale */
buffer[10] = 0;
/* 11 - BYTE[2]: ASCIIZ date separator */
buffer[11] = '/'; /* FIXME: Get from locale */
buffer[12] = 0;
/* 13 - BYTE[2]: ASCIIZ time separator */
buffer[13] = ':'; /* FIXME: Get from locale */
buffer[14] = 0;
/* 15 - BYTE: Currency format
* bit 2 = set if currency symbol replaces decimal point
* bit 1 = number of spaces between value and currency symbol
* bit 0 = 0 if currency symbol precedes value
* 1 if currency symbol follows value
*/
buffer[15] = 0; /* FIXME: Get from locale */
/* 16 - BYTE: Number of digits after decimal in currency */
buffer[16] = 0; /* FIXME: Get from locale */
/* 17 - BYTE: Time format
* bit 0 = 0 if 12-hour clock
* 1 if 24-hour clock
*/
buffer[17] = 1; /* FIXME: Get from locale */
/* 18 - DWORD: Address of case map routine */
*(DWORD*)(buffer + 18) = 0; /* FIXME: ptr to case map routine */
/* 22 - BYTE[2]: ASCIIZ data-list separator */
buffer[22] = ','; /* FIXME: Get from locale */
buffer[23] = 0;
/* 24 - BYTE[10]: Reserved */
memset( buffer + 24, 0, 10 );
}
/***********************************************************************
* INT21_FillHeap
*
* Initialize DOS heap.
*/
static void INT21_FillHeap( INT21_HEAP *heap )
{
static const char terminators[] = "\"\\./[]:|<>+=;,";
int i;
/*
* Uppercase table.
*/
heap->uppercase_size = 128;
for (i = 0; i < 128; i++)
heap->uppercase_table[i] = toupper( 128 + i );
/*
* Lowercase table.
*/
heap->lowercase_size = 256;
for (i = 0; i < 256; i++)
heap->lowercase_table[i] = tolower( i );
/*
* Collating table.
*/
heap->collating_size = 256;
for (i = 0; i < 256; i++)
heap->collating_table[i] = i;
/*
* Filename table.
*/
heap->filename_size = 8 + strlen(terminators);
heap->filename_illegal_size = strlen(terminators);
strcpy( heap->filename_illegal_table, terminators );
heap->filename_reserved1 = 0x01;
heap->filename_lowest = 0; /* FIXME: correct value? */
heap->filename_highest = 0xff; /* FIXME: correct value? */
heap->filename_reserved2 = 0x00;
heap->filename_exclude_first = 0x00; /* FIXME: correct value? */
heap->filename_exclude_last = 0x00; /* FIXME: correct value? */
heap->filename_reserved3 = 0x02;
/*
* DBCS lead byte table. This table is empty.
*/
heap->dbcs_size = 0;
memset( heap->dbcs_table, 0, sizeof(heap->dbcs_table) );
/*
* Initialize InDos flag.
*/
heap->misc_indos = 0;
}
/***********************************************************************
* INT21_GetHeapSelector
*
* Get segment/selector for DOS heap (INT21_HEAP).
* Creates and initializes heap on first call.
*/
static WORD INT21_GetHeapSelector( CONTEXT86 *context )
{
static WORD heap_segment = 0;
static WORD heap_selector = 0;
static BOOL heap_initialized = FALSE;
if (!heap_initialized)
{
INT21_HEAP *ptr = DOSVM_AllocDataUMB( sizeof(INT21_HEAP),
&heap_segment,
&heap_selector );
INT21_FillHeap( ptr );
heap_initialized = TRUE;
}
if (!ISV86(context) && DOSVM_IsWin16())
return heap_selector;
else
return heap_segment;
}
/***********************************************************************
* INT21_ExtendedCountryInformation
*
* Handler for function 0x65.
*/
static void INT21_ExtendedCountryInformation( CONTEXT86 *context )
{
BYTE *dataptr = CTX_SEG_OFF_TO_LIN( context, context->SegEs, context->Edi );
TRACE( "GET EXTENDED COUNTRY INFORMATION, subfunction %02x\n",
AL_reg(context) );
/*
* Check subfunctions that are passed country and code page.
*/
if (AL_reg(context) >= 0x01 && AL_reg(context) <= 0x07)
{
WORD country = DX_reg(context);
WORD codepage = BX_reg(context);
if (country != 0xffff && country != INT21_GetSystemCountryCode())
FIXME( "Requested info on non-default country %04x\n", country );
if (codepage != 0xffff && codepage != GetOEMCP())
FIXME( "Requested info on non-default code page %04x\n", codepage );
}
switch (AL_reg(context)) {
case 0x00: /* SET GENERAL INTERNATIONALIZATION INFO */
INT_BARF( context, 0x21 );
SET_CFLAG( context );
break;
case 0x01: /* GET GENERAL INTERNATIONALIZATION INFO */
TRACE( "Get general internationalization info\n" );
dataptr[0] = 0x01; /* Info ID */
*(WORD*)(dataptr+1) = 38; /* Size of the following info */
*(WORD*)(dataptr+3) = INT21_GetSystemCountryCode(); /* Country ID */
*(WORD*)(dataptr+5) = GetOEMCP(); /* Code page */
INT21_FillCountryInformation( dataptr + 7 );
SET_CX( context, 41 ); /* Size of returned info */
break;
case 0x02: /* GET POINTER TO UPPERCASE TABLE */
case 0x04: /* GET POINTER TO FILENAME UPPERCASE TABLE */
TRACE( "Get pointer to uppercase table\n" );
dataptr[0] = AL_reg(context); /* Info ID */
*(DWORD*)(dataptr+1) = MAKESEGPTR( INT21_GetHeapSelector( context ),
offsetof(INT21_HEAP, uppercase_size) );
SET_CX( context, 5 ); /* Size of returned info */
break;
case 0x03: /* GET POINTER TO LOWERCASE TABLE */
TRACE( "Get pointer to lowercase table\n" );
dataptr[0] = 0x03; /* Info ID */
*(DWORD*)(dataptr+1) = MAKESEGPTR( INT21_GetHeapSelector( context ),
offsetof(INT21_HEAP, lowercase_size) );
SET_CX( context, 5 ); /* Size of returned info */
break;
case 0x05: /* GET POINTER TO FILENAME TERMINATOR TABLE */
TRACE("Get pointer to filename terminator table\n");
dataptr[0] = 0x05; /* Info ID */
*(DWORD*)(dataptr+1) = MAKESEGPTR( INT21_GetHeapSelector( context ),
offsetof(INT21_HEAP, filename_size) );
SET_CX( context, 5 ); /* Size of returned info */
break;
case 0x06: /* GET POINTER TO COLLATING SEQUENCE TABLE */
TRACE("Get pointer to collating sequence table\n");
dataptr[0] = 0x06; /* Info ID */
*(DWORD*)(dataptr+1) = MAKESEGPTR( INT21_GetHeapSelector( context ),
offsetof(INT21_HEAP, collating_size) );
SET_CX( context, 5 ); /* Size of returned info */
break;
case 0x07: /* GET POINTER TO DBCS LEAD BYTE TABLE */
TRACE("Get pointer to DBCS lead byte table\n");
dataptr[0] = 0x07; /* Info ID */
*(DWORD*)(dataptr+1) = MAKESEGPTR( INT21_GetHeapSelector( context ),
offsetof(INT21_HEAP, dbcs_size) );
SET_CX( context, 5 ); /* Size of returned info */
break;
case 0x20: /* CAPITALIZE CHARACTER */
case 0xa0: /* CAPITALIZE FILENAME CHARACTER */
TRACE("Convert char to uppercase\n");
SET_DL( context, toupper(DL_reg(context)) );
break;
case 0x21: /* CAPITALIZE STRING */
case 0xa1: /* CAPITALIZE COUNTED FILENAME STRING */
TRACE("Convert string to uppercase with length\n");
{
char *ptr = (char *)CTX_SEG_OFF_TO_LIN( context,
context->SegDs,
context->Edx );
WORD len = CX_reg(context);
while (len--) { *ptr = toupper(*ptr); ptr++; }
}
break;
case 0x22: /* CAPITALIZE ASCIIZ STRING */
case 0xa2: /* CAPITALIZE ASCIIZ FILENAME */
TRACE("Convert ASCIIZ string to uppercase\n");
_strupr( (LPSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx) );
break;
case 0x23: /* DETERMINE IF CHARACTER REPRESENTS YES/NO RESPONSE */
INT_BARF( context, 0x21 );
SET_CFLAG( context );
break;
default:
INT_BARF( context, 0x21 );
SET_CFLAG(context);
break;
}
}
/***********************************************************************
* INT21_GetPSP
*
@ -501,10 +825,15 @@ void WINAPI DOSVM_Int21Handler( CONTEXT86 *context )
case 0x32: /* GET DOS DRIVE PARAMETER BLOCK FOR SPECIFIC DRIVE */
case 0x33: /* MULTIPLEXED */
case 0x34: /* GET ADDRESS OF INDOS FLAG */
INT_Int21Handler( context );
break;
case 0x34: /* GET ADDRESS OF INDOS FLAG */
TRACE( "GET ADDRESS OF INDOS FLAG\n" );
context->SegEs = INT21_GetHeapSelector( context );
SET_BX( context, offsetof(INT21_HEAP, misc_indos) );
break;
case 0x35: /* GET INTERRUPT VECTOR */
TRACE("GET INTERRUPT VECTOR 0x%02x\n",AL_reg(context));
{
@ -524,10 +853,20 @@ void WINAPI DOSVM_Int21Handler( CONTEXT86 *context )
break;
case 0x38: /* GET COUNTRY-SPECIFIC INFORMATION */
TRACE( "GET COUNTRY-SPECIFIC INFORMATION for country 0x%02x\n",
AL_reg(context) );
SET_AX( context, 0x02 ); /* no country support available */
SET_CFLAG( context );
TRACE( "GET COUNTRY-SPECIFIC INFORMATION\n" );
if (AL_reg(context))
{
WORD country = AL_reg(context);
if (country == 0xff)
country = BX_reg(context);
if (country != INT21_GetSystemCountryCode())
FIXME( "Requested info on non-default country %04x\n", country );
}
INT21_FillCountryInformation( CTX_SEG_OFF_TO_LIN(context,
context->SegDs,
context->Edx) );
SET_AX( context, INT21_GetSystemCountryCode() );
SET_BX( context, INT21_GetSystemCountryCode() );
break;
case 0x39: /* "MKDIR" - CREATE SUBDIRECTORY */
@ -723,16 +1062,26 @@ void WINAPI DOSVM_Int21Handler( CONTEXT86 *context )
case 0x5e: /* NETWORK 5E */
case 0x5f: /* NETWORK 5F */
case 0x60: /* "TRUENAME" - CANONICALIZE FILENAME OR PATH */
case 0x61: /* UNUSED */
INT_Int21Handler( context );
break;
case 0x61: /* UNUSED */
SET_AL( context, 0 );
break;
case 0x62: /* GET PSP ADDRESS */
INT21_GetPSP( context );
break;
case 0x63: /* MISC. LANGUAGE SUPPORT */
INT_Int21Handler( context );
switch (AL_reg(context)) {
case 0x00: /* GET DOUBLE BYTE CHARACTER SET LEAD-BYTE TABLE */
TRACE( "GET DOUBLE BYTE CHARACTER SET LEAD-BYTE TABLE\n" );
context->SegDs = INT21_GetHeapSelector( context );
SET_SI( context, offsetof(INT21_HEAP, dbcs_table) );
SET_AL( context, 0 ); /* success */
break;
}
break;
case 0x64: /* OS/2 DOS BOX */
@ -740,9 +1089,23 @@ void WINAPI DOSVM_Int21Handler( CONTEXT86 *context )
SET_CFLAG(context);
break;
case 0x65: /* GET EXTENDED COUNTRY INFORMATION */
case 0x65: /* EXTENDED COUNTRY INFORMATION */
INT21_ExtendedCountryInformation( context );
break;
case 0x66: /* GLOBAL CODE PAGE TABLE */
INT_Int21Handler( context );
switch (AL_reg(context))
{
case 0x01:
TRACE( "GET GLOBAL CODE PAGE TABLE\n" );
SET_BX( context, GetOEMCP() );
SET_DX( context, GetOEMCP() );
break;
case 0x02:
FIXME( "SET GLOBAL CODE PAGE TABLE, active %d, system %d - ignored\n",
BX_reg(context), DX_reg(context) );
break;
}
break;
case 0x67: /* SET HANDLE COUNT */

View file

@ -162,7 +162,6 @@ typedef struct
extern WORD DOSMEM_0000H;
extern WORD DOSMEM_BiosDataSeg;
extern WORD DOSMEM_BiosSysSeg;
extern DWORD DOSMEM_CollateTable;
/* msdos/dosmem.c */
extern BOOL DOSMEM_Init(BOOL);

View file

@ -50,8 +50,6 @@ WORD DOSMEM_0000H; /* segment at 0:0 */
WORD DOSMEM_BiosDataSeg; /* BIOS data segment at 0x40:0 */
WORD DOSMEM_BiosSysSeg; /* BIOS ROM segment at 0xf000:0 */
DWORD DOSMEM_CollateTable;
/* use 2 low bits of 'size' for the housekeeping */
#define DM_BLOCK_DEBUG 0xABE00000
@ -306,80 +304,6 @@ static void DOSMEM_FillBiosSegments(void)
*(pBiosSys+0xfffe) = 0xfc;
}
/***********************************************************************
* DOSMEM_InitCollateTable
*
* Initialises the collate table (character sorting, language dependent)
*/
static void DOSMEM_InitCollateTable()
{
DWORD x;
unsigned char *tbl;
int i;
x = GlobalDOSAlloc16(258);
DOSMEM_CollateTable = MAKELONG(0,(x>>16));
tbl = DOSMEM_MapRealToLinear(DOSMEM_CollateTable);
*(WORD*)tbl = 0x100;
tbl += 2;
for ( i = 0; i < 0x100; i++) *tbl++ = i;
}
/***********************************************************************
* DOSMEM_InitErrorTable
*
* Initialises the error tables (DOS 5+)
*/
static void DOSMEM_InitErrorTable()
{
#if 0 /* no longer used */
DWORD x;
char *call;
/* We will use a snippet of real mode code that calls */
/* a WINE-only interrupt to handle moving the requested */
/* message into the buffer... */
/* FIXME - There is still something wrong... */
/* FIXME - Find hex values for opcodes...
(On call, AX contains message number
DI contains 'offset' (??)
Resturn, ES:DI points to counted string )
PUSH BX
MOV BX, AX
MOV AX, (arbitrary subfunction number)
INT (WINE-only interrupt)
POP BX
RET
*/
const int code = 4;
const int buffer = 80;
const int SIZE_TO_ALLOCATE = code + buffer;
/* FIXME - Complete rewrite of the table system to save */
/* precious DOS space. Now, we return the 0001:???? as */
/* DOS 4+ (??, it seems to be the case in MS 7.10) treats that */
/* as a special case and programs will use the alternate */
/* interface (a farcall returned with INT 24 (AX = 0x122e, DL = */
/* 0x08) which lets us have a smaller memory footprint anyway. */
x = GlobalDOSAlloc16(SIZE_TO_ALLOCATE);
DOSMEM_ErrorCall = MAKELONG(0,(x>>16));
DOSMEM_ErrorBuffer = DOSMEM_ErrorCall + code;
call = DOSMEM_MapRealToLinear(DOSMEM_ErrorCall);
memset(call, 0, SIZE_TO_ALLOCATE);
#endif
/* FIXME - Copy assembly into buffer here */
}
/***********************************************************************
* DOSMEM_InitMemory
*
@ -480,8 +404,6 @@ BOOL DOSMEM_Init(BOOL dos_init)
DOSMEM_FillBiosSegments();
DOSMEM_FillIsrTable();
DOSMEM_InitMemory();
DOSMEM_InitCollateTable();
DOSMEM_InitErrorTable();
already_done = 1;
}
else if (dos_init && !already_mapped)

View file

@ -122,15 +122,12 @@ struct EDPB /* FAT32 extended Drive Parameter Block */
};
WORD CodePage = 437;
DWORD dpbsegptr;
struct DosHeap {
BYTE InDosFlag;
BYTE mediaID;
BYTE biosdate[8];
struct DPB dpb;
BYTE DummyDBCSLeadTable[6];
};
static struct DosHeap *heap;
static WORD DosHeapHandle;
@ -153,9 +150,7 @@ static BOOL INT21_CreateHeap(void)
}
heap = (struct DosHeap *) GlobalLock16(DosHeapHandle);
dpbsegptr = MAKESEGPTR(DosHeapHandle,(int)&heap->dpb-(int)heap);
heap->InDosFlag = 0;
strcpy(heap->biosdate, "01/01/80");
memset(heap->DummyDBCSLeadTable, 0, 6);
return TRUE;
}
@ -751,21 +746,6 @@ static BOOL INT21_GetCurrentDirectory( CONTEXT86 *context )
}
static void INT21_GetDBCSLeadTable( CONTEXT86 *context )
{
if (heap || INT21_CreateHeap())
{ /* return an empty table just as DOS 4.0+ does */
context->SegDs = DosHeapHandle;
SET_SI( context, (int)&heap->DummyDBCSLeadTable - (int)heap );
}
else
{
SET_AX( context, 0x1 ); /* error */
SET_CFLAG(context);
}
}
static int INT21_GetDiskSerialNumber( CONTEXT86 *context )
{
BYTE *dataptr = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
@ -1167,13 +1147,6 @@ void WINAPI INT_Int21Handler( CONTEXT86 *context )
}
break;
case 0x34: /* GET ADDRESS OF INDOS FLAG */
TRACE("GET ADDRESS OF INDOS FLAG\n");
if (!heap) INT21_CreateHeap();
context->SegEs = DosHeapHandle;
SET_BX( context, (int)&heap->InDosFlag - (int)heap );
break;
case 0x36: /* GET FREE DISK SPACE */
TRACE("GET FREE DISK SPACE FOR DRIVE %s\n",
INT21_DriveName( DL_reg(context)));
@ -1639,76 +1612,6 @@ void WINAPI INT_Int21Handler( CONTEXT86 *context )
}
break;
case 0x61: /* UNUSED */
case 0x63: /* misc. language support */
switch (AL_reg(context)) {
case 0x00: /* GET DOUBLE BYTE CHARACTER SET LEAD-BYTE TABLE */
INT21_GetDBCSLeadTable(context);
break;
}
break;
case 0x65:{/* GET EXTENDED COUNTRY INFORMATION */
BYTE *dataptr=CTX_SEG_OFF_TO_LIN(context, context->SegEs,context->Edi);
TRACE("GET EXTENDED COUNTRY INFORMATION code page %d country %d\n",
BX_reg(context), DX_reg(context));
switch (AL_reg(context)) {
case 0x01:
TRACE("\tget general internationalization info\n");
dataptr[0] = 0x1;
*(WORD*)(dataptr+1) = 41;
*(WORD*)(dataptr+3) = GetSystemDefaultLangID();
*(WORD*)(dataptr+5) = CodePage;
*(DWORD*)(dataptr+0x19) = 0; /* FIXME: ptr to case map routine */
break;
case 0x06:
TRACE("\tget pointer to collating sequence table\n");
dataptr[0] = 0x06;
*(DWORD*)(dataptr+1) = MAKELONG(DOSMEM_CollateTable & 0xFFFF,DOSMEM_AllocSelector(DOSMEM_CollateTable>>16));
SET_CX( context, 258 );/*FIXME: size of table?*/
break;
case 0x20:
TRACE("\tConvert char to uppercase\n");
SET_DL( context, toupper(DL_reg(context)) );
break;
case 0x21:
TRACE("\tconvert string to uppercase with length\n");
{
char *ptr = (char *)CTX_SEG_OFF_TO_LIN(context,context->SegDs,context->Edx);
WORD len = CX_reg(context);
while (len--) { *ptr = toupper(*ptr); ptr++; }
}
break;
case 0x22:
TRACE("\tConvert ASCIIZ string to uppercase\n");
_strupr( (LPSTR)CTX_SEG_OFF_TO_LIN(context,context->SegDs,context->Edx) );
break;
default:
TRACE("\tunimplemented function %d\n",AL_reg(context));
INT_BARF( context, 0x21 );
SET_CFLAG(context);
break;
}
break;
}
case 0x66: /* GLOBAL CODE PAGE TABLE */
switch (AL_reg(context))
{
case 0x01:
TRACE("GET GLOBAL CODE PAGE TABLE\n");
SET_BX( context, CodePage );
SET_DX( context, CodePage );
RESET_CFLAG(context);
break;
case 0x02:
TRACE("SET GLOBAL CODE PAGE TABLE active page %d system page %d\n",
BX_reg(context),DX_reg(context));
CodePage = BX_reg(context);
RESET_CFLAG(context);
break;
}
break;
case 0x68: /* "FFLUSH" - COMMIT FILE */
case 0x6a: /* COMMIT FILE */
TRACE("FFLUSH/COMMIT handle %d\n",BX_reg(context));