Subversion Repositories SvarDOS

Rev

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

Rev Author Line No. Line
433 mateuszvis 1
/*
2
 * Copyright (C) 2021 Mateusz Viste
3
 *
4
 * usage: tlumacz en fr pl etc
5
 *
6
 * computes a svarcom.lng file that contains all language ressources found
7
 * inside dirname.
8
 *
9
 * DAT format:
10
 *
11
 * 4-bytes signature:
12
 * "SvL\x1b"
13
 *
14
 * Then "LANG BLOCKS" follow. Each LANG BLOCK is prefixed with 4 bytes:
15
 * II LL    - II is the LANG identifier ("EN", "PL", etc) and LL is the size
16
 *            of the block (65535 bytes max).
17
 *
18
 * Inside a LANG BLOCK is a set of strings:
19
 *
20
 * II L S  where II is the string's 16-bit identifier, L is its length (1-255)
21
 *         and S is the actual string. All strings are ASCIIZ-formatted (ie.
22
 *         end with a NULL terminator).
23
 *
24
 * The list of strings ends with a single 0-long string.
25
 */
26
 
27
 
28
#include <stdio.h>
29
#include <stdlib.h>
30
#include <string.h>
31
 
32
#include "msgid.h"
33
 
34
 
35
/* read a single line from fd and fills it into dst, returns line length
36
 * ending CR/LF is trimmed, as well as any trailing spaces */
37
static unsigned short readl(char *dst, size_t dstsz, FILE *fd) {
38
  unsigned short l, lastnonspace = 0;
39
 
40
  if (fgets(dst, dstsz, fd) == NULL) return(0xffff); /* EOF */
41
  /* trim at first CR or LF and return len */
42
  for (l = 0; (dst[l] != 0) && (dst[l] != '\r') && (dst[l] != '\n'); l++) {
43
    if (dst[l] != ' ') lastnonspace = l;
44
  }
45
 
46
  if (lastnonspace < l) l = lastnonspace + 1; /* rtrim */
47
  dst[l] = 0;
48
 
49
  return(l);
50
}
51
 
52
 
53
/* parse a line in format "1.50:somestring". fills id and returns a pointer to
54
 * the actual string part on success, or NULL on error */
55
static char *parseline(unsigned short *id, char *s) {
56
  int i;
57
  int dotpos = 0, colpos = 0, gotdigits = 0;
58
 
59
  /* I must have a . and a : in the first 9 bytes */
60
  for (i = 0;; i++) {
61
    if (s[i] == '.') {
62
      if ((dotpos != 0) || (gotdigits == 0)) break;
63
      dotpos = i;
64
      gotdigits = 0;
65
    } else if (s[i] == ':') {
66
      if (gotdigits != 0) colpos = i;
67
      break;
68
    } else if ((s[i] < '0') || (s[i] > '9')) {
69
      break;
70
    }
71
    gotdigits++;
72
  }
73
  /* did I collect everything? */
74
  if ((dotpos == 0) || (colpos == 0)) return(NULL);
75
  if (s[colpos + 1] == 0) return(NULL);
76
 
77
  *id = atoi(s);
78
  *id <<= 8;
79
  *id |= atoi(s + dotpos + 1);
80
 
81
  /* printf("parseline(): %04X = '%s'\r\n", *id, s + colpos + 1); */
82
 
83
  return(s + colpos + 1);
84
}
85
 
86
 
87
/* opens a CATS-style file and compiles it into a ressources lang block */
88
static unsigned short gen_langstrings(unsigned char *buff, const char *langid) {
89
  unsigned short len = 0, linelen;
90
  FILE *fd;
91
  char fname[] = "NLS\\SVARCOM.XX";
92
  char linebuf[512];
93
  char *ptr;
94
  unsigned short id, linecount;
95
 
96
  strcpy(fname + strlen(fname) - 2, langid);
97
 
98
  fd = fopen(fname, "rb");
99
  if (fd == NULL) {
100
    printf("ERROR: FAILED TO OPEN '%s'\r\n", fname);
101
    return(0);
102
  }
103
 
104
  for (linecount = 1;; linecount++) {
105
 
106
    linelen = readl(linebuf, sizeof(linebuf), fd);
107
    if (linelen == 0xffff) break; /* EOF */
108
    if ((linelen == 0) || (linebuf[0] == '#')) continue;
109
 
110
    /* read id and get ptr to actual string ("1.15:string") */
111
    ptr = parseline(&id, linebuf);
112
    if (ptr == NULL) {
113
      printf("ERROR: line #%u of %s is malformed\r\n", linecount, fname);
114
      len = 0;
115
      break;
116
    }
117
 
118
    /* write string into block (II L S) */
119
    memcpy(buff + len, &id, 2);
120
    len += 2;
121
    buff[len++] = strlen(ptr) + 1;
122
    memcpy(buff + len, ptr, strlen(ptr) + 1);
123
    len += strlen(ptr) + 1;
124
  }
125
 
126
  /* write the block terminator (0-long string) */
127
  buff[len++] = 0; /* id */
128
  buff[len++] = 0; /* id */
129
  buff[len++] = 0; /* len */
130
 
131
  fclose(fd);
132
 
133
  return(len);
134
}
135
 
136
 
137
int main(int argc, char **argv) {
138
  FILE *fd;
139
  int ecode = 0;
140
  char *buff;
141
  unsigned short i;
142
 
143
  if (argc < 2) {
144
    puts("usage: tlumacz en fr pl etc");
145
    return(1);
146
  }
147
 
148
  buff = malloc(65500);
149
  if (buff == NULL) {
150
    puts("out of memory");
151
    return(1);
152
  }
153
 
154
  fd = fopen("svarcom.lng", "wb");
155
  if (fd == NULL) {
156
    puts("ERR: failed to open or create SVARCOM.LNG");
157
    return(1);
158
  }
159
 
160
  /* write sig */
161
  fwrite("SvL\x1b", 1, 4, fd);
162
 
163
  /* write lang blocks */
164
  for (i = 1; i < argc; i++) {
165
    unsigned short sz;
166
    char id[3];
167
 
168
    if (strlen(argv[i]) != 2) {
169
      printf("INVALID LANG SPECIFIED: %s\r\n", argv[i]);
170
      ecode = 1;
171
      break;
172
    }
173
 
174
    id[0] = argv[i][0];
175
    id[1] = argv[i][1];
176
    id[2] = 0;
177
    if (id[0] >= 'a') id[0] -= 'a' - 'A';
178
    if (id[1] >= 'a') id[1] -= 'a' - 'A';
179
 
180
    sz = gen_langstrings(buff, id);
181
    if (sz == 0) {
182
      printf("ERROR COMPUTING LANG '%s'\r\n", id);
183
      ecode = 1;
184
      break;
185
    } else {
186
      printf("computed %s lang block of %u bytes\r\n", id, sz);
187
    }
188
    /* write lang ID to file, followed by block size and then the actual block */
189
    if ((fwrite(id, 1, 2, fd) != 2) ||
190
        (fwrite(&sz, 1, 2, fd) != 2) ||
191
        (fwrite(buff, 1, sz, fd) != sz)) {
192
      printf("ERROR WRITING TO OUTPUT FILE\r\n");
193
      ecode = 1;
194
      break;
195
    }
196
    /* if EN, then it is also the default block */
197
    if (strcmp(id, "EN") == 0) {
198
      FILE *fd2;
199
      fd2 = fopen("DEFAULT.LNG", "wb");
200
      if (fd2 == NULL) {
201
        puts("ERROR: FAILED TO OPEN OR CREATE DEFAULT.LNG");
202
        break;
203
      }
204
      fwrite(buff, 1, sz, fd2);
205
      fclose(fd2);
206
    }
207
  }
208
 
209
  fclose(fd);
210
 
211
  return(ecode);
212
}