Subversion Repositories SvarDOS

Compare Revisions

Ignore whitespace Rev 584 → Rev 585

/localcfg/tags/0.90/Makefile
0,0 → 1,28
#
# localcfg Makefile for Turbo C 2.01
#
 
all: localcfg.com
 
localcfg.com: localcfg.c country.c
tcc -mt -lt -f- -O -Z -d -w localcfg.c country.c
upx --8086 -9 localcfg.com
 
clean:
del *.obj
del *.com
 
buildpkg: localcfg.com
mkdir appinfo
mkdir source
mkdir source\localcfg
mkdir progs
mkdir progs\localcfg
copy localcfg.lsm appinfo
copy localcfg.com progs\localcfg
copy *.txt progs\localcfg
copy *.c source\localcfg
copy *.h source\localcfg
copy *.txt source\localcfg
copy makefile.* source\localcfg
zip -9 -m -r localcfg.zip appinfo progs source
/localcfg/tags/0.90/Makefile.gcc
0,0 → 1,12
#
# localcfg Makefile for GCC
#
 
all: localcfg
 
localcfg: localcfg.c country.c
gcc -Wall -Wextra -pedantic -O3 -std=c89 -Wformat-security -o localcfg localcfg.c country.c
 
clean:
rm -f localcfg
rm -f *.o
/localcfg/tags/0.90/country.c
0,0 → 1,426
/*
* functions that read/write from/to the localcfg country.sys-like file.
* Copyright (C) Mateusz Viste 2015
*/
 
#include <stdio.h>
#include <string.h>
 
#include "country.h"
 
 
#define READSHORT(x) (short)(x[0] | (x[1] << 8))
 
/* fills a country struct with default values */
static void country_default(struct country *countrydata) {
/* first clears the memory */
memset(countrydata, 0, sizeof(struct country));
/* fill in fields - only non-zero values */
countrydata->id = 1;
countrydata->codepage = 437;
/* countrydata->datefmt = COUNTRY_DATE_MDY;
countrydata->timefmt = COUNTRY_TIME12; */
countrydata->currency[0] = '$';
countrydata->decimal = '.';
countrydata->thousands = ',';
countrydata->datesep = '/';
countrydata->timesep = ':';
countrydata->currencyprec = 2;
/* countrydata->currencydecsym = 0; */
/* countrydata->currencyspace = 0; */
/* countrydata->currencypos = 0; */
countrydata->yes = 'Y';
countrydata->no = 'N';
}
 
 
/* Loads data from a country.sys file into a country struct.
* Returns 0 on success, non-zero otherwise. */
int country_read(struct country *countrydata, char *fname) {
unsigned char filebuff[1024];
unsigned char buff[64];
short firstentryoffs;
unsigned char *subfunctions[16] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
short filesize;
short subfunctionscount;
unsigned char *functiondata;
int x;
FILE *fd;
 
/* preload the country struct with default values */
country_default(countrydata);
 
/* load the file into buff, if file exists */
fd = fopen(fname, "rb");
if (fd == NULL) return(0); /* "file doesn't exist" is not an error condition */
filesize = fread(filebuff, 1, sizeof(filebuff), fd);
fclose(fd);
 
/* check that it's a country file - should start with 0xFF COUNTRY 0x00 */
if (filebuff[0] != 0xFF) return(-2);
if (strcmp((char *)filebuff + 1, "COUNTRY") != 0) return(-2);
 
/* check that it's one of my country.sys files - should contain a trailer */
memcpy(buff, filebuff + filesize - 8, 8);
buff[8] = 0;
if (strcmp((char *)buff, "LOCALCFG") != 0) return(-3);
 
/* read the offset of the entries index - must be at least 23 */
functiondata = filebuff + 19;
firstentryoffs = READSHORT(functiondata);
if ((firstentryoffs < 23) || (firstentryoffs >= filesize)) return(-4);
functiondata = filebuff + firstentryoffs;
 
/* how many entries do we have? I expect exactly one. */
if (READSHORT(functiondata) != 1) return(-5);
/* skip to the first country entry */
functiondata += 2;
 
/* skip directly to the subfunctions of the first country */
/* ddwords: size, country, codepage, reserved, reserved, offset */
/* printf("Size = %d\n", READSHORT(functiondata)); */
functiondata += 2; /* skip size */
/* printf("Country = %d\n", READSHORT(functiondata[0]); */
functiondata += 2; /* skip country */
/* printf("Codepage = %d\n", READSHORT(functiondata)); */
functiondata += 2; /* skip codepage */
functiondata += 4; /* skip reserved fields */
firstentryoffs = READSHORT(functiondata); /* read offset of the subfunctions index */
functiondata = filebuff + firstentryoffs;
 
/* read all subfunctions, but no more than 15 */
subfunctionscount = READSHORT(functiondata);
/* printf("Found %d subfunctions\n", subfunctionscount); */
functiondata += 2;
for (x = 0; (x < 15) && (x < subfunctionscount); x++) {
short size = READSHORT(functiondata);
functiondata += 2;
functiondata += 2; /* skip ID of the subfunction */
subfunctions[x] = filebuff + READSHORT(functiondata);
/* printf("subfunction %d at 0x%p\n", x, subfunctions[x]); */
functiondata += size - 2;
}
 
/* load every subfunction, and feed the country struct with data */
for (x = 0; subfunctions[x] != NULL; x++) {
short functionsize;
/* the function name should always start with 0xFF */
if (subfunctions[x][0] != 0xFF) return(-6);
/* load the subfunction's name, and act accordingly */
memcpy(buff, subfunctions[x] + 1, 7);
buff[7] = 0;
functiondata = subfunctions[x] + 8;
functionsize = READSHORT(functiondata);
functiondata = subfunctions[x] + 10;
/* */
if (strcmp((char *)buff, "YESNO ") == 0) {
if (functionsize != 4) continue;
countrydata->yes = functiondata[0];
countrydata->no = functiondata[2];
} else if (strcmp((char *)buff, "CTYINFO") == 0) {
if (functionsize != 22) continue;
/* ID */
countrydata->id = READSHORT(functiondata);
functiondata += 2;
/* codepage */
countrydata->codepage = READSHORT(functiondata);
functiondata += 2;
/* date format */
countrydata->datefmt = READSHORT(functiondata);
functiondata += 2;
/* currency symbol */
countrydata->currency[0] = functiondata[0];
countrydata->currency[1] = functiondata[1];
countrydata->currency[2] = functiondata[2];
countrydata->currency[3] = functiondata[3];
countrydata->currency[4] = 0;
functiondata += 5;
/* thousands separator, decimal sep, date sep, time sep */
countrydata->thousands = READSHORT(functiondata);
functiondata += 2;
countrydata->decimal = READSHORT(functiondata);
functiondata += 2;
countrydata->datesep = READSHORT(functiondata);
functiondata += 2;
countrydata->timesep = READSHORT(functiondata);
functiondata += 2;
/* currency format */
countrydata->currencypos = *functiondata & 1;
countrydata->currencyspace = (*functiondata >> 1) & 1;
countrydata->currencydecsym = (*functiondata >> 2) & 1;
functiondata += 1;
/* currency precision */
countrydata->currencyprec = *functiondata;
functiondata += 1;
/* time format */
countrydata->timefmt = *functiondata;
functiondata += 1;
}
}
 
return(0);
}
 
 
#define MSB(x) (((x) >> 8) & 0xff)
#define LSB(x) ((x) & 0xff)
 
#define DWORDB1(x) ((x) & 0xff)
#define DWORDB2(x) (((x) >> 8) & 0xff)
#define DWORDB3(x) (((x) >> 16) & 0xff)
#define DWORDB4(x) (((x) >> 24) & 0xff)
 
 
/* Computes a new country.sys file based on data from a country struct.
* Returns 0 on success, non-zero otherwise. */
int country_write(char *fname, struct country *c) {
unsigned char filebuff[1024];
short filesize = 0;
FILE *fd;
int x;
short subfunction_id[7] = {1,2,4,5,6,7,35};
short subfunction_ptr[7];
 
const unsigned char ucase_437[128] = {128, 154, 69, 65, 142, 65, 143, 128,
69, 69, 69, 73, 73, 73, 142, 143,
144, 146, 146, 79, 153, 79, 85, 85,
89, 153, 154, 155, 156, 157, 158, 159,
65, 73, 79, 85, 165, 165, 166, 167,
168, 169, 170, 171, 172, 173, 174, 175,
176, 177, 178, 179, 180, 181, 182, 183,
184, 185, 186, 187, 188, 189, 190, 191,
192, 193, 194, 195, 196, 197, 198, 199,
200, 201, 202, 203, 204, 205, 206, 207,
208, 209, 210, 211, 212, 213, 214, 215,
216, 217, 218, 219, 220, 221, 222, 223,
224, 225, 226, 227, 228, 229, 230, 231,
232, 233, 234, 235, 236, 237, 238, 239,
240, 241, 242, 243, 244, 245, 246, 247,
248, 249, 250, 251, 252, 253, 254, 255};
 
const unsigned char collate_437[256] = { 0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 85, 86, 87,
88, 89, 90, 91, 92, 93, 94, 95,
96, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 85, 86, 87,
88, 89, 90, 123, 124, 125, 126, 127,
67, 85, 69, 65, 65, 65, 65, 67,
69, 69, 69, 73, 73, 73, 65, 65,
69, 65, 65, 79, 79, 79, 85, 85,
89, 79, 85, 36, 36, 36, 36, 36,
65, 73, 79, 85, 78, 78, 166, 167,
63, 169, 170, 171, 172, 33, 34, 34,
176, 177, 178, 179, 180, 181, 182, 183,
184, 185, 186, 187, 188, 189, 190, 191,
192, 193, 194, 195, 196, 197, 198, 199,
200, 201, 202, 203, 204, 205, 206, 207,
208, 209, 210, 211, 212, 213, 214, 215,
216, 217, 218, 219, 220, 221, 222, 223,
224, 83, 226, 227, 228, 229, 230, 231,
232, 233, 234, 235, 236, 237, 238, 239,
240, 241, 242, 243, 244, 245, 246, 247,
248, 249, 250, 251, 252, 253, 254, 255};
 
/* compute the country.sys structures */
memcpy(filebuff, "\377COUNTRY\0\0\0\0\0\0\0\0\1\0\1", 19); /* header */
filesize = 19;
/* first entry offset (always current offset+4) */
filebuff[filesize + 0] = DWORDB1(filesize+4);
filebuff[filesize + 1] = DWORDB2(filesize+4);
filebuff[filesize + 2] = DWORDB3(filesize+4);
filebuff[filesize + 3] = DWORDB4(filesize+4);
filesize += 4;
/* number of entries */
filebuff[filesize++] = 1;
filebuff[filesize++] = 0;
/* first (and only) entry / size, country, codepage, reserved(2), offset */
filebuff[filesize++] = 12; /* size LSB */
filebuff[filesize++] = 0; /* size MSB */
filebuff[filesize++] = LSB(c->id); /* country LSB */
filebuff[filesize++] = MSB(c->id); /* country MSB */
filebuff[filesize++] = LSB(c->codepage); /* codepage LSB */
filebuff[filesize++] = MSB(c->codepage); /* codepage MSB */
filebuff[filesize++] = 0; /* reserved */
filebuff[filesize++] = 0; /* reserved */
filebuff[filesize++] = 0; /* reserved */
filebuff[filesize++] = 0; /* reserved */
filebuff[filesize + 0] = DWORDB1(filesize+4); /* offset for subfunctions list (ptr + 4) */
filebuff[filesize + 1] = DWORDB2(filesize+4); /* offset for subfunctions list (ptr + 4) */
filebuff[filesize + 2] = DWORDB3(filesize+4); /* offset for subfunctions list (ptr + 4) */
filebuff[filesize + 3] = DWORDB4(filesize+4); /* offset for subfunctions list (ptr + 4) */
filesize += 4;
/* index of subfunctions */
filebuff[filesize++] = 7; /* there are 7 subfunctions */
filebuff[filesize++] = 0;
for (x = 0; x < 7; x++) { /* dump each subfunction (size, id, offset) */
/* size is always 6 */
filebuff[filesize++] = 6;
filebuff[filesize++] = 0;
/* id of the subfunction */
filebuff[filesize++] = LSB(subfunction_id[x]);
filebuff[filesize++] = MSB(subfunction_id[x]);
/* remember the offset of the subfunction pointer for later */
subfunction_ptr[x] = filesize;
filesize += 4;
}
/* write the CTYINFO subfunction */
filebuff[subfunction_ptr[0]+0] = DWORDB1(filesize); /* update the */
filebuff[subfunction_ptr[0]+1] = DWORDB2(filesize); /* subfunction */
filebuff[subfunction_ptr[0]+2] = DWORDB3(filesize); /* pointer with */
filebuff[subfunction_ptr[0]+3] = DWORDB4(filesize); /* correct value */
/* subfunction header */
memcpy(filebuff + filesize, "\377CTYINFO", 8);
filesize += 8;
/* subfunction size */
filebuff[filesize++] = 22;
filebuff[filesize++] = 0;
/* country preferences */
filebuff[filesize++] = LSB(c->id); /* ID */
filebuff[filesize++] = MSB(c->id); /* ID */
filebuff[filesize++] = LSB(c->codepage); /* CP */
filebuff[filesize++] = MSB(c->codepage); /* CP */
filebuff[filesize++] = LSB(c->datefmt); /* date format */
filebuff[filesize++] = MSB(c->datefmt); /* date format */
for (x = 0; x < 5; x++) {
filebuff[filesize++] = c->currency[x]; /* currency */
}
filebuff[filesize++] = LSB(c->thousands); /* thousands separator LSB */
filebuff[filesize++] = MSB(c->thousands); /* thousands separator MSB */
filebuff[filesize++] = LSB(c->decimal); /* decimal separator LSB */
filebuff[filesize++] = MSB(c->decimal); /* decimal separator MSB */
filebuff[filesize++] = LSB(c->datesep); /* date separator LSB */
filebuff[filesize++] = MSB(c->datesep); /* date separator MSB */
filebuff[filesize++] = LSB(c->timesep); /* time separator LSB */
filebuff[filesize++] = MSB(c->timesep); /* time separator MSB */
filebuff[filesize] = c->currencydecsym; /* currency format (bit 2) */
filebuff[filesize] <<= 8;
filebuff[filesize] |= c->currencyspace; /* currency format (bit 1) */
filebuff[filesize] <<= 8;
filebuff[filesize++] |= c->currencypos; /* currency format (bit 0) */
filebuff[filesize++] = c->currencyprec; /* currency precision */
filebuff[filesize++] = c->timefmt; /* time format */
 
/* write the UCASE subfunction (used for LCASE, too) */
filebuff[subfunction_ptr[1]+0] = DWORDB1(filesize); /* update the */
filebuff[subfunction_ptr[1]+1] = DWORDB2(filesize); /* subfunction */
filebuff[subfunction_ptr[1]+2] = DWORDB3(filesize); /* pointer with */
filebuff[subfunction_ptr[1]+3] = DWORDB4(filesize); /* correct value */
filebuff[subfunction_ptr[2]+0] = DWORDB1(filesize); /* update the */
filebuff[subfunction_ptr[2]+1] = DWORDB2(filesize); /* subfunction */
filebuff[subfunction_ptr[2]+2] = DWORDB3(filesize); /* pointer with */
filebuff[subfunction_ptr[2]+3] = DWORDB4(filesize); /* correct value */
/* subfunction header */
memcpy(filebuff + filesize, "\377UCASE ", 8);
filesize += 8;
/* subfunction size */
filebuff[filesize++] = 128;
filebuff[filesize++] = 0;
/* UCASE table */
for (x = 0; x < 128; x++) {
filebuff[filesize++] = ucase_437[x];
}
 
/* write the FCHAR subfunction (filename terminator table) */
filebuff[subfunction_ptr[3]+0] = DWORDB1(filesize); /* update the */
filebuff[subfunction_ptr[3]+1] = DWORDB2(filesize); /* subfunction */
filebuff[subfunction_ptr[3]+2] = DWORDB3(filesize); /* pointer with */
filebuff[subfunction_ptr[3]+3] = DWORDB4(filesize); /* correct value */
/* subfunction header */
memcpy(filebuff + filesize, "\377FCHAR ", 8);
filesize += 8;
/* subfunction size */
filebuff[filesize++] = 22;
filebuff[filesize++] = 0;
/* values here are quite obscure, dumped from country.sys */
filebuff[filesize++] = 142;
filebuff[filesize++] = 0;
filebuff[filesize++] = 255;
filebuff[filesize++] = 65;
filebuff[filesize++] = 0;
filebuff[filesize++] = 32;
filebuff[filesize++] = 238;
/* list of characters that terminates a filename */
filebuff[filesize++] = 14; /* how many of them */
filebuff[filesize++] = 46; /* . */
filebuff[filesize++] = 34; /* " */
filebuff[filesize++] = 47; /* / */
filebuff[filesize++] = 92; /* \ */
filebuff[filesize++] = 91; /* [ */
filebuff[filesize++] = 93; /* ] */
filebuff[filesize++] = 58; /* : */
filebuff[filesize++] = 124; /* | */
filebuff[filesize++] = 60; /* < */
filebuff[filesize++] = 62; /* > */
filebuff[filesize++] = 43; /* + */
filebuff[filesize++] = 61; /* = */
filebuff[filesize++] = 59; /* ; */
filebuff[filesize++] = 44; /* , */
 
/* write the COLLATE subfunction */
filebuff[subfunction_ptr[4]+0] = DWORDB1(filesize); /* update the */
filebuff[subfunction_ptr[4]+1] = DWORDB2(filesize); /* subfunction */
filebuff[subfunction_ptr[4]+2] = DWORDB3(filesize); /* pointer with */
filebuff[subfunction_ptr[4]+3] = DWORDB4(filesize); /* correct value */
/* subfunction header */
memcpy(filebuff + filesize, "\377COLLATE", 8);
filesize += 8;
/* subfunction size */
filebuff[filesize++] = LSB(256);
filebuff[filesize++] = MSB(256);
/* collation for standard CP437 */
for (x = 0; x < 256; x++) {
filebuff[filesize++] = collate_437[x];
}
 
/* write the DBCS subfunction */
filebuff[subfunction_ptr[5]+0] = DWORDB1(filesize); /* update the */
filebuff[subfunction_ptr[5]+1] = DWORDB2(filesize); /* subfunction */
filebuff[subfunction_ptr[5]+2] = DWORDB3(filesize); /* pointer with */
filebuff[subfunction_ptr[5]+3] = DWORDB4(filesize); /* correct value */
/* subfunction header */
memcpy(filebuff + filesize, "\377DBCS ", 8);
filesize += 8;
/* subfunction size */
filebuff[filesize++] = 0;
filebuff[filesize++] = 0;
/* table terminator (must be there even if no lenght is zero */
filebuff[filesize++] = 0;
filebuff[filesize++] = 0;
 
/* write the YESNO subfunction */
filebuff[subfunction_ptr[6]+0] = DWORDB1(filesize); /* update the */
filebuff[subfunction_ptr[6]+1] = DWORDB2(filesize); /* subfunction */
filebuff[subfunction_ptr[6]+2] = DWORDB3(filesize); /* pointer with */
filebuff[subfunction_ptr[6]+3] = DWORDB4(filesize); /* correct value */
memcpy(filebuff + filesize, "\377YESNO ", 8);
filesize += 8;
filebuff[filesize++] = 4; /* size (LSB) */
filebuff[filesize++] = 0; /* size (MSB) */
filebuff[filesize++] = c->yes; /* "Yes" letter */
filebuff[filesize++] = 0;
filebuff[filesize++] = c->no; /* "No" letter */
filebuff[filesize++] = 0;
 
/* write the file trailer */
memcpy(filebuff + filesize, "LOCALCFG", 8);
filesize += 8;
 
/* write the buffer to file */
fd = fopen(fname, "wb");
if (fd == NULL) return(-1);
fwrite(filebuff, 1, filesize, fd);
fclose(fd);
 
return(0);
}
/localcfg/tags/0.90/country.h
0,0 → 1,47
/*
* functions that read/write from/to the localcfg country.sys-like file.
* Copyright (C) Mateusz Viste 2015
*/
 
#ifndef country_h_sentinel
#define country_h_sentinel
 
enum COUNTRY_DATEFMT {
COUNTRY_DATE_MDY = 0, /* Month, Day, Year */
COUNTRY_DATE_DMY = 1, /* Day, Month, Year */
COUNTRY_DATE_YMD = 2 /* Year, Month, Day */
};
 
enum COUNTRY_TIMEFMT {
COUNTRY_TIME12 = 0, /* AM/PM format (like 6:32 PM) */
COUNTRY_TIME24 = 1 /* 24h format (like 18:32) */
};
 
 
struct country {
char currency[5]; /* currency symbold, ASCIIZ, 4 letters max */
enum COUNTRY_DATEFMT datefmt; /* date format */
enum COUNTRY_TIMEFMT timefmt; /* time format */
short id; /* international ID */
short codepage; /* usual codepage */
unsigned char currencyprec; /* currency precision (2 = 0.12) */
unsigned char currencydecsym; /* set if the currency symbol should replace the decimal point */
unsigned char currencyspace; /* set if the currency symbol should be one space away from the value */
unsigned char currencypos; /* 0=currency symbol precedes the value, 1=follows it */
char decimal; /* decimal separator (like . or ,) */
char thousands; /* thousands separatot */
char datesep; /* date separator (usually '-', '.' or '/') */
char timesep; /* time separator (usually ':') */
char yes; /* the "yes" character (example: 'Y') */
char no; /* the "no" character (example: 'N') */
};
 
/* Loads data from a country.sys file into a country struct.
* Returns 0 on success, non-zero otherwise. */
int country_read(struct country *countrydata, char *fname);
 
/* Computes a new country.sys file based on data from a country struct.
* Returns 0 on success, non-zero otherwise. */
int country_write(char *fname, struct country *countrydata);
 
#endif
/localcfg/tags/0.90/history.txt
0,0 → 1,4
localcfg history file
 
* localcfg v0.90 [02 June 2015]
- first public release
/localcfg/tags/0.90/localcfg.c
0,0 → 1,296
/*
* Locales configuration for DOS
* Copyright (C) Mateusz Viste 2015
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*/
 
#include <stdio.h>
#include <stdlib.h> /* atoi() */
#include <string.h> /* strchr */
 
#include "country.h"
 
#define PVER "0.90"
#define PDATE "2015"
 
 
static void about(void) {
puts("localcfg v" PVER " - locales configuration for DOS\n"
"Copyright (C) Mateusz Viste 2015 / http://localcfg.sourceforge.net\n"
"\n"
"localcfg creates a custom COUNTRY.SYS-like file matching your preferences.\n"
"\n"
"usage: localcfg myprefs.sys [options]\n"
"\n"
"options allow to configure country locales to your likening, as follows:\n"
" /country:XX indicates your country code is XX (1 for USA, 33 for France, etc)\n"
" /cp:XXX adapts country data for codepage XXX (example: '437')\n"
" /decim:X reconfigures the decimal symbol to be 'X'");
puts(" /thous:X reconfigures the thousands symbol to be 'X'\n"
" /datesep:X sets the date separator to 'X' (for example '/')\n"
" /datefmt:X sets the date format, can be: MDY, DMY or YMD\n"
" /timesep:X sets the time separator to 'X' (for example ':')\n"
" /timefmt:X sets the time format: 0=12h with AM/PM or 1=24h\n"
" /curr:XXX sets the currency to XXX (a string of 1 to 4 characters)\n"
" /currpos:X sets the currency symbol position to X, where X is either");
puts(" 0=currency precedes the value, 1=currency follows the value and\n"
" 2=currency replaces the decimal sign\n"
" /currspc:X space between the currency and the value (0=no, 1=yes)\n"
" /currprec:X currency's precision (number of decimal digits, 0..9)\n"
" /yesno:XY sets the 'Yes/No' letter to XY (default: YN)\n"
);
}
 
 
static char *datestring(struct country *c) {
static char result[16];
switch (c->datefmt) {
case COUNTRY_DATE_MDY:
sprintf(result, "12%c31%c1990", c->datesep, c->datesep);
break;
case COUNTRY_DATE_DMY:
sprintf(result, "31%c12%c1990", c->datesep, c->datesep);
break;
case COUNTRY_DATE_YMD:
default:
sprintf(result, "1990%c12%c31", c->datesep, c->datesep);
break;
}
return(result);
}
 
 
static char *timestring(struct country *c) {
static char result[16];
if (c->timefmt == COUNTRY_TIME12) {
sprintf(result, "11%c59%c59 PM", c->timesep, c->timesep);
} else {
sprintf(result, "23%c59%c59", c->timesep, c->timesep);
}
return(result);
}
 
 
static char *currencystring(struct country *c) {
static char result[16];
char decimalpart[16];
char space[2] = {0, 0};
char decsym[8];
char cursym[8];
decimalpart[0] = '1';
decimalpart[1] = '2';
decimalpart[2] = '3';
decimalpart[3] = '4';
decimalpart[4] = '5';
decimalpart[5] = '6';
decimalpart[6] = '7';
decimalpart[7] = '8';
decimalpart[8] = '9';
decimalpart[9] = 0;
/* prepare the decimal string first */
if (c->currencyprec < 9) {
decimalpart[c->currencyprec] = 0;
}
/* prepare the currency space string */
if (c->currencyspace != 0) {
space[0] = ' ';
}
/* prepare the currency and decimal symbols */
if (c->currencydecsym != 0) { /* currency replaces the decimal point */
sprintf(decsym, "%s", c->currency);
cursym[0] = 0;
} else {
sprintf(decsym, "%c", c->decimal);
sprintf(cursym, "%s", c->currency);
}
if (c->currencyprec == 0) decsym[0] = 0;
/* compute the final string */
if (c->currencypos == 0) { /* currency precedes value */
sprintf(result, "%s%s99%s%s", cursym, space, decsym, decimalpart);
} else { /* currency follows value or replaces decimal symbol */
sprintf(result, "99%s%s%s%s", decsym, decimalpart, space, cursym);
}
return(result);
}
 
 
/* checks if str starts with prefix. returns 0 if so, non-zero otherwise. */
static int stringstartswith(char *str, char *prefix) {
for (;;) {
/* end of prefix means success */
if (*prefix == 0) return(0);
/* otherwise there is no match */
if (*str != *prefix) return(-1);
/* if match good so far, look at next char */
str += 1;
prefix += 1;
}
}
 
 
/* processes an argument. returns 0 on success, non-zero otherwise. */
static int processarg(char *arg, struct country *c) {
char *value;
int intvalue;
/* an option must start with a '/' */
if (arg[0] != '/') return(-1);
arg += 1; /* skip the slash */
/* find where the value starts */
value = strchr(arg, ':');
/* if no value present, fail */
if (value == NULL) return(-2);
value += 1;
if (*value == 0) return(-3);
/* interpret the option now */
if (stringstartswith(arg, "country:") == 0) {
intvalue = atoi(value);
if ((intvalue > 0) && (intvalue < 1000)) {
c->id = intvalue;
return(0);
}
} else if (stringstartswith(arg, "cp:") == 0) {
intvalue = atoi(value);
if ((intvalue > 0) && (intvalue < 1000)) {
c->codepage = intvalue;
return(0);
}
} else if (stringstartswith(arg, "decim:") == 0) {
if (value[1] == 0) { /* value must be exactly one character */
c->decimal = *value;
return(0);
}
} else if (stringstartswith(arg, "thous:") == 0) {
if (value[1] == 0) { /* value must be exactly one character */
c->thousands = *value;
return(0);
}
} else if (stringstartswith(arg, "datesep:") == 0) {
if (value[1] == 0) { /* value must be exactly one character */
c->datesep = *value;
return(0);
}
} else if (stringstartswith(arg, "timesep:") == 0) {
if (value[1] == 0) { /* value must be exactly one character */
c->timesep = *value;
return(0);
}
} else if (stringstartswith(arg, "datefmt:") == 0) {
if (strcmp(value, "MDY") == 0) {
c->datefmt = COUNTRY_DATE_MDY;
return(0);
} else if (strcmp(value, "DMY") == 0) {
c->datefmt = COUNTRY_DATE_DMY;
return(0);
} else if (strcmp(value, "YMD") == 0) {
c->datefmt = COUNTRY_DATE_YMD;
return(0);
}
} else if (stringstartswith(arg, "timefmt:") == 0) {
if (value[1] == 0) {
if ((value[0] >= '0') && (value[0] <= '1')) {
c->timefmt = value[0] - '0';
return(0);
}
}
} else if (stringstartswith(arg, "curr:") == 0) {
if (strlen(value) <= 4) {
strcpy(c->currency, value);
return(0);
}
} else if (stringstartswith(arg, "currpos:") == 0) {
if (value[1] == 0) {
if (value[0] == '0') {
c->currencypos = 0;
return(0);
} else if (value[0] == '1') {
c->currencypos = 1;
return(0);
} else if (value[0] == '2') {
c->currencypos = 0;
c->currencydecsym = 1;
return(0);
}
}
} else if (stringstartswith(arg, "currspc:") == 0) {
if (value[1] == 0) {
if ((value[0] >= '0') && (value[0] <= '1')) {
c->currencyspace = value[0] - '0';
return(0);
}
}
} else if (stringstartswith(arg, "currprec:") == 0) {
if (value[1] == 0) {
if ((value[0] >= '0') && (value[0] <= '9')) {
c->currencyprec = value[0] - '0';
return(0);
}
}
} else if (stringstartswith(arg, "yesno:") == 0) {
/* string must be exactly 2 characters long */
if ((value[0] != 0) && (value[1] != 0) && (value[2] == 0)) {
c->yes = value[0];
c->no = value[1];
return(0);
}
}
/* if I'm here, something went wrong */
return(-4);
}
 
 
int main(int argc, char **argv) {
struct country cntdata;
int changedflag;
int x;
char *fname;
 
if ((argc < 2) || (argv[1][0] == '/')) {
about();
return(1);
}
 
fname = argv[1];
 
x = country_read(&cntdata, fname);
if (x != 0) {
printf("ERROR: failed to read the preference file [%d]\n", x);
return(2);
}
 
changedflag = argc - 2;
 
/* process command line arguments */
while (--argc > 1) {
if (processarg(argv[argc], &cntdata) != 0) {
about();
return(3);
}
}
 
printf("Country intl code.....: %03d\n", cntdata.id);
printf("Codepage..............: %d\n", cntdata.codepage);
printf("Decimal separator.....: %c\n", cntdata.decimal);
printf("Thousands separator...: %c\n", cntdata.thousands);
printf("Date format...........: %s\n", datestring(&cntdata));
printf("Time format...........: %s\n", timestring(&cntdata));
printf("Yes/No letters........: %c/%c\n", cntdata.yes, cntdata.no);
printf("Currency example......: %s\n", currencystring(&cntdata));
 
printf("\n"
"Note: Please make sure your CONFIG.SYS contains a COUNTRY directive pointing\n"
" to your custom preferences file. Example:\n"
" COUNTRY=%03d,,C:\\MYPREFS.SYS\n\n", cntdata.id);
 
/* if anything changed, write the new file */
if (changedflag != 0) country_write(fname, &cntdata);
 
return(0);
}
/localcfg/tags/0.90/localcfg.lsm
0,0 → 1,14
Begin3
Title: localcfg
Version: 0.90
Entered-date: 02 June 2015
Description: locales preferences configuration tool
Keywords: country.sys
Author: Mateusz Viste
Maintained-by:
Primary-site:
Alternate-site:
Original-site: http://localcfg.sourceforge.net
Platforms: DOS
Copying-policy: BSD
End
/localcfg/tags/0.90/localcfg.txt
0,0 → 1,43
 
localcfg - locales editor for DOS
Copyright (C) Mateusz Viste 2015
 
 
*** About ***
 
localcfg is a 16 bit tool designed for DOS. It provides an easy way of
configurating system locales by generating a custom COUNTRY.SYS file that
reflects the exact preferences of the user.
 
Run localcfg /? for exact usage instructions.
 
website: http://localcfg.sourceforge.net/
 
 
*** License ***
 
localcfg is written by Mateusz Viste, and released under the BSD "2-clause"
license, included below.
 
Copyright (C) 2015 Mateusz Viste
All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.