Subversion Repositories SvarDOS

Rev

Rev 586 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
585 mateuszvis 1
/*
2
 * functions that read/write from/to the localcfg country.sys-like file.
3
 * Copyright (C) Mateusz Viste 2015
4
 */
5
 
6
#include <stdio.h>
7
#include <string.h>
8
 
9
#include "country.h"
10
 
11
 
12
#define READSHORT(x) (short)(x[0] | (x[1] << 8))
13
 
14
/* fills a country struct with default values */
15
static void country_default(struct country *countrydata) {
16
  /* first clears the memory */
17
  memset(countrydata, 0, sizeof(struct country));
18
  /* fill in fields - only non-zero values */
19
  countrydata->id = 1;
20
  countrydata->codepage = 437;
21
  /* countrydata->datefmt = COUNTRY_DATE_MDY;
22
  countrydata->timefmt = COUNTRY_TIME12; */
23
  countrydata->currency[0] = '$';
24
  countrydata->decimal = '.';
25
  countrydata->thousands = ',';
26
  countrydata->datesep = '/';
27
  countrydata->timesep = ':';
28
  countrydata->currencyprec = 2;
29
  /* countrydata->currencydecsym = 0; */
30
  /* countrydata->currencyspace = 0; */
31
  /* countrydata->currencypos = 0; */
32
  countrydata->yes = 'Y';
33
  countrydata->no = 'N';
34
}
35
 
36
 
37
/* Loads data from a country.sys file into a country struct.
38
 * Returns 0 on success, non-zero otherwise. */
39
int country_read(struct country *countrydata, char *fname) {
40
  unsigned char filebuff[1024];
41
  unsigned char buff[64];
42
  short firstentryoffs;
43
  unsigned char *subfunctions[16] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
44
                                     NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
45
  short filesize;
46
  short subfunctionscount;
47
  unsigned char *functiondata;
48
  int x;
49
  FILE *fd;
50
 
51
  /* preload the country struct with default values */
52
  country_default(countrydata);
53
 
54
  /* load the file into buff, if file exists */
55
  fd = fopen(fname, "rb");
56
  if (fd == NULL) return(0); /* "file doesn't exist" is not an error condition */
57
  filesize = fread(filebuff, 1, sizeof(filebuff), fd);
58
  fclose(fd);
59
 
60
  /* check that it's a country file - should start with 0xFF COUNTRY 0x00 */
61
  if (filebuff[0] != 0xFF) return(-2);
62
  if (strcmp((char *)filebuff + 1, "COUNTRY") != 0) return(-2);
63
 
64
  /* check that it's one of my country.sys files - should contain a trailer */
65
  memcpy(buff, filebuff + filesize - 8, 8);
66
  buff[8] = 0;
67
  if (strcmp((char *)buff, "LOCALCFG") != 0) return(-3);
68
 
69
  /* read the offset of the entries index - must be at least 23 */
70
  functiondata = filebuff + 19;
71
  firstentryoffs = READSHORT(functiondata);
72
  if ((firstentryoffs < 23) || (firstentryoffs >= filesize)) return(-4);
73
  functiondata = filebuff + firstentryoffs;
74
 
75
  /* how many entries do we have? I expect exactly one. */
76
  if (READSHORT(functiondata) != 1) return(-5);
77
  /* skip to the first country entry */
78
  functiondata += 2;
79
 
80
  /* skip directly to the subfunctions of the first country */
81
  /* ddwords: size, country, codepage, reserved, reserved, offset */
82
  /* printf("Size = %d\n", READSHORT(functiondata)); */
83
  functiondata += 2; /* skip size */
84
  /* printf("Country = %d\n", READSHORT(functiondata[0]); */
85
  functiondata += 2; /* skip country */
86
  /* printf("Codepage = %d\n", READSHORT(functiondata)); */
87
  functiondata += 2; /* skip codepage */
88
  functiondata += 4; /* skip reserved fields */
89
  firstentryoffs = READSHORT(functiondata); /* read offset of the subfunctions index */
90
  functiondata = filebuff + firstentryoffs;
91
 
92
  /* read all subfunctions, but no more than 15 */
93
  subfunctionscount = READSHORT(functiondata);
94
  /* printf("Found %d subfunctions\n", subfunctionscount); */
95
  functiondata += 2;
96
  for (x = 0; (x < 15) && (x < subfunctionscount); x++) {
97
    short size = READSHORT(functiondata);
98
    functiondata += 2;
99
    functiondata += 2; /* skip ID of the subfunction */
100
    subfunctions[x] = filebuff + READSHORT(functiondata);
101
    /* printf("subfunction %d at 0x%p\n", x, subfunctions[x]); */
102
    functiondata += size - 2;
103
  }
104
 
105
  /* load every subfunction, and feed the country struct with data */
106
  for (x = 0; subfunctions[x] != NULL; x++) {
107
    short functionsize;
108
    /* the function name should always start with 0xFF */
109
    if (subfunctions[x][0] != 0xFF) return(-6);
110
    /* load the subfunction's name, and act accordingly */
111
    memcpy(buff, subfunctions[x] + 1, 7);
112
    buff[7] = 0;
113
    functiondata = subfunctions[x] + 8;
114
    functionsize = READSHORT(functiondata);
115
    functiondata = subfunctions[x] + 10;
116
    /* */
117
    if (strcmp((char *)buff, "YESNO  ") == 0) {
118
      if (functionsize != 4) continue;
119
      countrydata->yes = functiondata[0];
120
      countrydata->no = functiondata[2];
121
    } else if (strcmp((char *)buff, "CTYINFO") == 0) {
122
      if (functionsize != 22) continue;
123
      /* ID */
124
      countrydata->id = READSHORT(functiondata);
125
      functiondata += 2;
126
      /* codepage */
127
      countrydata->codepage = READSHORT(functiondata);
128
      functiondata += 2;
129
      /* date format */
130
      countrydata->datefmt = READSHORT(functiondata);
131
      functiondata += 2;
132
      /* currency symbol */
133
      countrydata->currency[0] = functiondata[0];
134
      countrydata->currency[1] = functiondata[1];
135
      countrydata->currency[2] = functiondata[2];
136
      countrydata->currency[3] = functiondata[3];
137
      countrydata->currency[4] = 0;
138
      functiondata += 5;
139
      /* thousands separator, decimal sep, date sep, time sep */
140
      countrydata->thousands = READSHORT(functiondata);
141
      functiondata += 2;
142
      countrydata->decimal = READSHORT(functiondata);
143
      functiondata += 2;
144
      countrydata->datesep = READSHORT(functiondata);
145
      functiondata += 2;
146
      countrydata->timesep = READSHORT(functiondata);
147
      functiondata += 2;
148
      /* currency format */
149
      countrydata->currencypos = *functiondata & 1;
150
      countrydata->currencyspace = (*functiondata >> 1) & 1;
151
      countrydata->currencydecsym = (*functiondata >> 2) & 1;
152
      functiondata += 1;
153
      /* currency precision */
154
      countrydata->currencyprec = *functiondata;
155
      functiondata += 1;
156
      /* time format */
157
      countrydata->timefmt = *functiondata;
158
      functiondata += 1;
159
    }
160
  }
161
 
162
  return(0);
163
}
164
 
165
 
166
#define MSB(x) (((x) >> 8) & 0xff)
167
#define LSB(x) ((x) & 0xff)
168
 
169
#define DWORDB1(x) ((x) & 0xff)
170
#define DWORDB2(x) (((x) >> 8) & 0xff)
171
#define DWORDB3(x) (((x) >> 16) & 0xff)
172
#define DWORDB4(x) (((x) >> 24) & 0xff)
173
 
174
 
175
/* Computes a new country.sys file based on data from a country struct.
176
 * Returns 0 on success, non-zero otherwise. */
177
int country_write(char *fname, struct country *c) {
178
  unsigned char filebuff[1024];
179
  short filesize = 0;
180
  FILE *fd;
181
  int x;
182
  short subfunction_id[7] = {1,2,4,5,6,7,35};
183
  short subfunction_ptr[7];
184
 
185
  const unsigned char ucase_437[128] = {128, 154,  69,  65, 142,  65, 143, 128,
186
                                         69,  69,  69,  73,  73,  73, 142, 143,
187
                                        144, 146, 146,  79, 153,  79,  85,  85,
188
                                         89, 153, 154, 155, 156, 157, 158, 159,
189
                                         65,  73,  79,  85, 165, 165, 166, 167,
190
                                        168, 169, 170, 171, 172, 173, 174, 175,
191
                                        176, 177, 178, 179, 180, 181, 182, 183,
192
                                        184, 185, 186, 187, 188, 189, 190, 191,
193
                                        192, 193, 194, 195, 196, 197, 198, 199,
194
                                        200, 201, 202, 203, 204, 205, 206, 207,
195
                                        208, 209, 210, 211, 212, 213, 214, 215,
196
                                        216, 217, 218, 219, 220, 221, 222, 223,
197
                                        224, 225, 226, 227, 228, 229, 230, 231,
198
                                        232, 233, 234, 235, 236, 237, 238, 239,
199
                                        240, 241, 242, 243, 244, 245, 246, 247,
200
                                        248, 249, 250, 251, 252, 253, 254, 255};
201
 
202
  const unsigned char collate_437[256] = {  0,   1,   2,   3,   4,   5,   6,   7,
203
                                            8,   9,  10,  11,  12,  13,  14,  15,
204
                                           16,  17,  18,  19,  20,  21,  22,  23,
205
                                           24,  25,  26,  27,  28,  29,  30,  31,
206
                                           32,  33,  34,  35,  36,  37,  38,  39,
207
                                           40,  41,  42,  43,  44,  45,  46,  47,
208
                                           48,  49,  50,  51,  52,  53,  54,  55,
209
                                           56,  57,  58,  59,  60,  61,  62,  63,
210
                                           64,  65,  66,  67,  68,  69,  70,  71,
211
                                           72,  73,  74,  75,  76,  77,  78,  79,
212
                                           80,  81,  82,  83,  84,  85,  86,  87,
213
                                           88,  89,  90,  91,  92,  93,  94,  95,
214
                                           96,  65,  66,  67,  68,  69,  70,  71,
215
                                           72,  73,  74,  75,  76,  77,  78,  79,
216
                                           80,  81,  82,  83,  84,  85,  86,  87,
217
                                           88,  89,  90, 123, 124, 125, 126, 127,
218
                                           67,  85,  69,  65,  65,  65,  65,  67,
219
                                           69,  69,  69,  73,  73,  73,  65,  65,
220
                                           69,  65,  65,  79,  79,  79,  85,  85,
221
                                           89,  79,  85,  36,  36,  36,  36,  36,
222
                                           65,  73,  79,  85,  78,  78, 166, 167,
223
                                           63, 169, 170, 171, 172,  33,  34,  34,
224
                                          176, 177, 178, 179, 180, 181, 182, 183,
225
                                          184, 185, 186, 187, 188, 189, 190, 191,
226
                                          192, 193, 194, 195, 196, 197, 198, 199,
227
                                          200, 201, 202, 203, 204, 205, 206, 207,
228
                                          208, 209, 210, 211, 212, 213, 214, 215,
229
                                          216, 217, 218, 219, 220, 221, 222, 223,
230
                                          224,  83, 226, 227, 228, 229, 230, 231,
231
                                          232, 233, 234, 235, 236, 237, 238, 239,
232
                                          240, 241, 242, 243, 244, 245, 246, 247,
233
                                          248, 249, 250, 251, 252, 253, 254, 255};
234
 
235
  /* compute the country.sys structures */
236
  memcpy(filebuff, "\377COUNTRY\0\0\0\0\0\0\0\0\1\0\1", 19); /* header */
237
  filesize = 19;
238
  /* first entry offset (always current offset+4) */
239
  filebuff[filesize + 0] = DWORDB1(filesize+4);
240
  filebuff[filesize + 1] = DWORDB2(filesize+4);
241
  filebuff[filesize + 2] = DWORDB3(filesize+4);
242
  filebuff[filesize + 3] = DWORDB4(filesize+4);
243
  filesize += 4;
244
  /* number of entries */
245
  filebuff[filesize++] = 1;
246
  filebuff[filesize++] = 0;
247
  /* first (and only) entry / size, country, codepage, reserved(2), offset */
248
  filebuff[filesize++] = 12; /* size LSB */
249
  filebuff[filesize++] = 0;  /* size MSB */
250
  filebuff[filesize++] = LSB(c->id);   /* country LSB */
251
  filebuff[filesize++] = MSB(c->id);   /* country MSB */
252
  filebuff[filesize++] = LSB(c->codepage); /* codepage LSB */
253
  filebuff[filesize++] = MSB(c->codepage); /* codepage MSB */
254
  filebuff[filesize++] = 0; /* reserved */
255
  filebuff[filesize++] = 0; /* reserved */
256
  filebuff[filesize++] = 0; /* reserved */
257
  filebuff[filesize++] = 0; /* reserved */
258
  filebuff[filesize + 0] = DWORDB1(filesize+4); /* offset for subfunctions list (ptr + 4) */
259
  filebuff[filesize + 1] = DWORDB2(filesize+4); /* offset for subfunctions list (ptr + 4) */
260
  filebuff[filesize + 2] = DWORDB3(filesize+4); /* offset for subfunctions list (ptr + 4) */
261
  filebuff[filesize + 3] = DWORDB4(filesize+4); /* offset for subfunctions list (ptr + 4) */
262
  filesize += 4;
263
  /* index of subfunctions */
264
  filebuff[filesize++] = 7; /* there are 7 subfunctions */
265
  filebuff[filesize++] = 0;
266
  for (x = 0; x < 7; x++) { /* dump each subfunction (size, id, offset) */
267
    /* size is always 6 */
268
    filebuff[filesize++] = 6;
269
    filebuff[filesize++] = 0;
270
    /* id of the subfunction */
271
    filebuff[filesize++] = LSB(subfunction_id[x]);
272
    filebuff[filesize++] = MSB(subfunction_id[x]);
273
    /* remember the offset of the subfunction pointer for later */
274
    subfunction_ptr[x] = filesize;
275
    filesize += 4;
276
  }
277
  /* write the CTYINFO subfunction */
278
  filebuff[subfunction_ptr[0]+0] = DWORDB1(filesize); /* update the    */
279
  filebuff[subfunction_ptr[0]+1] = DWORDB2(filesize); /* subfunction   */
280
  filebuff[subfunction_ptr[0]+2] = DWORDB3(filesize); /* pointer with  */
281
  filebuff[subfunction_ptr[0]+3] = DWORDB4(filesize); /* correct value */
282
  /* subfunction header */
283
  memcpy(filebuff + filesize, "\377CTYINFO", 8);
284
  filesize += 8;
285
  /* subfunction size */
286
  filebuff[filesize++] = 22;
287
  filebuff[filesize++] = 0;
288
  /* country preferences */
289
  filebuff[filesize++] = LSB(c->id); /* ID */
290
  filebuff[filesize++] = MSB(c->id); /* ID */
291
  filebuff[filesize++] = LSB(c->codepage); /* CP */
292
  filebuff[filesize++] = MSB(c->codepage); /* CP */
293
  filebuff[filesize++] = LSB(c->datefmt); /* date format */
294
  filebuff[filesize++] = MSB(c->datefmt); /* date format */
295
  for (x = 0; x < 5; x++) {
296
    filebuff[filesize++] = c->currency[x]; /* currency */
297
  }
298
  filebuff[filesize++] = LSB(c->thousands);  /* thousands separator LSB */
299
  filebuff[filesize++] = MSB(c->thousands);  /* thousands separator MSB */
300
  filebuff[filesize++] = LSB(c->decimal);    /* decimal separator LSB */
301
  filebuff[filesize++] = MSB(c->decimal);    /* decimal separator MSB */
302
  filebuff[filesize++] = LSB(c->datesep);    /* date separator LSB */
303
  filebuff[filesize++] = MSB(c->datesep);    /* date separator MSB */
304
  filebuff[filesize++] = LSB(c->timesep);    /* time separator LSB */
305
  filebuff[filesize++] = MSB(c->timesep);    /* time separator MSB */
306
  filebuff[filesize] = c->currencydecsym; /* currency format (bit 2) */
307
  filebuff[filesize] <<= 8;
308
  filebuff[filesize] |= c->currencyspace; /* currency format (bit 1) */
309
  filebuff[filesize] <<= 8;
310
  filebuff[filesize++] |= c->currencypos; /* currency format (bit 0) */
311
  filebuff[filesize++] = c->currencyprec; /* currency precision */
312
  filebuff[filesize++] = c->timefmt;      /* time format */
313
 
314
  /* write the UCASE subfunction (used for LCASE, too) */
315
  filebuff[subfunction_ptr[1]+0] = DWORDB1(filesize); /* update the    */
316
  filebuff[subfunction_ptr[1]+1] = DWORDB2(filesize); /* subfunction   */
317
  filebuff[subfunction_ptr[1]+2] = DWORDB3(filesize); /* pointer with  */
318
  filebuff[subfunction_ptr[1]+3] = DWORDB4(filesize); /* correct value */
319
  filebuff[subfunction_ptr[2]+0] = DWORDB1(filesize); /* update the    */
320
  filebuff[subfunction_ptr[2]+1] = DWORDB2(filesize); /* subfunction   */
321
  filebuff[subfunction_ptr[2]+2] = DWORDB3(filesize); /* pointer with  */
322
  filebuff[subfunction_ptr[2]+3] = DWORDB4(filesize); /* correct value */
323
  /* subfunction header */
324
  memcpy(filebuff + filesize, "\377UCASE  ", 8);
325
  filesize += 8;
326
  /* subfunction size */
327
  filebuff[filesize++] = 128;
328
  filebuff[filesize++] = 0;
329
  /* UCASE table */
330
  for (x = 0; x < 128; x++) {
331
    filebuff[filesize++] = ucase_437[x];
332
  }
333
 
334
  /* write the FCHAR subfunction (filename terminator table) */
335
  filebuff[subfunction_ptr[3]+0] = DWORDB1(filesize); /* update the    */
336
  filebuff[subfunction_ptr[3]+1] = DWORDB2(filesize); /* subfunction   */
337
  filebuff[subfunction_ptr[3]+2] = DWORDB3(filesize); /* pointer with  */
338
  filebuff[subfunction_ptr[3]+3] = DWORDB4(filesize); /* correct value */
339
  /* subfunction header */
340
  memcpy(filebuff + filesize, "\377FCHAR  ", 8);
341
  filesize += 8;
342
  /* subfunction size */
343
  filebuff[filesize++] = 22;
344
  filebuff[filesize++] = 0;
345
  /* values here are quite obscure, dumped from country.sys */
346
  filebuff[filesize++] = 142;
347
  filebuff[filesize++] = 0;
348
  filebuff[filesize++] = 255;
349
  filebuff[filesize++] = 65;
350
  filebuff[filesize++] = 0;
351
  filebuff[filesize++] = 32;
352
  filebuff[filesize++] = 238;
353
  /* list of characters that terminates a filename */
354
  filebuff[filesize++] = 14;  /* how many of them */
355
  filebuff[filesize++] = 46;  /* . */
356
  filebuff[filesize++] = 34;  /* " */
357
  filebuff[filesize++] = 47;  /* / */
358
  filebuff[filesize++] = 92;  /* \ */
359
  filebuff[filesize++] = 91;  /* [ */
360
  filebuff[filesize++] = 93;  /* ] */
361
  filebuff[filesize++] = 58;  /* : */
362
  filebuff[filesize++] = 124; /* | */
363
  filebuff[filesize++] = 60;  /* < */
364
  filebuff[filesize++] = 62;  /* > */
365
  filebuff[filesize++] = 43;  /* + */
366
  filebuff[filesize++] = 61;  /* = */
367
  filebuff[filesize++] = 59;  /* ; */
368
  filebuff[filesize++] = 44;  /* , */
369
 
370
  /* write the COLLATE subfunction */
371
  filebuff[subfunction_ptr[4]+0] = DWORDB1(filesize); /* update the    */
372
  filebuff[subfunction_ptr[4]+1] = DWORDB2(filesize); /* subfunction   */
373
  filebuff[subfunction_ptr[4]+2] = DWORDB3(filesize); /* pointer with  */
374
  filebuff[subfunction_ptr[4]+3] = DWORDB4(filesize); /* correct value */
375
  /* subfunction header */
376
  memcpy(filebuff + filesize, "\377COLLATE", 8);
377
  filesize += 8;
378
  /* subfunction size */
379
  filebuff[filesize++] = LSB(256);
380
  filebuff[filesize++] = MSB(256);
381
  /* collation for standard CP437 */
382
  for (x = 0; x < 256; x++) {
383
    filebuff[filesize++] = collate_437[x];
384
  }
385
 
386
  /* write the DBCS subfunction */
387
  filebuff[subfunction_ptr[5]+0] = DWORDB1(filesize); /* update the    */
388
  filebuff[subfunction_ptr[5]+1] = DWORDB2(filesize); /* subfunction   */
389
  filebuff[subfunction_ptr[5]+2] = DWORDB3(filesize); /* pointer with  */
390
  filebuff[subfunction_ptr[5]+3] = DWORDB4(filesize); /* correct value */
391
  /* subfunction header */
392
  memcpy(filebuff + filesize, "\377DBCS   ", 8);
393
  filesize += 8;
394
  /* subfunction size */
395
  filebuff[filesize++] = 0;
396
  filebuff[filesize++] = 0;
397
  /* table terminator (must be there even if no lenght is zero */
398
  filebuff[filesize++] = 0;
399
  filebuff[filesize++] = 0;
400
 
401
  /* write the YESNO subfunction */
402
  filebuff[subfunction_ptr[6]+0] = DWORDB1(filesize); /* update the    */
403
  filebuff[subfunction_ptr[6]+1] = DWORDB2(filesize); /* subfunction   */
404
  filebuff[subfunction_ptr[6]+2] = DWORDB3(filesize); /* pointer with  */
405
  filebuff[subfunction_ptr[6]+3] = DWORDB4(filesize); /* correct value */
406
  memcpy(filebuff + filesize, "\377YESNO  ", 8);
407
  filesize += 8;
408
  filebuff[filesize++] = 4;  /* size (LSB) */
409
  filebuff[filesize++] = 0;  /* size (MSB) */
410
  filebuff[filesize++] = c->yes;  /* "Yes" letter */
411
  filebuff[filesize++] = 0;
412
  filebuff[filesize++] = c->no;   /* "No" letter */
413
  filebuff[filesize++] = 0;
414
 
415
  /* write the file trailer */
416
  memcpy(filebuff + filesize, "LOCALCFG", 8);
417
  filesize += 8;
418
 
419
  /* write the buffer to file */
420
  fd = fopen(fname, "wb");
421
  if (fd == NULL) return(-1);
422
  fwrite(filebuff, 1, filesize, fd);
423
  fclose(fd);
424
 
425
  return(0);
426
}