:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / tools / wmc / write.c
1 /*
2  * Wine Message Compiler output generation
3  *
4  * Copyright 2000 Bertho A. Stultiens (BS)
5  *
6  */
7
8 #include <windows.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <assert.h>
13 #include <ctype.h>
14
15 #include "wmc.h"
16 #include "utils.h"
17 #include "lang.h"
18 #include "write.h"
19
20 /*
21  * The binary resource layout is as follows:
22  *
23  *         +===============+
24  * Header  |    NBlocks    |
25  *         +===============+
26  * Block 0 |    Low ID     |
27  *         +---------------+
28  *         |    High ID    |
29  *         +---------------+
30  *         |    Offset     |---+
31  *         +===============+   |
32  * Block 1 |    Low ID     |   |
33  *         +---------------+   |
34  *         |    High ID    |   |
35  *         +---------------+   |
36  *         |    Offset     |------+
37  *         +===============+   |  |
38  *         |               |   |  |
39  *        ...             ...  |  |
40  *         |               |   |  |
41  *         +===============+ <-+  |
42  * B0 LoID |  Len  | Flags |      |
43  *         +---+---+---+---+      |
44  *         | b | l | a | b |      |
45  *         +---+---+---+---+      |
46  *         | l | a | \0| \0|      |
47  *         +===============+      |
48  *         |               |      |
49  *        ...             ...     |
50  *         |               |      |
51  *         +===============+      |
52  * B0 HiID |  Len  | Flags |      |
53  *         +---+---+---+---+      |
54  *         | M | o | r | e |      |
55  *         +---+---+---+---+      |
56  *         | b | l | a | \0|      |
57  *         +===============+ <----+
58  * B1 LoID |  Len  | Flags |
59  *         +---+---+---+---+
60  *         | J | u | n | k |
61  *         +---+---+---+---+
62  *         | \0| \0| \0| \0|
63  *         +===============+
64  *         |               |
65  *        ...             ...
66  *         |               |
67  *         +===============+
68  *
69  * All Fields are aligned on their natural boundaries. The length
70  * field (Len) covers both the length of the string and the header
71  * fields (Len and Flags). Strings are '\0' terminated. Flags is 0
72  * for normal character strings and 1 for unicode strings.
73  */
74
75 static char str_header[] =
76         "/* This file is generated with wmc version " WMC_FULLVERSION ". Do not edit! */\n"
77         "/* Source : %s */\n"
78         "/* Cmdline: %s */\n"
79         "/* Date   : %s */\n"
80         "\n"
81         ;
82
83 static char *dup_u2c(int cp, const WCHAR *uc)
84 {
85         int len = unistrlen(uc);
86         char *cptr = xmalloc(len+1);
87 //      const union cptable *cpdef = find_codepage(cp);
88 //      if(!cpdef)
89 //              internal_error(__FILE__, __LINE__, "Codepage %d not found (vanished?)", cp);
90 //      if((len = cp_wcstombs(cpdef, 0, uc, unistrlen(uc)+1, cptr, len+1, NULL, NULL)) < 0)
91         if((len = WideCharToMultiByte(cp, 0, uc, unistrlen(uc)+1, cptr, len+1, NULL, NULL)) < 0)\r
92                 internal_error(__FILE__, __LINE__, "Buffer overflow? code %d.", len);
93         return cptr;
94 }
95
96 static void killnl(char *s, int ddd)
97 {
98         char *tmp;
99         tmp = strstr(s, "\r\n");
100         if(tmp)
101         {
102                 if(ddd && tmp - s > 3)
103                 {
104                         tmp[0] = tmp[1] = tmp[2] = '.';
105                         tmp[3] = '\0';
106                 }
107                 else
108                         *tmp = '\0';
109         }
110         tmp = strchr(s, '\n');
111         if(tmp)
112         {
113                 if(ddd && tmp - s > 3)
114                 {
115                         tmp[0] = tmp[1] = tmp[2] = '.';
116                         tmp[3] = '\0';
117                 }
118                 else
119                         *tmp = '\0';
120         }
121 }
122
123 static int killcomment(char *s)
124 {
125         char *tmp = s;
126         int b = 0;
127         while((tmp = strstr(tmp, "/*")))
128         {
129                 tmp[1] = 'x';
130                 b++;
131         }
132         tmp = s;
133         while((tmp = strstr(tmp, "*/")))
134         {
135                 tmp[0] = 'x';
136                 b++;
137         }
138         return b;
139 }
140
141 void write_h_file(const char *fname)
142 {
143         node_t *ndp;
144         char *cptr;
145         char *cast;
146         FILE *fp;
147         token_t *ttab;
148         int ntab;
149         int i;
150         int once = 0;
151         int idx_en = 0;
152
153         fp = fopen(fname, "w");
154         if(!fp)
155         {
156                 perror(fname);
157                 exit(1);
158         }
159         cptr = ctime(&now);
160         killnl(cptr, 0);
161         fprintf(fp, str_header, input_name ? input_name : "<stdin>", cmdline, cptr);
162         fprintf(fp, "#ifndef __WMCGENERATED_%08lx_H\n", now);
163         fprintf(fp, "#define __WMCGENERATED_%08lx_H\n", now);
164         fprintf(fp, "\n");
165
166         /* Write severity and facility aliases */
167         get_tokentable(&ttab, &ntab);
168         fprintf(fp, "/* Severity codes */\n");
169         for(i = 0; i < ntab; i++)
170         {
171                 if(ttab[i].type == tok_severity && ttab[i].alias)
172                 {
173                         cptr = dup_u2c(WMC_DEFAULT_CODEPAGE, ttab[i].alias);
174                         fprintf(fp, "#define %s\t0x%x\n", cptr, ttab[i].token);
175                         free(cptr);
176                 }
177         }
178         fprintf(fp, "\n");
179
180         fprintf(fp, "/* Facility codes */\n");
181         for(i = 0; i < ntab; i++)
182         {
183                 if(ttab[i].type == tok_facility && ttab[i].alias)
184                 {
185                         cptr = dup_u2c(WMC_DEFAULT_CODEPAGE, ttab[i].alias);
186                         fprintf(fp, "#define %s\t0x%x\n", cptr, ttab[i].token);
187                         free(cptr);
188                 }
189         }
190         fprintf(fp, "\n");
191
192         /* Write the message codes */
193         fprintf(fp, "/* Message definitions */\n");
194         for(ndp = nodehead; ndp; ndp = ndp->next)
195         {
196                 switch(ndp->type)
197                 {
198                 case nd_comment:
199                         cptr = dup_u2c(WMC_DEFAULT_CODEPAGE, ndp->u.comment+1);
200                         killnl(cptr, 0);
201                         killcomment(cptr);
202                         if(*cptr)
203                                 fprintf(fp, "/* %s */\n", cptr);
204                         else
205                                 fprintf(fp, "\n");
206                         free(cptr);
207                         break;
208                 case nd_msg:
209                         if(!once)
210                         {
211                                 /*
212                                  * Search for an english text.
213                                  * If not found, then use the first in the list
214                                  */
215                                 once++;
216                                 for(i = 0; i < ndp->u.msg->nmsgs; i++)
217                                 {
218                                         if(ndp->u.msg->msgs[i]->lan == 0x409)
219                                         {
220                                                 idx_en = i;
221                                                 break;
222                                         }
223                                 }
224                                 fprintf(fp, "\n");
225                         }
226                         fprintf(fp, "/* MessageId  : 0x%08x */\n", ndp->u.msg->realid);
227                         cptr = dup_u2c(ndp->u.msg->msgs[idx_en]->cp, ndp->u.msg->msgs[idx_en]->msg);
228                         killnl(cptr, 0);
229                         killcomment(cptr);
230                         fprintf(fp, "/* Approx. msg: %s */\n", cptr);
231                         free(cptr);
232                         cptr = dup_u2c(WMC_DEFAULT_CODEPAGE, ndp->u.msg->sym);
233                         if(ndp->u.msg->cast)
234                                 cast = dup_u2c(WMC_DEFAULT_CODEPAGE, ndp->u.msg->cast);
235                         else
236                                 cast = NULL;
237                         switch(ndp->u.msg->base)
238                         {
239                         case 8:
240                                 if(cast)
241                                         fprintf(fp, "#define %s\t((%s)0%oL)\n\n", cptr, cast, ndp->u.msg->realid);
242                                 else
243                                         fprintf(fp, "#define %s\t0%oL\n\n", cptr, ndp->u.msg->realid);
244                                 break;
245                         case 10:
246                                 if(cast)
247                                         fprintf(fp, "#define %s\t((%s)%dL)\n\n", cptr, cast, ndp->u.msg->realid);
248                                 else
249                                         fprintf(fp, "#define %s\t%dL\n\n", cptr, ndp->u.msg->realid);
250                                 break;
251                         case 16:
252                                 if(cast)
253                                         fprintf(fp, "#define %s\t((%s)0x%08xL)\n\n", cptr, cast, ndp->u.msg->realid);
254                                 else
255                                         fprintf(fp, "#define %s\t0x%08xL\n\n", cptr, ndp->u.msg->realid);
256                                 break;
257                         default:
258                                 internal_error(__FILE__, __LINE__, "Invalid base for number print");
259                         }
260                         free(cptr);
261                         if(cast)
262                                 free(cast);
263                         break;
264                 default:
265                         internal_error(__FILE__, __LINE__, "Invalid node type %d", ndp->type);
266                 }
267         }
268         fprintf(fp, "\n#endif\n");
269         fclose(fp);
270 }
271
272 static void write_rcbin(FILE *fp)
273 {
274         lan_blk_t *lbp;
275         token_t *ttab;
276         int ntab;
277         int i;
278
279         get_tokentable(&ttab, &ntab);
280
281         for(lbp = lanblockhead; lbp; lbp = lbp->next)
282         {
283                 char *cptr = NULL;
284                 fprintf(fp, "LANGUAGE 0x%x, 0x%x\n", lbp->lan & 0x3ff, lbp->lan >> 10);
285                 for(i = 0; i < ntab; i++)
286                 {
287                         if(ttab[i].type == tok_language && ttab[i].token == lbp->lan)
288                         {
289                                 if(ttab[i].alias)
290                                         cptr = dup_u2c(WMC_DEFAULT_CODEPAGE, ttab[i].alias);
291                                 break;
292                         }
293                 }
294                 if(!cptr)
295                         internal_error(__FILE__, __LINE__, "Filename vanished for language 0x%0x", lbp->lan);
296                 fprintf(fp, "1 MESSAGETABLE \"%s.bin\"\n", cptr);
297                 free(cptr);
298         }
299 }
300
301 static char *make_string(WCHAR *uc, int len, int codepage)
302 {
303         char *str = xmalloc(7*len + 1);
304         char *cptr = str;
305         int i;
306         int b;
307
308         if(!codepage)
309         {
310                 *cptr++ = ' ';
311                 *cptr++ = 'L';
312                 *cptr++ = '"';
313                 for(i = b = 0; i < len; i++, uc++)
314                 {
315                         int n;
316                         if(*uc < 0x100)
317                         {
318                                 if(isprint(*uc))
319                                 {
320                                         *cptr++ = (char)*uc;
321                                         b++;
322                                 }
323                                 else
324                                 {
325                                         switch(*uc)
326                                         {
327                                         case '\a': *cptr++ = '\\'; *cptr++ = 'a'; b += 2; break;
328                                         case '\b': *cptr++ = '\\'; *cptr++ = 'b'; b += 2; break;
329                                         case '\f': *cptr++ = '\\'; *cptr++ = 'f'; b += 2; break;
330                                         case '\n': *cptr++ = '\\'; *cptr++ = 'n'; b += 2; break;
331                                         case '\r': *cptr++ = '\\'; *cptr++ = 'r'; b += 2; break;
332                                         case '\t': *cptr++ = '\\'; *cptr++ = 't'; b += 2; break;
333                                         case '\v': *cptr++ = '\\'; *cptr++ = 'v'; b += 2; break;
334                                         case '\\': *cptr++ = '\\'; *cptr++ = '\\'; b += 2; break;
335                                         case '"':  *cptr++ = '\\'; *cptr++ = '"'; b += 2; break;
336                                         default:
337                                                 n = sprintf(cptr, "\\x%04x", *uc & 0xffff);
338                                                 cptr += n;
339                                                 b += n;
340                                         }
341                                 }
342                         }
343                         else
344                         {
345                                 n = sprintf(cptr, "\\x%04x", *uc & 0xffff);
346                                 cptr += n;
347                                 b += n;
348                         }
349                         if(i < len-1 && b >= 72)
350                         {
351                                 *cptr++ = '"';
352                                 *cptr++ = ',';
353                                 *cptr++ = '\n';
354                                 *cptr++ = ' ';
355                                 *cptr++ = 'L';
356                                 *cptr++ = '"';
357                                 b = 0;
358                         }
359                 }
360                 len = (len + 3) & ~3;
361                 for(; i < len; i++)
362                 {
363                         *cptr++ = '\\';
364                         *cptr++ = 'x';
365                         *cptr++ = '0';
366                         *cptr++ = '0';
367                         *cptr++ = '0';
368                         *cptr++ = '0';
369                 }
370                 *cptr++ = '"';
371                 *cptr = '\0';
372         }
373         else
374         {
375                 char *tmp = xmalloc(2*len+1);
376                 char *cc = tmp;
377 //              const union cptable *cpdef = find_codepage(codepage);
378
379 //              assert(cpdef != NULL);
380 //              if((i = cp_wcstombs(cpdef, 0, uc, unistrlen(uc)+1, tmp, 2*len+1, NULL, NULL)) < 0)
381                 if((i = WideCharToMultiByte(codepage, 0, uc, unistrlen(uc)+1, tmp, 2*len+1, NULL, NULL)) < 0)\r
382                         internal_error(__FILE__, __LINE__, "Buffer overflow? code %d.", i);
383                 *cptr++ = ' ';
384                 *cptr++ = '"';
385                 for(i = b = 0; i < len; i++, cc++)
386                 {
387                         int n;
388                         if(isprint(*cc))
389                         {
390                                 *cptr++ = *cc;
391                                 b++;
392                         }
393                         else
394                         {
395                                 switch(*cc)
396                                 {
397                                 case '\a': *cptr++ = '\\'; *cptr++ = 'a'; b += 2; break;
398                                 case '\b': *cptr++ = '\\'; *cptr++ = 'b'; b += 2; break;
399                                 case '\f': *cptr++ = '\\'; *cptr++ = 'f'; b += 2; break;
400                                 case '\n': *cptr++ = '\\'; *cptr++ = 'n'; b += 2; break;
401                                 case '\r': *cptr++ = '\\'; *cptr++ = 'r'; b += 2; break;
402                                 case '\t': *cptr++ = '\\'; *cptr++ = 't'; b += 2; break;
403                                 case '\v': *cptr++ = '\\'; *cptr++ = 'v'; b += 2; break;
404                                 case '\\': *cptr++ = '\\'; *cptr++ = '\\'; b += 2; break;
405                                 case '"':  *cptr++ = '\\'; *cptr++ = '"'; b += 2; break;
406                                 default:
407                                         n = sprintf(cptr, "\\x%02x", *cc & 0xff);
408                                         cptr += n;
409                                         b += n;
410                                 }
411                         }
412                         if(i < len-1 && b >= 72)
413                         {
414                                 *cptr++ = '"';
415                                 *cptr++ = ',';
416                                 *cptr++ = '\n';
417                                 *cptr++ = ' ';
418                                 *cptr++ = '"';
419                                 b = 0;
420                         }
421                 }
422                 len = (len + 3) & ~3;
423                 for(; i < len; i++)
424                 {
425                         *cptr++ = '\\';
426                         *cptr++ = 'x';
427                         *cptr++ = '0';
428                         *cptr++ = '0';
429                 }
430                 *cptr++ = '"';
431                 *cptr = '\0';
432                 free(tmp);
433         }
434         return str;
435 }
436
437
438 static char *make_bin_string(WCHAR *uc, int len, int *retlen, int codepage)\r
439 {
440         char *str = xmalloc(7 * len + 1);
441         int i;
442         int b;
443
444         if(!codepage)
445         {
446                 WCHAR *cptr = (WCHAR*)str;
447
448                 for(i = b = 0; i < len; i++, uc++)
449                 {
450                         *cptr++ = *uc;
451                 }
452                 len = (len + 1) & ~1;
453                 for(; i < len; i++)
454                 {
455                         *cptr++ = 0;
456                 }
457                 *retlen = len * 2;
458         }
459         else
460         {
461                 char *tmp = xmalloc(2*len+1);
462                 char *cc = tmp;
463                 char *cptr = str;
464 //              const union cptable *cpdef = find_codepage(codepage);
465
466 //              assert(cpdef != NULL);
467 //              if((i = cp_wcstombs(cpdef, 0, uc, unistrlen(uc)+1, tmp, 2*len+1, NULL, NULL)) < 0)
468                 if((i = WideCharToMultiByte(codepage, 0, uc, unistrlen(uc)+1, tmp, 2*len+1, NULL, NULL)) < 0)
469                         internal_error(__FILE__, __LINE__, "Buffer overflow? code %d.", i);
470                 for(i = b = 0; i < len; i++, cc++)
471                 {
472                         *cptr++ = *cc;
473                         b++;
474                 }
475                 len = (len + 3) & ~3;
476                 for(; i < len; i++)
477                 {
478                         *cptr++ = 0;
479                 }
480                 free(tmp);
481                 *retlen = len;
482         }
483         return str;
484 }
485
486 static void write_rcinline(FILE *fp)
487 {
488         lan_blk_t *lbp;
489         int i;
490         int j;
491
492         for(lbp = lanblockhead; lbp; lbp = lbp->next)
493         {
494                 unsigned offs = 4 * (lbp->nblk * 3 + 1);
495                 fprintf(fp, "\n1 MESSAGETABLE\n");
496                 fprintf(fp, "LANGUAGE 0x%x, 0x%x\n", lbp->lan & 0x3ff, lbp->lan >> 10);
497                 fprintf(fp, "{\n");
498                 fprintf(fp, " /* NBlocks    */ 0x%08xL,\n", lbp->nblk);
499                 for(i = 0; i < lbp->nblk; i++)
500                 {
501                         fprintf(fp, " /* Lo,Hi,Offs */ 0x%08xL, 0x%08xL, 0x%08xL,\n",
502                                         lbp->blks[i].idlo,
503                                         lbp->blks[i].idhi,
504                                         offs);
505                         offs += lbp->blks[i].size;
506                 }
507                 for(i = 0; i < lbp->nblk; i++)
508                 {
509                         block_t *blk = &lbp->blks[i];
510                         for(j = 0; j < blk->nmsg; j++)
511                         {
512                                 char *cptr;
513                                 int l = blk->msgs[j]->len;
514                                 char *comma = j == blk->nmsg-1  && i == lbp->nblk-1 ? "" : ",";
515                                 cptr = make_string(blk->msgs[j]->msg, l, unicodeout ? 0 : blk->msgs[j]->cp);
516                                 fprintf(fp, "\n /* Msg 0x%08x */ 0x%04x, 0x000%c,\n",
517                                         blk->idlo + j,
518                                         (unicodeout ? (l*2+3)&~3 : (l+3)&~3)+4,
519                                         unicodeout ? '1' : '0');
520                                 fprintf(fp, "%s%s\n", cptr, comma);
521                                 free(cptr);
522                         }
523                 }
524                 fprintf(fp, "}\n");
525         }
526 }
527
528 void write_rc_file(const char *fname)
529 {
530         FILE *fp;
531         char *cptr;
532
533         fp = fopen(fname, "w");
534         if(!fp)
535         {
536                 perror(fname);
537                 exit(1);
538         }
539         cptr = ctime(&now);
540         killnl(cptr, 0);
541         fprintf(fp, str_header, input_name ? input_name : "<stdin>", cmdline, cptr);
542
543         if(rcinline)
544                 write_rcinline(fp);
545         else
546                 write_rcbin(fp);
547         fclose(fp);
548 }
549
550 void write_bin_files(void)
551 {
552   lan_blk_t *lbp;
553   token_t *ttab;
554   int ntab;
555   int i;
556   int j;
557   char fname[16];
558   FILE *fp;
559
560   get_tokentable(&ttab, &ntab);
561
562   for (lbp = lanblockhead; lbp; lbp = lbp->next)
563     {
564       unsigned offs = 4 * (lbp->nblk * 3 + 1); 
565
566       char *cptr = NULL;
567       for(i = 0; i < ntab; i++)
568         {
569           if (ttab[i].type == tok_language && ttab[i].token == lbp->lan)
570             {
571               if (ttab[i].alias)
572                 cptr = dup_u2c(WMC_DEFAULT_CODEPAGE, ttab[i].alias);
573               break;
574             }
575         }
576
577       if (!cptr)
578         internal_error(__FILE__, __LINE__, "Filename vanished for language 0x%0x", lbp->lan);
579       sprintf(fname, "%s.bin", cptr);
580       free(cptr);
581
582       fp = fopen(fname, "wb");
583       if (!fp)
584         {
585           perror(fname);
586           exit(1);
587         }
588
589       /* NBlocks */
590       fwrite(&lbp->nblk, sizeof(unsigned long), 1, fp);
591       for(i = 0; i < lbp->nblk; i++)
592         {
593           /* Lo */
594           fwrite(&lbp->blks[i].idlo, sizeof(unsigned long), 1, fp);
595           /* Hi */
596           fwrite(&lbp->blks[i].idhi, sizeof(unsigned long), 1, fp);
597           /* Offs */
598           fwrite(&offs, sizeof(unsigned long), 1, fp);
599           offs += lbp->blks[i].size;
600         }
601
602       for (i = 0; i < lbp->nblk; i++)
603         {
604           block_t *blk = &lbp->blks[i];
605           for (j = 0; j < blk->nmsg; j++)
606             {
607               char *cptr;
608               int l = blk->msgs[j]->len;
609               int retlen = 0;
610
611               unsigned short length = (unicodeout ? (l*2+3)&~3 : (l+3)&~3)+4;
612               unsigned short flags = unicodeout ? 1 : 0;
613
614               /* Lo */
615               fwrite(&length, sizeof(unsigned short), 1, fp);
616               /* Hi */
617               fwrite(&flags, sizeof(unsigned short), 1, fp);
618
619               /* message text */
620               cptr = make_bin_string(blk->msgs[j]->msg, l, &retlen, unicodeout ? 0 : blk->msgs[j]->cp);
621               fwrite(cptr, retlen, 1, fp);
622
623               free(cptr);
624             }
625         }
626
627       fclose(fp);
628     }
629 }
630
631 /* EOF */