Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/tools/wmc/write.c
4389 views
1
/*
2
* Wine Message Compiler output generation
3
*
4
* Copyright 2000 Bertho A. Stultiens (BS)
5
*
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2.1 of the License, or (at your option) any later version.
10
*
11
* This library is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Lesser General Public License for more details.
15
*
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with this library; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19
*/
20
21
#include "config.h"
22
23
#include <stdio.h>
24
#include <stdlib.h>
25
#include <string.h>
26
#include <assert.h>
27
#include <ctype.h>
28
29
#include "wmc.h"
30
#include "utils.h"
31
#include "lang.h"
32
#include "write.h"
33
34
/*
35
* The binary resource layout is as follows:
36
*
37
* +===============+
38
* Header | NBlocks |
39
* +===============+
40
* Block 0 | Low ID |
41
* +---------------+
42
* | High ID |
43
* +---------------+
44
* | Offset |---+
45
* +===============+ |
46
* Block 1 | Low ID | |
47
* +---------------+ |
48
* | High ID | |
49
* +---------------+ |
50
* | Offset |------+
51
* +===============+ | |
52
* | | | |
53
* ... ... | |
54
* | | | |
55
* +===============+ <-+ |
56
* B0 LoID | Len | Flags | |
57
* +---+---+---+---+ |
58
* | b | l | a | b | |
59
* +---+---+---+---+ |
60
* | l | a | \0| \0| |
61
* +===============+ |
62
* | | |
63
* ... ... |
64
* | | |
65
* +===============+ |
66
* B0 HiID | Len | Flags | |
67
* +---+---+---+---+ |
68
* | M | o | r | e | |
69
* +---+---+---+---+ |
70
* | b | l | a | \0| |
71
* +===============+ <----+
72
* B1 LoID | Len | Flags |
73
* +---+---+---+---+
74
* | J | u | n | k |
75
* +---+---+---+---+
76
* | \0| \0| \0| \0|
77
* +===============+
78
* | |
79
* ... ...
80
* | |
81
* +===============+
82
*
83
* All Fields are aligned on their natural boundaries. The length
84
* field (Len) covers both the length of the string and the header
85
* fields (Len and Flags). Strings are '\0' terminated. Flags is 0
86
* for normal character strings and 1 for unicode strings.
87
*/
88
89
static const char str_header[] =
90
"/* This file is generated with wmc version " PACKAGE_VERSION ". Do not edit! */\n"
91
"/* Source : %s */\n"
92
"/* Cmdline: %s */\n"
93
"\n"
94
;
95
96
static char *dup_u2c(const WCHAR *uc)
97
{
98
int i;
99
char *cptr = xmalloc( unistrlen(uc)+1 );
100
101
for (i = 0; *uc; i++, uc++) cptr[i] = (*uc <= 0xff) ? *uc : '_';
102
cptr[i] = 0;
103
return cptr;
104
}
105
106
static void killnl(char *s, int ddd)
107
{
108
char *tmp;
109
tmp = strstr(s, "\r\n");
110
if(tmp)
111
{
112
if(ddd && tmp - s > 3)
113
{
114
tmp[0] = tmp[1] = tmp[2] = '.';
115
tmp[3] = '\0';
116
}
117
else
118
*tmp = '\0';
119
}
120
tmp = strchr(s, '\n');
121
if(tmp)
122
{
123
if(ddd && tmp - s > 3)
124
{
125
tmp[0] = tmp[1] = tmp[2] = '.';
126
tmp[3] = '\0';
127
}
128
else
129
*tmp = '\0';
130
}
131
}
132
133
static int killcomment(char *s)
134
{
135
char *tmp = s;
136
int b = 0;
137
while((tmp = strstr(tmp, "/*")))
138
{
139
tmp[1] = 'x';
140
b++;
141
}
142
tmp = s;
143
while((tmp = strstr(tmp, "*/")))
144
{
145
tmp[0] = 'x';
146
b++;
147
}
148
return b;
149
}
150
151
void write_h_file(const char *fname)
152
{
153
struct node *ndp;
154
char *cptr;
155
char *cast;
156
FILE *fp;
157
struct token *ttab;
158
int ntab;
159
int i;
160
int once = 0;
161
int idx_en = 0;
162
163
fp = fopen(fname, "w");
164
if(!fp)
165
{
166
perror(fname);
167
exit(1);
168
}
169
fprintf(fp, str_header, input_name ? input_name : "<stdin>", cmdline);
170
fprintf(fp, "#ifndef __WMCGENERATED_H\n");
171
fprintf(fp, "#define __WMCGENERATED_H\n");
172
fprintf(fp, "\n");
173
174
/* Write severity and facility aliases */
175
get_tokentable(&ttab, &ntab);
176
fprintf(fp, "/* Severity codes */\n");
177
for(i = 0; i < ntab; i++)
178
{
179
if(ttab[i].type == tok_severity && ttab[i].alias)
180
{
181
cptr = dup_u2c(ttab[i].alias);
182
fprintf(fp, "#define %s\t0x%x\n", cptr, ttab[i].token);
183
free(cptr);
184
}
185
}
186
fprintf(fp, "\n");
187
188
fprintf(fp, "/* Facility codes */\n");
189
for(i = 0; i < ntab; i++)
190
{
191
if(ttab[i].type == tok_facility && ttab[i].alias)
192
{
193
cptr = dup_u2c(ttab[i].alias);
194
fprintf(fp, "#define %s\t0x%x\n", cptr, ttab[i].token);
195
free(cptr);
196
}
197
}
198
fprintf(fp, "\n");
199
200
/* Write the message codes */
201
fprintf(fp, "/* Message definitions */\n");
202
for(ndp = nodehead; ndp; ndp = ndp->next)
203
{
204
switch(ndp->type)
205
{
206
case nd_comment:
207
cptr = dup_u2c(ndp->u.comment+1);
208
killnl(cptr, 0);
209
killcomment(cptr);
210
if(*cptr)
211
fprintf(fp, "/* %s */\n", cptr);
212
else
213
fprintf(fp, "\n");
214
free(cptr);
215
break;
216
case nd_msg:
217
if(!once)
218
{
219
/*
220
* Search for an English text.
221
* If not found, then use the first in the list
222
*/
223
once++;
224
for(i = 0; i < ndp->u.msg->nmsgs; i++)
225
{
226
if(ndp->u.msg->msgs[i]->lan == 0x409)
227
{
228
idx_en = i;
229
break;
230
}
231
}
232
fprintf(fp, "\n");
233
}
234
fprintf(fp, "/* MessageId : 0x%08x */\n", ndp->u.msg->realid);
235
cptr = dup_u2c(ndp->u.msg->msgs[idx_en]->msg);
236
killnl(cptr, 0);
237
killcomment(cptr);
238
fprintf(fp, "/* Approximate msg: %s */\n", cptr);
239
free(cptr);
240
cptr = dup_u2c(ndp->u.msg->sym);
241
if(ndp->u.msg->cast)
242
cast = dup_u2c(ndp->u.msg->cast);
243
else
244
cast = NULL;
245
switch(ndp->u.msg->base)
246
{
247
case 8:
248
if(cast)
249
fprintf(fp, "#define %s\t((%s)0%oL)\n\n", cptr, cast, ndp->u.msg->realid);
250
else
251
fprintf(fp, "#define %s\t0%oL\n\n", cptr, ndp->u.msg->realid);
252
break;
253
case 10:
254
if(cast)
255
fprintf(fp, "#define %s\t((%s)%dL)\n\n", cptr, cast, ndp->u.msg->realid);
256
else
257
fprintf(fp, "#define %s\t%dL\n\n", cptr, ndp->u.msg->realid);
258
break;
259
case 16:
260
if(cast)
261
fprintf(fp, "#define %s\t((%s)0x%08xL)\n\n", cptr, cast, ndp->u.msg->realid);
262
else
263
fprintf(fp, "#define %s\t0x%08xL\n\n", cptr, ndp->u.msg->realid);
264
break;
265
default:
266
internal_error(__FILE__, __LINE__, "Invalid base for number print\n");
267
}
268
free(cptr);
269
free(cast);
270
break;
271
default:
272
internal_error(__FILE__, __LINE__, "Invalid node type %d\n", ndp->type);
273
}
274
}
275
fprintf(fp, "\n#endif\n");
276
fclose(fp);
277
}
278
279
static void write_rcbin(FILE *fp)
280
{
281
struct lan_blk *lbp;
282
struct token *ttab;
283
int ntab;
284
int i;
285
286
get_tokentable(&ttab, &ntab);
287
288
for(lbp = lanblockhead; lbp; lbp = lbp->next)
289
{
290
char *cptr = NULL;
291
fprintf(fp, "LANGUAGE 0x%x, 0x%x\n", lbp->lan & 0x3ff, lbp->lan >> 10);
292
for(i = 0; i < ntab; i++)
293
{
294
if(ttab[i].type == tok_language && ttab[i].token == lbp->lan)
295
{
296
if(ttab[i].alias)
297
cptr = dup_u2c(ttab[i].alias);
298
break;
299
}
300
}
301
if(!cptr)
302
internal_error(__FILE__, __LINE__, "Filename vanished for language 0x%0x\n", lbp->lan);
303
fprintf(fp, "1 MESSAGETABLE \"%s.bin\"\n", cptr);
304
free(cptr);
305
}
306
}
307
308
static char *make_string(WCHAR *uc, int len)
309
{
310
char *str = xmalloc(7*len + 12);
311
char *str_end = str + (7*len + 12);
312
char *cptr = str;
313
int i;
314
int b;
315
316
*cptr++ = ' ';
317
*cptr++ = 'L';
318
*cptr++ = '"';
319
for(i = b = 0; i < len; i++, uc++)
320
{
321
switch(*uc)
322
{
323
case '\a': *cptr++ = '\\'; *cptr++ = 'a'; b += 2; break;
324
case '\b': *cptr++ = '\\'; *cptr++ = 'b'; b += 2; break;
325
case '\f': *cptr++ = '\\'; *cptr++ = 'f'; b += 2; break;
326
case '\n': *cptr++ = '\\'; *cptr++ = 'n'; b += 2; break;
327
case '\r': *cptr++ = '\\'; *cptr++ = 'r'; b += 2; break;
328
case '\t': *cptr++ = '\\'; *cptr++ = 't'; b += 2; break;
329
case '\v': *cptr++ = '\\'; *cptr++ = 'v'; b += 2; break;
330
case '\\': *cptr++ = '\\'; *cptr++ = '\\'; b += 2; break;
331
case '"': *cptr++ = '\\'; *cptr++ = '"'; b += 2; break;
332
default:
333
if (*uc < 0x100 && isprint(*uc))
334
{
335
*cptr++ = *uc;
336
b++;
337
}
338
else
339
{
340
int n = snprintf(cptr, str_end - cptr, "\\x%04x", *uc);
341
cptr += n;
342
b += n;
343
}
344
break;
345
}
346
if(i < len-1 && b >= 72)
347
{
348
*cptr++ = '"';
349
*cptr++ = ',';
350
*cptr++ = '\n';
351
*cptr++ = ' ';
352
*cptr++ = 'L';
353
*cptr++ = '"';
354
b = 0;
355
}
356
}
357
len = (len + 1) & ~1;
358
for(; i < len; i++)
359
{
360
*cptr++ = '\\';
361
*cptr++ = 'x';
362
*cptr++ = '0';
363
*cptr++ = '0';
364
*cptr++ = '0';
365
*cptr++ = '0';
366
}
367
*cptr++ = '"';
368
*cptr = '\0';
369
return str;
370
}
371
372
static void write_rcinline(FILE *fp)
373
{
374
struct lan_blk *lbp;
375
int i;
376
int j;
377
378
for(lbp = lanblockhead; lbp; lbp = lbp->next)
379
{
380
unsigned offs = 4 * (lbp->nblk * 3 + 1);
381
fprintf(fp, "\n1 MESSAGETABLE\n");
382
fprintf(fp, "LANGUAGE 0x%x, 0x%x\n", lbp->lan & 0x3ff, lbp->lan >> 10);
383
fprintf(fp, "{\n");
384
fprintf(fp, " /* NBlocks */ 0x%08xL,\n", lbp->nblk);
385
for(i = 0; i < lbp->nblk; i++)
386
{
387
fprintf(fp, " /* Lo,Hi,Offs */ 0x%08xL, 0x%08xL, 0x%08xL,\n",
388
lbp->blks[i].idlo,
389
lbp->blks[i].idhi,
390
offs);
391
offs += lbp->blks[i].size;
392
}
393
for(i = 0; i < lbp->nblk; i++)
394
{
395
struct block *blk = &lbp->blks[i];
396
for(j = 0; j < blk->nmsg; j++)
397
{
398
char *cptr;
399
int l = blk->msgs[j]->len;
400
const char *comma = j == blk->nmsg-1 && i == lbp->nblk-1 ? "" : ",";
401
cptr = make_string(blk->msgs[j]->msg, l);
402
fprintf(fp, "\n /* Msg 0x%08x */ 0x%04x, 0x0001,\n",
403
blk->idlo + j, ((l * 2 + 3) & ~3) + 4 );
404
fprintf(fp, "%s%s\n", cptr, comma);
405
free(cptr);
406
}
407
}
408
fprintf(fp, "}\n");
409
}
410
}
411
412
void write_rc_file(const char *fname)
413
{
414
FILE *fp = fopen(fname, "w");
415
416
if(!fp)
417
{
418
perror(fname);
419
exit(1);
420
}
421
fprintf(fp, str_header, input_name ? input_name : "<stdin>", cmdline);
422
423
if(rcinline)
424
write_rcinline(fp);
425
else
426
write_rcbin(fp);
427
fclose(fp);
428
}
429
430
static void output_bin_data( struct lan_blk *lbp )
431
{
432
unsigned int offs = 4 * (lbp->nblk * 3 + 1);
433
int i, j, k;
434
435
put_dword( lbp->nblk ); /* NBlocks */
436
for (i = 0; i < lbp->nblk; i++)
437
{
438
put_dword( lbp->blks[i].idlo ); /* Lo */
439
put_dword( lbp->blks[i].idhi ); /* Hi */
440
put_dword( offs ); /* Offs */
441
offs += lbp->blks[i].size;
442
}
443
for (i = 0; i < lbp->nblk; i++)
444
{
445
struct block *blk = &lbp->blks[i];
446
for (j = 0; j < blk->nmsg; j++)
447
{
448
int len = (2 * blk->msgs[j]->len + 3) & ~3;
449
put_word( len + 4 );
450
put_word( 1 );
451
for (k = 0; k < blk->msgs[j]->len; k++) put_word( blk->msgs[j]->msg[k] );
452
align_output( 4 );
453
}
454
}
455
}
456
457
void write_bin_files(void)
458
{
459
struct lan_blk *lbp;
460
struct token *ttab;
461
int ntab;
462
int i;
463
464
get_tokentable(&ttab, &ntab);
465
466
for (lbp = lanblockhead; lbp; lbp = lbp->next)
467
{
468
char *cptr = NULL;
469
470
for (i = 0; i < ntab; i++)
471
{
472
if (ttab[i].type == tok_language && ttab[i].token == lbp->lan)
473
{
474
if (ttab[i].alias) cptr = dup_u2c(ttab[i].alias);
475
break;
476
}
477
}
478
if(!cptr)
479
internal_error(__FILE__, __LINE__, "Filename vanished for language 0x%0x\n", lbp->lan);
480
init_output_buffer();
481
output_bin_data( lbp );
482
cptr = xrealloc( cptr, strlen(cptr) + 5 );
483
strcat( cptr, ".bin" );
484
flush_output_buffer( cptr );
485
free(cptr);
486
}
487
}
488
489
void write_res_file( const char *name )
490
{
491
struct lan_blk *lbp;
492
int i, j;
493
494
init_output_buffer();
495
496
put_dword( 0 ); /* ResSize */
497
put_dword( 32 ); /* HeaderSize */
498
put_word( 0xffff ); /* ResType */
499
put_word( 0x0000 );
500
put_word( 0xffff ); /* ResName */
501
put_word( 0x0000 );
502
put_dword( 0 ); /* DataVersion */
503
put_word( 0 ); /* Memory options */
504
put_word( 0 ); /* Language */
505
put_dword( 0 ); /* Version */
506
put_dword( 0 ); /* Characteristics */
507
508
for (lbp = lanblockhead; lbp; lbp = lbp->next)
509
{
510
unsigned int data_size = 4 * (lbp->nblk * 3 + 1);
511
unsigned int header_size = 5 * sizeof(unsigned int) + 6 * sizeof(unsigned short);
512
513
for (i = 0; i < lbp->nblk; i++)
514
{
515
struct block *blk = &lbp->blks[i];
516
for (j = 0; j < blk->nmsg; j++) data_size += 4 + ((blk->msgs[j]->len * 2 + 3) & ~3);
517
}
518
519
put_dword( data_size ); /* ResSize */
520
put_dword( header_size ); /* HeaderSize */
521
put_word( 0xffff ); /* ResType */
522
put_word( 0x000b /*RT_MESSAGETABLE*/ );
523
put_word( 0xffff ); /* ResName */
524
put_word( 0x0001 );
525
align_output( 4 );
526
put_dword( 0 ); /* DataVersion */
527
put_word( 0x30 ); /* Memory options */
528
put_word( lbp->lan ); /* Language */
529
put_dword( lbp->version ); /* Version */
530
put_dword( 0 ); /* Characteristics */
531
532
output_bin_data( lbp );
533
}
534
flush_output_buffer( name );
535
}
536
537