Subversion Repositories SvarDOS

Rev

Rev 592 | Rev 603 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 592 Rev 593
1
/*
1
/*
2
 * Locales configuration for SvarDOS
2
 * Locales configuration for SvarDOS
3
 *
3
 *
4
 * Copyright (C) Mateusz Viste 2015-2022
4
 * Copyright (C) Mateusz Viste 2015-2022
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 "country.h"
31
#include "country.h"
32
 
32
 
33
#define PVER "20220202"
33
#define PVER "20220202"
34
#define PDATE "2015-2022"
34
#define PDATE "2015-2022"
35
 
35
 
36
 
36
 
37
static void about(void) {
37
static void about(void) {
38
  puts("localcfg ver " PVER " - locales configuration for DOS\n"
38
  puts("localcfg ver " PVER " - locales configuration for DOS\n"
39
       "Copyright (C) Mateusz Viste " PDATE "\n"
39
       "Copyright (C) " PDATE " Mateusz Viste\n"
40
       "\n"
40
       "\n"
41
       "localcfg creates a custom COUNTRY.SYS-like file matching your preferences.\n"
41
       "localcfg creates or edits a custom COUNTRY.SYS-like file with your preferences.\n"
42
       "\n"
42
       "\n"
43
       "usage: localcfg myprefs.sys [options]\n"
43
       "usage: localcfg [COUNTRY.SYS] [options]\n"
44
       "\n"
44
       "\n"
45
       "options allow to configure country locales to your likening, as follows:\n"
45
       "options allow to configure country locales to your likening, as follows:\n"
46
       "  /country:XX indicates your country code is XX (1 for USA, 33 for France, etc)\n"
46
       "  /country:XX indicates your country code is XX (1 for USA, 33 for France, etc)\n"
47
       "  /cp:XXX     adapts country data for codepage XXX (example: '437')\n"
47
       "  /cp:XXX     adapts country data for codepage XXX (example: '437')\n"
48
       "  /decim:X    reconfigures the decimal symbol to be 'X'");
48
       "  /decim:X    reconfigures the decimal symbol to be 'X'");
49
  puts("  /thous:X    reconfigures the thousands symbol to be 'X'\n"
49
  puts("  /thous:X    reconfigures the thousands symbol to be 'X'\n"
50
       "  /datesep:X  sets the date separator to 'X' (for example '/')\n"
50
       "  /datesep:X  sets the date separator to 'X' (for example '/')\n"
51
       "  /datefmt:X  sets the date format, can be: MDY, DMY or YMD\n"
51
       "  /datefmt:X  sets the date format, can be: MDY, DMY or YMD\n"
52
       "  /timesep:X  sets the time separator to 'X' (for example ':')\n"
52
       "  /timesep:X  sets the time separator to 'X' (for example ':')\n"
53
       "  /timefmt:X  sets the time format: 0=12h with AM/PM or 1=24h\n"
53
       "  /timefmt:X  sets the time format: 0=12h with AM/PM or 1=24h\n"
54
       "  /curr:XXX   sets the currency to XXX (a string of 1 to 4 characters)\n"
54
       "  /curr:XXX   sets the currency to XXX (a string of 1 to 4 characters)\n"
55
       "  /currpos:X  sets the currency symbol position to X, where X is either");
55
       "  /currpos:X  sets the currency symbol position to X, where X is either");
56
  puts("              0=currency precedes the value, 1=currency follows the value and\n"
56
  puts("              0=currency precedes the value, 1=currency follows the value and\n"
57
       "              2=currency replaces the decimal sign\n"
57
       "              2=currency replaces the decimal sign\n"
58
       "  /currspc:X  space between the currency and the value (0=no, 1=yes)\n"
58
       "  /currspc:X  space between the currency and the value (0=no, 1=yes)\n"
59
       "  /currprec:X currency's precision (number of decimal digits, 0..9)\n"
59
       "  /currprec:X currency's precision (number of decimal digits, 0..9)\n"
60
       "  /yesno:XY   sets the 'Yes/No' letter to XY (default: YN)\n"
60
       "  /yesno:XY   sets the 'Yes/No' letter to XY (default: YN)\n"
-
 
61
       "\n"
-
 
62
       "If COUNTRY.SYS location is not provided, then localcfg tries loading it\n"
-
 
63
       "from %DOSDIR%\\CFG\\COUNTRY.SYS\n"
61
      );
64
      );
62
}
65
}
63
 
66
 
64
 
67
 
65
static char *datestring(struct country *c) {
68
static char *datestring(struct country *c) {
66
  static char result[16];
69
  static char result[16];
67
  switch (c->CTYINFO.datefmt) {
70
  switch (c->CTYINFO.datefmt) {
68
    case COUNTRY_DATE_MDY:
71
    case COUNTRY_DATE_MDY:
69
      sprintf(result, "12%c31%c1990", c->CTYINFO.datesep[0], c->CTYINFO.datesep[0]);
72
      sprintf(result, "12%c31%c1990", c->CTYINFO.datesep[0], c->CTYINFO.datesep[0]);
70
      break;
73
      break;
71
    case COUNTRY_DATE_DMY:
74
    case COUNTRY_DATE_DMY:
72
      sprintf(result, "31%c12%c1990", c->CTYINFO.datesep[0], c->CTYINFO.datesep[0]);
75
      sprintf(result, "31%c12%c1990", c->CTYINFO.datesep[0], c->CTYINFO.datesep[0]);
73
      break;
76
      break;
74
    case COUNTRY_DATE_YMD:
77
    case COUNTRY_DATE_YMD:
75
    default:
78
    default:
76
      sprintf(result, "1990%c12%c31", c->CTYINFO.datesep[0], c->CTYINFO.datesep[0]);
79
      sprintf(result, "1990%c12%c31", c->CTYINFO.datesep[0], c->CTYINFO.datesep[0]);
77
      break;
80
      break;
78
  }
81
  }
79
  return(result);
82
  return(result);
80
}
83
}
81
 
84
 
82
 
85
 
83
static char *timestring(struct country *c) {
86
static char *timestring(struct country *c) {
84
  static char result[16];
87
  static char result[16];
85
  if (c->CTYINFO.timefmt == COUNTRY_TIME12) {
88
  if (c->CTYINFO.timefmt == COUNTRY_TIME12) {
86
    sprintf(result, "11%c59%c59 PM", c->CTYINFO.timesep[0], c->CTYINFO.timesep[0]);
89
    sprintf(result, "11%c59%c59 PM", c->CTYINFO.timesep[0], c->CTYINFO.timesep[0]);
87
  } else {
90
  } else {
88
    sprintf(result, "23%c59%c59", c->CTYINFO.timesep[0], c->CTYINFO.timesep[0]);
91
    sprintf(result, "23%c59%c59", c->CTYINFO.timesep[0], c->CTYINFO.timesep[0]);
89
  }
92
  }
90
  return(result);
93
  return(result);
91
}
94
}
92
 
95
 
93
 
96
 
94
static char *currencystring(struct country *c) {
97
static char *currencystring(struct country *c) {
95
  static char result[16];
98
  static char result[16];
96
  char decimalpart[16];
99
  char decimalpart[16];
97
  char space[2] = {0, 0};
100
  char space[2] = {0, 0};
98
  char decsym[8];
101
  char decsym[8];
99
  char cursym[8];
102
  char cursym[8];
100
  decimalpart[0] = '1';
103
  decimalpart[0] = '1';
101
  decimalpart[1] = '2';
104
  decimalpart[1] = '2';
102
  decimalpart[2] = '3';
105
  decimalpart[2] = '3';
103
  decimalpart[3] = '4';
106
  decimalpart[3] = '4';
104
  decimalpart[4] = '5';
107
  decimalpart[4] = '5';
105
  decimalpart[5] = '6';
108
  decimalpart[5] = '6';
106
  decimalpart[6] = '7';
109
  decimalpart[6] = '7';
107
  decimalpart[7] = '8';
110
  decimalpart[7] = '8';
108
  decimalpart[8] = '9';
111
  decimalpart[8] = '9';
109
  decimalpart[9] = 0;
112
  decimalpart[9] = 0;
110
  /* prepare the decimal string first */
113
  /* prepare the decimal string first */
111
  if (c->CTYINFO.currprec < 9) {
114
  if (c->CTYINFO.currprec < 9) {
112
    decimalpart[c->CTYINFO.currprec] = 0;
115
    decimalpart[c->CTYINFO.currprec] = 0;
113
  }
116
  }
114
  /* prepare the currency space string */
117
  /* prepare the currency space string */
115
  if (c->CTYINFO.currspace != 0) {
118
  if (c->CTYINFO.currspace != 0) {
116
    space[0] = ' ';
119
    space[0] = ' ';
117
  }
120
  }
118
  /* prepare the currency and decimal symbols */
121
  /* prepare the currency and decimal symbols */
119
  if (c->CTYINFO.currdecsym != 0) { /* currency replaces the decimal point */
122
  if (c->CTYINFO.currdecsym != 0) { /* currency replaces the decimal point */
120
    sprintf(decsym, "%s", c->CTYINFO.currsym);
123
    sprintf(decsym, "%s", c->CTYINFO.currsym);
121
    cursym[0] = 0;
124
    cursym[0] = 0;
122
  } else {
125
  } else {
123
    sprintf(decsym, "%c", c->CTYINFO.decimal[0]);
126
    sprintf(decsym, "%c", c->CTYINFO.decimal[0]);
124
    sprintf(cursym, "%s", c->CTYINFO.currsym);
127
    sprintf(cursym, "%s", c->CTYINFO.currsym);
125
  }
128
  }
126
  if (c->CTYINFO.currprec == 0) decsym[0] = 0;
129
  if (c->CTYINFO.currprec == 0) decsym[0] = 0;
127
  /* compute the final string */
130
  /* compute the final string */
128
  if (c->CTYINFO.currpos == 0) { /* currency precedes value */
131
  if (c->CTYINFO.currpos == 0) { /* currency precedes value */
129
    sprintf(result, "%s%s99%s%s", cursym, space, decsym, decimalpart);
132
    sprintf(result, "%s%s99%s%s", cursym, space, decsym, decimalpart);
130
  } else { /* currency follows value or replaces decimal symbol */
133
  } else { /* currency follows value or replaces decimal symbol */
131
    sprintf(result, "99%s%s%s%s", decsym, decimalpart, space, cursym);
134
    sprintf(result, "99%s%s%s%s", decsym, decimalpart, space, cursym);
132
  }
135
  }
133
  return(result);
136
  return(result);
134
}
137
}
135
 
138
 
136
 
139
 
137
/* checks if str starts with prefix. returns 0 if so, non-zero otherwise. */
140
/* checks if str starts with prefix. returns 0 if so, non-zero otherwise. */
138
static int stringstartswith(char *str, char *prefix) {
141
static int stringstartswith(char *str, char *prefix) {
139
  for (;;) {
142
  for (;;) {
140
    /* end of prefix means success */
143
    /* end of prefix means success */
141
    if (*prefix == 0) return(0);
144
    if (*prefix == 0) return(0);
142
    /* otherwise there is no match */
145
    /* otherwise there is no match */
143
    if (*str != *prefix) return(-1);
146
    if (*str != *prefix) return(-1);
144
    /* if match good so far, look at next char */
147
    /* if match good so far, look at next char */
145
    str += 1;
148
    str += 1;
146
    prefix += 1;
149
    prefix += 1;
147
  }
150
  }
148
}
151
}
149
 
152
 
150
 
153
 
151
/* processes an argument. returns 0 on success, non-zero otherwise. */
154
/* processes an argument. returns 0 on success, non-zero otherwise. */
152
static int processarg(char *arg, struct country *c) {
155
static int processarg(char *arg, struct country *c) {
153
  char *value;
156
  char *value;
154
  int intvalue;
157
  int intvalue;
155
  /* an option must start with a '/' */
158
  /* an option must start with a '/' */
156
  if (arg[0] != '/') return(-1);
159
  if (arg[0] != '/') return(-1);
157
  arg += 1; /* skip the slash */
160
  arg += 1; /* skip the slash */
158
  /* find where the value starts */
161
  /* find where the value starts */
159
  value = strchr(arg, ':');
162
  value = strchr(arg, ':');
160
  /* if no value present, fail */
163
  /* if no value present, fail */
161
  if (value == NULL) return(-2);
164
  if (value == NULL) return(-2);
162
  value += 1;
165
  value += 1;
163
  if (*value == 0) return(-3);
166
  if (*value == 0) return(-3);
164
  /* interpret the option now */
167
  /* interpret the option now */
165
  if (stringstartswith(arg, "country:") == 0) {
168
  if (stringstartswith(arg, "country:") == 0) {
166
    intvalue = atoi(value);
169
    intvalue = atoi(value);
167
    if ((intvalue > 0) && (intvalue < 1000)) {
170
    if ((intvalue > 0) && (intvalue < 1000)) {
168
      c->CTYINFO.id = intvalue;
171
      c->CTYINFO.id = intvalue;
169
      return(0);
172
      return(0);
170
    }
173
    }
171
  } else if (stringstartswith(arg, "cp:") == 0) {
174
  } else if (stringstartswith(arg, "cp:") == 0) {
172
    intvalue = atoi(value);
175
    intvalue = atoi(value);
173
    if ((intvalue > 0) && (intvalue < 1000)) {
176
    if ((intvalue > 0) && (intvalue < 1000)) {
174
      c->CTYINFO.codepage = intvalue;
177
      c->CTYINFO.codepage = intvalue;
175
      return(0);
178
      return(0);
176
    }
179
    }
177
  } else if (stringstartswith(arg, "decim:") == 0) {
180
  } else if (stringstartswith(arg, "decim:") == 0) {
178
    if (value[1] == 0) { /* value must be exactly one character */
181
    if (value[1] == 0) { /* value must be exactly one character */
179
      c->CTYINFO.decimal[0] = *value;
182
      c->CTYINFO.decimal[0] = *value;
180
      return(0);
183
      return(0);
181
    }
184
    }
182
  } else if (stringstartswith(arg, "thous:") == 0) {
185
  } else if (stringstartswith(arg, "thous:") == 0) {
183
    if (value[1] == 0) { /* value must be exactly one character */
186
    if (value[1] == 0) { /* value must be exactly one character */
184
      c->CTYINFO.thousands[0] = *value;
187
      c->CTYINFO.thousands[0] = *value;
185
      return(0);
188
      return(0);
186
    }
189
    }
187
  } else if (stringstartswith(arg, "datesep:") == 0) {
190
  } else if (stringstartswith(arg, "datesep:") == 0) {
188
    if (value[1] == 0) { /* value must be exactly one character */
191
    if (value[1] == 0) { /* value must be exactly one character */
189
      c->CTYINFO.datesep[0] = *value;
192
      c->CTYINFO.datesep[0] = *value;
190
      return(0);
193
      return(0);
191
    }
194
    }
192
  } else if (stringstartswith(arg, "timesep:") == 0) {
195
  } else if (stringstartswith(arg, "timesep:") == 0) {
193
    if (value[1] == 0) { /* value must be exactly one character */
196
    if (value[1] == 0) { /* value must be exactly one character */
194
      c->CTYINFO.timesep[0] = *value;
197
      c->CTYINFO.timesep[0] = *value;
195
      return(0);
198
      return(0);
196
    }
199
    }
197
  } else if (stringstartswith(arg, "datefmt:") == 0) {
200
  } else if (stringstartswith(arg, "datefmt:") == 0) {
198
    if (strcmp(value, "MDY") == 0) {
201
    if (strcmp(value, "MDY") == 0) {
199
      c->CTYINFO.datefmt = COUNTRY_DATE_MDY;
202
      c->CTYINFO.datefmt = COUNTRY_DATE_MDY;
200
      return(0);
203
      return(0);
201
    } else if (strcmp(value, "DMY") == 0) {
204
    } else if (strcmp(value, "DMY") == 0) {
202
      c->CTYINFO.datefmt = COUNTRY_DATE_DMY;
205
      c->CTYINFO.datefmt = COUNTRY_DATE_DMY;
203
      return(0);
206
      return(0);
204
    } else if (strcmp(value, "YMD") == 0) {
207
    } else if (strcmp(value, "YMD") == 0) {
205
      c->CTYINFO.datefmt = COUNTRY_DATE_YMD;
208
      c->CTYINFO.datefmt = COUNTRY_DATE_YMD;
206
      return(0);
209
      return(0);
207
    }
210
    }
208
  } else if (stringstartswith(arg, "timefmt:") == 0) {
211
  } else if (stringstartswith(arg, "timefmt:") == 0) {
209
    if (value[1] == 0) {
212
    if (value[1] == 0) {
210
      if ((value[0] >= '0') && (value[0] <= '1')) {
213
      if ((value[0] >= '0') && (value[0] <= '1')) {
211
        c->CTYINFO.timefmt = value[0] - '0';
214
        c->CTYINFO.timefmt = value[0] - '0';
212
        return(0);
215
        return(0);
213
      }
216
      }
214
    }
217
    }
215
  } else if (stringstartswith(arg, "curr:") == 0) {
218
  } else if (stringstartswith(arg, "curr:") == 0) {
216
    if (strlen(value) <= 4) {
219
    if (strlen(value) <= 4) {
217
      strcpy(c->CTYINFO.currsym, value);
220
      strcpy(c->CTYINFO.currsym, value);
218
      return(0);
221
      return(0);
219
    }
222
    }
220
  } else if (stringstartswith(arg, "currpos:") == 0) {
223
  } else if (stringstartswith(arg, "currpos:") == 0) {
221
    if (value[1] == 0) {
224
    if (value[1] == 0) {
222
      if (value[0] == '0') {
225
      if (value[0] == '0') {
223
        c->CTYINFO.currpos = 0;
226
        c->CTYINFO.currpos = 0;
224
        return(0);
227
        return(0);
225
      } else if (value[0] == '1') {
228
      } else if (value[0] == '1') {
226
        c->CTYINFO.currpos = 1;
229
        c->CTYINFO.currpos = 1;
227
        return(0);
230
        return(0);
228
      } else if (value[0] == '2') {
231
      } else if (value[0] == '2') {
229
        c->CTYINFO.currpos = 0;
232
        c->CTYINFO.currpos = 0;
230
        c->CTYINFO.currdecsym = 1;
233
        c->CTYINFO.currdecsym = 1;
231
        return(0);
234
        return(0);
232
      }
235
      }
233
    }
236
    }
234
  } else if (stringstartswith(arg, "currspc:") == 0) {
237
  } else if (stringstartswith(arg, "currspc:") == 0) {
235
    if (value[1] == 0) {
238
    if (value[1] == 0) {
236
      if ((value[0] >= '0') && (value[0] <= '1')) {
239
      if ((value[0] >= '0') && (value[0] <= '1')) {
237
        c->CTYINFO.currspace = value[0] - '0';
240
        c->CTYINFO.currspace = value[0] - '0';
238
        return(0);
241
        return(0);
239
      }
242
      }
240
    }
243
    }
241
  } else if (stringstartswith(arg, "currprec:") == 0) {
244
  } else if (stringstartswith(arg, "currprec:") == 0) {
242
    if (value[1] == 0) {
245
    if (value[1] == 0) {
243
      if ((value[0] >= '0') && (value[0] <= '9')) {
246
      if ((value[0] >= '0') && (value[0] <= '9')) {
244
        c->CTYINFO.currprec = value[0] - '0';
247
        c->CTYINFO.currprec = value[0] - '0';
245
        return(0);
248
        return(0);
246
      }
249
      }
247
    }
250
    }
248
  } else if (stringstartswith(arg, "yesno:") == 0) {
251
  } else if (stringstartswith(arg, "yesno:") == 0) {
249
    /* string must be exactly 2 characters long */
252
    /* string must be exactly 2 characters long */
250
    if ((value[0] != 0) && (value[1] != 0) && (value[2] == 0)) {
253
    if ((value[0] != 0) && (value[1] != 0) && (value[2] == 0)) {
251
      c->YESNO.yes[0] = value[0];
254
      c->YESNO.yes[0] = value[0];
252
      c->YESNO.no[0] = value[1];
255
      c->YESNO.no[0] = value[1];
253
      return(0);
256
      return(0);
254
    }
257
    }
255
  }
258
  }
256
  /* if I'm here, something went wrong */
259
  /* if I'm here, something went wrong */
257
  return(-4);
260
  return(-4);
258
}
261
}
259
 
262
 
260
 
263
 
261
/* converts a path to its canonic representation, returns 0 on success
264
/* converts a path to its canonic representation, returns 0 on success
262
 * or DOS err on failure (invalid drive) */
265
 * or DOS err on failure (invalid drive) */
263
static unsigned short file_truename(const char *dst, char *src) {
266
static unsigned short file_truename(const char *dst, char *src) {
264
  unsigned short res = 0;
267
  unsigned short res = 0;
265
  _asm {
268
  _asm {
266
    push es
269
    push es
267
    mov ah, 0x60  /* query truename, DS:SI=src, ES:DI=dst */
270
    mov ah, 0x60  /* query truename, DS:SI=src, ES:DI=dst */
268
    push ds
271
    push ds
269
    pop es
272
    pop es
270
    mov si, src
273
    mov si, src
271
    mov di, dst
274
    mov di, dst
272
    int 0x21
275
    int 0x21
273
    jnc DONE
276
    jnc DONE
274
    mov [res], ax
277
    mov [res], ax
275
    DONE:
278
    DONE:
276
    pop es
279
    pop es
277
  }
280
  }
278
  return(res);
281
  return(res);
279
}
282
}
280
 
283
 
281
 
284
 
-
 
285
static void default_country_path(char *s) {
-
 
286
  char *dosdir = getenv("DOSDIR");
-
 
287
  size_t dosdirlen;
-
 
288
  s[0] = 0;
-
 
289
  if (dosdir == NULL) return;
-
 
290
  dosdirlen = strlen(dosdir);
-
 
291
  if (dosdirlen == 0) return;
-
 
292
  /* drop trailing backslash if present */
-
 
293
  if (dosdir[dosdirlen - 1] == '\\') dosdirlen--;
-
 
294
  /* copy dosdir to s and append the rest of the path */
-
 
295
  memcpy(s, dosdir, dosdirlen);
-
 
296
  strcpy(s + dosdirlen, "\\CFG\\COUNTRY.SYS");
-
 
297
}
-
 
298
 
-
 
299
 
282
int main(int argc, char **argv) {
300
int main(int argc, char **argv) {
283
  struct country cntdata;
301
  struct country cntdata;
284
  int changedflag;
302
  int changedflag;
285
  int x;
303
  int x;
286
  static char fname[130];
304
  static char fname[130];
287
 
305
 
-
 
306
  /* scan argv looking for the path to country.sys */
-
 
307
  for (x = 1; x < argc; x++) {
288
  if ((argc < 2) || (argv[1][0] == '/')) {
308
    if (argv[x][0] != '/') {
-
 
309
      if (fname[0] != 0) {
-
 
310
        puts("ERROR: file path can be provided only once");
-
 
311
        return(1);
-
 
312
      }
-
 
313
      /* */
-
 
314
      if (file_truename(fname, argv[x]) != 0) {
-
 
315
        puts("ERROR: bad file path");
-
 
316
        return(1);
-
 
317
      }
-
 
318
    } else if (strcmp(argv[x], "/?") == 0) { /* is it /? */
289
    about();
319
      about();
290
    return(1);
320
      return(1);
-
 
321
    }
291
  }
322
  }
292
 
323
 
293
  if (file_truename(fname, argv[1]) != 0) {
324
  /* if no file path provided, look into %DOSDIR%\CFG\COUNTRY.SYS */
294
    puts("ERROR: bad file path");
325
  if (fname[0] == 0) default_country_path(fname);
295
    return(1);
-
 
296
  }
-
 
297
 
326
 
298
  x = country_read(&cntdata, fname);
327
  x = country_read(&cntdata, fname);
299
  if (x != 0) {
328
  if (x != 0) {
300
    printf("ERROR: failed to read the preference file [%d]\n", x);
329
    printf("ERROR: failed to read the preference file [%d]\n", x);
301
    return(2);
330
    return(2);
302
  }
331
  }
303
 
332
 
304
  changedflag = argc - 2;
333
  changedflag = 0;
305
 
334
 
306
  /* process command line arguments */
335
  /* process command line arguments */
307
  while (--argc > 1) {
336
  for (x = 1; x < argc; x++) {
-
 
337
    if (argv[x][0] != '/') continue; /* skip country.sys filename (processed earlier) */
-
 
338
    changedflag++;
308
    if (processarg(argv[argc], &cntdata) != 0) {
339
    if (processarg(argv[x], &cntdata) != 0) {
309
      about();
340
      puts("ERROR: invalid parameter syntax");
310
      return(3);
341
      return(3);
311
    }
342
    }
312
  }
343
  }
313
 
344
 
314
  printf("Country intl code.....: %03d\n", cntdata.CTYINFO.id);
345
  printf("Country intl code.....: %03d\n", cntdata.CTYINFO.id);
315
  printf("Codepage..............: %d\n", cntdata.CTYINFO.codepage);
346
  printf("Codepage..............: %d\n", cntdata.CTYINFO.codepage);
316
  printf("Decimal separator.....: %c\n", cntdata.CTYINFO.decimal[0]);
347
  printf("Decimal separator.....: %c\n", cntdata.CTYINFO.decimal[0]);
317
  printf("Thousands separator...: %c\n", cntdata.CTYINFO.thousands[0]);
348
  printf("Thousands separator...: %c\n", cntdata.CTYINFO.thousands[0]);
318
  printf("Date format...........: %s\n", datestring(&cntdata));
349
  printf("Date format...........: %s\n", datestring(&cntdata));
319
  printf("Time format...........: %s\n", timestring(&cntdata));
350
  printf("Time format...........: %s\n", timestring(&cntdata));
320
  printf("Yes/No letters........: %c/%c\n", cntdata.YESNO.yes[0], cntdata.YESNO.no[0]);
351
  printf("Yes/No letters........: %c/%c\n", cntdata.YESNO.yes[0], cntdata.YESNO.no[0]);
321
  printf("Currency example......: %s\n", currencystring(&cntdata));
352
  printf("Currency example......: %s\n", currencystring(&cntdata));
322
 
353
 
323
  printf("\n"
354
  printf("\n"
324
         "Please make sure your CONFIG.SYS contains a COUNTRY directive that points to\n"
355
         "Make sure that your CONFIG.SYS contains this directive:\n"
325
         "your custom preferences file:\n"
-
 
326
         "COUNTRY=%03d,%03d,%s\n\n", cntdata.CTYINFO.id, cntdata.CTYINFO.codepage, fname);
356
         "COUNTRY=%03d,%03d,%s\n\n", cntdata.CTYINFO.id, cntdata.CTYINFO.codepage, fname);
327
 
357
 
328
  /* if anything changed, write the new file */
358
  /* if anything changed, write the new file */
329
  if (changedflag != 0) country_write(fname, &cntdata);
359
  if (changedflag != 0) country_write(fname, &cntdata);
330
 
360
 
331
  return(0);
361
  return(0);
332
}
362
}
333
 
363