Subversion Repositories SvarDOS

Rev

Rev 1618 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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