diff options
Diffstat (limited to 'kitten.c')
| -rw-r--r-- | kitten.c | 756 |
1 files changed, 141 insertions, 615 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 */ |
