aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kitten.c756
-rw-r--r--kitten.h50
-rw-r--r--kittenc.c548
-rw-r--r--kittenc.h44
-rw-r--r--makefile36
-rw-r--r--mousmain.c4
-rw-r--r--sfmain.c28
-rw-r--r--unitbl2c.c206
8 files changed, 1007 insertions, 665 deletions
diff --git a/kitten.c b/kitten.c
index 3e7f9d9..421ed81 100644
--- a/kitten.c
+++ b/kitten.c
@@ -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 */
diff --git a/kitten.h b/kitten.h
index 3ce631d..b38b688 100644
--- a/kitten.h
+++ b/kitten.h
@@ -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 */
diff --git a/makefile b/makefile
index 0ae4f28..1383c12 100644
--- a/makefile
+++ b/makefile
@@ -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
diff --git a/mousmain.c b/mousmain.c
index 02540de..24801b7 100644
--- a/mousmain.c
+++ b/mousmain.c
@@ -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);
diff --git a/sfmain.c b/sfmain.c
index 59acbca..4f102bb 100644
--- a/sfmain.c
+++ b/sfmain.c
@@ -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;
+}