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