/****************************************************************/
/*                                                              */
/*                            NLS.H                             */
/*                           FreeDOS                            */
/*                                                              */
/*    National Language Support data structures                 */
/*                                                              */
/*                   Copyright (c) 2000                         */
/*                         Steffen Kaiser                       */
/*                      All Rights Reserved                     */
/*                                                              */
/* This file is part of FreeDOS.                                */
/*                                                              */
/* DOS-C is free software; you can redistribute it and/or       */
/* modify it under the terms of the GNU General Public License  */
/* as published by the Free Software Foundation; either version */
/* 2, or (at your option) any later version.                    */
/*                                                              */
/* DOS-C is distributed in the hope that it will be useful, but */
/* WITHOUT ANY WARRANTY; without even the implied warranty of   */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See    */
/* the GNU General Public License for more details.             */
/*                                                              */
/* You should have received a copy of the GNU General Public    */
/* License along with DOS-C; see the file COPYING.  If not,     */
/* write to the Free Software Foundation, 675 Mass Ave,         */
/* Cambridge, MA 02139, USA.                                    */
/****************************************************************/

/* one byte alignment */
#include "algnbyte.h"

/*
 *	Description of the organization of NLS information -- 2000/02/13 ska
 *
 *	Glossar:
 *	NLS package -- NLS information incl. any code required to access or
 *		correctly interprete this particular information
 *
 *	Abbreviation:
 *	(NLS) pkg -- NLS package
 *
 *	The code included into the kernel does "only" support NLS packages
 *	structurally compatible with the one of the U.S.A. / CP437.
 *	I guess that most NLS packages has been tweaked to be compatible,
 *	so that this is not a real limitation, but for all other packages
 *	the external NLSFUNC can supply every piece of code necessary.
 *	To allow this the interface between the kernel and NLSFUNC has been
 *	extended; at the same time the interface has been reduced, because some
 *	of the API functions do not seem to offer any functionality required
 *	for now. This, however, may be a misinterpretation because of
 *	lack of understanding.
 *
 *	The supported structure consists of the following assumptions:
 *	1) The pkg must contain the tables 2 (Upcase character), 4
 *		(Upcase filename character) and 5 (filename termination
 *		characters); because they are used internally.
 *	2) The tables 2 and 4 must contain exactly 128 (0x80) characters.
 *		The character at index 0 corresponses to character 128 (0x80).
 *		The characters in the range of 0..0x7f are constructed out of
 *		the 7-bit US-ASCII (+ control characters) character set and are
 *		upcased not through the table, but by the expression:
 *			(ch >= 'a' && ch <= 'z')? ch - 'a' + 'A': ch
 *			with: 'a' == 97; 'z' == 122; 'A' == 65
 *	3) The data to be returned by DOS-65 is enlisted in the
 *		nlsPointer[] array of the nlsPackage structure, including
 *		the DOS-65-01 data, which always must be last entry of the
 *		array.
 *	4) DOS-38 returns the 34 bytes beginning with the byte at offset
 *		4 behind the size field of DOS-65-01.
 *
 *	It seems that pure DOS can internally maintain two NLS pkgs:
 *	NLS#1: The hardcoded pkg of U.S.A. on CP437, and
 *	NLS#2: the pkg loaded via COUNTRY= from within CONFIG.SYS.
 *	I do interprete this behaviour as follows:
 *	CONFIG.SYS is read in more passes; before COUTRY= can be evaluated,
 *	many actions must be performed, e.g. to load kernel at all, open
 *	CONFIG.SYS and begin reading. The kernel requires at least two
 *	NLS information _before_ COUNTRY= has been evaluated - both upcase
 *	tables. To not implement the same function multiple times, e.g.
 *	to upcase with and without table, the kernel uses the default
 *	NLS pkg until a more appropriate one can be loaded and hopes that
 *	the BIOS (and the user) can live with its outcome.
 *	Though, theoretically, the hardcoded NLS pkg could be purged
 *	or overwritten once the COUNTRY= statement has been evaluated.
 *	It would be possible that this NLS pkg internally performs different
 *	purposes, for now this behaviour will be kept.
 *
 *	The current implementation extends the above "two maintained
 *	NLS pkgs" into that the kernel chains all NLS pkgs loaded in
 *	memory into one single linked list. When the user does neither
 *	wants to load other NLS pkgs without executing NLSFUNC and the
 *	loaded NLS pkgs do not contain code themselves, no other code is
 *	required, but some memory to store the NLS pkgs into.
 *
 *	Furthermore, because the kernel needs to include the code for the
 *	hardcoded NLS pkg anyway, every NLS pkg can use it; so only
 *	NLS pkgs that structurally differ from U.S.A./CP437 actually need
 *	to add any code and residently install the MUX handler for NLSFUNC.
 *	This technique reduces the overhead calling the MUX handler, when
 *	it is not needed.
 *	However, NLSFUNC is always required if the user wants to return
 *	information about NLS pkgs _not_ loaded into memory.
 *
 *=== Attention: Because the nlsInfoBlock structure differs from the
 *===	the "traditional" (aka MS) implementation, the MUX-14 interface
 *===	is _not_ MS-compatible, although all the registers etc.
 *===	do conform. -- 2000/02/26 ska
 *
 *	Previous failed attempts to implement NLS handling and a full-
 *	featured MUX-14 supporting any-structured NLS pkgs suggest
 *	to keep the implement as simple as possible and keep the
 *	optimization direction off balance and to tend toward either
 *	an optimization for speed or size.
 *
 *	The most problem is that the MUX interrupt chain is considered
 *	highly overcrowded, so if the kernels invokes it itself, the
 *	performance might decrease dramatically; on the other side, the
 *	more complex the interface between kernel and a _probably_ installed
 *	external NLSFUNC becomes the more difficult all the stuff is becoming
 *	and, most importantly, the size grows unnecessarily, because many
 *	people don't use NLSFUNC at all.
 *
 *	The kernel uses the NLS pkg itself for two operations:
 *	1) DOS-65-2x and DOS-65-Ax: Upcase character, string, memory area, &
 *	2) whenever a filename is passed into the kernel, its components
 *		must be identified, invalid characters must be detected
 *		and, finally, all letters must be uppercased.
 *	I do not consider operation 1) an action critical for performance,
 *	because traditional DOS programming praxis says: Do it Yourself; so
 *	one can consider oneself lucky that a program aquires the upcase
 *	table once in its life time (I mean: lucky the program calls NLS at all).
 *	Operation 2), in opposite, might dramatically reduce performance, if
 *	it lacks proper implementations.
 *
 *	Straight forward implementation:
 *	The basic implementation of the NLS channels all requests of DOS-65,
 *	DOS-66, and DOS-38 through MUX-14. Hereby, any external program, such
 *	as NLSFUNC, may (or may not) install a piece of code to filter
 *	one, few, or all requests in order to perform them itself, by default
 *	all requests will end within the root of the MUX interrupt, which is
 *	located within the kernel itself. An access path could look like this:
 *	1. Call to DOS-65-XX, DOS-66-XX, or DOS-38.
 *	2. The kernel is enterred through the usual INT-21 API handler.
 *	3. The request is decoded and one of the NLS.C function is called.
 *	4. This function packs a new request and calls MUX-14.
 *	5. Every TSR/driver hooking INT-2F will check, if the request is
 *		directed for itself;
 *	5.1. If not, the request is passed on to the next item of the MUX
 *		interrupt chain;
 *	5.2. If so, the TSR, e.g. NLSFUNC, tests if the request is to be
 *		performed internally;
 *	5.2.1. If so, the request is performed and the MUX-14 call is
 *		terminated (goto step 8.)
 *	5.2.2. If not, the request is passed on (see step 5.1.)
 *	6. If all TSRs had their chance to filter requests, but none decided
 *		to perform the request itself, the kernel is (re-)enterred
 *		through its INT-2F (MUX) API handler.
 *	7. Here the request is decoded again and performed with the kernel-
 *		internal code; then the MUX-14 call is terminated.
 *	8. When the MUX-14 call returns, it has setup all return parameters
 *		already, so the INT-21 call is terminated as well.
 *
 *	Note: The traditional MUX-14 is NOT supported to offer functionality
 *	to the kernel at the first place, but to let the kernel access and
 *	return any values they must be loaded into memory, but the user may
 *	request information through the DOS-65 interface of NLS pkgs _not_
 *	already loaded. Theoretically, NLSFUNC needs not allocate any internal
 *	buffer to load the data into, because the user already supplied one;
 *	also if the kernel would instruct NLSFUNC to load the requested
 *	NLS pkg, more memory than necessary would be allocated. However, all
 *	except subfunction 1 return a _pointer_ to the data rather than the
 *	data itself; that means that NLSFUNC must cache the requested data
 *	somewhere, but how long?
 *
 *	Performance tweaks:
 *	When the system -- This word applies to the combination of kernel and
 *	any loaded MUX-14 extension � la NLSFUNC here. -- uppercases
 *	_filenames_, it must perform a DOS-65-A2 internally. In the basic
 *	implementation this request would be channeled through MUX-14, even
 *	if there is no external NLSFUNC at all. Also, when a NLS pkg had
 *	been loaded by the kernel itself, it complies to above mentioned
 *	rules and it is very unlikely that it is necessary to probe if
 *	a MUX-14 TSR might want to perform the request itself. Therefore
 *	each NLS pkg contains some flags that allow the kernel to bypass
 *	the MUX-14 request and invoke the proper function directly. Both
 *	default NLS pkgs will have those flags enabled, because they are
 *	already loaded into memory and must comply to the rules.
 *
 *	Note: Those flags do not alter the way the request is actually
 *	performed, but the MUX-14 call is omitted only (steps 4. through 6.).
 *
 *	======= Description of the API
 *
 *	There are three APIs to be supported by NLS:
 *	1) DOS API: DOS-38, DOS-65, DOS-66;
 *	2) MUX-14, and
 *	3) internal: upcasing filenames.
 *
 *	1) and 2) address the used NLS pkg by the country code / codepage pair.
 *	3) uses the currently active NLS pkg only; furthermore, these functions
 *	more or less match DOS-64-A*. Therefore, the NLS system merges the
 *	interfaces 1) and 3) and offers function suitable for both ones.
 *
 *	Both 1) and 3) must channel the request through the MUX chain, if
 *	appropriate, whereas 2) is the back-end and does natively process the
 *	request totally on its own.
 *
 *	The API of 1) and 3) consists of:
 *		+ DosUpChar(), DosUpString(), and DosUpMem(): to upcase an object
 *	(DOS-65-2[0-2]);
 *		+ DosYesNo(): to check a character, if it is the yes or no prompt
 *	(DOS-65-23);
 *		+ DosUpFChar(), DosUpFString(), and DosUpFMem(): to upcase an object
 *	for filenames (DOS-65-A[0-2]);
 *		+ DosGetData(): to retreive certain information (DOS-38, all the
 *	other DOS-65-** subfunctions);
 *		+ DosSetCountry(): to change the currently active country code
 *	(DOS-38);
 *		+ DosSetCodepage(): to change the currently active codepage (DOS-66).
 *
 *	The API of 2) consists of:
 *		+ syscall_MUX14().
 *	This function is invoked for all MUX-14 requests and recieves the
 *	registers of the particular INT-2F call, it will then decode the
 *	registers and pass the request forth to a NLS-internal interface
 *	consisting of the following "static" functions:
 *		+ nlsUpMem(): called for DosUp*(),
 *		+ nlsUpFMem(): called for DosUpF*(),
 *		+ nlsYesNo(): called for DosYesNo(),
 *		+ nlsGetData(): called for DosGetData(),&
 *		+ nlsSetPackage(): called for DosSetCountry() and DosSetCodepage().
 *	In opposite of the APIs 1) through 3) the NLS-internal functions address
 *	the NLS pkg to operate upon by a (struct nlsInfoBlock *) pointer.
 *
 *	This designs supports to easily implement to bypass the MUX chain to
 *	speed up especially the internal API to upcase filenames, because
 *	the Dos*() functions can decide do not pass the request through MUX,
 *	but directly call the nls*() function instead. This way it is ensured
 *	that the performed actions are the same in both cases and, with repect
 *	to the functions that operate with the currently active NLS pkg, the
 *	performance is rather high, because one can use the globally available
 *	pointer to the current NLS pkg and need not search for a country code/
 *	codepage pair.
 *
 *	======== Compile-time options
 *
 *	Win9x supports to change the individual portions of a NLS pkg
 *	through DOS-65-00; also there are no references what happens when
 *	a program changes the areas addressed by returned pointers. The
 *	current implementation does _not_ support changes of the NLS pkg
 *	except by invoking DOS-38 (Set Country Code) or DOS-66 (Set Codepage).
 *	Future implementations might offer this ability; to reduce the
 *	overhead introduced by this feature, the macro NLS_MODIFYABLE_DATA
 *	enables the appropriate code.
 *	NLS_MODIFYABLE_DATA is *disabled* by default.
 *
 *	The tables 2 and 4 (upcase tables) are accessed relatively often,
 *	but theoretically these tables could be located at any position
 *	of the pointer array. If the macro NLS_REORDER_POINTERS is enabled,
 *	both NLSFUNC and the internal loader will reorder the pointers
 *	array so that mandatory tables are located at predictable indexes.
 *	This removes that the kernel must search for the table when
 *	one of the DOS-65-[2A]x functions is called or a filename has been
 *	passed in (which must be uppercased to be suitable for internal
 *	purpose). However, when some program try to tweak the internal
 *	tables this assumption could be wrong.
 *	This setting has any effect only, if the kernel tries to access
 *	information itself; it is ignored when the user calls DOS-65-0x
 *	to return such pointer.
 *	NLS_REORDER_POINTERS is *enabled* by default.
 *      UPDATE: With NLS_REORDER_POINTERS, now table 7 (DBCS) is also
 *      expected to be located at a predictable index. -- eca
 */

/* Define if some user program possibly modifies the value of the internal
	tables or the DOS-65-00 (Set Country Information) API function
	is to be supported. */
/* Currently unimplemented! -- 2000/02/13 ska*/
/* #define NLS_MODIFYABLE_DATA */

/* Define if the pointer array shall be reordered to allow a quick
	access to often used and mandatoryly present tables. */
#define NLS_REORDER_POINTERS

/*
 *	How the kernel and NLSFUNC communicate with each other
 */
        /* 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 0xFD02
        /* Represents a call to DOS-38 within DOS-65 handlers.
           Current implementation relys on 0x101! */
#define NLS_DOS_38 0x101
        /* NLSFUNC may return NLS_REDO to instruct the kernel to
           try to perform the same action another time. This is most
           useful if the kernel only loads the NLS pkg into memory so
           the kernel will find it and will process the request internally
           now. */
#define NLS_REDO 353

/* Codes of the subfunctions of external NLSFUNC */
#define NLSFUNC_INSTALL_CHECK	0
#define NLSFUNC_DOS38			4
#define NLSFUNC_GETDATA			2
#define NLSFUNC_DRDOS_GETDATA	0xfe
#define NLSFUNC_LOAD_PKG		3
#define NLSFUNC_LOAD_PKG2		1
#define NLSFUNC_UPMEM			0x22
#define NLSFUNC_YESNO			0x23
#define NLSFUNC_FILE_UPMEM		0xa2

/* The NLS implementation flags encode what feature is in effect;
	a "1" in the bitfield means that the feature is active.
	All currently non-defined bits are to be zero to allow future
	useage. */
#define NLS_CODE_MODIFYABLE_DATA	0x0001
#define NLS_CODE_REORDER_POINTERS 	0x0002

/* NLS package useage flags encode what feature is in effect for this
	particular package:
	a "1" in the bitfield means that the feature is active/enabled.
	All currently non-defined bits are to be zero to allow future
	useage. */
#define NLS_FLAG_DIRECT_UPCASE		0x0001  /* DOS-65-2[012], */
#define NLS_FLAG_DIRECT_FUPCASE		0x0002  /* DOS-65-A[012], internal */
#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		\
							| NLS_FLAG_DIRECT_FUPCASE	\
							| NLS_FLAG_DIRECT_YESNO		\
							| NLS_FLAG_DIRECT_GETDATA)

        /* No codepage / country code given */
#define NLS_DEFAULT ((UWORD)-1)

struct CountrySpecificInfo {
  short CountryID;    /*  = W1 W437   # Country ID & Codepage */
  short CodePage;
  short DateFormat;           /*    Date format: 0/1/2: U.S.A./Europe/Japan */
  char  CurrencyString[5];    /* '$' ,'EUR'   */
  char  ThousandSeparator[2]; /* ','          # Thousand's separator */
  char  DecimalPoint[2];      /* '.'        # Decimal point        */
  char  DateSeparator[2];     /* '-'  */
  char  TimeSeparator[2];     /* ':'  */
  char  CurrencyFormat;       /* = 0  # Currency format (bit array) 
                                 0Fh    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    
                              */
  char  CurrencyPrecision;    /* = 2  # Currency precision           */
  char  TimeFormat;           /* = 0  # time format: 0/1: 12/24 houres */
  void FAR *CharMapFn;        /* far pointer to user callable character mapping function */
  char  DataSeparator[2];     /* ',' ASCIIZ value */
                              /* 5 words reserved, should be 0 */
};

/*
 *	This is the data in the exact order returned by DOS-65-01
 */
struct nlsExtCntryInfo {
  UBYTE subfct;                 /* always 1 */
  WORD size;                    /* size of this structure
                                   without this WORD itself */
  WORD countryCode;             /* current country code */
  WORD codePage;                /* current code page (CP) */

  /*
   *      This is the data in the exact order as to return on
   *      DOS-38; it is also the most (important) part of DOS-65-01
   */
  /* Note: The ASCIZ strings might become
     a totally different understanding with
     DBCS (Double Byte Character Support) */
  WORD dateFmt;                 /* order of portions of date
                                   0: mm/dd/yyyy (USA)
                                   1: dd/mm/yyyy (Europe)
                                   2: yyyy/mm/dd (Japan)
                                 */
  char curr[5];                 /* ASCIZ of currency string */
  char thSep[2];                /* ASCIZ of thousand's separator */
  char point[2];                /* ASCIZ of decimal point */
  char dateSep[2];              /* ASCIZ of date separator */
  char timeSep[2];              /* ASCIZ of time separator */
  BYTE currFmt;                 /* format of currency:
                                   bit 0: currency string is placed
                                   0: before number
                                   1: behind number
                                   bit 1: currency string and number are
                                   separated by a space
                                   0: No
                                   1: Yes
                                   bit 2: currency string replaces decimal
                                   sign
                                   0: No
                                   1: Yes
                                 */
  BYTE prescision;              /* of monetary numbers */
  BYTE timeFmt;                 /* time format:
                                   0: 12 hours (append AM/PM)
                                   1: 24 houres
                                 */
  intvec upCaseFct;             /* far call to a function upcasing the
                                           character in register AL */
  char dataSep[2];              /* ASCIZ of separator in data records */
};

struct nlsPointer {             /* Information of DOS-65-0X is addressed
                                   by a pointer */
  UBYTE subfct;                 /* number of the subfunction */
  VOID FAR *pointer;            /* the pointer to be returned when the subfunction
                                   of DOS-65 is called (Note: won't work for
                                   subfunctions 0, 1, 0x20, 0x21, 0x22, 0x23,
                                   0xA0, 0xA1,& 0xA2 */
};

struct nlsPackage {             /* the contents of one chain item of the
                                   list of NLS packages */
  struct nlsPackage FAR *nxt;   /* next item in chain */
  UWORD cntry, cp;              /* country ID / codepage of this NLS pkg */
  int flags;                    /* direct access and other flags */
  /* Note: Depending on the flags above all remaining
     portions may be omitted, if the external NLSFUNC-like
     MUX-14 processor does not require them and performs
     all actions itself, so that the kernel never tries to
     fetch this information itself. */
  UWORD yeschar;                /* yes / no character DOS-65-23 */
  UWORD nochar;
  unsigned numSubfct;           /* number of supported sub-functions */
  struct nlsPointer nlsPointers[5];     /* may grow dynamically */
  struct nlsExtCntryInfo nlsExt;
};

struct nlsDBCS {                /* The internal structure is unknown to me */
  UWORD numEntries;
  UWORD dbcsTbl[4];             /* I don't know max size but it should need
                                   at least 3 words (6 bytes)
                                   ({0x81,0x9f,0xe0,0xfc,0,0} for CP932-Japan)
                                   -- lpproj 2014/10/27 */
};

struct nlsCharTbl {
  /* table containing a list of characters */
  UWORD numEntries;             /* number of entries of this table.
                                   If <= 0x80, the first element of
                                   the table corresponse to character 0x80 */
  unsigned char tbl[1];         /* grows dynamically */
};
#define nlsChBuf(len)		struct nlsCharTbl##len {		\
			UWORD numEntries;							\
			unsigned char tbl[len];						\
		}
nlsChBuf(128);
nlsChBuf(256);

/* in file names permittable characters for DOS-65-05 */
struct nlsFnamTerm {
  WORD size;                    /* size of this structure */
  BYTE dummy1;
  char firstCh, lastCh;         /* first, last permittable character */
  BYTE dummy2;
  char firstExcl, lastExcl;     /* first, last excluded character */
  BYTE dummy3;
  BYTE numSep;                  /* number of file name separators */
  char separators[1];           /* grows dynamically */
};

struct nlsInfoBlock {           /* This block contains all information
                                   shared by the kernel and the external NLSFUNC program */
  char FAR *fname;              /* filename from COUNTRY=;
                                   maybe tweaked by NLSFUNC */
  UWORD sysCodePage;            /* system code page */
  unsigned flags;               /* implementation flags */
#ifdef __GNUC__
  /* need to initialize using explicit segment/offset */
  union {
    struct { struct nlsPackage *off; char *seg; };
    struct nlsPackage FAR *p;
  } actPkg, chain;
  #define actPkg actPkg.p
  #define chain chain.p
#else
  struct nlsPackage FAR *actPkg;        /* current NLS package */
  struct nlsPackage FAR *chain; /* first item of info chain --
                                   hardcoded U.S.A./CP437 */
#endif
};

extern struct nlsInfoBlock ASM nlsInfo;
extern struct nlsPackage      DOSFAR ASM nlsPackageHardcoded;
extern BYTE FAR hcTablesStart[], hcTablesEnd[];

/***********************************************************************
 ***** Definitions & Declarations for COUNTRY.SYS **********************
 ***********************************************************************/

/* Note: These definitions are shared among all tools accessing the
	COUNTRY.SYS file as well -- 2000/06/11 ska*/

/* File structure:
	S0: Base (Primary) structure -- file header
	Offset	Size	Meaning
	0		array	ID string "FreeDOS COUNTRY.SYS v1.0\r\n"
	26		array	Copyright etc. (plain 7bit ASCII text)
	26+N	2byte	\x1a\0
	26+N+2	array	padded with \0 upto next offset
	128		word	number of country/codepage pairs	(N1)
	130		8byte	country code / codepage entries	(S1)
	130+8*N1	end of array
	===
	S1: structure of country/codepage pair
	Offset	Size	Meaning
	0		dword	relative position of table definition	(S2)
	4		word	codepage ID
	6		word	country code
	8		end of structure
	===
	S2: table definition of one country/codepage pair
	Offset	Size	Meaning
	0		word	number of function entries	(N2)
	2		8byte	function definition	(S3)
	2+8*N2	end of array
	===
	S3: function definition
	Offset	Size	Meaning
	0		dword	relative position of function data (see S4)
	4		word	number of bytes of data
	6		byte	function ID (same as passed to DOS-65-XX)
	7		byte	reserved for future use (currently 0 (zero))
	8		end of structure
	===
	S4: function data
	In opposite of the structures and arrays, the function data
	is just a structure-less stream of bytes, which is used as it is.
	Currently no validation check is performed over this data.
	That means, for instance, that a definition of function 2 (upcase
	table) has length 130 and the data consists of a word value with
	the length (128) and 128 bytes individual information.
	That way the DBCS is implemented exactly the same way as all the
	other tables; the only exception is pseudo-table 0x23.
	===
	"relative position" means this DWord specifies the amount of bytes
	between end of the current structure and the data the pointer is
	referring to. This shall enable future implementations to embed
	COUNTRY.SYS into other files.
*/

#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;
  UBYTE csys_fctID;             /* As passed to DOS-65-XX */
  UBYTE csys_reserved1;         /* always 0, reserved for future use */
};

struct csys_ccDefinition {   /* S1: country/codepage reference */
  UDWORD csys_rpos;             /* moving the 4byte value to the front
                                   can increase performance */
  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
	  UWORD yeschar;                is filled
	  UWORD 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;
};

/* 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 */
};

/* Structure created by CountryInfoLoad() */
struct nlsCSys_loadPackage {
	UWORD csys_size;
	struct nlsPackage csys_pkg;
};

/* standard alignment */
#include "algndflt.h"

#ifdef DEBUG
        /* Enable debugging of NLS part */

        /* Caution: Enabling NLS debugging usually generates
           _a_lot_ of noise. */
/*& #define NLS_DEBUG */

#endif
