/svarlang.lib |
---|
File deleted |
\ No newline at end of file |
Property changes: |
Deleted: svn:special |
-* |
\ No newline at end of property |
/svarlang.lib/svarlang.lib/autoload.c |
---|
0,0 → 1,38 |
/* This file is part of the svarlang project and is published under the terms |
* of the MIT license. |
* |
* Copyright (C) 2021-2022 Mateusz Viste |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
* DEALINGS IN THE SOFTWARE. |
*/ |
#include <stdlib.h> |
#include "svarlang.h" |
int svarlang_autoload(const char *progname) { |
const char *s; |
char langid[3]; |
s = getenv("LANG"); |
if ((s == NULL) || (*s == 0)) return(-1); |
langid[0] = s[0]; |
langid[1] = s[1]; |
langid[2] = 0; |
return(svarlang_load(progname, langid, getenv("NLSPATH"))); |
} |
/svarlang.lib/svarlang.lib/makefile |
---|
0,0 → 1,38 |
# |
# make instructions to build svarlang and tlumacz.exe with OpenWatcom |
# Copyright (C) 2021-2022 Mateusz Viste |
# |
all: svarlngs.lib svarlngc.lib svarlngm.lib svarlngl.lib tlumacz.exe |
CFLAGS=-0 -wx -we -ox |
svarlngs.lib: autoload.c svarlang.c |
wcc $(CFLAGS) -ms autoload.c |
wcc $(CFLAGS) -ms svarlang.c |
wlib svarlngs.lib +autoload.obj +svarlang.obj |
svarlngc.lib: autoload.c svarlang.c |
wcc $(CFLAGS) -mc autoload.c |
wcc $(CFLAGS) -mc svarlang.c |
wlib svarlngc.lib +autoload.obj +svarlang.obj |
svarlngm.lib: autoload.c svarlang.c |
wcc $(CFLAGS) -mm autoload.c |
wcc $(CFLAGS) -mm svarlang.c |
wlib svarlngm.lib +autoload.obj +svarlang.obj |
svarlngl.lib: autoload.c svarlang.c |
wcc $(CFLAGS) -ml autoload.c |
wcc $(CFLAGS) -ml svarlang.c |
wlib svarlngl.lib +autoload.obj +svarlang.obj |
tlumacz.exe: tlumacz.c |
wcl -0 -y -cc -wx -mc -lr -we -ox tlumacz.c |
del *.obj |
clean: .symbolic |
del *.exe |
del *.obj |
del *.lib |
/svarlang.lib/svarlang.lib/svarlang.c |
---|
0,0 → 1,105 |
/* This file is part of the svarlang project and is published under the terms |
* of the MIT license. |
* |
* Copyright (C) 2021-2022 Mateusz Viste |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
* DEALINGS IN THE SOFTWARE. |
*/ |
#include <stdio.h> /* FILE */ |
#include <stdlib.h> /* NULL */ |
#include <string.h> /* memcmp(), strcpy() */ |
#include "svarlang.h" |
/* supplied through DEFLANG.C */ |
extern char svarlang_mem[]; |
extern const unsigned short svarlang_memsz; |
const char *svarlang_strid(unsigned short id) { |
const char *ptr = svarlang_mem; |
/* find the string id in langblock memory */ |
for (;;) { |
if (((unsigned short *)ptr)[0] == id) { |
ptr += 3; |
return(ptr); |
} |
if (ptr[2] == 0) return(NULL); |
ptr += ptr[2] + 3; |
} |
} |
int svarlang_load(const char *progname, const char *lang, const char *nlspath) { |
unsigned short langid; |
FILE *fd; |
char buff[128]; |
unsigned short buff16[2]; |
unsigned short i; |
if ((lang == NULL) || (nlspath == NULL)) return(-1); |
langid = *((unsigned short *)lang); |
langid &= 0xDFDF; /* make sure lang is upcase */ |
/* copy nlspath to buff and remember len */ |
for (i = 0; nlspath[i] != 0; i++) buff[i] = nlspath[i]; |
/* */ |
if ((i > 0) && (buff[i - 1] == '\\')) i--; |
buff[i++] = '\\'; |
strcpy(buff + i, progname); |
strcat(buff + i, ".lng"); |
fd = fopen(buff, "rb"); |
if (fd == NULL) return(-2); |
/* read hdr, should be "SvL\33" */ |
if ((fread(buff, 1, 4, fd) != 4) || (memcmp(buff, "SvL\33", 4) != 0)) { |
fclose(fd); |
return(-3); |
} |
/* read next lang id in file */ |
while (fread(buff16, 1, 4, fd) == 4) { |
/* is it the lang I am looking for? */ |
if (buff16[0] != langid) { /* skip to next lang */ |
fseek(fd, buff16[1], SEEK_CUR); |
continue; |
} |
/* found - but do I have enough memory space? */ |
if (buff16[1] >= svarlang_memsz) { |
fclose(fd); |
return(-4); |
} |
/* load strings */ |
if (fread(svarlang_mem, 1, buff16[1], fd) != buff16[1]) break; |
fclose(fd); |
return(0); |
} |
fclose(fd); |
return(-5); |
} |
/svarlang.lib/svarlang.lib/svarlang.h |
---|
0,0 → 1,45 |
/* This file is part of the svarlang project and is published under the terms |
* of the MIT license. |
* |
* Copyright (C) 2021-2022 Mateusz Viste |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
* DEALINGS IN THE SOFTWARE. |
*/ |
#ifndef SVARLANG_H |
#define SVARLANG_H |
/* loads translations for program PROGNAME, language LANG, in the path NLSPATH. |
* returns 0 on success. */ |
int svarlang_load(const char *progname, const char *lang, const char *nlspath); |
/* same as svarlang_load(), but relies on getenv() to pull LANG and NLSPATH. */ |
int svarlang_autoload(const char *progname); |
/* Returns a pointer to the string "id". Does not require svalang_load() to be |
* executed, but then it will only return the reference language strings. |
* a string id is the concatenation of the CATS-style identifiers, for example |
* string 1,0 becomes 0x0100, string 2.10 is 0x020A, etc. */ |
const char *svarlang_strid(unsigned short id); |
/* a convenience definition to fetch strings by their CATS-style pairs instead |
* of the 16-bit id. */ |
#define svarlang_str(x, y) svarlang_strid((x << 8) | y) |
#endif |
/svarlang.lib/svarlang.lib/svarlang.txt |
---|
0,0 → 1,71 |
SVARLANG.LIB - THE SVARDOS TRANSLATION C LIBRARY |
SvarLANG is a library and tooling for enabling SvarDOS applications to easily |
support multiple languages. |
### PREPARING TRANSLATION FILES ### |
The translation files must be CATS-style text files in the usual format: |
1.1:Hello, World! |
1.2:Help screen |
2.0:Type /? for more options |
The files must be named as EN.TXT, DE.TXT, FR.TXT, etc. Then, they must be |
"compiled" into SvarLANG's binary format using the TLUMACZ tool: |
tlumacz en fr pl (...) |
The first language provided in the command line is the reference language and |
is used both as the default (embedded in the application) language, as well as |
to substitute messages missing in other languages. |
TLUMACZ computes two files: |
* OUT.LNG - the binary file that contains all translations |
* DEFLANG.C - the default translations that will be embedded into the program |
Then, DEFLANG.C must be compiled and linked to your program along with |
SVARLNGx.LIB. From there, you will be able to use the following calls: |
/* loads translations for program PROGNAME, language LANG, in the path NLSPATH. |
* returns 0 on success. */ |
int svarlang_load(const char *progname, const char *lang, const char *nlspath); |
/* same as svarlang_load(), but relies on getenv() to pull LANG and NLSPATH. */ |
int svarlang_autoload(const char *progname); |
/* Returns a pointer to the string "id". Does not require svalang_load() to be |
* executed, but then it will only return the reference language strings. |
* a string id is the concatenation of the CATS-style identifiers, for example |
* string 1,0 becomes 0x0100, string 2.10 is 0x020A, etc. */ |
const char *svarlang_strid(unsigned short id); |
/* a convenience definition to fetch strings by their CATS-style pairs instead |
* of the 16-bit id. */ |
#define svarlang_str(x, y) svarlang_strid((x << 8) | y) |
### ENVIRONMENT ### |
All translations files should be placed in the %NLSPATH% directory and should |
be named the same as the program's name, with the LNG extension (for example |
"INSTALL.LNG" if the program is named "INSTALL"). |
The %LANG% environment variable defines what language should be loaded. |
### WHY IS IT BETTER THAN CATS? ### |
The CATS library is heavier and slower, as it embeds a text-file parser. |
Translations also take more disk space since each file is in a separate file |
leading to cluster waste. Finally, CATS requires default strings to be part of |
the application's source code, while SvarLANG keeps all strings in TXT files |
and embedds the default one inside the application in an automated way at |
compile time. |
======================================================================= EOF === |
/svarlang.lib/svarlang.lib/tlumacz.c |
---|
0,0 → 1,275 |
/* |
* Copyright (C) 2021-2022 Mateusz Viste |
* |
* usage: tlumacz en fr pl etc |
* |
* computes an out.lng file that contains all language ressources. |
* |
* DAT format: |
* |
* 4-bytes signature: |
* "SvL\x1b" |
* |
* Then "LANG BLOCKS" follow. Each LANG BLOCK is prefixed with 4 bytes: |
* II LL - II is the LANG identifier ("EN", "PL", etc) and LL is the size |
* of the block (65535 bytes max). |
* |
* Inside a LANG BLOCK is a set of strings: |
* |
* II L S where II is the string's 16-bit identifier, L is its length (1-255) |
* and S is the actual string. All strings are ASCIIZ-formatted (ie. |
* end with a NULL terminator). |
* |
* The list of strings ends with a single 0-long string. |
*/ |
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
struct bitmap { |
unsigned char bits[8192]; |
}; |
static void bitmap_set(struct bitmap *b, unsigned short id) { |
b->bits[id / 8] |= 1 << (id & 7); |
} |
static int bitmap_get(const struct bitmap *b, unsigned short id) { |
return(b->bits[id / 8] & (1 << (id & 7))); |
} |
static void bitmap_init(struct bitmap *b) { |
memset(b, 0, sizeof(struct bitmap)); |
} |
/* read a single line from fd and fills it into dst, returns line length |
* ending CR/LF is trimmed, as well as any trailing spaces */ |
static unsigned short readl(char *dst, size_t dstsz, FILE *fd) { |
unsigned short l, lastnonspace = 0; |
if (fgets(dst, dstsz, fd) == NULL) return(0xffff); /* EOF */ |
/* trim at first CR or LF and return len */ |
for (l = 0; (dst[l] != 0) && (dst[l] != '\r') && (dst[l] != '\n'); l++) { |
if (dst[l] != ' ') lastnonspace = l; |
} |
if (lastnonspace < l) l = lastnonspace + 1; /* rtrim */ |
dst[l] = 0; |
return(l); |
} |
/* parse a line in format "1.50:somestring". fills id and returns a pointer to |
* the actual string part on success, or NULL on error */ |
static char *parseline(unsigned short *id, char *s) { |
int i; |
int dotpos = 0, colpos = 0, gotdigits = 0; |
/* I must have a . and a : in the first 9 bytes */ |
for (i = 0;; i++) { |
if (s[i] == '.') { |
if ((dotpos != 0) || (gotdigits == 0)) break; |
dotpos = i; |
gotdigits = 0; |
} else if (s[i] == ':') { |
if (gotdigits != 0) colpos = i; |
break; |
} else if ((s[i] < '0') || (s[i] > '9')) { |
break; |
} |
gotdigits++; |
} |
/* did I collect everything? */ |
if ((dotpos == 0) || (colpos == 0)) return(NULL); |
if (s[colpos + 1] == 0) return(NULL); |
*id = atoi(s); |
*id <<= 8; |
*id |= atoi(s + dotpos + 1); |
/* printf("parseline(): %04X = '%s'\r\n", *id, s + colpos + 1); */ |
return(s + colpos + 1); |
} |
/* opens a CATS-style file and compiles it into a ressources lang block */ |
static unsigned short gen_langstrings(unsigned char *buff, const char *langid, struct bitmap *b, const struct bitmap *refb, const unsigned char *refblock) { |
unsigned short len = 0, linelen; |
FILE *fd; |
char fname[] = "XX.TXT"; |
char linebuf[512]; |
char *ptr; |
unsigned short id, linecount; |
bitmap_init(b); |
memcpy(fname + strlen(fname) - 6, langid, 2); |
fd = fopen(fname, "rb"); |
if (fd == NULL) { |
printf("ERROR: FAILED TO OPEN '%s'\r\n", fname); |
return(0); |
} |
for (linecount = 1;; linecount++) { |
linelen = readl(linebuf, sizeof(linebuf), fd); |
if (linelen == 0xffff) break; /* EOF */ |
if ((linelen == 0) || (linebuf[0] == '#')) continue; |
/* read id and get ptr to actual string ("1.15:string") */ |
ptr = parseline(&id, linebuf); |
if (ptr == NULL) { |
printf("ERROR: line #%u of %s is malformed\r\n", linecount, fname); |
len = 0; |
break; |
} |
/* write string into block (II L S) */ |
memcpy(buff + len, &id, 2); |
len += 2; |
buff[len++] = strlen(ptr) + 1; |
memcpy(buff + len, ptr, strlen(ptr) + 1); |
len += strlen(ptr) + 1; |
/* if reference bitmap provided: check that the id is valid */ |
if ((refb != NULL) && (bitmap_get(refb, id) == 0)) { |
printf("WARNING: %s[#%u] has an invalid id (%u.%u not present in ref lang)\r\n", fname, linecount, id >> 8, id & 0xff); |
} |
/* make sure this id is not already present */ |
if (bitmap_get(b, id) == 0) { |
/* set bit in bitmap to remember I have this string */ |
bitmap_set(b, id); |
} else { |
printf("WARNING: %s[#%u] has a duplicated id (%u.%u)\r\n", fname, linecount, id >> 8, id & 0xff); |
} |
} |
fclose(fd); |
/* if refblock provided, pull missing strings from it */ |
if (refblock != NULL) { |
for (;;) { |
id = *((unsigned short *)refblock); |
if ((id == 0) && (refblock[2] == 0)) break; |
if (bitmap_get(b, id) == 0) { |
printf("WARNING: %s is missing string %u.%u (pulled from ref lang)\r\n", fname, id >> 8, id & 0xff); |
/* copy missing string from refblock */ |
memcpy(buff + len, refblock, refblock[2] + 3); |
len += refblock[2] + 3; |
} |
refblock += refblock[2] + 3; |
} |
} |
/* write the block terminator (0-long string) */ |
buff[len++] = 0; /* id */ |
buff[len++] = 0; /* id */ |
buff[len++] = 0; /* len */ |
return(len); |
} |
#define MEMBLOCKSZ 65000 |
int main(int argc, char **argv) { |
FILE *fd; |
int ecode = 0; |
char *buff, *refblock; |
static struct bitmap bufbitmap; |
static struct bitmap refbitmap; |
unsigned short i; |
if (argc < 2) { |
puts("usage: tlumacz en fr pl etc"); |
return(1); |
} |
buff = malloc(MEMBLOCKSZ); |
refblock = malloc(MEMBLOCKSZ); |
if ((buff == NULL) || (refblock == NULL)) { |
puts("out of memory"); |
return(1); |
} |
fd = fopen("out.lng", "wb"); |
if (fd == NULL) { |
puts("ERR: failed to open or create SVARCOM.LNG"); |
return(1); |
} |
/* write sig */ |
fwrite("SvL\x1b", 1, 4, fd); |
/* write lang blocks */ |
for (i = 1; i < argc; i++) { |
unsigned short sz; |
char id[3]; |
if (strlen(argv[i]) != 2) { |
printf("INVALID LANG SPECIFIED: %s\r\n", argv[i]); |
ecode = 1; |
break; |
} |
id[0] = argv[i][0]; |
id[1] = argv[i][1]; |
id[2] = 0; |
if (id[0] >= 'a') id[0] -= 'a' - 'A'; |
if (id[1] >= 'a') id[1] -= 'a' - 'A'; |
sz = gen_langstrings(buff, id, &bufbitmap, (i != 1)?&refbitmap:NULL, (i != 1)?refblock:NULL); |
if (sz == 0) { |
printf("ERROR COMPUTING LANG '%s'\r\n", id); |
ecode = 1; |
break; |
} else { |
printf("computed %s lang block of %u bytes\r\n", id, sz); |
} |
/* write lang ID to file, followed by block size and then the actual block */ |
if ((fwrite(id, 1, 2, fd) != 2) || |
(fwrite(&sz, 1, 2, fd) != 2) || |
(fwrite(buff, 1, sz, fd) != sz)) { |
printf("ERROR WRITING TO OUTPUT FILE\r\n"); |
ecode = 1; |
break; |
} |
/* compute the default block for reference language */ |
if (i == 1) { |
unsigned short x; |
FILE *fd2; |
fd2 = fopen("DEFLANG.C", "wb"); |
if (fd2 == NULL) { |
puts("ERROR: FAILED TO OPEN OR CREATE DEFLANG.C"); |
break; |
} |
fprintf(fd2, "/* THIS FILE HAS BEEN AUTOGENERATE BY TLUMACZ (PART OF THE SVARLANG LIBRARY) */\r\n"); |
fprintf(fd2, "const unsigned short svarlang_memsz = %uu;\r\n", sz * 2); |
fprintf(fd2, "char svarlang_mem[%u] = {\r\n", sz * 2); |
for (x = 0; x < sz; x++) { |
fprintf(fd2, "%u", buff[x]); |
if (x + 1 < sz) fprintf(fd2, ","); |
if ((x & 15) == 15) fprintf(fd2, "\r\n"); |
} |
fprintf(fd2, "};\r\n"); |
fclose(fd2); |
/* remember reference data for other languages */ |
memcpy(refblock, buff, MEMBLOCKSZ); |
memcpy(&refbitmap, &bufbitmap, sizeof(struct bitmap)); |
} |
} |
fclose(fd); |
return(ecode); |
} |