Subversion Repositories SvarDOS

Rev

Rev 1293 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1293 Rev 1295
Line 1... Line 1...
1
/*
1
/*
2
 * Copyright (C) 2021-2023 Mateusz Viste
2
 * Copyright (C) 2021-2023 Mateusz Viste
3
 *
3
 *
-
 
4
 * Dictionary-based lookups contributed by Bernd Boeckmann, 2023
-
 
5
 *
4
 * usage: tlumacz en fr pl etc
6
 * usage: tlumacz en fr pl etc
5
 *
7
 *
6
 * computes an out.lng file that contains all language ressources.
8
 * computes an out.lng file that contains all language resources.
7
 *
9
 *
8
 */
10
 */
9
 
11
 
10
 
12
 
11
#include <stdio.h>
13
#include <stdio.h>
Line 98... Line 100...
98
  return(i);
100
  return(i);
99
}
101
}
100
 
102
 
101
#pragma pack(1)
103
#pragma pack(1)
102
typedef struct dict_entry {
104
typedef struct dict_entry {
103
    unsigned short id;
105
  unsigned short id;
104
    unsigned short offset;
106
  unsigned short offset;
105
} dict_entry_t;
107
} dict_entry_t;
106
#pragma pack()
108
#pragma pack()
107
 
109
 
108
typedef struct svl_lang {
110
typedef struct svl_lang {
109
  char id[2];
111
  char id[2];
Line 117... Line 119...
117
  size_t strings_cap;
119
  size_t strings_cap;
118
 
120
 
119
} svl_lang_t;
121
} svl_lang_t;
120
 
122
 
121
 
123
 
122
static svl_lang_t * svl_lang_new(char langid[2], size_t dict_cap, size_t strings_cap)
124
static svl_lang_t *svl_lang_new(const char langid[2], size_t dict_cap, size_t strings_cap) {
123
{
-
 
124
  svl_lang_t *l;
125
  svl_lang_t *l;
125
 
126
 
126
  l = malloc(sizeof(svl_lang_t));
127
  l = malloc(sizeof(svl_lang_t));
127
  if (!l) return NULL;
128
  if (!l) return(NULL);
128
 
129
 
129
  l->id[0] = (char)toupper(langid[0]);
130
  l->id[0] = (char)toupper(langid[0]);
130
  l->id[1] = (char)toupper(langid[1]);
131
  l->id[1] = (char)toupper(langid[1]);
131
 
132
 
132
  l->dict = malloc(dict_cap * sizeof(dict_entry_t));
133
  l->dict = malloc(dict_cap * sizeof(dict_entry_t));
133
  if (!l->dict) {
134
  if (!l->dict) return(NULL);
134
    return NULL;
-
 
135
  }
135
 
136
  l->dict_cap = dict_cap;
136
  l->dict_cap = dict_cap;
137
 
137
 
138
  l->num_strings = 0;
138
  l->num_strings = 0;
139
  l->strings = l->strings_end = malloc(strings_cap);
139
  l->strings = l->strings_end = malloc(strings_cap);
140
  if (!l->strings) {
140
  if (!l->strings) {
141
    free(l->dict);
141
    free(l->dict);
142
    return NULL;
142
    return(NULL);
143
  }
143
  }
144
  l->strings_cap = strings_cap;
144
  l->strings_cap = strings_cap;
-
 
145
 
145
  return l;
146
  return(l);
146
}
147
}
147
 
148
 
148
 
149
 
149
/* compacts the dict and string buffer */
150
/* compacts the dict and string buffer */
150
static void svl_compact_lang(svl_lang_t *l)
151
static void svl_compact_lang(svl_lang_t *l) {
151
{
-
 
152
  size_t bytes;
152
  size_t bytes;
153
  bytes = l->strings_end - l->strings;
153
  bytes = l->strings_end - l->strings;
154
  if (bytes < l->strings_cap) {
154
  if (bytes < l->strings_cap) {
155
    l->strings = l->strings_end = realloc(l->strings, bytes);
155
    l->strings = l->strings_end = realloc(l->strings, bytes);
156
    l->strings_end += bytes;
156
    l->strings_end += bytes;
Line 159... Line 159...
159
  l->dict_cap = l->num_strings;
159
  l->dict_cap = l->num_strings;
160
  l->dict = realloc(l->dict, l->dict_cap * sizeof(dict_entry_t));
160
  l->dict = realloc(l->dict, l->dict_cap * sizeof(dict_entry_t));
161
}
161
}
162
 
162
 
163
 
163
 
164
static void svl_lang_free(svl_lang_t *l)
164
static void svl_lang_free(svl_lang_t *l) {
165
{
-
 
166
  l->num_strings = 0;
165
  l->num_strings = 0;
167
  if (l->dict) {
166
  if (l->dict) {
168
    free(l->dict);
167
    free(l->dict);
169
    l->dict = NULL;
168
    l->dict = NULL;
170
  }
169
  }
Line 175... Line 174...
175
  l->dict_cap = 0;
174
  l->dict_cap = 0;
176
  l->strings_cap = 0;
175
  l->strings_cap = 0;
177
}
176
}
178
 
177
 
179
 
178
 
180
static size_t svl_strings_bytes(svl_lang_t *l)
179
static size_t svl_strings_bytes(const svl_lang_t *l) {
181
{
-
 
182
  return l->strings_end - l->strings;
180
  return(l->strings_end - l->strings);
183
}
181
}
184
 
182
 
185
 
183
 
186
static size_t svl_dict_bytes(svl_lang_t *l)
184
static size_t svl_dict_bytes(const svl_lang_t *l) {
187
{
-
 
188
  return l->num_strings * sizeof(dict_entry_t);
185
  return(l->num_strings * sizeof(dict_entry_t));
189
}
186
}
190
 
187
 
191
 
188
 
192
static int svl_add_str(svl_lang_t *l, unsigned short id, const char *s)
189
static int svl_add_str(svl_lang_t *l, unsigned short id, const char *s) {
193
{
-
 
194
  size_t len = strlen(s) + 1;
190
  size_t len = strlen(s) + 1;
195
  size_t cursor;
191
  size_t cursor;
196
 
192
 
197
  if (l->strings_cap < svl_strings_bytes(l) + len ||
-
 
198
      l->dict_cap < (l->num_strings + 1) * sizeof(dict_entry_t)) {
193
  if ((l->strings_cap < svl_strings_bytes(l) + len) || (l->dict_cap < (l->num_strings + 1) * sizeof(dict_entry_t))) {
199
    return 0;
194
    return(0);
200
  }
195
  }
201
 
196
 
202
  /* find dictionary insert position, search backwards in assumption
197
  /* find dictionary insert position, search backwards in assumption
203
     that in translation files, strings are generally ordered ascending */
198
     that in translation files, strings are generally ordered ascending */
204
  for (cursor = l->num_strings; cursor > 0 && l->dict[cursor-1].id > id; cursor--);
199
  for (cursor = l->num_strings; cursor > 0 && l->dict[cursor-1].id > id; cursor--);
Line 209... Line 204...
209
 
204
 
210
  memcpy(l->strings_end, s, len);
205
  memcpy(l->strings_end, s, len);
211
  l->strings_end += len;
206
  l->strings_end += len;
212
  l->num_strings++;
207
  l->num_strings++;
213
 
208
 
214
  return 1;
209
  return(1);
215
}
210
}
216
 
211
 
217
 
212
 
218
static int svl_find(svl_lang_t *l, unsigned short id)
213
static int svl_find(const svl_lang_t *l, unsigned short id) {
219
{
-
 
220
   size_t left = 0, right = l->num_strings - 1, x;
214
  size_t left = 0, right = l->num_strings - 1, x;
221
   unsigned short v;
215
  unsigned short v;
222
 
216
 
223
   if (l->num_strings == 0) return 0;
217
  if (l->num_strings == 0) return(0);
224
 
218
 
225
   while (left <= right ) {
219
  while (left <= right ) {
226
      x = left + ( (right - left ) >> 2 );
220
    x = left + ( (right - left ) >> 2 );
227
      v = l->dict[x].id;
221
    v = l->dict[x].id;
228
      if ( id == v ) return 1;
222
    if ( id == v ) {
-
 
223
      return(1);
229
      else if ( id > v ) left = x + 1;
224
    } else if (id > v) {
-
 
225
      left = x + 1;
-
 
226
    } else {
230
      else right = x - 1;
227
      right = x - 1;
231
   }
228
    }
-
 
229
  }
232
   return 0;
230
  return(0);
233
}
231
}
234
 
232
 
-
 
233
 
235
/* opens a CATS-style file and compiles it into a ressources lang block
234
/* opens a CATS-style file and compiles it into a ressources lang block
236
 * returns 0 on error, or the size of the generated data block otherwise */
235
 * returns 0 on error, or the size of the generated data block otherwise */
237
static unsigned short svl_lang_from_cats_file(svl_lang_t *l, svl_lang_t *refl) {
236
static unsigned short svl_lang_from_cats_file(svl_lang_t *l, svl_lang_t *refl) {
238
  unsigned short linelen;
237
  unsigned short linelen;
239
  FILE *fd;
238
  FILE *fd;
Line 281... Line 280...
281
      printf("WARNING: %s[#%u] string id %u.%u is flagged as 'dirty'\r\n", fname, linecount, id >> 8, id & 0xff);
280
      printf("WARNING: %s[#%u] string id %u.%u is flagged as 'dirty'\r\n", fname, linecount, id >> 8, id & 0xff);
282
    }
281
    }
283
 
282
 
284
    /* add the string contained in current line, if conditions are met */
283
    /* add the string contained in current line, if conditions are met */
285
    if (!svl_find(l, id)) {
284
    if (!svl_find(l, id)) {
286
      if (refl == NULL || svl_find(refl, id)) {
285
      if ((refl == NULL) || (svl_find(refl, id))) {
287
        if (!svl_add_str(l, id, ptr)) {
286
        if (!svl_add_str(l, id, ptr)) {
288
          printf("ERROR: %s[#%u] output size limit exceeded\r\n", fname, linecount);
287
          printf("ERROR: %s[#%u] output size limit exceeded\r\n", fname, linecount);
289
          fclose(fd);
288
          fclose(fd);
290
          return 0;
289
          return(0);
291
        }
290
        }
292
        if (id >= maxid) {
291
        if (id >= maxid) {
293
          maxid = id;
292
          maxid = id;
294
          maxid_line = linecount;
293
          maxid_line = linecount;
295
        }
-
 
296
        else {
294
        } else {
297
          printf("WARNING:%s[#%u] file unsorted - line %u has higher id %u.%u\r\n", fname, linecount, maxid_line, maxid >> 8, maxid & 0xff);
295
          printf("WARNING:%s[#%u] file unsorted - line %u has higher id %u.%u\r\n", fname, linecount, maxid_line, maxid >> 8, maxid & 0xff);
298
        }
296
        }
299
      }
-
 
300
      else {
297
      } else {
301
        printf("WARNING: %s[#%u] has an invalid id (%u.%u not present in ref lang)\r\n", fname, linecount, id >> 8, id & 0xff);
298
        printf("WARNING: %s[#%u] has an invalid id (%u.%u not present in ref lang)\r\n", fname, linecount, id >> 8, id & 0xff);
302
      }
299
      }
303
    }
-
 
304
    else {
300
    } else {
305
      printf("WARNING: %s[#%u] has a duplicated id (%u.%u)\r\n", fname, linecount, id >> 8, id & 0xff);
301
      printf("WARNING: %s[#%u] has a duplicated id (%u.%u)\r\n", fname, linecount, id >> 8, id & 0xff);
306
    }
302
    }
307
  }
303
  }
308
 
304
 
309
  fclose(fd);
305
  fclose(fd);
Line 314... Line 310...
314
      id = refl->dict[i].id;
310
      id = refl->dict[i].id;
315
      if (!svl_find(l, id)) {
311
      if (!svl_find(l, id)) {
316
        printf("WARNING: %s is missing string %u.%u (pulled from ref lang)\r\n", fname, id >> 8, id & 0xff);
312
        printf("WARNING: %s is missing string %u.%u (pulled from ref lang)\r\n", fname, id >> 8, id & 0xff);
317
        if (!svl_add_str(l, id, refl->strings + refl->dict[i].offset)) {
313
        if (!svl_add_str(l, id, refl->strings + refl->dict[i].offset)) {
318
          printf("ERROR: %s[#%u] output size limit exceeded\r\n", fname, linecount);
314
          printf("ERROR: %s[#%u] output size limit exceeded\r\n", fname, linecount);
319
          return 0;
315
          return(0);
320
        }
316
        }
321
      }
317
      }
322
    }
318
    }
323
  }
319
  }
324
 
320
 
325
  return(svl_strings_bytes(l));
321
  return(svl_strings_bytes(l));
326
}
322
}
327
 
323
 
328
 
324
 
329
static int svl_write_header(unsigned short num_strings, FILE *fd)
325
static int svl_write_header(unsigned short num_strings, FILE *fd) {
330
{
-
 
331
  return (fwrite("SvL\x1a", 1, 4, fd) == 4) &&
-
 
332
          (fwrite(&num_strings, 1, 2, fd) == 2);
326
  return((fwrite("SvL\x1a", 1, 4, fd) == 4) && (fwrite(&num_strings, 1, 2, fd) == 2));
333
}
327
}
334
 
328
 
335
 
329
 
336
static int svl_write_lang(svl_lang_t *l, FILE *fd)
330
static int svl_write_lang(const svl_lang_t *l, FILE *fd) {
337
{
-
 
338
  unsigned short strings_bytes = svl_strings_bytes(l);
331
  unsigned short strings_bytes = svl_strings_bytes(l);
339
 
332
 
340
  return (fwrite(&l->id, 1, 2, fd) == 2) &&
333
  return((fwrite(&l->id, 1, 2, fd) == 2) &&
341
         (fwrite(&strings_bytes, 1, 2, fd) == 2) &&
334
         (fwrite(&strings_bytes, 1, 2, fd) == 2) &&
342
         (fwrite(l->dict, 1, svl_dict_bytes(l), fd) == svl_dict_bytes(l)) &&
335
         (fwrite(l->dict, 1, svl_dict_bytes(l), fd) == svl_dict_bytes(l)) &&
343
         (fwrite(l->strings, 1, svl_strings_bytes(l), fd) == svl_strings_bytes(l));
336
         (fwrite(l->strings, 1, svl_strings_bytes(l), fd) == svl_strings_bytes(l)));
344
}
337
}
345
 
338
 
346
 
339
 
347
static int svl_write_c_source(svl_lang_t *l, const char *fn, unsigned short biggest_langsz)
340
static int svl_write_c_source(const svl_lang_t *l, const char *fn, unsigned short biggest_langsz) {
348
{
-
 
349
  FILE *fd;
341
  FILE *fd;
350
  int i;
342
  int i;
351
  unsigned short strings_bytes = svl_strings_bytes(l);
343
  unsigned short strings_bytes = svl_strings_bytes(l);
352
  unsigned short nextnlat = 0;
344
  unsigned short nextnlat = 0;
-
 
345
  unsigned short allocsz;
353
 
346
 
354
  fd = fopen(fn, "wb");
347
  fd = fopen(fn, "wb");
355
  if (fd == NULL) {
348
  if (fd == NULL) {
356
    puts("ERROR: FAILED TO OPEN OR CREATE DEFLANG.C");
349
    puts("ERROR: FAILED TO OPEN OR CREATE DEFLANG.C");
357
    return 0;
350
    return(0);
358
  } else {
-
 
359
    unsigned short allocsz = biggest_langsz + (biggest_langsz / 20);
-
 
360
    printf("biggest lang block is %u bytes -> allocating a %u bytes buffer (5%% safety margin)\n", biggest_langsz,
-
 
361
           allocsz);
-
 
362
    fprintf(fd, "/* THIS FILE HAS BEEN GENERATED BY TLUMACZ (PART OF THE SVARLANG LIBRARY) */\r\n");
-
 
363
    fprintf(fd, "const unsigned short svarlang_memsz = %uu;\r\n", allocsz);
-
 
364
    fprintf(fd, "const unsigned short svarlang_string_count = %uu;\r\n\r\n", l->num_strings);
-
 
365
    fprintf(fd, "char svarlang_mem[%u] = {\r\n", allocsz);
-
 
366
    for (i = 0; i < strings_bytes; i++) {
-
 
367
      if (!fprintf(fd, "0x%02x", l->strings[i])) {
-
 
368
        fclose(fd);
-
 
369
        return 0;
-
 
370
      }
-
 
371
 
-
 
372
      if (i + 1 < strings_bytes) fprintf(fd, ",");
-
 
373
      nextnlat++;
-
 
374
      if (l->strings[i] == '\0' || nextnlat == 16) {
-
 
375
        fprintf(fd, "\r\n");
-
 
376
        nextnlat = 0;
-
 
377
      }
-
 
378
    }
351
  }
379
    fprintf(fd, "};\r\n\r\n");
-
 
380
 
352
 
-
 
353
  allocsz = biggest_langsz + (biggest_langsz / 20);
-
 
354
  printf("biggest lang block is %u bytes -> allocating a %u bytes buffer (5%% safety margin)\n", biggest_langsz, allocsz);
-
 
355
  fprintf(fd, "/* THIS FILE HAS BEEN GENERATED BY TLUMACZ (PART OF THE SVARLANG LIBRARY) */\r\n");
-
 
356
  fprintf(fd, "const unsigned short svarlang_memsz = %uu;\r\n", allocsz);
381
    fprintf(fd, "unsigned short svarlang_dict[%u] = {\r\n", l->num_strings * 2);
357
  fprintf(fd, "const unsigned short svarlang_string_count = %uu;\r\n\r\n", l->num_strings);
-
 
358
  fprintf(fd, "char svarlang_mem[%u] = {\r\n", allocsz);
-
 
359
 
382
    for (i = 0; i < l->num_strings; i++) {
360
  for (i = 0; i < strings_bytes; i++) {
383
      if (!fprintf(fd, "0x%04x,0x%04x", l->dict[i].id, l->dict[i].offset)) {
361
    if (!fprintf(fd, "0x%02x", l->strings[i])) {
384
        fclose(fd);
362
      fclose(fd);
385
        return 0;
363
      return(0);
386
      }
364
    }
-
 
365
 
387
      if (i + 1 < l->num_strings) fprintf(fd, ",");
366
    if (i + 1 < strings_bytes) fprintf(fd, ",");
-
 
367
    nextnlat++;
-
 
368
    if (l->strings[i] == '\0' || nextnlat == 16) {
388
      fprintf(fd, "\r\n");
369
      fprintf(fd, "\r\n");
-
 
370
      nextnlat = 0;
389
    }
371
    }
-
 
372
  }
390
    fprintf(fd, "};\r\n");
373
  fprintf(fd, "};\r\n\r\n");
391
 
374
 
-
 
375
  fprintf(fd, "unsigned short svarlang_dict[%u] = {\r\n", l->num_strings * 2);
-
 
376
  for (i = 0; i < l->num_strings; i++) {
-
 
377
    if (!fprintf(fd, "0x%04x,0x%04x", l->dict[i].id, l->dict[i].offset)) {
392
    fclose(fd);
378
      fclose(fd);
-
 
379
      return(0);
-
 
380
    }
-
 
381
    if (i + 1 < l->num_strings) fprintf(fd, ",");
-
 
382
    fprintf(fd, "\r\n");
393
  }
383
  }
-
 
384
  fprintf(fd, "};\r\n");
394
 
385
 
-
 
386
  fclose(fd);
-
 
387
 
395
  return 1;
388
  return(1);
396
}
389
}
397
 
390
 
398
 
391
 
399
int main(int argc, char **argv) {
392
int main(int argc, char **argv) {
400
  FILE *fd;
393
  FILE *fd;
401
  int ecode = 0;
394
  int ecode = 0;
402
  svl_lang_t *lang, *reflang = NULL;
-
 
403
 
-
 
404
  int i;
395
  int i;
405
  unsigned short biggest_langsz = 0;
396
  unsigned short biggest_langsz = 0;
-
 
397
  svl_lang_t *lang, *reflang = NULL;
406
 
398
 
407
  if (argc < 2) {
399
  if (argc < 2) {
408
    puts("tlumacz ver " SVARLANGVER " - this tool is part of the SvarLANG project.");
400
    puts("tlumacz ver " SVARLANGVER " - this tool is part of the SvarLANG project.");
409
    puts("converts a set of CATS-style translations in files EN.TXT, PL.TXT, etc");
401
    puts("converts a set of CATS-style translations in files EN.TXT, PL.TXT, etc");
410
    puts("into a single resource file (OUT.LNG).");
402
    puts("into a single resource file (OUT.LNG).");
Line 467... Line 459...
467
    }
459
    }
468
 
460
 
469
    /* remember reference data for other languages */
461
    /* remember reference data for other languages */
470
    if (i == 1) {
462
    if (i == 1) {
471
      reflang = lang;
463
      reflang = lang;
472
    }
-
 
473
    else {
464
    } else {
474
      svl_lang_free(lang);
465
      svl_lang_free(lang);
475
      lang = NULL;
466
      lang = NULL;
476
    }
467
    }
477
  }
468
  }
478
 
469