Subversion Repositories SvarDOS

Rev

Rev 593 | Rev 606 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
585 mateuszvis 1
/*
588 mateuszvis 2
 * Locales configuration for SvarDOS
585 mateuszvis 3
 *
588 mateuszvis 4
 * Copyright (C) Mateusz Viste 2015-2022
5
 *
592 mateuszvis 6
 * MIT license
585 mateuszvis 7
 *
592 mateuszvis 8
 * Permission is hereby granted, free of charge, to any person obtaining a copy
9
 * of this software and associated documentation files (the "Software"), to
10
 * deal in the Software without restriction, including without limitation the
11
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12
 * sell copies of the Software, and to permit persons to whom the Software is
13
 * furnished to do so, subject to the following conditions:
14
 *
15
 * The above copyright notice and this permission notice shall be included in
16
 * all copies or substantial portions of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24
 * IN THE SOFTWARE.
585 mateuszvis 25
 */
26
 
27
#include <stdio.h>
28
#include <stdlib.h> /* atoi() */
29
#include <string.h> /* strchr */
30
 
603 mateuszvis 31
#include "svarlang.lib/svarlang.h"
32
 
585 mateuszvis 33
#include "country.h"
34
 
603 mateuszvis 35
#define PVER "20220203"
588 mateuszvis 36
#define PDATE "2015-2022"
585 mateuszvis 37
 
38
 
603 mateuszvis 39
enum NLS_STRINGS {
40
  NLS_HLP_VER           = 0x0000,
41
  NLS_HLP_DESC          = 0x0001,
42
  NLS_HLP_USAGE         = 0x0002,
43
  NLS_HLP_OPTIONS       = 0x0003,
44
  NLS_HLP_COUNTRY       = 0x000A,
45
  NLS_HLP_CP            = 0x000B,
46
  NLS_HLP_DECIM         = 0x000C,
47
  NLS_HLP_THOUS         = 0x000D,
48
  NLS_HLP_DATESEP       = 0x000E,
49
  NLS_HLP_DATEFMT       = 0x000F,
50
  NLS_HLP_TIMESEP       = 0x0010,
51
  NLS_HLP_TIMEFMT       = 0x0011,
52
  NLS_HLP_CURR          = 0x0012,
53
  NLS_HLP_CURRPOS0      = 0x0013,
54
  NLS_HLP_CURRPOS1      = 0x0014,
55
  NLS_HLP_CURRPOS2      = 0x0015,
56
  NLS_HLP_CURRSPC       = 0x0016,
57
  NLS_HLP_CURRPREC      = 0x0017,
58
  NLS_HLP_YESNO         = 0x0018,
59
  NLS_HLP_INFOLOC1      = 0x0032,
60
  NLS_HLP_INFOLOC2      = 0x0033,
61
 
62
  NLS_INFO_COUNTRY      = 0x0700,
63
  NLS_INFO_CODEPAGE     = 0x0701,
64
  NLS_INFO_DECSEP       = 0x0702,
65
  NLS_INFO_THOUSEP      = 0x0703,
66
  NLS_INFO_DATEFMT      = 0x0704,
67
  NLS_INFO_TIMEFMT      = 0x0705,
68
  NLS_INFO_YESNO        = 0x0706,
69
  NLS_INFO_CURREXAMPLE  = 0x0707,
70
  NLS_MAKESURE          = 0x0709,
71
 
72
  NLS_ERR_FILEPATHTWICE = 0x0900,
73
  NLS_ERR_BADPATH       = 0x0901,
74
  NLS_ERR_READFAIL      = 0x0902,
75
  NLS_ERR_INVPARAM      = 0x0903
76
};
77
 
78
 
79
static void nls_puts(enum NLS_STRINGS id) {
80
  puts(svarlang_strid(id));
81
}
82
 
83
 
84
static void nls_put(enum NLS_STRINGS id) {
85
  printf("%s", svarlang_strid(id));
86
}
87
 
88
 
89
static void crlf(void) {
90
  puts("");
91
}
92
 
93
 
585 mateuszvis 94
static void about(void) {
603 mateuszvis 95
  printf("localcfg ");
96
  nls_put(NLS_HLP_VER);
97
  puts(" " PVER ", (C) " PDATE " Mateusz Viste");
98
  crlf();
99
  nls_puts(NLS_HLP_DESC);
100
  crlf();
101
  nls_puts(NLS_HLP_USAGE);
102
  crlf();
103
  nls_puts(NLS_HLP_OPTIONS);
104
  crlf();
105
  nls_puts(NLS_HLP_COUNTRY);
106
  nls_puts(NLS_HLP_CP);
107
  nls_puts(NLS_HLP_DECIM);
108
  nls_puts(NLS_HLP_THOUS);
109
  nls_puts(NLS_HLP_DATESEP);
110
  nls_puts(NLS_HLP_DATEFMT);
111
  nls_puts(NLS_HLP_TIMESEP);
112
  nls_puts(NLS_HLP_TIMEFMT);
113
  nls_puts(NLS_HLP_CURR);
114
  nls_puts(NLS_HLP_CURRPOS0);
115
  nls_puts(NLS_HLP_CURRPOS1);
116
  nls_puts(NLS_HLP_CURRPOS2);
117
  nls_puts(NLS_HLP_CURRSPC);
118
  nls_puts(NLS_HLP_CURRPREC);
119
  nls_puts(NLS_HLP_YESNO);
120
  crlf();
121
  nls_puts(NLS_HLP_INFOLOC1);
122
  nls_puts(NLS_HLP_INFOLOC2);
585 mateuszvis 123
}
124
 
125
 
126
static char *datestring(struct country *c) {
127
  static char result[16];
591 mateuszvis 128
  switch (c->CTYINFO.datefmt) {
585 mateuszvis 129
    case COUNTRY_DATE_MDY:
591 mateuszvis 130
      sprintf(result, "12%c31%c1990", c->CTYINFO.datesep[0], c->CTYINFO.datesep[0]);
585 mateuszvis 131
      break;
132
    case COUNTRY_DATE_DMY:
591 mateuszvis 133
      sprintf(result, "31%c12%c1990", c->CTYINFO.datesep[0], c->CTYINFO.datesep[0]);
585 mateuszvis 134
      break;
135
    case COUNTRY_DATE_YMD:
136
    default:
591 mateuszvis 137
      sprintf(result, "1990%c12%c31", c->CTYINFO.datesep[0], c->CTYINFO.datesep[0]);
585 mateuszvis 138
      break;
139
  }
140
  return(result);
141
}
142
 
143
 
144
static char *timestring(struct country *c) {
145
  static char result[16];
591 mateuszvis 146
  if (c->CTYINFO.timefmt == COUNTRY_TIME12) {
147
    sprintf(result, "11%c59%c59 PM", c->CTYINFO.timesep[0], c->CTYINFO.timesep[0]);
585 mateuszvis 148
  } else {
591 mateuszvis 149
    sprintf(result, "23%c59%c59", c->CTYINFO.timesep[0], c->CTYINFO.timesep[0]);
585 mateuszvis 150
  }
151
  return(result);
152
}
153
 
154
 
155
static char *currencystring(struct country *c) {
156
  static char result[16];
157
  char decimalpart[16];
158
  char space[2] = {0, 0};
159
  char decsym[8];
160
  char cursym[8];
161
  decimalpart[0] = '1';
162
  decimalpart[1] = '2';
163
  decimalpart[2] = '3';
164
  decimalpart[3] = '4';
165
  decimalpart[4] = '5';
166
  decimalpart[5] = '6';
167
  decimalpart[6] = '7';
168
  decimalpart[7] = '8';
169
  decimalpart[8] = '9';
170
  decimalpart[9] = 0;
171
  /* prepare the decimal string first */
591 mateuszvis 172
  if (c->CTYINFO.currprec < 9) {
173
    decimalpart[c->CTYINFO.currprec] = 0;
585 mateuszvis 174
  }
175
  /* prepare the currency space string */
591 mateuszvis 176
  if (c->CTYINFO.currspace != 0) {
585 mateuszvis 177
    space[0] = ' ';
178
  }
179
  /* prepare the currency and decimal symbols */
591 mateuszvis 180
  if (c->CTYINFO.currdecsym != 0) { /* currency replaces the decimal point */
181
    sprintf(decsym, "%s", c->CTYINFO.currsym);
585 mateuszvis 182
    cursym[0] = 0;
183
  } else {
591 mateuszvis 184
    sprintf(decsym, "%c", c->CTYINFO.decimal[0]);
185
    sprintf(cursym, "%s", c->CTYINFO.currsym);
585 mateuszvis 186
  }
591 mateuszvis 187
  if (c->CTYINFO.currprec == 0) decsym[0] = 0;
585 mateuszvis 188
  /* compute the final string */
591 mateuszvis 189
  if (c->CTYINFO.currpos == 0) { /* currency precedes value */
585 mateuszvis 190
    sprintf(result, "%s%s99%s%s", cursym, space, decsym, decimalpart);
191
  } else { /* currency follows value or replaces decimal symbol */
192
    sprintf(result, "99%s%s%s%s", decsym, decimalpart, space, cursym);
193
  }
194
  return(result);
195
}
196
 
197
 
198
/* checks if str starts with prefix. returns 0 if so, non-zero otherwise. */
199
static int stringstartswith(char *str, char *prefix) {
200
  for (;;) {
201
    /* end of prefix means success */
202
    if (*prefix == 0) return(0);
203
    /* otherwise there is no match */
204
    if (*str != *prefix) return(-1);
205
    /* if match good so far, look at next char */
206
    str += 1;
207
    prefix += 1;
208
  }
209
}
210
 
211
 
212
/* processes an argument. returns 0 on success, non-zero otherwise. */
213
static int processarg(char *arg, struct country *c) {
214
  char *value;
215
  int intvalue;
216
  /* an option must start with a '/' */
217
  if (arg[0] != '/') return(-1);
218
  arg += 1; /* skip the slash */
219
  /* find where the value starts */
220
  value = strchr(arg, ':');
221
  /* if no value present, fail */
222
  if (value == NULL) return(-2);
223
  value += 1;
224
  if (*value == 0) return(-3);
225
  /* interpret the option now */
226
  if (stringstartswith(arg, "country:") == 0) {
227
    intvalue = atoi(value);
228
    if ((intvalue > 0) && (intvalue < 1000)) {
591 mateuszvis 229
      c->CTYINFO.id = intvalue;
585 mateuszvis 230
      return(0);
231
    }
232
  } else if (stringstartswith(arg, "cp:") == 0) {
233
    intvalue = atoi(value);
234
    if ((intvalue > 0) && (intvalue < 1000)) {
591 mateuszvis 235
      c->CTYINFO.codepage = intvalue;
585 mateuszvis 236
      return(0);
237
    }
238
  } else if (stringstartswith(arg, "decim:") == 0) {
239
    if (value[1] == 0) { /* value must be exactly one character */
591 mateuszvis 240
      c->CTYINFO.decimal[0] = *value;
585 mateuszvis 241
      return(0);
242
    }
243
  } else if (stringstartswith(arg, "thous:") == 0) {
244
    if (value[1] == 0) { /* value must be exactly one character */
591 mateuszvis 245
      c->CTYINFO.thousands[0] = *value;
585 mateuszvis 246
      return(0);
247
    }
248
  } else if (stringstartswith(arg, "datesep:") == 0) {
249
    if (value[1] == 0) { /* value must be exactly one character */
591 mateuszvis 250
      c->CTYINFO.datesep[0] = *value;
585 mateuszvis 251
      return(0);
252
    }
253
  } else if (stringstartswith(arg, "timesep:") == 0) {
254
    if (value[1] == 0) { /* value must be exactly one character */
591 mateuszvis 255
      c->CTYINFO.timesep[0] = *value;
585 mateuszvis 256
      return(0);
257
    }
258
  } else if (stringstartswith(arg, "datefmt:") == 0) {
259
    if (strcmp(value, "MDY") == 0) {
591 mateuszvis 260
      c->CTYINFO.datefmt = COUNTRY_DATE_MDY;
585 mateuszvis 261
      return(0);
262
    } else if (strcmp(value, "DMY") == 0) {
591 mateuszvis 263
      c->CTYINFO.datefmt = COUNTRY_DATE_DMY;
585 mateuszvis 264
      return(0);
265
    } else if (strcmp(value, "YMD") == 0) {
591 mateuszvis 266
      c->CTYINFO.datefmt = COUNTRY_DATE_YMD;
585 mateuszvis 267
      return(0);
268
    }
269
  } else if (stringstartswith(arg, "timefmt:") == 0) {
270
    if (value[1] == 0) {
271
      if ((value[0] >= '0') && (value[0] <= '1')) {
591 mateuszvis 272
        c->CTYINFO.timefmt = value[0] - '0';
585 mateuszvis 273
        return(0);
274
      }
275
    }
276
  } else if (stringstartswith(arg, "curr:") == 0) {
277
    if (strlen(value) <= 4) {
591 mateuszvis 278
      strcpy(c->CTYINFO.currsym, value);
585 mateuszvis 279
      return(0);
280
    }
281
  } else if (stringstartswith(arg, "currpos:") == 0) {
282
    if (value[1] == 0) {
283
      if (value[0] == '0') {
591 mateuszvis 284
        c->CTYINFO.currpos = 0;
585 mateuszvis 285
        return(0);
286
      } else if (value[0] == '1') {
591 mateuszvis 287
        c->CTYINFO.currpos = 1;
585 mateuszvis 288
        return(0);
289
      } else if (value[0] == '2') {
591 mateuszvis 290
        c->CTYINFO.currpos = 0;
291
        c->CTYINFO.currdecsym = 1;
585 mateuszvis 292
        return(0);
293
      }
294
    }
295
  } else if (stringstartswith(arg, "currspc:") == 0) {
296
    if (value[1] == 0) {
297
      if ((value[0] >= '0') && (value[0] <= '1')) {
591 mateuszvis 298
        c->CTYINFO.currspace = value[0] - '0';
585 mateuszvis 299
        return(0);
300
      }
301
    }
302
  } else if (stringstartswith(arg, "currprec:") == 0) {
303
    if (value[1] == 0) {
304
      if ((value[0] >= '0') && (value[0] <= '9')) {
591 mateuszvis 305
        c->CTYINFO.currprec = value[0] - '0';
585 mateuszvis 306
        return(0);
307
      }
308
    }
309
  } else if (stringstartswith(arg, "yesno:") == 0) {
310
    /* string must be exactly 2 characters long */
311
    if ((value[0] != 0) && (value[1] != 0) && (value[2] == 0)) {
591 mateuszvis 312
      c->YESNO.yes[0] = value[0];
313
      c->YESNO.no[0] = value[1];
585 mateuszvis 314
      return(0);
315
    }
316
  }
317
  /* if I'm here, something went wrong */
318
  return(-4);
319
}
320
 
321
 
588 mateuszvis 322
/* converts a path to its canonic representation, returns 0 on success
323
 * or DOS err on failure (invalid drive) */
324
static unsigned short file_truename(const char *dst, char *src) {
325
  unsigned short res = 0;
326
  _asm {
327
    push es
328
    mov ah, 0x60  /* query truename, DS:SI=src, ES:DI=dst */
329
    push ds
330
    pop es
331
    mov si, src
332
    mov di, dst
333
    int 0x21
334
    jnc DONE
335
    mov [res], ax
336
    DONE:
337
    pop es
338
  }
339
  return(res);
340
}
341
 
342
 
593 mateuszvis 343
static void default_country_path(char *s) {
344
  char *dosdir = getenv("DOSDIR");
345
  size_t dosdirlen;
346
  s[0] = 0;
347
  if (dosdir == NULL) return;
348
  dosdirlen = strlen(dosdir);
349
  if (dosdirlen == 0) return;
350
  /* drop trailing backslash if present */
351
  if (dosdir[dosdirlen - 1] == '\\') dosdirlen--;
352
  /* copy dosdir to s and append the rest of the path */
353
  memcpy(s, dosdir, dosdirlen);
354
  strcpy(s + dosdirlen, "\\CFG\\COUNTRY.SYS");
355
}
356
 
357
 
585 mateuszvis 358
int main(int argc, char **argv) {
359
  struct country cntdata;
360
  int changedflag;
361
  int x;
588 mateuszvis 362
  static char fname[130];
585 mateuszvis 363
 
603 mateuszvis 364
  svarlang_autoload("localcfg");
365
 
593 mateuszvis 366
  /* scan argv looking for the path to country.sys */
367
  for (x = 1; x < argc; x++) {
368
    if (argv[x][0] != '/') {
369
      if (fname[0] != 0) {
603 mateuszvis 370
        nls_puts(NLS_ERR_FILEPATHTWICE);
593 mateuszvis 371
        return(1);
372
      }
373
      /* */
374
      if (file_truename(fname, argv[x]) != 0) {
603 mateuszvis 375
        nls_puts(NLS_ERR_BADPATH);
593 mateuszvis 376
        return(1);
377
      }
378
    } else if (strcmp(argv[x], "/?") == 0) { /* is it /? */
379
      about();
380
      return(1);
381
    }
585 mateuszvis 382
  }
383
 
593 mateuszvis 384
  /* if no file path provided, look into %DOSDIR%\CFG\COUNTRY.SYS */
385
  if (fname[0] == 0) default_country_path(fname);
585 mateuszvis 386
 
387
  x = country_read(&cntdata, fname);
388
  if (x != 0) {
603 mateuszvis 389
    nls_puts(NLS_ERR_READFAIL);
585 mateuszvis 390
    return(2);
391
  }
392
 
593 mateuszvis 393
  changedflag = 0;
585 mateuszvis 394
 
395
  /* process command line arguments */
593 mateuszvis 396
  for (x = 1; x < argc; x++) {
397
    if (argv[x][0] != '/') continue; /* skip country.sys filename (processed earlier) */
398
    changedflag++;
399
    if (processarg(argv[x], &cntdata) != 0) {
603 mateuszvis 400
      nls_puts(NLS_ERR_INVPARAM);
585 mateuszvis 401
      return(3);
402
    }
403
  }
404
 
603 mateuszvis 405
  nls_put(NLS_INFO_COUNTRY);
406
  printf(" %03d\r\n", cntdata.CTYINFO.id);
407
  nls_put(NLS_INFO_CODEPAGE);
408
  printf(" %d\r\n", cntdata.CTYINFO.codepage);
409
  nls_put(NLS_INFO_DECSEP);
410
  printf(" %c\r\n", cntdata.CTYINFO.decimal[0]);
411
  nls_put(NLS_INFO_THOUSEP);
412
  printf(" %c\r\n", cntdata.CTYINFO.thousands[0]);
413
  nls_put(NLS_INFO_DATEFMT);
414
  printf(" %s\r\n", datestring(&cntdata));
415
  nls_put(NLS_INFO_TIMEFMT);
416
  printf(" %s\r\n", timestring(&cntdata));
417
  nls_put(NLS_INFO_YESNO);
418
  printf(" %c/%c\r\n", cntdata.YESNO.yes[0], cntdata.YESNO.no[0]);
419
  nls_put(NLS_INFO_CURREXAMPLE);
420
  printf(" %s\r\n", currencystring(&cntdata));
585 mateuszvis 421
 
603 mateuszvis 422
  crlf();
423
  nls_puts(NLS_MAKESURE);
424
  printf("COUNTRY=%03d,%03d,%s", cntdata.CTYINFO.id, cntdata.CTYINFO.codepage, fname);
425
  crlf();
585 mateuszvis 426
 
427
  /* if anything changed, write the new file */
428
  if (changedflag != 0) country_write(fname, &cntdata);
429
 
430
  return(0);
431
}