diff options
| -rw-r--r-- | kitten.c | 756 | ||||
| -rw-r--r-- | kitten.h | 50 | ||||
| -rw-r--r-- | kittenc.c | 548 | ||||
| -rw-r--r-- | kittenc.h | 44 | ||||
| -rw-r--r-- | makefile | 36 | ||||
| -rw-r--r-- | mousmain.c | 4 | ||||
| -rw-r--r-- | sfmain.c | 28 | ||||
| -rw-r--r-- | unitbl2c.c | 206 |
8 files changed, 1007 insertions, 665 deletions
@@ -1,180 +1,61 @@ /* Functions that emulate UNIX catgets */ -/* Copyright (C) 1999,2000,2001 Jim Hall <jhall@freedos.org> */ -/* Kitten version 2003 by Tom Ehlert, heavily modified by Eric Auer 2003 */ +/* Kitten version 2021 by Tom Ehlert, */ /* - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include <stdio.h> /* sprintf */ -#include <stdlib.h> /* getenv */ -#include <string.h> /* strchr */ -#include <fcntl.h> -#include <dos.h> -#if !defined(__TURBOC__) -#include <sys/stat.h> -#include <sys/types.h> -#endif - -#include "kitten.h" - -#if defined(__TURBOC__) -int dos_open(char *filename, int mode); -#define open(filename,mode) dos_open(filename,mode) - -int dos_read(int file, void *ptr, unsigned count); -#define read(file, ptr, count) dos_read(file,ptr,count) - -int dos_write(int file, void *ptr, unsigned count); -#define write(file, ptr, count) dos_write(file,ptr,count) - -void dos_close(int file); -#define close(file) dos_close(file) -#endif - -static char catcontents[6144]; /* *** Maximum size of PROGRAM.%LANG% file *** */ - -struct catstring{ - char key1; - char key2; - char *text; -}; - -typedef struct catstring catstring_t; + This software is free software; free to use, + modify, pass to others, whatever -static catstring_t catpoints[128]; /* max 128 strings can be defined... */ - - -/* Local prototypes */ + use it at your own risk +*/ -int catread (char *catfile); /* Reads a catfile into the hash */ -char *processEscChars(char *line); /* Converts c escape sequences to chars */ +/* Minor modifications to use internal static buffer to keep API compatible + * with regular kitten. */ -int get_char(int); /* not meant for external use */ -/* external use would cause consistency problems if */ -/* value or related file of the file handle changes */ +#ifndef NO_KITTEN -int mystrtoul(char *, int, int); +#include <stdio.h> /* sprintf */ +#include <stdlib.h> /* getenv */ +#include <io.h> /* sprintf */ +#include <fcntl.h> /* sprintf */ +#include <string.h> /* sprintf */ +#include "kitten.h" +#include "kittenc.h" /* Globals */ -static nl_catd _kitten_catalog = 0; /* _kitten_catalog descriptor or 0 */ -static char catfile[128]; /* full path to _kitten_catalog */ - -static char getlbuf[1024]; /* read buffer (better speed) -- 7/2004: 1k, not 8k */ -static char *getlp; /* current point in buffer */ -static int getlrem = -1; /* remaining bytes in buffer */ - - -#if defined(__TURBOC__) -/* DOS handle based file usage */ - -int dos_open(char *filename, int mode) -{ - union REGS r; - struct SREGS s; - (void)mode; /* mode ignored - readonly supported */ - r.h.ah = 0x3d; - r.h.al = 0; /* read mode only supoported now !! */ - r.x.dx = FP_OFF(filename); - s.ds = FP_SEG(filename); - intdosx(&r,&r,&s); - return ( (r.x.cflag) ? -1 : r.x.ax ); -} - - -int dos_read(int file, void *ptr, unsigned count) -{ - union REGS r; - struct SREGS s; - r.h.ah = 0x3f; - r.x.bx = file; - r.x.cx = count; - r.x.dx = FP_OFF(ptr); - s.ds = FP_SEG(ptr); - intdosx(&r,&r,&s); - return ( (r.x.cflag) ? 0 : r.x.ax ); -} - - -int dos_write(int file, void *ptr, unsigned count) -{ - union REGS r; - struct SREGS s; - r.h.ah = 0x40; - r.x.bx = file; - r.x.cx = count; - r.x.dx = FP_OFF(ptr); - s.ds = FP_SEG(ptr); - intdosx(&r,&r,&s); - return ( (r.x.cflag) ? 0 : r.x.ax ); -} - - -void dos_close(int file) -{ - union REGS r; - r.h.ah = 0x3e; - r.x.bx = file; - intdos(&r,&r); -} -#else -#include <unistd.h> -#endif +static char global_nls_buffer[4096] = {0}; /* Functions */ - /** * On success, catgets() returns a pointer to an internal * buffer area containing the null-terminated message string. * On failure, catgets() returns the value 'message'. */ -const char *kittengets(int setnum, int msgnum, const char *message) +const char * +_kittengets (int msgID, const char *message) { + struct message_header *message_header; // if this is != 0 then init was done - int i = 0; - - while ((catpoints[i].key1 != setnum) || (catpoints[i].key2 != msgnum)) { - if ((catpoints[i].text == NULL) || (i>127)) /* at EOF */ - return message; - i++; - } - - if (catpoints[i].text == NULL) - return message; - else - return (catpoints[i].text); -} + if (global_nls_buffer[0] == 0) + return message; -/** - * Obtains path to current exec. - */ -static char * get_cmd_path(char *buf) -{ - char cmd_drive[_MAX_DRIVE]; - char cmd_dir[_MAX_DIR]; + message_header = (struct message_header *)global_nls_buffer; + + for ( ; message_header->len != 0; message_header = (struct message_header *)((char*)message_header + message_header->len)) + { + if (message_header->id== msgID) + { + return (const char*)message_header + sizeof(struct message_header); + } - _splitpath(__argv[0], cmd_drive, cmd_dir, NULL, NULL); - _makepath(buf, cmd_drive, cmd_dir, "", NULL); + } - return buf; + return message; } @@ -182,483 +63,128 @@ static char * get_cmd_path(char *buf) * Initialize kitten for program (name). */ -nl_catd kittenopen(char *name) -{ - /* catopen() returns a message _kitten_catalog descriptor * - * of type nl_catd on success. On failure, it returns -1. */ - - char catlang[3]; /* from LANG environment var. */ - char *nlsptr; /* ptr to NLSPATH */ - char *lang; /* ptr to LANG */ - int i; - - /* Open the _kitten_catalog file */ - /* The value of `_kitten_catalog' will be set based on catread */ - - if (_kitten_catalog) { /* Already one open */ - write(1,"cat already open\r\n",strlen("cat already open\r\n")); - return (-1); - } - - for (i=0; i<128; i++) - catpoints[i].text = NULL; - - if (strchr (name, '\\')) { - /* unusual case: 'name' is a filename */ - write(1,"found \\\r\n",9); - _kitten_catalog = catread (name); - if (_kitten_catalog) - return (_kitten_catalog); - } - - /* If the message _kitten_catalog file name does not contain a directory * - * separator, then we need to try to locate the message _kitten_catalog. */ - - /* We will need the value of LANG, and may need a 2-letter abbrev of - LANG later on, so get it now. */ - - lang = getenv ("LANG"); - - if (lang == NULL) { - /* printf("no lang= found\n"); */ /* not fatal, though */ - /* Return failure - we won't be able to locate the cat file */ - return (-1); - } - - if ( ( strlen(lang) < 2 ) || - ( (strlen(lang) > 2) && (lang[2] != '-') ) ) { - /* Return failure - we won't be able to locate the cat file */ - return (-1); - } - - memcpy(catlang, lang, 2); - /* we copy the full LANG value or the part before "-" if "-" found */ - catlang[2] = '\0'; - - /* first try to find catalog file in the same path as exe */ - get_cmd_path(catfile); - strcat(catfile, name); - strcat(catfile, "."); - strcat(catfile, catlang); - _kitten_catalog = catread (catfile); - if (_kitten_catalog) - return (_kitten_catalog); - - /* maybe exe_path\nls\cat.%LANG% ? */ - get_cmd_path(catfile); - strcat(catfile, "NLS\\"); - strcat(catfile, name); - strcat(catfile, "."); - strcat(catfile, catlang); - _kitten_catalog = catread (catfile); - if (_kitten_catalog) - return (_kitten_catalog); - - /* otherwise step through NLSPATH */ - nlsptr = getenv ("NLSPATH"); - - if (nlsptr == NULL) { - /* printf("no NLSPATH= found\n"); */ /* not fatal either */ - /* Return failure - we won't be able to locate the cat file */ - return (-1); - } - - catfile[0] = '\0'; - - while (nlsptr != NULL) { - char *tok = strchr(nlsptr, ';'); - int toklen; - - if (tok == NULL) - toklen = strlen(nlsptr); /* last segment */ - else - toklen = (int)(tok - nlsptr); /* segment terminated by ';' */ - - /* catfile = malloc(toklen+1+strlen(name)+1+strlen(lang)+1); */ - /* Try to find the _kitten_catalog file in each path from NLSPATH */ - - if ((toklen+6+strlen(name)) > sizeof(catfile)) { - write(1,"NLSPATH overflow\r\n",strlen("NLSPATH overflow\r\n")); - return 0; /* overflow in NLSPATH, should never happen */ - } - - /* Rule #1: %NLSPATH%\%LANG%\cat */ - - memcpy(catfile, nlsptr, toklen); - strcpy(catfile+toklen,"\\"); - strcat(catfile,catlang); - strcat(catfile,"\\"); - strcat(catfile,name); - _kitten_catalog = catread (catfile); - if (_kitten_catalog) - return (_kitten_catalog); - - /* Rule #2: %NLSPATH%\cat.%LANG% */ - - /* memcpy(catfile, nlsptr, toklen); */ - strcpy(catfile+toklen,"\\"); - strcat(catfile,name); - strcat(catfile,"."); - strcat(catfile,catlang); - _kitten_catalog = catread (catfile); - if (_kitten_catalog) - return (_kitten_catalog); - - /* Grab next tok for the next while iteration */ - - nlsptr = tok; - if (nlsptr) nlsptr++; - - } /* while tok */ - - /* We could not find it. Return failure. */ - - return (-1); -} +#define _toupper(c) (c & ~0x20) - -/** - * Load a message catalog into memory. - */ - -int catread (char *catfile) -{ - int file; /* pointer to the catfile */ - int i; - char *where; - char *tok; - - /* Get the whole catfile into a buffer and parse it */ - - file = open (catfile, O_RDONLY); - if (file < 0) - /* Cannot open the file. Return failure */ - return 0; - - for (i=0; i<128; i++) - catpoints[i].text = NULL; - - for (i=0; i<sizeof(catcontents); i++) - catcontents[i] = '\0'; - - /* Read the file into memory */ - i = read (file, catcontents, sizeof(catcontents)-1); - - if ((i == sizeof(catcontents)-1) || (i < 1)) - return 0; /* file was too big or too small */ - - where = catcontents; - i = 0; /* catpoints entry */ - - do { - char *msg; - char *key; - int key1 = 0; - int key2 = 0; - - tok = strchr(where, '\n'); - - if (tok == NULL) { /* done? */ - close(file); - return 1; /* success */ - } - - tok[0] = '\0'; /* terminate here */ - tok--; /* guess: \r before \n */ - if (tok[0] != '\r') - tok++; /* if not, go back */ - else { - tok[0] = '\0'; /* terminate here already */ - tok++; - } - tok++; /* this is where the next line starts */ - - if ( (where[0] >= '0') && (where[0] <= '9') && - ( (msg = strchr(where,':')) != NULL) ) { - /* Skip everything which starts with # or with no digit */ - /* Entries look like "1.2:This is a message" */ - - msg[0] = '\0'; /* remove : */ - msg++; /* go past the : */ - - if ((key = strchr (where, '.')) != NULL) { - key[0] = '\0'; /* turn . into terminator */ - key++; /* go past the . */ - key1 = mystrtoul(where, 10, strlen(where)); - key2 = mystrtoul(key, 10, strlen(key)); - - if ((key1 >= 0) && (key2 >= 0)) { - catpoints[i].key1 = key1; - catpoints[i].key2 = key2; - catpoints[i].text = processEscChars(msg); - if (catpoints[i].text == NULL) /* ESC parse error */ - catpoints[i].text = msg; - i++; /* next entry! */ - } /* valid keys */ - - } /* . found */ - - } /* : and digit found */ - - where = tok; /* go to next line */ - - } while (1); -} - - -void kittenclose (void) -{ - /* close a message _kitten_catalog */ - _kitten_catalog = 0; -} - - -/** - * Parse a string that represents an unsigned integer. - * Returns -1 if an error is found. The first size - * chars of the string are parsed. - */ - -int mystrtoul(char *src, int base, int size) +nl_catd +kittenopen (const char *name) { - int ret = 0; + int fd; + struct message_end message_end; + struct content content[KITTEN_MAX_RESOURCES]; + char *language; + int i; + long len; + char exename[_MAX_PATH]; + long fileendnow, seekoffset; + + //printf("kittenopen %s\n", name); - for (; size > 0; size--) { - int digit; - int ch = *src; - src++; - - if (ch >= '0' && ch <= '9') - digit = ch - '0'; - else if (ch >= 'A' && ch <= 'Z') - digit = ch - 'A' + 10; - else if (ch >= 'a' && ch <= 'z') - digit = ch - 'a' + 10; - else - return -1; - - if (digit >= base) - return -1; - - ret = ret * base + digit; - } /* for */ - - return ret; -} - - -/** - * Process strings, converting \n, \t, \v, \b, \r, \f, \\, - * \ddd, \xdd and \x0dd to actual chars. - * (Note: \x is an extension to support hexadecimal) - * This is used to allow the messages to use c escape sequences. - * Modifies the line in-place (always same size or shorter). - * Returns a pointer to input string. - */ - -char *processEscChars(char *line) -{ - char *src = line; - char *dst = line; /* possible as dst is shorter than src */ - - /* used when converting \xdd and \ddd (hex or octal) characters */ - char ch; - - if (line == NULL) - return line; - - /* cycle through copying characters, except when a \ is encountered. */ - while (*src != '\0') { - ch = *src; - src++; - - if (ch == '\\') { - ch = *src; /* what follows slash? */ - src++; - - switch (ch) { - case '\\': /* a single slash */ - *dst = '\\'; - dst++; - break; - case 'n': /* a newline (linefeed) */ - *dst = '\n'; - dst++; - break; - case 'r': /* a carriage return */ - *dst = '\r'; - dst++; - break; - case 't': /* a horizontal tab */ - *dst = '\t'; - dst++; - break; - case 'v': /* a vertical tab */ - *dst = '\v'; - dst++; - break; - case 'b': /* a backspace */ - *dst = '\b'; - dst++; - break; - case 'a': /* alert */ - *dst = '\a'; - dst++; - break; - case 'f': /* formfeed */ - *dst = '\f'; - dst++; - break; - case 'x': /* extension supporting hex numbers \xdd or \x0dd */ - { - int chx = mystrtoul(src, 16, 2); /* get value */ - if (chx >= 0) { /* store character */ - *dst = chx; - dst++; - src += 2; - } else /* error so just store x (loose slash) */ - { - *dst = *src; - dst++; - } - } - break; - default: /* just store letter (loose slash) or handle octal */ - { - int chx = mystrtoul(src, 8, 3); /* get value */ - if (chx >= 0) {/* store character */ - *dst = chx; - dst++; - src += 3; - } else - { - *dst = *src; - dst++; - } - } - break; - } /* switch */ - } /* if backslash */ - else - { - *dst = ch; - dst++; - } - } /* while */ - - /* ensure '\0' terminated */ - *dst = '\0'; - - return line; -} - - -int get_char(int file) { - int rval = -1; - - if (getlrem <= 0) { /* (re)init buffer */ - getlrem = read(file, getlbuf, sizeof(getlbuf)); - if (getlrem <= 0) - return -1; /* fail: read error / EOF */ - getlp = getlbuf; /* init pointer */ - } - - if (getlrem > 0) { /* consume byte from buffer */ - rval = getlp[0]; - getlp++; - getlrem--; - } - - return rval; -} - - -/** - * Read a line of text from file. You must call this with - * a null buffer or null size to flush buffers when you are - * done with a file before using it on the next file. Cannot - * be used for 2 files at the same time. - */ - -int get_line (int file, char *orig_str, int size) -{ - int ch; - char *str = orig_str; + if ((fd = open(name, _O_RDONLY | _O_BINARY)) < 0) + { + sprintf(exename, "%s.exe", name); + if ((fd = open(exename, _O_RDONLY | _O_BINARY)) < 0) + { + printf("can't open %s\n", name); // should never happen + return 0; + } + } + + fileendnow = lseek(fd, 0, SEEK_END); + + lseek(fd, - (int)sizeof(struct message_end), SEEK_END); + + read(fd, &message_end, sizeof(struct message_end)); + + if (memcmp(message_end.ID, "KITTENC", 8) != 0) + { + //printf("no KITTENC record found\n"); + return 0; + } + + if (message_end.resource_count > KITTEN_MAX_RESOURCES) + { + printf("resource > %d\n", KITTEN_MAX_RESOURCES); + return 0; + } + + seekoffset = fileendnow - message_end.fileend_orig; + + if (lseek(fd, message_end.filepos+seekoffset, SEEK_SET) != message_end.filepos+seekoffset) + { + printf("can't seek 1\n"); + return 0; + } + + + read(fd, &content, sizeof(content[0]) * message_end.resource_count); + + language = getenv("LANG"); + + // printf("using language %s\n", language); + + if (message_end.resource_count == 1) + { + if (language && + _toupper(language[0]) == 'E' && + _toupper(language[0]) == 'N') + { + // set LANG=EN switches to internal strings + close(fd); + return 0; + } + // otherwise use the only compiled language + i = 0; + + goto found_my_language; + } + + if (language == NULL) // language not found + { // use internal strings + close(fd); + return 0; + } + + // see if we find our language in the existing resources + for (i = 0; i < message_end.resource_count; i++) + { + if(_toupper(content[i].language[0]) == _toupper(language[0]) && + _toupper(content[i].language[1]) == _toupper(language[1])) + { + goto found_my_language; + } + } + + // language not found + close(fd); + return 0; - if ((size == 0) || (str == NULL)) { /* re-init get_line buffers */ - getlp = getlbuf; - getlrem = -1; - return 0; - } - - str[0] = '\0'; + - while (size > 0) { - ch = get_char (file); - if (ch < 0) { - /* encountered EOF / read error, so no more content*/ - str[0] = '\0'; - /* test if the pointers are equal, there is not content in the buffer */ - if(str == orig_str) - return 0; /* fail, no more content */ - - return 1; /* success */ - } +found_my_language: + // found our language + // printf(" language %s found between %lx and %lx\n", language, content[i].filepos_start, content[i].filepos_end); - if (ch == '\r') - ch = get_char (file); /* ignore \r */ + // printf("seek %lu --> %lu\n", content[i].filepos_start, content[i].filepos_start+seekoffset); - str[0] = ch; + lseek(fd, content[i].filepos_start+seekoffset, SEEK_SET); + len = content[i].filepos_end - content[i].filepos_start; - if ( (ch == '\n') || (ch == '\r') || (ch < 0) ) { /* done? */ - str[0] = '\0'; - return 1; /* success */ - } + if (len > sizeof(global_nls_buffer)) + { + printf("nls_buffer too small(%d). we need at least %l\n", + sizeof(global_nls_buffer), len); + close(fd); + return 1; + } - str++; - size--; - } /* while */ + read(fd, global_nls_buffer, (int)len); - str[0] = '\0'; /* terminate buffer */ + close(fd); + return 0; +} - return 0; /* fail, because the line is longer than the buffer? */ -} -/* - * input - * s : input string to be parsed - * delimiters : start, intermediate and end - * responses : output buffer (has to be long enough for num chars) - * num : required number of responses - * - * return - * 0 on failure - * 1 on success - */ -int kitten_extract_response(const char *s, const char *delimiters, - char *responses, int num) { - int slen = strlen(s); - const char *p, *q; - int i; - - /* Response parsing requires substring usually of the form '(%c/%c)' */ - p = strchr(s, delimiters[0]); - if (!p) - return 0; - - /* Each response requires letter followed by a delimiter e.g. 'Y/' or 'N)' */ - if (p + 1 - s > slen - 2 * num) - return 0; - - for (i = 0; i < num; i++) { - q = p + 2 + i * 2; - if (*q != delimiters[1] && *q != delimiters[2]) - return 0; - responses[i] = *(p + 1 + i * 2); - } - - return 1; -} +#endif /*NO_KITTEN */ @@ -20,45 +20,43 @@ */ -#ifndef _CATGETS_H -#define _CATGETS_H +#ifndef KITTEN_H +#define KITTEN_H #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/* Data types */ +#define _(catalog,messageid,message) kittengets(catalog,messageid,message) + +#ifdef NO_KITTEN + +#define kittengets(x,y,z) (z) +#define kittenclose() +#define kittenopen(a) -#if defined(__GNUC__) -typedef int __attribute__((used)) nl_catd; #else -typedef int nl_catd; -#endif + +/* Data types */ + +#define nl_catd int /* Functions */ -#ifdef NOCATS /* #define NOCATS to disable completely */ -#define catgets(c,x,y,s) s -#define catopen(x,y) 1 -#define catclose(x) -#define _(x,y,s) s -#else -#define catgets(catalog,set,message_number,message) kittengets(set,message_number,message) -#define catopen(name,flag) kittenopen(name) -#define catclose(catalog) kittenclose() -#define _(set,message_number,message) kittengets(set,message_number,message) -#endif -const char *kittengets(int setnum, int msgnum, const char *message); -nl_catd kittenopen(char *name); -void kittenclose (void); +#define catgets(catalog, set,message_number,message) _kittengets((catalog << 8) + set,default_message) +#define catopen(name,flag) kittenopen(argv[0]) +#define catclose(catalog) -int get_line (int file, char *buffer, int size); +#define kittengets(catalog, messageid,message) _kittengets((catalog << 8) + messageid,message) +#define kittenclose(catalog) -int kitten_extract_response(const char *s, const char *delimiters, - char *responses, int num); + const char *_kittengets (int messageid, const char *message); + nl_catd kittenopen (const char *exename); +#endif /*NO_KITTEN */ #ifdef __cplusplus } #endif -#endif /* _CATGETS_H */ +#endif /* KITTEN_H */ diff --git a/kittenc.c b/kittenc.c new file mode 100644 index 0000000..79011ea --- /dev/null +++ b/kittenc.c @@ -0,0 +1,548 @@ +/* + KITTENC - compile kitten files and attach this to + executables in a way that the kitten library retrieves + the language resources, in the same way that + catgets/kittengets ever did + +*/ +/* + This software is free software; free to use, + modify, pass to others, whatever + + use it at your own risk +*/ +/* Minor modifications to compile on UNIX host */ + + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <string.h> +#include <io.h> + +#include "kitten.h" +#include "kittenc.h" +#include "kitten.c" // Small hack to keep everything in one file + +void usage() + { + printf(kittengets(1,0,"KITTENC - KITTEN compiler\n")); + printf(kittengets(1,1,"usage\n")); + printf(kittengets(1,2,"KITTENC program.exe ATTACH NLS\\program.??\n")); + printf(kittengets(1,3,"KITTENC program.exe ATTACH NLS\\program.DE\n")); + printf(kittengets(1,4,"KITTENC program.exe ATTACH NLS\\program.DE NLS\\program.fr\n")); + printf(kittengets(1,5,"KITTENC program.exe INFO : show info about language resources\n")); + printf(kittengets(1,6,"KITTENC program.exe DUMP : recreate language resources\n")); + printf(kittengets(1,7,"KITTENC program.exe TRUNCATE : delete attached resources\n")); + } + + + +/** + * Parse a string that represents an unsigned integer. + * Returns -1 if an error is found. The first size + * chars of the string are parsed. + */ + +int +mystrtoul (char *src, int base, int size) +{ + int ret = 0; + + for (; size > 0; size--) + { + int digit; + int ch = *src; + + src++; + + if (ch >= '0' && ch <= '9') + digit = ch - '0'; + else if (ch >= 'A' && ch <= 'Z') + digit = ch - 'A' + 10; + else if (ch >= 'a' && ch <= 'z') + digit = ch - 'a' + 10; + else + return -1; + + if (digit >= base) + return -1; + + ret = ret * base + digit; + } /* for */ + + return ret; +} + + + + +/** + * Process strings, converting \n, \t, \v, \b, \r, \f, \\, + * \ddd, \xdd and \x0dd to actual chars. + * (Note: \x is an extension to support hexadecimal) + * This is used to allow the messages to use C escape sequences. + * Modifies the line in-place (always same size or shorter). + * Returns a pointer to input string. + */ + +char special[] = "\\nrtvbafx"; +char translated[]= "\\\n\r\t\v\b\a\fx"; + + +char * +processEscChars (char *line) +{ + /* used when converting \xdd and \ddd (hex or octal) characters */ + char ch; + char *src = line; + char *dst = line; /* possible as dst is shorter than src */ + char *s; + int chx; + + + if (line == NULL) + return line; + + /* cycle through copying characters, except when a \ is encountered. */ + while (*src != '\0') + { + ch = *src; + src++; + + if (ch != '\\') + { + *dst++ = ch; + continue; + } + + ch = *src; /* what follows slash? */ + src++; + + s = strchr(special, ch); /* is it a special character?? */ + + if (s == NULL) /* no. store the character as is */ + { + *dst++ = ch; + continue; + } + ch = translated[s - special]; + + if (ch != 'x') /* newline, formfeed etc. */ + { + *dst++ = ch; + continue; + } + + chx = mystrtoul (src, 16, 2); /* get value */ + if (chx >= 0) + { /* store character */ + *dst = chx; + dst++; + src += 2; + } + else /* error so just store x (loose slash) */ + { + *dst = *src; + dst++; + } + } /* while */ + + /* ensure '\0' terminated */ + *dst = '\0'; + + return line; +} + + +// +// process a single FIND.DE file +// + +int process_language_file(FILE *fd, char *filename) + { + FILE *fdres; + char linebuff[512]; + char msg[512]; + int id1, id2; + struct message_header message_header; + int len; + int linecount = 0; + + if ((fdres = fopen(filename, "r")) == 0) + { + printf("can't open %s\n", filename); + return 0; + } + + while (fgets(linebuff, sizeof(linebuff), fdres)) + { + char *s = linebuff; + + linecount++; + + for (len = strlen(s); len > 0; ) // delete trailing white space + { // from line + len--; + if (strchr(" \t\r\n", s[len]) == NULL) + break; + s[len] = '\0'; + } + if (len == 0) + continue; + + + if (linebuff[0] == '#') + { + // Skip comment line + } + else if (sscanf(linebuff, " %u . %u :%s", &id1, &id2, msg) != 3) + { + if (sscanf(linebuff, " %c", &id1) == 0 || // empty line + id1 == '#') // # comment line + continue; + + printf("%3u:%10.10s: missing 'num, num :' \n", linecount, linebuff); + continue; + } + s = strchr(linebuff, ':'); + if (s == NULL) continue; + + s++; + + processEscChars(s); + + if (strlen(s) > 250) + { + printf("%10.10s: lines must not be longer then 250 characters, is %u\n", linebuff, strlen(s)); + s[250] = 0; + } + + /* now here we have destilled id1, id2, message s */ + + message_header.len = strlen(s) // the message + + 1 // the trailing \0 + + sizeof(message_header); + message_header.id = (id1 << 8) + id2; + + fwrite(&message_header, 1, sizeof(message_header), fd); + fwrite(s, strlen(s)+1,1,fd); + + } + + + message_header.len = 0; // END message + message_header.id = 0; + + fwrite(&message_header, 1, sizeof(message_header), fd); + + return linecount; + } + + +// this is the 'compiler' part of KITTENC +// +// attach("FIND.EXE", "NLS\\FIND.??", 1) +// attach("FIND.EXE", "NLS\\FIND.DE", NLS\\FIND.ES", 2) +// + +int attach(char *progname, char *args[], int argc) + { + int i; + FILE *fd; + struct _finddata_t fileinfo; + long search_handle; + char *s; + char *filename; + char path_buffer[_MAX_PATH]; + struct content content[KITTEN_MAX_RESOURCES]; + struct message_end message_end; + int linecount; + + int resourcecount = 0; + + if ((fd = fopen(progname, "r+b")) == NULL) + { + printf(kittengets(2,1, "executable file <%s> can't be opened. because <%s>\n"), progname, strerror( errno )); + return 1; + } + fseek(fd, 0, SEEK_END); + + for (i = 0; i < argc; i++) + { + filename = args[i]; + +#ifdef __UNIX__ + /* no need to expand wildcards on unix */ + strcpy(path_buffer, filename); +#else + + if ((search_handle = _findfirst(args[i], &fileinfo)) == 0) + { + printf(kittengets(2,2,"%s: no such file\n"), args[i]); + return 1; + } + + do { /* the name is name only, without the path */ + + if ((s = strrchr(filename, '\\')) != NULL || + (s = strrchr(filename, '/')) != NULL || + (s = strrchr(filename, ':')) != NULL) + { + memcpy(path_buffer, filename, s-filename+1); + strcpy(path_buffer + (s-filename) +1, fileinfo.name); + } + else + strcpy(path_buffer, fileinfo.name); + +#endif + + printf("%s:", path_buffer); + + + if ((s = strrchr(path_buffer, '.')) == NULL || + strlen(path_buffer) - (s - path_buffer) != 3) + { + printf(kittengets(2,3,"file names MUST end with .EN\n")); + continue; + } + + if (resourcecount > KITTEN_MAX_RESOURCES) + { + printf(kittengets(2,4,"too many resourcefiles (max %d)\n"), KITTEN_MAX_RESOURCES); + continue; + } + + content[resourcecount].filepos_start = ftell(fd); + strcpy(content[resourcecount].language,s+1); + + + linecount = process_language_file(fd, path_buffer); + + content[resourcecount].filepos_end = ftell(fd); + content[resourcecount].reserved = 0; + + printf("%u messages, %lu byte\n", linecount, content[resourcecount].filepos_end - content[resourcecount].filepos_start); + + resourcecount++; + +#ifndef __UNIX__ + } while (_findnext(search_handle, &fileinfo) == 0); +#endif + } + + message_end.filepos = ftell(fd); + + /* make all absolute filepositions relative to file end + to make UPX support easier */ + + + fwrite(&content, sizeof(content[0]),resourcecount,fd); + + message_end.resource_count = resourcecount; + memcpy(message_end.ID, "KITTENC",8); + + message_end.fileend_orig = ftell(fd) + sizeof(message_end); + + fwrite(&message_end, sizeof(message_end),1,fd); + fclose(fd); + + return 0; + } + +enum { KITTEN_TRUNCATE, KITTEN_INFO, KITTEN_DUMP }; + +do_kitten_stuff(char *progname, int mode) + { + int fd; + struct message_end message_end; + struct content content[KITTEN_MAX_RESOURCES]; + int i; + long fileendnow, seekoffset; + + + + if ((fd = open(progname, _O_RDWR | _O_BINARY)) < 0) + { + printf("can't open %s because<%s>\n", progname, strerror(errno)); + return 0; + } + fileendnow = lseek(fd, 0, SEEK_END); + + lseek(fd, - (int)sizeof(struct message_end), SEEK_END); + + read(fd, &message_end, sizeof(struct message_end)); + + if (memcmp(message_end.ID, "KITTENC", 8) != 0) + { + printf("no KITTENC record found\n"); + goto RETURN; + } + + if (message_end.resource_count > KITTEN_MAX_RESOURCES) + { + printf("resource > %d\n", KITTEN_MAX_RESOURCES); + goto RETURN; + } + + seekoffset = fileendnow - message_end.fileend_orig; + + if (lseek(fd, message_end.filepos+seekoffset, SEEK_SET) != message_end.filepos+seekoffset) + { + printf("can't seek 1\n"); + goto RETURN; + } + + read(fd, &content, sizeof(content[0]) * message_end.resource_count); + + + if (mode == KITTEN_TRUNCATE) + { + _chsize(fd, content[0].filepos_start); // truncate file + goto RETURN; + } + if (mode == KITTEN_INFO) + { + printf("%s: %u languages supported\n", progname, message_end.resource_count); + + for (i = 0; i < message_end.resource_count; i++) + { + printf("%2.2s %lu byte\n", content[i].language, content[i].filepos_end - content[i].filepos_start); + } + + goto RETURN; + } + + if (mode == KITTEN_DUMP) + { + char resname[_MAX_PATH],*s; + char outname[_MAX_PATH]; + FILE *fdout; + int i; + int linecount; + + for (i = 0; i < message_end.resource_count; i++) // for each language + { + _splitpath(progname, NULL,NULL, resname, NULL); // reconstruct KITTENC.DE + + sprintf(outname, "%s.%c%c", resname, content[i].language[0], content[i].language[1]);; + + if ((fdout = fopen(outname, "w")) == NULL) // create KITTENC.DE + { + printf("can't write resourcefile %s\n", outname); + goto RETURN; + } + lseek(fd, content[i].filepos_start+seekoffset, SEEK_SET); + + printf("%s : ", outname); + + linecount= 0; + + while (1) + { + short len, id; char c; + + read(fd, &len, sizeof(short)); + + if (len == 0) + break; + + read(fd,&id, sizeof(short)); + + fprintf(fdout, "%u,%u:", id >> 8, id & 0xff); + + while (read(fd, &c, 1) == 1 && + c != 0) + { + if (c >= 0x20) + fputc(c, fdout); + else + { + if ((s = strchr(translated, c)) != NULL) /* \t \n \f */ + { + fprintf(fdout, "\\%c", special[s - translated]); + } + else + fprintf(fdout, "\\x%02x", c); + } + } // next character + + fprintf(fdout, "\n"); + linecount++; + } // next line + + printf("%u messages\n", linecount); + fclose(fdout); + } // next language + + + goto RETURN; + } + + + +RETURN: + close(fd); + return 0; + + } + + +main(int argc, char *argv[]) +{ + char *progname; + char buffer[_MAX_PATH]; + + kittenopen(argv[0]); + + printf("KITTENC 1.0\n"); + + //printf(kittengets(0,0,"hallo world\n")); + + if (argc < 3) + { + usage(); + exit(1); + } + + progname = argv[1]; +#ifndef __UNIX__ + strupr(progname); + + if (strstr(progname, ".EXE") == NULL && + strstr(progname, ".COM") == NULL) + { + sprintf(buffer,"%s.EXE", progname); + progname = buffer; + } +#endif + + if (stricmp(argv[2], "ATTACH") == 0) + { + do_kitten_stuff(progname, KITTEN_TRUNCATE); + return attach(progname, argv+3, argc-3); + + } + else if (stricmp(argv[2], "TRUNCATE") == 0) + { + return do_kitten_stuff(progname, KITTEN_TRUNCATE); + + + } + else if (stricmp(argv[2], "INFO") == 0) + { + return do_kitten_stuff(progname, KITTEN_INFO); + } + else if (stricmp(argv[2], "DUMP") == 0) + { + return do_kitten_stuff(progname, KITTEN_DUMP); + } + else { + printf("'%s' is wrong %s %s %s\n", argv[2], argv[0], argv[1], argv[2]); + usage(); + exit(1); + } + +} + + diff --git a/kittenc.h b/kittenc.h new file mode 100644 index 0000000..d42ec27 --- /dev/null +++ b/kittenc.h @@ -0,0 +1,44 @@ +/* + KITTENC - compile kitten files and attach this to + executables in a way that the kitten library retrieves + the language resources, in the same way that + catgets/kittengets ever did + +*/ +/* + This software is free software; free to use, + modify, pass to others, whatever + + use it at your own risk +*/ + +#ifndef KITTENC_H +#define KITTENC_H + +//internal stuff shared between kitten.c and kittenc.c +struct message_header +{ + short len; + short id; + // char message[]; +}; + +struct content +{ + char language[4]; + long filepos_start; // for this language + long filepos_end; + long reserved; // align on 16 byte to look better in hex editor +}; + +struct message_end +{ + long filepos; // points to content + long resource_count;// number of entries + long fileend_orig; // file end NOW because UPX + char ID[8]; // "KITTENC" +}; + +#define KITTEN_MAX_RESOURCES 16 + +#endif /* KITTENC_H */ @@ -37,16 +37,25 @@ w16dll_cflags = -bt=windows -bd -mc -zu -s -6 -osi -w3 -wcd=202 compile_dos = *wcc -fo=$^@ $(dos_cflags) $[@ compile_dostsr = *wcc -fo=$^@ $(dostsr_cflags) $[@ compile_w16dll = *wcc -fo=$^@ $(w16dll_cflags) $[@ +compile_link_host = *wcl386 -i=$(%originclude) -os -fe=$^@ $[@ + +!ifdef __UNIX__ +run_host = ./ +!else +run_host = +!endif .BEFORE: # We need DOS and Windows headers, not host platform's + set originclude=$(%include) set include=$(%watcom)/h/win;$(%watcom)/h all: $(bins) .SYMBOLIC # DOS mouse driver -vbmouse.exe: vbmouse.lnk $(mousedos_objs) +vbmouse.exe: vbmouse.lnk $(mousedos_objs) kittenc.exe *wlink @$[@ name $@ file { $(mousedos_objs) } + $(run_host)kittenc.exe $@ attach nls/vbmouse.* mousetsr.obj: mousetsr.c .AUTODEPEND $(compile_dostsr) @@ -62,13 +71,14 @@ mousew16.obj: mousew16.c .AUTODEPEND $(compile_w16dll) # DOS shared folders -vbsf.exe: vbsf.lnk $(sfdos_objs) +vbsf.exe: vbsf.lnk $(sfdos_objs) kittenc.exe *wlink @$[@ name $@ file { $(sfdos_objs) } + $(run_host)kittenc.exe $@ attach nls/vbsf.* sftsr.obj: sftsr.c .AUTODEPEND $(compile_dostsr) -sfmain.obj: sfmain.c .AUTODEPEND +sfmain.obj: sfmain.c unitbl.h .AUTODEPEND $(compile_dos) # Auxiliary object files @@ -78,6 +88,10 @@ vbox.obj: vbox.c .AUTODEPEND kitten.obj: kitten.c .AUTODEPEND $(compile_dos) +# embed all unitbl/*.tbl files into a single unitbl.h +unitbl.h: unitbl2c.exe $(unitbls) + $(run_host)unitbl2c.exe $@ unitbl/*.tbl + # Test programs moustest_objs = moustest.obj @@ -87,16 +101,22 @@ moustest.exe: moustest.obj moustest.obj: moustest.c .AUTODEPEND $(compile_dos) -mc -zu +# Programs to build for the host +host_bins = unitbl2c.exe kittenc.exe +unitbl2c.exe: unitbl2c.c + $(compile_link_host) + +kittenc.exe: kittenc.c + $(compile_link_host) + # Other targets clean: .SYMBOLIC - rm -f vbmouse.exe vbmouse.drv vbsf.exe moustest.exe - rm -f *.obj *.map rm -f vbados.zip vbados.flp vbasrc.zip + rm -f $(bins) $(host_bins) + rm -f *.obj *.map vbados.flp: mformat -C -f 1440 -v VBADOS -i $^@ :: - mcopy -i $^@ unitbl/*.tbl :: - mcopy -i $^@ nls/vbsf.* nls/vbmouse.* :: # Build a floppy image containing the driver flp: vbados.flp $(bins) $(infs) .SYMBOLIC @@ -104,7 +124,7 @@ flp: vbados.flp $(bins) $(infs) .SYMBOLIC # Build a zip with the driver binaries zip: vbmouse.exe vbmouse.drv oemsetup.inf vbsf.exe .SYMBOLIC - zip --DOS-names -fz- -j vbados.zip unitbl/*.tbl nls/vbsf.* nls/vbmouse.* + zip --DOS-names -fz- -j vbados.zip nls/vbsf.* nls/vbmouse.* zip --DOS-names -fz- vbados.zip $(bins) $(infs) srczip: .SYMBOLIC @@ -35,8 +35,6 @@ #include "dostsr.h" #include "mousetsr.h" -static nl_catd cat; - #if USE_WHEEL static bool detect_ps2_wheel(LPTSRDATA data) { @@ -761,7 +759,7 @@ int main(int argc, const char *argv[]) LPTSRDATA data = get_tsr_data(true); int err, argi = 1; - cat = kittenopen("vbmouse"); + kittenopen(argv[0]); printf(_(1, 20, "\nVBMouse %x.%x (reporting as MSMOUSE %x.%x)\n"), VERSION_MAJOR, VERSION_MINOR, REPORTED_VERSION_MAJOR, REPORTED_VERSION_MINOR); @@ -30,10 +30,9 @@ #include "vboxshfl.h" #include "dostsr.h" #include "sftsr.h" +#include "unitbl.h" #include "unicode.h" -static nl_catd cat; - static char get_drive_letter(const char *path) { if (!path || path[0] == '\0') return '\0'; if (path[1] == '\0' || (path[1] == ':' && path[2] == '\0')) { @@ -169,13 +168,12 @@ static void close_openfiles(LPTSRDATA data, int drive) static int mount_shfl(LPTSRDATA data, int drive, const char *folder) { int32_t err; - SHFLSTRING_WITH_BUF(str, SHFL_MAX_LEN); + SHFLSTRING_WITH_BUF(utf8name, SHFL_MAX_LEN); SHFLROOT root = SHFL_ROOT_NIL; - unsigned flags = SHFL_MIQF_DRIVE_LETTER, version = 0; - shflstring_strcpy(&str.shflstr, folder); + utf8name.shflstr.u16Length = local_to_utf8(data, utf8name.buf, folder, utf8name.shflstr.u16Size); - err = vbox_shfl_map_folder(&data->vb, data->hgcm_client_id, &str.shflstr, &root); + err = vbox_shfl_map_folder(&data->vb, data->hgcm_client_id, &utf8name.shflstr, &root); if (err) { fprintf(stderr, _(3, 3, "Cannot mount shared folder '%s', err=%d\n"), folder, err); return -1; @@ -237,7 +235,7 @@ static bool is_mounted_drive(LPTSRDATA data, char drive_letter, int drive) return true; } -static int mount(LPTSRDATA data, char *folder, char drive_letter, MOUNTOPTS *opts) +static int mount(LPTSRDATA data, const char *folder, char drive_letter, MOUNTOPTS *opts) { int drive = drive_letter_to_index(drive_letter); DOSLOL __far *lol = dos_get_list_of_lists(); @@ -270,7 +268,6 @@ static int mount(LPTSRDATA data, char *folder, char drive_letter, MOUNTOPTS *opt // By setting the physical flag, we also let DOS know the drive is present cds->flags = DOS_CDS_FLAG_NETWORK | DOS_CDS_FLAG_PHYSICAL; - (void)utf8_to_local(data, folder, folder, NULL); printf(_(1, 3, "Shared folder '%s' mounted as drive %c:\n"), folder, drive_letter); return EXIT_SUCCESS; @@ -481,7 +478,8 @@ static void load_unicode_table(uint16_t far *unicode_table) char fullpath[_MAX_PATH]; char buffer[256]; FILE *f; - int i, ret; + const uint16_t *builtin_tbl; + int ret; // get current Code Page // @@ -502,6 +500,12 @@ static void load_unicode_table(uint16_t far *unicode_table) goto error; } + // Try one of the builtin tables first + if ((builtin_tbl = get_uni_tbl(r.x.bx))) { + _fmemcpy(unicode_table, builtin_tbl, 256); + return; + } + sprintf(filename, r.x.bx > 999 ? "c%duni.tbl" : "cp%duni.tbl", r.x.bx); // Search in the same directory as the executable first @@ -812,9 +816,8 @@ int main(int argc, const char *argv[]) { LPTSRDATA data = get_tsr_data(true); int err, argi = 1; - SHFLSTRING_WITH_BUF(utf8name, SHFL_MAX_LEN); - cat = kittenopen("vbsf"); + kittenopen(argv[0]); if (argi >= argc || stricmp(argv[argi], "install") == 0) { uint8_t hash_chars = DEF_HASH_CHARS; @@ -890,8 +893,7 @@ int main(int argc, const char *argv[]) err = parse_mountopts(&opts, &argi, argc, argv); if (err) return err; - local_to_utf8(data, utf8name.buf, folder, utf8name.shflstr.u16Size); - return mount(data, utf8name.buf, drive, &opts); + return mount(data, folder, drive, &opts); } else if (stricmp(argv[argi], "umount") == 0 || stricmp(argv[argi], "unmount") == 0) { char drive; if (!data) return driver_not_found(); diff --git a/unitbl2c.c b/unitbl2c.c new file mode 100644 index 0000000..f2e76cc --- /dev/null +++ b/unitbl2c.c @@ -0,0 +1,206 @@ +/* + * VBSF - generate C file with codepage -> unicode tables based on uni*.tbl files + * Copyright (C) 2022 Javier S. Pedro + * + * This program 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 + * of the License, or (at your option) any later version. + + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <libgen.h> +#include <ctype.h> +#include <string.h> + +/** size of codepage -> unicode table */ +#define TBL_SIZE 128 /* in 16bit words */ +/** maximum number of codepages in the same C file */ +#define MAX_CPS 32 + +static FILE *fout; +static unsigned all_cps[MAX_CPS] = {0}; +static unsigned num_cps = 0; + +static void print_table(const uint16_t *table, unsigned cp) +{ + int i; + int col = 0; + + fprintf(fout, "static const uint16_t cp%utbl[%u] = {\n ", cp, TBL_SIZE); + + for (i = 0; i < TBL_SIZE; i++) + { + if (col) + { + fprintf(fout, ", "); + } + if (col >= 8) + { + fprintf(fout, "\n "); + col = 0; + } + fprintf(fout, "0x%04X", table[i]); + col++; + } + + fprintf(fout, "\n};\n\n"); +} + +static int process_table(FILE *fp, const char *base, unsigned cp) +{ + char buffer[TBL_SIZE*2]; + int err; + + // Read "Description of table" (terminated by \r\n) + if (!fgets(buffer, sizeof(buffer), fp)) { + return -1; + } + + fprintf(fout, "// %s", buffer); + + // Read "Table format designator" (currently only format 1 is supported) + err = fread(buffer, 1, 1, fp); + if (err != 1 || buffer[0] != 1) { + return -1; + } + + // Now read the actual table (256 bytes in format 1) + if ((err = fread(buffer, 1, sizeof(buffer), fp)) != sizeof(buffer)) { + return -1; + } + + print_table((const uint16_t *)buffer, cp); + + all_cps[num_cps++] = cp; + + return 0; +} + +static int process_file(char *filename) +{ + FILE *fp = fopen(filename, "rb"); + char *base = basename(filename); + unsigned cp = 0; + + if (!fp) { + fprintf(stderr, "Cannot open file '%s'\n", filename); + return -1; + } + + if (strnicmp(&base[0], "CP", 2) == 0 + && isdigit(base[2]) && isdigit(base[3]) && isdigit(base[4]) + && strnicmp(&base[5], "UNI.TBL", 7) == 0) { + cp = atoi(&base[2]); + } else if (strnicmp(&base[0], "C", 2) == 0 + && isdigit(base[1]) && isdigit(base[2]) && isdigit(base[3]) && isdigit(base[4]) + && strnicmp(&base[5], "UNI.TBL", 7) == 0) { + cp = atoi(&base[1]); + } + + if (!cp) { + fprintf(stderr, "Cannot guess codepage number from filename '%s'\n", base); + fclose(fp); + return -1; + } + + if (process_table(fp, base, cp) != 0) { + fprintf(stderr, "Cannot read table format from '%s'\n", base); + fclose(fp); + return -1; + } + + fclose(fp); + return 0; +} + +#ifdef __UNIX__ +// no need to process wildcards on UNIX +static int process_arg(char *arg) +{ + return process_file(arg); +} +#else +#include <io.h> + +static int process_arg(char *arg) +{ + struct _finddata_t fileinfo; + intptr_t fh = _findfirst(arg, &fileinfo); + + if (!fh) { + fprintf(stderr, "Cannot find '%s'\n", arg); + return -1; + } + + do { + // Name of file in fileinfo will be without path + // If so copy the path from the arg + char namebuf[_MAX_PATH]; + char *s; + + if ((s = strrchr(arg, '\\')) || (s = strrchr(arg, '/')) || (s = strrchr(arg, ':'))) { + memcpy(namebuf, arg, s-arg+1); + strcpy(namebuf + (s-arg) +1, fileinfo.name); + } else { + strcpy(namebuf, fileinfo.name); + } + + if (process_file(namebuf) != 0) { + return -1; + } + } while (_findnext(fh, &fileinfo) == 0); + + return 0; +} +#endif + +int main(int argc, char **argv) +{ + int i; + + if (argc < 3) + { + fprintf(stderr, + "Usage: bin2c <output c file> <unitbl/*.tbl>\n"); + return 1; + } + + fout = fopen(argv[1], "wt"); + fprintf(fout, "#include <stdint.h>\n"); + + for (i = 2; i < argc; i++) { + if (process_arg(argv[i])) { + return EXIT_FAILURE; + } + } + + fprintf(fout, "static const uint16_t * get_uni_tbl(unsigned cp) {\n"); + fprintf(fout, " switch (cp) {\n"); + for (i = 0; i < num_cps; i++) { + unsigned cp = all_cps[i]; + fprintf(fout, " case %u:\n", cp); + fprintf(fout, " return cp%utbl;\n", cp); + } + fprintf(fout, " default:\n"); + fprintf(fout, " return 0;\n"); + fprintf(fout, " }\n"); + fprintf(fout, "}\n\n"); + + fclose(fout); + + printf("Processed %u tables\n", num_cps); + + return EXIT_SUCCESS; +} |
