NLS changes from Steffen

git-svn-id: https://svn.code.sf.net/p/freedos/svn/kernel/trunk@625 6ac86273-5f31-0410-b378-82cca8765d1b
This commit is contained in:
Bart Oldeman 2003-06-27 22:02:57 +00:00
parent 2fdf99331d
commit 4780a1fc94
3 changed files with 75 additions and 381 deletions

View File

@ -284,8 +284,12 @@
/*
* How the kernel and NLSFUNC communicate with each other
*/
/* Must be returned by NLSFUNC upon MUX-14-00 */
/* Must be pased to and returned by NLSFUNC upon MUX-14-00 */
#define NLS_FREEDOS_NLSFUNC_ID 0x534b
/* What version of nlsInfo and accompanying associations
Must be passed to NLSFUNC upon MUX-14-00 to identify the
correct kernel to the tools. */
#define NLS_FREEDOS_NLSFUNC_VERSION 0xFD01
/* Represents a call to DOS-38 within DOS-65 handlers.
Current implementation relys on 0x101! */
#define NLS_DOS_38 0x101
@ -324,10 +328,10 @@
#define NLS_FLAG_DIRECT_YESNO 0x0004 /* DOS-65-23 */
#define NLS_FLAG_DIRECT_GETDATA 0x0008 /* DOS-65-XX, DOS-38 */
#define NLS_FLAG_HARDCODED NLS_FLAG_DIRECT_UPCASE \
#define NLS_FLAG_HARDCODED (NLS_FLAG_DIRECT_UPCASE \
| NLS_FLAG_DIRECT_FUPCASE \
| NLS_FLAG_DIRECT_YESNO \
| NLS_FLAG_DIRECT_GETDATA
| NLS_FLAG_DIRECT_GETDATA)
/* No codepage / country code given */
#define NLS_DEFAULT ((UWORD)-1)
@ -535,8 +539,9 @@ extern BYTE FAR hcTablesStart[], hcTablesEnd[];
COUNTRY.SYS into other files.
*/
#define CSYS_FD_IDSTRING "FreeDOS COUNTRY.SYS v1.0\r\n"
#define CSYS_FD_IDSTRING "FreeDOS COUNTRY.SYS v1.0\r\n\x1a"
#if 0
struct csys_function { /* S3: function definition */
UDWORD csys_rpos; /* relative position to actual data */
UWORD csys_length;
@ -550,20 +555,62 @@ struct csys_ccDefinition { /* S1: country/codepage reference */
UWORD csys_cp;
UWORD csys_cntry;
};
#endif
struct csys_ccDefinition { /* country/codepage reference */
UDWORD csys_pos; /* moving the 4byte value to the front
can increase performance */
UWORD csys_cntry;
UWORD csys_cp;
UWORD csys_size1; /* size of nlsPackage struct rpos is pointing to */
/* initially the object rpos is pointing to conforms to a
struct nlsPackage, where:
struct nlsPackage FAR *nxt; is missing
UWORD cntry, cp; is missing
int flags; is NLS_FLAG_HARDCODED, if the
kernel is to handle the data of its own
UBYTE yeschar; is filled
UBYTE nochar; is filled
unsigned numSubfct; is filled
struct nlsPointer nlsPointers[1]; is filled
the pointer member is the absolute
position of the data within the file
of this structure:
UWORD count
count bytes
The "count" value is not a part
of the data itself.
Also: The data must be ordered corresponding to
NLS_CODE_REORDER_POINTERS.
Also: The last nlsPointer is subfct #1 _incl_ all its
data [is the extended country information: struct nlsExtCntryInfo]
*/
};
struct csys_numEntries { /* helper structure for "number of entries" */
UWORD csys_entries;
};
/* Actually, this structure is never really used */
struct nlsCSys_fileHeader { /* S0: primary structure */
unsigned char csys_idstring[sizeof(CSYS_FD_IDSTRING) - 1];
/* decrement by 1 to cut off \0 from IDString -- ska */
/* Header of the COUNTRY.SYS file */
struct nlsCSys_fileHeader { /* COUNTRY.SYS header */
unsigned char csys_idstring[sizeof(CSYS_FD_IDSTRING)];
UWORD csys_maxTotalSize; /* maximal size of the total amount of
any individual definition, that includes
the nlsPackage skeleton and the sum of
all bytes required to load all the
subfunctions individually.
--> The code is to allocate maxTotalSize
and load any country definition of this
file into this buffer without any
overflow. */
DWORD csys_posIndex; /* absolute position of index table */
};
struct csys_completeFileHeader { /* as S0, but full 128 bytes */
unsigned char csys_idstring[sizeof(CSYS_FD_IDSTRING) - 1];
unsigned char csys_padbytes[128 - (sizeof(CSYS_FD_IDSTRING) - 1)];
/* Structure created by CountryInfoLoad() */
struct nlsCSys_loadPackage {
UWORD csys_size;
struct nlsPackage csys_pkg;
};
/* standard alignment */

View File

@ -130,7 +130,11 @@ COUNT muxLoadPkg(UWORD cp, UWORD cntry)
/* 0x1401 == not installed, not ok to install */
/* 0x14FF == installed */
r.BX = 0; /* make sure the NLSFUNC ID is updated */
r.BX = NLS_FREEDOS_NLSFUNC_VERSION; /* What version of nlsInfo */
#if NLS_FREEDOS_NLSFUNC_VERSION == NLS_FREEDOS_NLSFUNC_ID
/* make sure the NLSFUNC ID is updated */
#error "NLS_FREEDOS_NLSFUNC_VERSION == NLS_FREEDOS_NLSFUNC_ID"
#endif
r.CX = NLS_FREEDOS_NLSFUNC_ID;
if (muxGo(0, &r) != 0x14ff)
return DE_FILENOTFND; /* No NLSFUNC --> no load */

View File

@ -36,373 +36,16 @@ static BYTE *RcsId =
"$Id$";
#endif
#define filename Config.cfgCSYS_fnam
#define cntry Config.cfgCSYS_cntry
#define cp Config.cfgCSYS_cp
STATIC int err(void)
{
printf("Syntax error in or invalid COUNTRY.SYS: \"%s\"\n", filename);
return 0;
}
#define readStruct(s) readStructure(&(s), sizeof(s), fd)
STATIC int readStructure(void *buf, unsigned size, COUNT fd)
{
if (read(fd, buf, size) == size)
return 1;
return err();
}
/* Evaluate each argument only once */
#define readFct(p,f) readFct_((p), (f), fd)
int readFct_(void *buf, struct csys_function *fct, COUNT fd)
{
if (lseek(fd, fct->csys_rpos, 0) >= 0)
return readStructure(buf, fct->csys_length, fd);
return err();
}
#define seek(n) rseek((LONG)(n), fd)
static int rseek(LONG rpos, COUNT fd)
{
if (lseek(fd, rpos, 1) >= 0)
return 1;
return err();
}
COUNT csysOpen(void)
{
COUNT fd;
struct nlsCSys_fileHeader header;
if ((fd = open(filename, 0)) < 0)
{
printf("Cannot open: \"%s\"\n", filename);
return 1;
}
if ((read(fd, &header, sizeof(header)) != sizeof(header))
||strcmp(header.csys_idstring, CSYS_FD_IDSTRING) != 0
|| lseek(fd, (LONG) sizeof(struct csys_completeFileHeader), 0)
!= (LONG) sizeof(struct csys_completeFileHeader))
{
printf("No valid COUNTRY.SYS: \"%s\"\n\nTry NLSFUNC /i %s\n", filename,
filename);
close(fd);
return -1;
}
return fd;
}
/* Searches for function definition of table #fctID and
moves it at index idx */
STATIC int chkTable(int idx, int fctID, struct csys_function *fcts,
int numFct)
{
struct csys_function *fct, hfct;
int i;
for (i = 0, fct = fcts; i < numFct; ++i, ++fct)
if (fct->csys_fctID == fctID)
{
/* function found */
if (i == idx) /* already best place */
return 1;
/* Swap both places */
fmemcpy(&hfct, fct, sizeof(hfct));
fmemcpy(fct, &fcts[idx], sizeof(hfct));
fmemcpy(&fcts[idx], &hfct, sizeof(hfct));
return 1;
}
printf("Mandatory table %u not found.\n", fctID);
return 0;
}
/*
* Description of the algorithm the COUNTRY= information is loaded.
1) LoadCountry() is activated in pass 1, because it offers the functionality
how to upcase characters to the kernel, it should be activated as
soon as possible within processing CONFIG.SYS.
2) The method to locate the actual data within COUNTRY.SYS is pretty
basic and straight forward; so no detailed description here.
3) To reduce permanent memory useage the option NLS_MODIFYABLE_DATA
controls whether or not the loaded NLS pkg may be modified. By default,
modifying this data is _not_ supported.
The reason is to allow to re-use already loaded data, e.g. to use the
same physical table for #2 (normal upcase) and #4 (filename upcase).
NLSFUNC even can re-use the data loaded via COUNTRY= and the hardcoded data.
4) The problem is that even without point 3) it is not easily possible to
pre-judge how many bytes the NLS pkg will allocate in memory, because
this NLS implementation wants to support a wider range of NLS pkgs; because
neither the number of subfunctions nor the size of the data per subfunction
is fixed globally.
Therefore, the package is built-up incrementally:
4.1) First all function definition structures (S3) are read into memory.
While doing so the position field is transformed into the absolute
position within COUNTRY.SYS.
4.2) Then they are checked if a subfunction is defined more than once.
4.3) Then the entries are sorted in that way that tables 0x23, 1, 2, 4 and 5
lead the table in that order.
4.4) Then the basic nlsPackage with as many entries within nlsPointers[]
is allocated as there are function definitions left (minus one as the
pseudo-table 0x23 does not require an entry).
4.5) Pseudo-table 0x23 is installed.
4.6) Table 1 is installed at the very end of the nlsPointers[] array.
4.7) In the order all remaining function definitions are installed in
the same order as in the other array.
5) "Installing" means (except table 0x23):
5.1) Enlarge the nlsPackage structure to hold the necessary bytes of the
function definition (member csys_length).
5.2) Only if NLS_MODIFYABLE_DATA is _not_ defined and table is not #1:
The loaded data is compared to already loaded data and if such pattern is
already found in memory, a pointer to that memory area is used and the
loaded data is discarded.
First the local data is searched through, then the area of the hardcoded
NLS pkg.
Efficiency: function definitions with the same file position can automatically
use the same memory area.
6) When all function definitions are loaded, the nlsPackage structure is
tightly filled without any pad bytes; two areas are wasted:
a) The area containing the S3 structures, and
b) probably the last loaded data could be found within the memory already,
so the nlsPackage structure is larger than necessary.
8) But the memory allocation in pass 1 is temporary anyway, because in
the PostConfig() phase, all memory allocations are revoked and created
anew. At this point -- immediately after revoking all memory and
_before_ allocating any new memory -- the NLS pkg is located completely
within memory and one knows exactly which bytes to spare, and which data
can share the same physical memory; but if the normal PostConfig()
process would go on, this information would be lost, because it could be
overwritten.
==> Therefore the almost first operation within PostConfig() is to
move the NLS pkg upto the top (base?) of memory, thus, making sure
it is not overwritten and one need not re-load all the structures from
memory and, by doing so, loose the information which memory can be shared.
9) Once this operation has been completed, the NLS pkg is joined into the
nlsInfo chain of loaded packages and is made active.
===
To ease implementation the value of FP_SEG(nlsPointers[].pointer) != 0,
if the pointer refers to an absolute place, whereas FP_SEG() == 0,
indicates that the FP_OFF(...) is the offset base-relative to the data
offset; which is base-relative to the "nls" pointer.
*/
int csysLoadPackage(COUNT fd)
{
struct csys_numEntries entries;
struct csys_ccDefinition entry;
struct csys_function *fcts;
struct nlsPackage *nls;
struct nlsPointer *poi;
int highmark, numFct, i, j;
int totalSize;
#ifndef NLS_MODIFYABLE_DATA
BYTE FAR *p;
#endif
#define numE entries.csys_entries
#define bufp(offset) (((BYTE*)nls) + (offset))
#define fct fcts[numFct]
/* When this function is called, the position of the file is
at offset 128 (number of country/codepage pairs) */
if (!readStruct(entries))
return 0;
while (numE--)
{
if (!readStruct(entry))
return 0;
if (entry.csys_cntry == cntry
&& (cp == NLS_DEFAULT || entry.csys_cp == cp))
{
/* Requested entry found! */
if (!seek(entry.csys_rpos) || !readStruct(entries))
return 0;
/* Now reading the function definitions at this position */
if (numE < 5)
{
printf("Syntax error in COUNTRY.SYS: Too few subfunctions\n");
return 0;
}
/* If the file structure is good, each but one entry (0x23) is
one item within nlsPointers[] array */
fcts = KernelAlloc(sizeof(struct csys_function) * numE);
numFct = 0; /* number of already loaded fct definition */
totalSize = 0;
{
if (!readStruct(fct))
return 0;
switch (fct.csys_fctID)
{
case 0:
case 0x20:
case 0x21:
case 0x22:
case 0xA0:
case 0xA1:
case 0xA2:
printf("Invalid subfunction %u ignored", fct.csys_fctID);
continue;
case 0x23:
if (fct.csys_length != 2)
{
printf("Pseudo-table 35 length mismatch\n");
continue;
}
}
/* Search if the subfunction is already there */
for (j = 0; j < numFct && fcts[j].csys_fctID != fct.csys_fctID;
++j) ;
if (j != numFct)
{
printf("Subfunction %u defined multiple times, ignored\n",
fct.csys_fctID);
continue;
}
/* OK --> update the rpos member */
fct.csys_rpos += DosLtell(fd);
totalSize += fct.csys_length;
++numFct;
}
while (--numE) ;
/* i is the number of available function definition */
/* check if all mandatory tables are loaded, at the same
time re-order the function definitions like that:
0x23, 1, 2, 4, 5
*/
/* That's automatically a check that more than 3 definitions
are available */
if (!chkTable(0, 0x23, fcts, numFct) /* pseudo-table 0x23 yes/no */
|| !chkTable(1, 1, fcts, numFct) /* ext cntry info */
|| !chkTable(2, 2, fcts, numFct) /* normal upcase */
|| !chkTable(3, 4, fcts, numFct) /* filename upcase */
|| !chkTable(4, 5, fcts, numFct)) /* filename terminator chars */
return 0;
/* Begin the loading process by to allocate memory as if
we had to load every byte */
/* One nlsPointers structure is already part of nlsPackage;
two function definitions need no nlsPointers entry (0x32, 1);
one additional byte is required by table 1, but which is
already within totalSize as the length of pseudo-table
0x23 has been counted. */
nls = KernelAlloc((data = sizeof(struct nlsPackage)
+ (numFct - 3) * sizeof(struct nlsPointer)) +
totalSize);
/* data := first byte not used by the control area of
the nlsPackage structure; at this point it is the
offset where table #1 is to be loaded to */
/* Install pseudo-table 0x23 */
if (!readFct((BYTE *) & nls->yeschar, fcts))
return 0;
nls->numSubfct = numFct - 1; /* pseudo-table 0x23 */
/* Install table #1 has it must overlay the last nlsPointers[]
item */
*bufp(data) = 1; /* table #1 starts with the subfctID
then the data from the file follows */
if (!readFct(bufp(++data), ++fcts))
return 0;
data += fcts->csys_length; /* first byte of local data area */
highmark = data; /* first unused byte */
for (j = 0, poi = nls->nlsPointers; j < numFct - 1; ++j, ++poi)
{
/* consecutively load all functions */
if (!readFct(bufp(data), ++fcts))
return 0;
poi->subfct = fcts->csys_fctID;
/* Now the function data is located at the current top of
used memory and, if allowed, the other memory is
tested, if such image is already loaded */
#ifndef NLS_MODIFYABLE_DATA
/* Try to locate the contents of the buffer */
/** brute force **/
/* For the standard tables one need to match tables
2 and 4 only. */
for (i = data; i + fcts->csys_length < highmark; ++i)
{
if (memcmp(bufp(i), bufp(highmark), fcts->csys_length) == 0)
{
/* found! */
/* ==> leave highmark untouch, but modify pointer */
poi->pointer = MK_FP(0, i);
/* the segment portion == 0 identifies this pointer
as local within the current data area */
goto nxtEntry;
}
}
/* Now try the hardcoded area */
for (p = hcTablesStart; p < hcTablesEnd - fcts->csys_length; ++p)
{
if (fmemcmp(p, bufp(highmark), fcts->csys_length) == 0)
{
/* found! */
/* ==> leave highmark untouch, but modify pointer */
poi->pointer = p;
/* the segment portion != 0 identifies this is an
absolute pointer */
goto nxtEntry;
}
}
#endif
/* Either not found or modifyable data allowed */
poi->pointer = MK_FP(0, highmark); /* local address */
highmark += fcts->csys_length; /* need to keep the data */
nxtEntry:
}
/* how many memory is really required */
Country.cfgCSYS_memory = highmark;
Country.cfgCSYS_data = nls;
return 1;
}
}
#undef numE
if (cp == NLS_DEFAULT)
printf("No definition of country ID %u in file \"%s\"\n",
cntry, filename);
else
printf
("No definition of country ID %u for codepage %u in file \"%s\"\n",
cntry, cp, filename);
return 0;
}
BOOL LoadCountryInfo(char *fnam)
{
COUNT fd;
int rc;
if (strlen(fnam) < sizeof(filename))
{
strcpy(filename, fnam);
if ((fd = csysOpen()) >= 0)
{
rc = csysLoadPackage(fd);
close(fd);
return rc;
}
}
else
printf("Filename too long\n");
return 0;
}
/** Setup the environment for shared source NLS_LOAD.SRC **/
/**ska obsoleted #define cfgMemory Config.cfgCSYS_memory */
/**ska obsoleted #define cfgFilename Config.cfgCSYS_fnam */
#define cfgFilename nlsInfo.fname /* char FAR * */
/**ska obsoleted #define cfgCountry Config.cfgCSYS_cntry */
/**ska obsoleted #define cfgCodepage Config.cfgCSYS_cp */
#define cfgData Config.cfgCSYS_data /* struct nlsCSys_loadPackage FAR * */
#define getMem(bytes) KernelAlloc(bytes)
#define openSYSFile(filename) open(filename, 0) /* read-only, binary */
#define nlsStartOfChain nlsInfo.chain
#define upCaseFct CharMapSrvc
#include "nls_load.src"