aboutsummaryrefslogtreecommitdiff
path: root/kitten.c
diff options
context:
space:
mode:
Diffstat (limited to 'kitten.c')
-rw-r--r--kitten.c756
1 files changed, 141 insertions, 615 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 */