makefiles: Generate the dependencies line to avoid some code duplication.
[wine] / tools / wrc / translation.c
1 /*
2  * Copyright 2003 Vincent BĂ©ron
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21
22 #include "dumpres.h"
23 #include "wrc.h"
24
25 #define MASTER_LANGUAGE LANG_ENGLISH
26 #define NB_LANG 0x94
27
28 enum lang_type_e {
29         lang_type_master = 0,
30         lang_type_neutral,
31         lang_type_normal
32 };
33
34 static int present_resources[res_usr+1];
35 static char *res_names[res_usr+1];
36 static int nb_resources[res_usr+1][lang_type_normal+1];
37 static resource_t **list_resources[res_usr+1][lang_type_normal+1];
38
39 static int get_language_id(resource_t *resource) {
40         switch(resource->type) {
41                 case res_acc:
42                         return resource->res.acc->lvc.language->id;
43                 case res_bmp:
44                         return resource->res.bmp->data->lvc.language->id;
45                 case res_cur:
46                         return resource->res.cur->lvc.language->id;
47                 case res_curg:
48                         return resource->res.curg->lvc.language->id;
49                 case res_dlg:
50                         return resource->res.dlg->lvc.language->id;
51                 case res_dlgex:
52                         return resource->res.dlgex->lvc.language->id;
53                 case res_fnt:
54                         return resource->res.fnt->data->lvc.language->id;
55                 case res_fntdir:
56                         return resource->res.fnd->data->lvc.language->id;
57                 case res_ico:
58                         return resource->res.ico->lvc.language->id;
59                 case res_icog:
60                         return resource->res.icog->lvc.language->id;
61                 case res_men:
62                         return resource->res.men->lvc.language->id;
63                 case res_menex:
64                         return resource->res.menex->lvc.language->id;
65                 case res_rdt:
66                         return resource->res.rdt->data->lvc.language->id;
67                 case res_stt:
68                         return resource->res.stt->lvc.language->id;
69                 case res_usr:
70                         return resource->res.usr->data->lvc.language->id;
71                 case res_msg:
72                         return resource->res.msg->data->lvc.language->id;
73                 case res_ver:
74                         return resource->res.ver->lvc.language->id;
75                 case res_dlginit:
76                         return resource->res.dlgi->data->lvc.language->id;
77                 case res_toolbar:
78                         return resource->res.tbt->lvc.language->id;
79                 case res_anicur:
80                 case res_aniico:
81                         return resource->res.ani->data->lvc.language->id;
82                 default:
83                         /* Not supposed to reach here */
84                         fprintf(stderr, "Not supposed to reach here (get_language_id())\n");
85                         abort();
86                         return -1;
87         }
88 }
89
90 static void add_resource(resource_t *resource) {
91         enum lang_type_e lang_type;
92         enum res_e res_type = resource->type;
93         int lid = get_language_id(resource);
94
95         if(lid == MASTER_LANGUAGE) {
96                 lang_type = lang_type_master;
97         } else if(lid == LANG_NEUTRAL) {
98                 lang_type = lang_type_neutral;
99         } else {
100                 lang_type = lang_type_normal;
101         }
102         nb_resources[res_type][lang_type]++;
103         list_resources[res_type][lang_type] = realloc(list_resources[res_type][lang_type], nb_resources[res_type][lang_type]*sizeof(resource_t *));
104         list_resources[res_type][lang_type][nb_resources[res_type][lang_type]-1] = resource;
105 }
106
107 #if 0
108
109 #define PRETTYPRINTLANG(langid) \
110         if(LANG_##langid == lid) { \
111                 return #langid; \
112         }
113
114 static const char *get_language_name(int lid) {
115         PRETTYPRINTLANG(NEUTRAL)
116         PRETTYPRINTLANG(AFRIKAANS)
117         PRETTYPRINTLANG(ALBANIAN)
118         PRETTYPRINTLANG(ARABIC)
119         PRETTYPRINTLANG(ARMENIAN)
120         PRETTYPRINTLANG(ASSAMESE)
121         PRETTYPRINTLANG(AZERI)
122         PRETTYPRINTLANG(BASQUE)
123         PRETTYPRINTLANG(BELARUSIAN)
124         PRETTYPRINTLANG(BENGALI)
125         PRETTYPRINTLANG(BULGARIAN)
126         PRETTYPRINTLANG(CATALAN)
127         PRETTYPRINTLANG(CHINESE)
128         PRETTYPRINTLANG(CROATIAN)
129         PRETTYPRINTLANG(CZECH)
130         PRETTYPRINTLANG(DANISH)
131         PRETTYPRINTLANG(DIVEHI)
132         PRETTYPRINTLANG(DUTCH)
133         PRETTYPRINTLANG(ENGLISH)
134         PRETTYPRINTLANG(ESTONIAN)
135         PRETTYPRINTLANG(FAEROESE)
136         PRETTYPRINTLANG(FARSI)
137         PRETTYPRINTLANG(FINNISH)
138         PRETTYPRINTLANG(FRENCH)
139         PRETTYPRINTLANG(GALICIAN)
140         PRETTYPRINTLANG(GEORGIAN)
141         PRETTYPRINTLANG(GERMAN)
142         PRETTYPRINTLANG(GREEK)
143         PRETTYPRINTLANG(GUJARATI)
144         PRETTYPRINTLANG(HEBREW)
145         PRETTYPRINTLANG(HINDI)
146         PRETTYPRINTLANG(HUNGARIAN)
147         PRETTYPRINTLANG(ICELANDIC)
148         PRETTYPRINTLANG(INDONESIAN)
149         PRETTYPRINTLANG(ITALIAN)
150         PRETTYPRINTLANG(JAPANESE)
151         PRETTYPRINTLANG(KANNADA)
152         PRETTYPRINTLANG(KASHMIRI)
153         PRETTYPRINTLANG(KAZAK)
154         PRETTYPRINTLANG(KONKANI)
155         PRETTYPRINTLANG(KOREAN)
156         PRETTYPRINTLANG(KYRGYZ)
157         PRETTYPRINTLANG(LATVIAN)
158         PRETTYPRINTLANG(LITHUANIAN)
159         PRETTYPRINTLANG(MACEDONIAN)
160         PRETTYPRINTLANG(MALAY)
161         PRETTYPRINTLANG(MALAYALAM)
162         PRETTYPRINTLANG(MANIPURI)
163         PRETTYPRINTLANG(MARATHI)
164         PRETTYPRINTLANG(MONGOLIAN)
165         PRETTYPRINTLANG(NEPALI)
166         PRETTYPRINTLANG(NORWEGIAN)
167         PRETTYPRINTLANG(ORIYA)
168         PRETTYPRINTLANG(POLISH)
169         PRETTYPRINTLANG(PORTUGUESE)
170         PRETTYPRINTLANG(PUNJABI)
171         PRETTYPRINTLANG(ROMANIAN)
172         PRETTYPRINTLANG(RUSSIAN)
173         PRETTYPRINTLANG(SANSKRIT)
174         PRETTYPRINTLANG(SERBIAN)
175         PRETTYPRINTLANG(SINDHI)
176         PRETTYPRINTLANG(SLOVAK)
177         PRETTYPRINTLANG(SLOVENIAN)
178         PRETTYPRINTLANG(SPANISH)
179         PRETTYPRINTLANG(SWAHILI)
180         PRETTYPRINTLANG(SWEDISH)
181         PRETTYPRINTLANG(SYRIAC)
182         PRETTYPRINTLANG(TAMIL)
183         PRETTYPRINTLANG(TATAR)
184         PRETTYPRINTLANG(TELUGU)
185         PRETTYPRINTLANG(THAI)
186         PRETTYPRINTLANG(TURKISH)
187         PRETTYPRINTLANG(UKRAINIAN)
188         PRETTYPRINTLANG(URDU)
189         PRETTYPRINTLANG(UZBEK)
190         PRETTYPRINTLANG(VIETNAMESE)
191         PRETTYPRINTLANG(GAELIC)
192         PRETTYPRINTLANG(MALTESE)
193         PRETTYPRINTLANG(MAORI)
194         PRETTYPRINTLANG(RHAETO_ROMANCE)
195         PRETTYPRINTLANG(SAAMI)
196         PRETTYPRINTLANG(SORBIAN)
197         PRETTYPRINTLANG(SUTU)
198         PRETTYPRINTLANG(TSONGA)
199         PRETTYPRINTLANG(TSWANA)
200         PRETTYPRINTLANG(VENDA)
201         PRETTYPRINTLANG(XHOSA)
202         PRETTYPRINTLANG(ZULU)
203         PRETTYPRINTLANG(ESPERANTO)
204         PRETTYPRINTLANG(WALON)
205         PRETTYPRINTLANG(CORNISH)
206         PRETTYPRINTLANG(WELSH)
207         PRETTYPRINTLANG(BRETON)
208         return "Unknown language";
209 }
210 #endif
211
212 static int compare_accelerator(accelerator_t *accelerator1, accelerator_t *accelerator2) {
213         int different = 0;
214         event_t *ev1 = NULL, *ev2 = NULL;
215         if(!different &&
216            ((accelerator1->memopt != accelerator2->memopt) ||
217            (accelerator1->lvc.version != accelerator2->lvc.version) ||
218            (accelerator1->lvc.characts != accelerator2->lvc.characts)))
219                 different = 1;
220         ev1 = accelerator1->events;
221         ev2 = accelerator2->events;
222         while(!different && ev1 && ev2) {
223                 if(!different &&
224                    ((ev1->id != ev2->id) ||
225                    (ev1->flags != ev2->flags)))
226                         different = 1;
227                 ev1 = ev1->next;
228                 ev2 = ev2->next;
229         }
230         if(!different &&
231            ((ev1 && !ev2) || (!ev1 && ev2)))
232                 different = 1;
233         return different;
234 }
235
236 static int compare_bitmap(bitmap_t *bitmap1, bitmap_t *bitmap2) {
237         int different = 0;
238         if(!different &&
239            ((bitmap1->memopt != bitmap2->memopt) ||
240            (bitmap1->data->lvc.version != bitmap2->data->lvc.version) ||
241            (bitmap1->data->lvc.characts != bitmap2->data->lvc.characts)))
242                 different = 1;
243         return different;
244 }
245
246 static int compare_cursor(cursor_t *cursor1, cursor_t *cursor2) {
247         int different = 0;
248         if(!different &&
249            ((cursor1->id != cursor2->id) ||
250            (cursor1->width != cursor2->width) ||
251            (cursor1->height != cursor2->height) ||
252            (cursor1->xhot != cursor2->xhot) ||
253            (cursor1->yhot != cursor2->yhot)))
254                 different = 1;
255         if(!different &&
256            ((cursor1->lvc.version != cursor2->lvc.version) ||
257            (cursor1->lvc.characts != cursor2->lvc.characts)))
258                 different = 1;
259         return different;
260 }
261
262 static int compare_cursor_group(cursor_group_t *cursor_group1, cursor_group_t *cursor_group2) {
263         int different = 0;
264         cursor_t *cursor1 = NULL, *cursor2 = NULL;
265         if(!different &&
266            ((cursor_group1->memopt != cursor_group2->memopt) ||
267            (cursor_group1->lvc.version != cursor_group2->lvc.version) ||
268            (cursor_group1->lvc.characts != cursor_group2->lvc.characts)))
269                 different = 1;
270         if(!different &&
271            (cursor_group1->ncursor != cursor_group2->ncursor))
272                 different = 1;
273         if(!different) {
274                 cursor1 = cursor_group1->cursorlist;
275                 cursor2 = cursor_group2->cursorlist;
276                 while(!different && cursor1 && cursor2) {
277                         different = compare_cursor(cursor1, cursor2);
278                         cursor1 = cursor1->next;
279                         cursor2 = cursor2->next;
280                 }
281                 if(!different &&
282                    ((cursor1 && !cursor2) ||
283                    (!cursor1 && cursor2)))
284                         different = 1;
285         }
286         return different;
287 }
288
289 static int compare_control(control_t *control1, control_t *control2) {
290         int different = 0;
291         char *nameid = NULL;
292         if(!different &&
293                 ((control1 && !control2) ||
294                 (!control1 && control2)))
295                         different = 1;
296         if(different || !control1 || !control2)
297                 return different;
298         nameid = strdup(get_nameid_str(control1->ctlclass));
299         if(!different && strcmp(nameid, get_nameid_str(control2->ctlclass)))
300                 different = 1;
301         free(nameid);
302         if(!different && 
303            (control1->id != control2->id))
304                 different = 1;
305         if(!different && control1->gotstyle && control2->gotstyle) {
306                 if((!control1->style || !control2->style) ||
307                    (control1->style->and_mask || control2->style->and_mask) ||
308                    (control1->style->or_mask != control2->style->or_mask))
309                         different = 1;
310         } else if(!different &&
311                   ((control1->gotstyle && !control2->gotstyle) ||
312                   (!control1->gotstyle && control2->gotstyle)))
313                         different = 1;
314         if(!different && control1->gotexstyle && control2->gotexstyle) {
315                 if((!control1->exstyle || !control2->exstyle) ||
316                    (control1->exstyle->and_mask || control2->exstyle->and_mask) ||
317                    (control1->exstyle->or_mask != control2->exstyle->or_mask))
318                         different = 1;
319         } else if(!different &&
320                   ((control1->gotexstyle && !control2->gotexstyle) ||
321                   (!control1->gotexstyle && control2->gotexstyle)))
322                         different = 1;
323         if(!different && control1->gothelpid && control2->gothelpid) {
324                 if(control1->helpid != control2->helpid)
325                         different = 1;
326         } else if(!different &&
327                   ((control1->gothelpid && !control2->gothelpid) ||
328                   (!control1->gothelpid && control2->gothelpid)))
329                         different = 1;
330         return different;
331 }
332
333 static int compare_dialog(dialog_t *dialog1, dialog_t *dialog2) {
334         int different = 0;
335         char *nameid = NULL;
336         if(!different &&
337            ((dialog1->memopt != dialog2->memopt) ||
338            (dialog1->lvc.version != dialog2->lvc.version) ||
339            (dialog1->lvc.characts != dialog2->lvc.characts)))
340                 different = 1;
341         if(!different && dialog1->gotstyle && dialog2->gotstyle) {
342                 if((!dialog1->style || !dialog2->style) ||
343                    (dialog1->style->and_mask || dialog2->style->and_mask) ||
344                    (dialog1->style->or_mask != dialog2->style->or_mask))
345                         different = 1;
346         } else if(!different &&
347                   ((dialog1->gotstyle && !dialog2->gotstyle) ||
348                   (!dialog1->gotstyle && dialog2->gotstyle)))
349                         different = 1;
350         if(!different && dialog1->gotexstyle && dialog2->gotexstyle) {
351                 if((!dialog1->exstyle || !dialog2->exstyle) ||
352                    (dialog1->exstyle->and_mask || dialog2->exstyle->and_mask) ||
353                    (dialog1->exstyle->or_mask != dialog2->exstyle->or_mask))
354                         different = 1;
355         } else if(!different &&
356                   ((dialog1->gotexstyle && !dialog2->gotexstyle) ||
357                   (!dialog1->gotexstyle && dialog2->gotexstyle)))
358                         different = 1;
359         nameid = strdup(get_nameid_str(dialog1->menu));
360         if(!different && strcmp(nameid, get_nameid_str(dialog2->menu)))
361                 different = 1;
362         free(nameid);
363         nameid = strdup(get_nameid_str(dialog1->dlgclass));
364         if(!different && strcmp(nameid, get_nameid_str(dialog2->dlgclass)))
365                 different = 1;
366         free(nameid);
367         if(!different)
368                 different = compare_control(dialog1->controls, dialog2->controls);
369         return different;
370 }
371
372 static int compare_dialogex(dialogex_t *dialogex1, dialogex_t *dialogex2) {
373         int different = 0;
374         char *nameid = NULL;
375         if(!different &&
376            ((dialogex1->memopt != dialogex2->memopt) ||
377            (dialogex1->lvc.version != dialogex2->lvc.version) ||
378            (dialogex1->lvc.characts != dialogex2->lvc.characts)))
379                 different = 1;
380         if(!different && dialogex1->gotstyle && dialogex2->gotstyle) {
381                 if((!dialogex1->style || !dialogex2->style) ||
382                    (dialogex1->style->and_mask || dialogex2->style->and_mask) ||
383                    (dialogex1->style->or_mask != dialogex2->style->or_mask))
384                         different = 1;
385         } else if(!different &&
386                   ((dialogex1->gotstyle && !dialogex2->gotstyle) ||
387                   (!dialogex1->gotstyle && dialogex2->gotstyle)))
388                         different = 1;
389         if(!different && dialogex1->gotexstyle && dialogex2->gotexstyle) {
390                 if((!dialogex1->exstyle || !dialogex2->exstyle) ||
391                    (dialogex1->exstyle->and_mask || dialogex2->exstyle->and_mask) ||
392                    (dialogex1->exstyle->or_mask != dialogex2->exstyle->or_mask))
393                         different = 1;
394         } else if(!different &&
395                   ((dialogex1->gotexstyle && !dialogex2->gotexstyle) ||
396                   (!dialogex1->gotexstyle && dialogex2->gotexstyle)))
397                         different = 1;
398         if(!different && dialogex1->gothelpid && dialogex2->gothelpid) {
399                 if(dialogex1->helpid != dialogex2->helpid)
400                         different = 1;
401         } else if(!different &&
402                   ((dialogex1->gothelpid && !dialogex2->gothelpid) ||
403                   (!dialogex1->gothelpid && dialogex2->gothelpid)))
404                         different = 1;
405         nameid = strdup(get_nameid_str(dialogex1->menu));
406         if(!different && strcmp(nameid, get_nameid_str(dialogex2->menu)))
407                 different = 1;
408         free(nameid);
409         nameid = strdup(get_nameid_str(dialogex1->dlgclass));
410         if(!different && strcmp(nameid, get_nameid_str(dialogex2->dlgclass)))
411                 different = 1;
412         free(nameid);
413         if(!different)
414                 different = compare_control(dialogex1->controls, dialogex2->controls);
415         return different;
416 }
417
418 static int compare_font(font_t *font1, font_t *font2) {
419         int different = 0;
420         if(!different &&
421            ((font1->memopt != font2->memopt) ||
422            (font1->data->lvc.version != font2->data->lvc.version) ||
423            (font1->data->lvc.characts != font2->data->lvc.characts)))
424                 different = 1;
425         return different;
426 }
427
428 static int compare_fontdir(fontdir_t *fontdir1, fontdir_t *fontdir2) {
429         int different = 0;
430         if(!different &&
431            ((fontdir1->memopt != fontdir2->memopt) ||
432            (fontdir1->data->lvc.version != fontdir2->data->lvc.version) ||
433            (fontdir1->data->lvc.characts != fontdir2->data->lvc.characts)))
434                 different = 1;
435         return different;
436 }
437
438 static int compare_icon(icon_t *icon1, icon_t *icon2) {
439         int different = 0;
440         if(!different &&
441            ((icon1->id != icon2->id) ||
442            (icon1->width != icon2->width) ||
443            (icon1->height != icon2->height)))
444                 different = 1;
445         if(!different &&
446            ((icon1->lvc.version != icon2->lvc.version) ||
447            (icon1->lvc.characts != icon2->lvc.characts)))
448                 different = 1;
449         return different;
450 }
451
452 static int compare_icon_group(icon_group_t *icon_group1, icon_group_t *icon_group2) {
453         int different = 0;
454         icon_t *icon1 = NULL, *icon2 = NULL;
455         if(!different &&
456            ((icon_group1->memopt != icon_group2->memopt) ||
457            (icon_group1->lvc.version != icon_group2->lvc.version) ||
458            (icon_group1->lvc.characts != icon_group2->lvc.characts)))
459                 different = 1;
460         if(!different &&
461            (icon_group1->nicon != icon_group2->nicon))
462                 different = 1;
463         if(!different) {
464                 icon1 = icon_group1->iconlist;
465                 icon2 = icon_group2->iconlist;
466                 while(!different && icon1 && icon2) {
467                         different = compare_icon(icon1, icon2);
468                         icon1 = icon1->next;
469                         icon2 = icon2->next;
470                 }
471                 if(!different &&
472                    ((icon1 && !icon2) ||
473                    (!icon1 && icon2)))
474                         different = 1;
475         }
476         return different;
477 }
478
479 static int compare_menu_item(menu_item_t *menu_item1, menu_item_t *menu_item2) {
480         int different = 0;
481         while(!different && menu_item1 && menu_item2) {
482                 if(menu_item1->popup && menu_item2->popup)
483                         different = compare_menu_item(menu_item1->popup, menu_item2->popup);
484                 else if(!menu_item1->popup && !menu_item2->popup) {
485                         if(menu_item1->name && menu_item2->name) {
486                                 if((menu_item1->id != menu_item2->id) ||
487                                    (menu_item1->state != menu_item2->state))
488                                         different = 1;
489                         } else if((menu_item1->name && !menu_item2->name) ||
490                                   (!menu_item1->name && menu_item2->name))
491                                         different = 1;
492                 } else
493                         different = 1;
494                 menu_item1 = menu_item1->next;
495                 menu_item2 = menu_item2->next;
496         }
497         if(!different &&
498            ((menu_item1 && !menu_item2) ||
499            (!menu_item1 && menu_item2)))
500                 different = 1;
501         return different;
502 }
503
504 static int compare_menu(menu_t *menu1, menu_t *menu2) {
505         int different = 0;
506         if(!different &&
507            ((menu1->memopt != menu2->memopt) ||
508            (menu1->lvc.version != menu2->lvc.version) ||
509            (menu1->lvc.characts != menu2->lvc.characts)))
510                 different = 1;
511         if(!different)
512                 different = compare_menu_item(menu1->items, menu2->items);
513         return different;
514 }
515
516 static int compare_menuex_item(menuex_item_t *menuex_item1, menuex_item_t *menuex_item2) {
517         int different = 0;
518         while(!different && menuex_item1 && menuex_item2) {
519                 if(menuex_item1->popup && menuex_item2->popup) {
520                         if(!different && menuex_item1->gotid && menuex_item2->gotid) {
521                                 if(menuex_item1->id != menuex_item2->id)
522                                         different = 1;
523                         } else if(!different &&
524                                   ((menuex_item1->gotid && !menuex_item2->gotid) ||
525                                   (!menuex_item2->gotid && menuex_item2->gotid)))
526                                         different = 1;
527                         if(!different && menuex_item1->gottype && menuex_item2->gottype) {
528                                 if(menuex_item1->type != menuex_item2->type)
529                                         different = 1;
530                         } else if(!different &&
531                                   ((menuex_item1->gottype && !menuex_item2->gottype) ||
532                                   (!menuex_item2->gottype && menuex_item2->gottype)))
533                                         different = 1;
534                         if(!different && menuex_item1->gotstate && menuex_item2->gotstate) {
535                                 if(menuex_item1->state != menuex_item2->state)
536                                         different = 1;
537                         } else if(!different &&
538                                   ((menuex_item1->gotstate && !menuex_item2->gotstate) ||
539                                   (!menuex_item2->gotstate && menuex_item2->gotstate)))
540                                         different = 1;
541                         if(!different && menuex_item1->gothelpid && menuex_item2->gothelpid) {
542                                 if(menuex_item1->helpid != menuex_item2->helpid)
543                                         different = 1;
544                         } else if(!different &&
545                                   ((menuex_item1->gothelpid && !menuex_item2->gothelpid) ||
546                                   (!menuex_item2->gothelpid && menuex_item2->gothelpid)))
547                                         different = 1;
548                         if(!different)
549                                 different = compare_menuex_item(menuex_item1->popup, menuex_item2->popup);
550                 } else if(!menuex_item1->popup && !menuex_item2->popup) {
551                         if(menuex_item1->name && menuex_item2->name) {
552                                 if(!different && menuex_item1->gotid && menuex_item2->gotid) {
553                                         if(menuex_item1->id != menuex_item2->id)
554                                                 different = 1;
555                                 } else if(!different &&
556                                           ((menuex_item1->gotid && !menuex_item2->gotid) ||
557                                           (!menuex_item2->gotid && menuex_item2->gotid)))
558                                                 different = 1;
559                                 if(!different && menuex_item1->gottype && menuex_item2->gottype) {
560                                         if(menuex_item1->type != menuex_item2->type)
561                                                 different = 1;
562                                 } else if(!different &&
563                                           ((menuex_item1->gottype && !menuex_item2->gottype) ||
564                                           (!menuex_item2->gottype && menuex_item2->gottype)))
565                                                 different = 1;
566                                 if(!different && menuex_item1->gotstate && menuex_item2->gotstate) {
567                                         if(menuex_item1->state != menuex_item2->state)
568                                                 different = 1;
569                                 } else if(!different &&
570                                           ((menuex_item1->gotstate && !menuex_item2->gotstate) ||
571                                           (!menuex_item2->gotstate && menuex_item2->gotstate)))
572                                                 different = 1;
573                                 if(!different && menuex_item1->gothelpid && menuex_item2->gothelpid) {
574                                         if(menuex_item1->helpid != menuex_item2->helpid)
575                                                 different = 1;
576                                 } else if(!different &&
577                                           ((menuex_item1->gothelpid && !menuex_item2->gothelpid) ||
578                                           (!menuex_item2->gothelpid && menuex_item2->gothelpid)))
579                                                 different = 1;
580                         } else if((menuex_item1->name && !menuex_item2->name) ||
581                                   (!menuex_item1->name && menuex_item2->name))
582                                         different = 1;
583                 } else
584                         different = 1;
585                 menuex_item1 = menuex_item1->next;
586                 menuex_item2 = menuex_item2->next;
587         }
588         if(!different &&
589            ((menuex_item1 && !menuex_item2) ||
590            (!menuex_item1 && menuex_item2)))
591                 different = 1;
592         return different;
593 }
594
595 static int compare_menuex(menuex_t *menuex1, menuex_t *menuex2) {
596         int different = 0;
597         if(!different &&
598            ((menuex1->memopt != menuex2->memopt) ||
599            (menuex1->lvc.version != menuex2->lvc.version) ||
600            (menuex1->lvc.characts != menuex2->lvc.characts)))
601                 different = 1;
602         if(!different)
603                 different = compare_menuex_item(menuex1->items, menuex2->items);
604         return different;
605 }
606
607 static int compare_rcdata(rcdata_t *rcdata1, rcdata_t *rcdata2) {
608         int different = 0;
609         if(!different &&
610            ((rcdata1->memopt != rcdata2->memopt) ||
611            (rcdata1->data->lvc.version != rcdata2->data->lvc.version) ||
612            (rcdata1->data->lvc.characts != rcdata2->data->lvc.characts)))
613                 different = 1;
614         return different;
615 }
616
617 static int compare_stringtable(stringtable_t *stringtable1, stringtable_t *stringtable2) {
618         int different = 0;
619         int i;
620         while(!different && stringtable1 && stringtable2) {
621                 if((stringtable1->memopt != stringtable2->memopt) ||
622                    (stringtable1->lvc.version != stringtable2->lvc.version) ||
623                    (stringtable1->lvc.characts != stringtable2->lvc.characts))
624                         different = 1;
625                 if(!different) {
626                         if((stringtable1->nentries != stringtable2->nentries) ||
627                            (stringtable1->idbase != stringtable2->idbase))
628                                 different = 1;
629                         else
630                                 for(i = 0 ; i < stringtable1->nentries; i++)
631                                         if((stringtable1->entries[i].id != stringtable2->entries[i].id) ||
632                                            (stringtable1->entries[i].memopt != stringtable2->entries[i].memopt) ||
633                                            (stringtable1->entries[i].str && !stringtable2->entries[i].str) ||
634                                            (!stringtable1->entries[i].str && stringtable2->entries[i].str)) {
635                                                 different = 1;
636                                                 break;
637                                         }
638                 }
639                 stringtable1 = stringtable1->next;
640                 stringtable2 = stringtable2->next;
641         }
642         return different;
643 }
644
645 static int compare_user(user_t *user1, user_t *user2) {
646         int different = 0;
647         char *nameid = NULL;
648         if(!different &&
649            ((user1->memopt != user2->memopt) ||
650            (user1->data->lvc.version != user2->data->lvc.version) ||
651            (user1->data->lvc.characts != user2->data->lvc.characts)))
652                 different = 1;
653         nameid = strdup(get_nameid_str(user1->type));
654         if(!different && strcmp(nameid, get_nameid_str(user2->type)))
655                 different = 1;
656         free(nameid);
657         return different;
658 }
659
660 static int compare_messagetable(messagetable_t *messagetable1, messagetable_t *messagetable2) {
661         int different = 0;
662         if(!different &&
663            ((messagetable1->memopt != messagetable2->memopt) ||
664            (messagetable1->data->lvc.version != messagetable2->data->lvc.version) ||
665            (messagetable1->data->lvc.characts != messagetable2->data->lvc.characts)))
666                 different = 1;
667         return different;
668 }
669
670 static int compare_string(string_t *string1, string_t *string2) {
671         int different = 0;
672         if(!different &&
673            ((string1->size != string2->size) ||
674            (string1->type != string2->type)))
675                 different = 1;
676         if(!different) {
677                 if(string1->type == str_char)
678                         different = memcmp(string1->str.cstr, string2->str.cstr, string1->size);
679                 else if(string1->type == str_unicode)
680                         different = memcmp(string1->str.wstr, string2->str.wstr, string1->size*sizeof(WCHAR));
681                 else
682                         different = 1;
683         }
684         return different;
685 }
686
687 static int compare_ver_block(ver_block_t *ver_block1, ver_block_t *ver_block2);
688
689 static int compare_ver_value(ver_value_t *ver_value1, ver_value_t *ver_value2) {
690         int different = 0;
691         int i = 0;
692         if(!different &&
693            (ver_value1->type == ver_value2->type)) {
694                 switch(ver_value1->type) {
695                         case val_str:
696                                 if(!different && ver_value1->key && ver_value2->key)
697                                         different = compare_string(ver_value1->key, ver_value2->key);
698                                 else if(!different &&
699                                         ((ver_value1->key && !ver_value2->key) ||
700                                         (!ver_value1->key && ver_value2->key)))
701                                                 different = 1;
702                                 break;
703                         case val_words:
704                                 if(!different && ver_value1->key && ver_value2->key)
705                                         different = compare_string(ver_value1->key, ver_value2->key);
706                                 else if(!different &&
707                                         ((ver_value1->key && !ver_value2->key) ||
708                                         (!ver_value1->key && ver_value2->key)))
709                                                 different = 1;
710                                 if(!different && ver_value1->value.words && ver_value2->value.words) {
711                                         if(!different &&
712                                            (ver_value1->value.words->nwords != ver_value2->value.words->nwords))
713                                                 different = 1;
714                                         if(!different)
715                                                 for(i = 0; i < ver_value1->value.words->nwords; i++) {
716                                                         if(ver_value1->value.words->words[i] != ver_value2->value.words->words[i]) {
717                                                                 different = 1;
718                                                                 break;
719                                                         }
720                                                 }
721                                 } else if(!different &&
722                                           ((ver_value1->value.words && !ver_value2->value.words) ||
723                                           (!ver_value1->value.words && ver_value2->value.words)))
724                                                 different = 1;
725                                 break;
726                         case val_block:
727                                 if(!different && ver_value1->value.block && ver_value2->value.block)
728                                         different = compare_ver_block(ver_value1->value.block, ver_value2->value.block);
729                                 else if(!different &&
730                                         ((ver_value1->value.block && !ver_value2->value.block) ||
731                                         (!ver_value1->value.block && ver_value2->value.block)))
732                                                 different = 1;
733                                 break;
734                         default:
735                                 different = 1;
736                 }
737         } else
738                 different = 1;
739         return different;
740 }
741
742 static int compare_ver_block(ver_block_t *ver_block1, ver_block_t *ver_block2) {
743         int different = 0;
744         ver_value_t *ver_value1 = NULL, *ver_value2 = NULL;
745         if(!different) {
746                 ver_value1 = ver_block1->values;
747                 ver_value2 = ver_block2->values;
748                 while(!different && ver_value1 && ver_value2) {
749                         different = compare_ver_value(ver_value1, ver_value2);
750                         ver_value1 = ver_value1->next;
751                         ver_value2 = ver_value2->next;
752                 }
753                 if(!different &&
754                    ((ver_value1 && !ver_value2) ||
755                    (!ver_value1 && ver_value2)))
756                         different = 1;
757         }
758         return different;
759 }
760
761 static int compare_versioninfo(versioninfo_t *versioninfo1, versioninfo_t *versioninfo2) {
762         int different = 0;
763         ver_block_t *ver_block1 = NULL, *ver_block2 = NULL;
764         if(!different &&
765            ((versioninfo1->memopt != versioninfo2->memopt) ||
766            (versioninfo1->lvc.version != versioninfo2->lvc.version) ||
767            (versioninfo1->lvc.characts != versioninfo2->lvc.characts)))
768                 different = 1;
769         if(!different && versioninfo1->gotit.fv && versioninfo2->gotit.fv) {
770                 if((versioninfo1->filever_maj1 != versioninfo2->filever_maj1) ||
771                    (versioninfo1->filever_maj2 != versioninfo2->filever_maj2) ||
772                    (versioninfo1->filever_min1 != versioninfo2->filever_min1) ||
773                    (versioninfo1->filever_min2 != versioninfo2->filever_min2))
774                         different = 1;
775         } else if(!different &&
776                   ((versioninfo1->gotit.fv && !versioninfo2->gotit.fv) ||
777                   (!versioninfo1->gotit.fv && versioninfo2->gotit.fv)))
778                         different = 1;
779         if(!different && versioninfo1->gotit.pv && versioninfo2->gotit.pv) {
780                 if((versioninfo1->prodver_maj1 != versioninfo2->prodver_maj1) ||
781                    (versioninfo1->prodver_maj2 != versioninfo2->prodver_maj2) ||
782                    (versioninfo1->prodver_min1 != versioninfo2->prodver_min1) ||
783                    (versioninfo1->prodver_min2 != versioninfo2->prodver_min2))
784                         different = 1;
785         } else if(!different &&
786                   ((versioninfo1->gotit.pv && !versioninfo2->gotit.pv) ||
787                   (!versioninfo1->gotit.pv && versioninfo2->gotit.pv)))
788                         different = 1;
789         if(!different && versioninfo1->gotit.fo && versioninfo2->gotit.fo) {
790                 if(versioninfo1->fileos != versioninfo2->fileos)
791                         different = 1;
792         } else if(!different &&
793                   ((versioninfo1->gotit.fo && !versioninfo2->gotit.fo) ||
794                   (!versioninfo1->gotit.fo && versioninfo2->gotit.fo)))
795                         different = 1;
796         if(!different && versioninfo1->gotit.ff && versioninfo2->gotit.ff) {
797                 if(versioninfo1->fileflags != versioninfo2->fileflags)
798                         different = 1;
799         } else if(!different &&
800                   ((versioninfo1->gotit.ff && !versioninfo2->gotit.ff) ||
801                   (!versioninfo1->gotit.ff && versioninfo2->gotit.ff)))
802                         different = 1;
803         if(!different && versioninfo1->gotit.ffm && versioninfo2->gotit.ffm) {
804                 if(versioninfo1->fileflagsmask != versioninfo2->fileflagsmask)
805                         different = 1;
806         } else if(!different &&
807                   ((versioninfo1->gotit.ffm && !versioninfo2->gotit.ffm) ||
808                   (!versioninfo1->gotit.ffm && versioninfo2->gotit.ffm)))
809                         different = 1;
810         if(!different && versioninfo1->gotit.ft && versioninfo2->gotit.ft) {
811                 if(versioninfo1->filetype != versioninfo2->filetype)
812                         different = 1;
813         } else if(!different &&
814                   ((versioninfo1->gotit.ft && !versioninfo2->gotit.ft) ||
815                   (!versioninfo1->gotit.ft && versioninfo2->gotit.ft)))
816                         different = 1;
817         if(!different && versioninfo1->gotit.fst && versioninfo2->gotit.fst) {
818                 if(versioninfo1->filesubtype != versioninfo2->filesubtype)
819                         different = 1;
820         } else if(!different &&
821                   ((versioninfo1->gotit.fst && !versioninfo2->gotit.fst) ||
822                   (!versioninfo1->gotit.fst && versioninfo2->gotit.fst)))
823                         different = 1;
824         if(!different) {
825                 ver_block1 = versioninfo1->blocks;
826                 ver_block2 = versioninfo2->blocks;
827                 while(!different && ver_block1 && ver_block2) {
828                         different = compare_ver_block(ver_block1, ver_block2);
829                         ver_block1 = ver_block1->next;
830                         ver_block2 = ver_block2->next;
831                 }
832                 if(!different &&
833                    ((ver_block1 && !ver_block2) ||
834                    (ver_block1 && !ver_block2)))
835                         different = 1;
836         }
837         return different;
838 }
839
840 static int compare_dlginit(dlginit_t *dlginit1, dlginit_t *dlginit2) {
841         int different = 0;
842         if(!different &&
843            ((dlginit1->memopt != dlginit2->memopt) ||
844            (dlginit1->data->lvc.version != dlginit2->data->lvc.version) ||
845            (dlginit1->data->lvc.characts != dlginit2->data->lvc.characts)))
846                 different = 1;
847         return different;
848 }
849
850 static int compare_toolbar_item(toolbar_item_t *toolbar_item1, toolbar_item_t *toolbar_item2) {
851         int different = 0;
852         while(!different && toolbar_item1 && toolbar_item2) {
853                 if((toolbar_item1->id && !toolbar_item2->id) ||
854                    (!toolbar_item1->id && toolbar_item2->id))
855                         different = 1;
856                 toolbar_item1 = toolbar_item1->next;
857                 toolbar_item2 = toolbar_item2->next;
858         }
859         if(!different &&
860            ((toolbar_item1 && !toolbar_item2) ||
861            (!toolbar_item1 && toolbar_item2)))
862                 different = 1;
863         return different;
864 }
865
866 static int compare_toolbar(toolbar_t *toolbar1, toolbar_t *toolbar2) {
867         int different = 0;
868         if(!different &&
869            ((toolbar1->memopt != toolbar2->memopt) ||
870            (toolbar1->lvc.version != toolbar2->lvc.version) ||
871            (toolbar1->lvc.characts != toolbar2->lvc.characts)))
872                 different = 1;
873         if(!different)
874                 different = compare_toolbar_item(toolbar1->items, toolbar2->items);
875         return different;
876 }
877
878 static int compare_ani_curico(ani_curico_t *ani_curico1, ani_curico_t *ani_curico2) {
879         int different = 0;
880         if(!different &&
881            ((ani_curico1->memopt != ani_curico2->memopt) ||
882            (ani_curico1->data->lvc.version != ani_curico2->data->lvc.version) ||
883            (ani_curico1->data->lvc.characts != ani_curico2->data->lvc.characts)))
884                 different = 1;
885         return different;
886 }
887
888 static int compare(resource_t *resource1, resource_t *resource2) {
889         switch(resource1->type) {
890                 case res_acc:
891                         return compare_accelerator(resource1->res.acc, resource2->res.acc);
892                 case res_bmp:
893                         return compare_bitmap(resource1->res.bmp, resource2->res.bmp);
894                 case res_cur:
895                         return compare_cursor(resource1->res.cur, resource2->res.cur);
896                 case res_curg:
897                         return compare_cursor_group(resource1->res.curg, resource2->res.curg);
898                 case res_dlg:
899                         return compare_dialog(resource1->res.dlg, resource2->res.dlg);
900                 case res_dlgex:
901                         return compare_dialogex(resource1->res.dlgex, resource2->res.dlgex);
902                 case res_fnt:
903                         return compare_font(resource1->res.fnt, resource2->res.fnt);
904                 case res_fntdir:
905                         return compare_fontdir(resource1->res.fnd, resource2->res.fnd);
906                 case res_ico:
907                         return compare_icon(resource1->res.ico, resource2->res.ico);
908                 case res_icog:
909                         return compare_icon_group(resource1->res.icog, resource2->res.icog);
910                 case res_men:
911                         return compare_menu(resource1->res.men, resource2->res.men);
912                 case res_menex:
913                         return compare_menuex(resource1->res.menex, resource2->res.menex);
914                 case res_rdt:
915                         return compare_rcdata(resource1->res.rdt, resource2->res.rdt);
916                 case res_stt:
917                         return compare_stringtable(resource1->res.stt, resource2->res.stt);
918                 case res_usr:
919                         return compare_user(resource1->res.usr, resource2->res.usr);
920                 case res_msg:
921                         return compare_messagetable(resource1->res.msg, resource2->res.msg);
922                 case res_ver:
923                         return compare_versioninfo(resource1->res.ver, resource2->res.ver);
924                 case res_dlginit:
925                         return compare_dlginit(resource1->res.dlgi, resource2->res.dlgi);
926                 case res_toolbar:
927                         return compare_toolbar(resource1->res.tbt, resource2->res.tbt);
928                 case res_anicur:
929                 case res_aniico:
930                         return compare_ani_curico(resource1->res.ani, resource2->res.ani);
931                 default:
932                         /* Not supposed to reach here */
933                         fprintf(stderr, "Not supposed to reach here (compare())\n");
934                         abort();
935                         return -1;
936         }
937 }
938
939 void verify_translations(resource_t *top) {
940         enum lang_type_e lang_type;
941         enum res_e res_type;
942         int **presence;
943         int i, j;
944         char *nameid;
945         char **problems;
946         int nb_problems, last_problem;
947         int complete, needs_work, partial;
948         resource_t *next = top;
949
950         for(res_type = res_0; res_type <= res_usr; res_type++) {
951                 present_resources[res_type] = 0;
952                 for(lang_type = lang_type_master; lang_type <= lang_type_normal; lang_type++) {
953                         nb_resources[res_type][lang_type] = 0;
954                         list_resources[res_type][lang_type] = NULL;
955                 }
956         }
957
958         while(next) {
959                 switch(next->type) {
960                         case res_acc:
961                         case res_bmp:
962                         case res_cur:
963                         case res_curg:
964                         case res_dlg:
965                         case res_dlgex:
966                         case res_fnt:
967                         case res_fntdir:
968                         case res_ico:
969                         case res_icog:
970                         case res_men:
971                         case res_menex:
972                         case res_rdt:
973                         case res_stt:
974                         case res_usr:
975                         case res_msg:
976                         case res_ver:
977                         case res_dlginit:
978                         case res_toolbar:
979                         case res_anicur:
980                         case res_aniico:
981                                 add_resource(next);
982                                 break;
983                         default:
984                                 fprintf(stderr, "Report this: unknown resource type parsed %08x\n", next->type);
985                 }
986                 next = next->next;
987         }
988         present_resources[res_acc] = 1;
989         res_names[res_acc] = strdup("accelerator");
990         present_resources[res_bmp] = 1;
991         res_names[res_bmp] = strdup("bitmap");
992         present_resources[res_cur] = 1;
993         res_names[res_cur] = strdup("cursor");
994         present_resources[res_curg] = 1;
995         res_names[res_curg] = strdup("cursor_group");
996         present_resources[res_dlg] = 1;
997         res_names[res_dlg] = strdup("dialog");
998         present_resources[res_dlgex] = 1;
999         res_names[res_dlgex] = strdup("dialogex");
1000         present_resources[res_fnt] = 1;
1001         res_names[res_fnt] = strdup("font");
1002         present_resources[res_fntdir] = 1;
1003         res_names[res_fntdir] = strdup("fontdir");
1004         present_resources[res_ico] = 1;
1005         res_names[res_ico] = strdup("icon");
1006         present_resources[res_icog] = 1;
1007         res_names[res_icog] = strdup("icon_group");
1008         present_resources[res_men] = 1;
1009         res_names[res_men] = strdup("menu");
1010         present_resources[res_menex] = 1;
1011         res_names[res_menex] = strdup("menuex");
1012         present_resources[res_rdt] = 1;
1013         res_names[res_rdt] = strdup("rcdata");
1014         present_resources[res_stt] = 1;
1015         res_names[res_stt] = strdup("stringtable");
1016         present_resources[res_usr] = 1;
1017         res_names[res_usr] = strdup("user");
1018         present_resources[res_msg] = 1;
1019         res_names[res_msg] = strdup("messagetable");
1020         present_resources[res_ver] = 1;
1021         res_names[res_ver] = strdup("versioninfo");
1022         present_resources[res_dlginit] = 1;
1023         res_names[res_dlginit] = strdup("dlginit");
1024         present_resources[res_toolbar] = 1;
1025         res_names[res_toolbar] = strdup("toolbar");
1026         present_resources[res_anicur] = 1;
1027         res_names[res_anicur] = strdup("ani_cursor");
1028         present_resources[res_aniico] = 1;
1029         res_names[res_aniico] = strdup("ani_icon");
1030
1031         for(res_type = res_0; res_type <= res_usr; res_type++) {
1032                 if(!present_resources[res_type]) {
1033                         continue;
1034                 }
1035                 if(nb_resources[res_type][lang_type_normal] > 0) {
1036                         if(nb_resources[res_type][lang_type_master] && nb_resources[res_type][lang_type_neutral]) {
1037                                 fprintf(stderr, "Type %s:\n", res_names[res_type]);
1038                                 fprintf(stderr, "There are both a NEUTRAL and a MASTER version for %s, along with additional localized versions. The NEUTRAL versions will not be checked against other versions.\n", res_names[res_type]);
1039                         } else if(nb_resources[res_type][lang_type_neutral]) {
1040                                 fprintf(stderr, "Type %s:\n", res_names[res_type]);
1041                                 fprintf(stderr, "There are no MASTER version, but there are some NEUTRAL versions for %s, so will use those instead of MASTER for comparison.\n", res_names[res_type]);
1042                                 list_resources[res_type][lang_type_master] = list_resources[res_type][lang_type_neutral];
1043                                 nb_resources[res_type][lang_type_master] = nb_resources[res_type][lang_type_neutral];
1044                         } else if(!nb_resources[res_type][lang_type_master]) {
1045                                 fprintf(stderr, "Type %s:\n", res_names[res_type]);
1046                                 fprintf(stderr, "There are no NEUTRAL nor MASTER versions for %s, but there are some other localized versions. No comparison will be done at all.\n", res_names[res_type]);
1047                         }
1048                 } else {
1049                         if(nb_resources[res_type][lang_type_master] && nb_resources[res_type][lang_type_neutral]) {
1050                                 fprintf(stderr, "Type %s:\n", res_names[res_type]);
1051                                 fprintf(stderr, "There are both a NEUTRAL and a MASTER versions for %s, but no other localized version. No comparison will be done at all.\n", res_names[res_type]);
1052                         } else if(nb_resources[res_type][lang_type_master]) {
1053                                 fprintf(stderr, "Type %s:\n", res_names[res_type]);
1054                                 fprintf(stderr, "There are only MASTER versions for %s. No comparison will be done at all.\n", res_names[res_type]);
1055                         } else if(nb_resources[res_type][lang_type_neutral]) {
1056                                 /* fprintf(stderr, "There are only NEUTRAL versions for %s. No comparison will be done at all.\n", res_names[res_type]); */
1057                         } else {
1058                                 /* fprintf(stderr, "There are no versions at all for %s. No comparison will be done at all.\n", res_names[res_type]); */
1059                         }
1060                 }
1061
1062                 presence = malloc(nb_resources[res_type][lang_type_master]*sizeof(int *));
1063                 for(i = 0; i < nb_resources[res_type][lang_type_master]; i++) {
1064                         presence[i] = calloc(NB_LANG, sizeof(int));
1065                         presence[i][MASTER_LANGUAGE] = -1;
1066                 }
1067
1068                 for(i = 0; i < nb_resources[res_type][lang_type_normal]; i++) {
1069                         for(j = 0; j < nb_resources[res_type][lang_type_master]; j++) {
1070                                 nameid = strdup(get_nameid_str(list_resources[res_type][lang_type_normal][i]->name));
1071                                 if(!strcmp(nameid, get_nameid_str(list_resources[res_type][lang_type_master][j]->name))) {
1072                                         if(compare(list_resources[res_type][lang_type_normal][i], list_resources[res_type][lang_type_master][j])) {
1073                                                 presence[j][get_language_id(list_resources[res_type][lang_type_normal][i])] = 2;
1074                                                 /* fprintf(stderr, "Differences in type %s, ID %s, for language %s\n", res_names[res_type], nameid, get_language_name(get_language_id(list_resources[res_type][lang_type_normal][i]))); */
1075                                         } else {
1076                                                 presence[j][get_language_id(list_resources[res_type][lang_type_normal][i])] = 1;
1077                                         }
1078                                 }
1079                                 free(nameid);
1080                         }
1081                 }
1082
1083                 problems = malloc(sizeof(char *));
1084                 problems[0] = strdup("");
1085                 nb_problems = 0;
1086                 last_problem = -1;
1087                 for(i = 0; i < NB_LANG; i++) {
1088                         complete = 1;
1089                         needs_work = 0;
1090                         partial = 0;
1091                         for(j = 0; j < nb_resources[res_type][lang_type_master]; j++) {
1092                                 if(presence[j][i]) {
1093                                         partial = 1;
1094                                         if(presence[j][i] == 2) {
1095                                                 needs_work = 1;
1096                                                 problems = realloc(problems, (++nb_problems+1)*sizeof(char *));
1097                                                 problems[nb_problems] = malloc(strlen(get_nameid_str(list_resources[res_type][lang_type_master][j]->name)) + 9);
1098                                                 sprintf(problems[nb_problems], "DIFF %s %02x", get_nameid_str(list_resources[res_type][lang_type_master][j]->name), i);
1099                                                 if(last_problem == i) {
1100                                                         problems[nb_problems-1] = realloc(problems[nb_problems-1], strlen(problems[nb_problems-1]) + 3);
1101                                                         strcat(problems[nb_problems-1], " \\");
1102                                                 } else {
1103                                                         last_problem = i;
1104                                                 }
1105                                         }
1106                                 } else {
1107                                         complete = 0;
1108                                         problems = realloc(problems, (++nb_problems+1)*sizeof(char *));
1109                                         problems[nb_problems] = malloc(strlen(get_nameid_str(list_resources[res_type][lang_type_master][j]->name)) + 8);
1110                                         sprintf(problems[nb_problems], "ABS %s %02x", get_nameid_str(list_resources[res_type][lang_type_master][j]->name), i);
1111                                         if(last_problem == i) {
1112                                                 problems[nb_problems-1] = realloc(problems[nb_problems-1], strlen(problems[nb_problems-1]) + 3);
1113                                                 strcat(problems[nb_problems-1], " \\");
1114                                         } else {
1115                                                 last_problem = i;
1116                                         }
1117                                 }
1118                         }
1119                         if(complete && partial && !needs_work) {
1120                                 /* Support is complete, no need to do anything */
1121                                 /* fprintf(stderr, "Support for language %s is complete for %s.\n", get_language_name(i), res_names[res_type]); */
1122                                 printf(".");
1123                         } else if(complete && partial && needs_work) {
1124                                 /* Support is incomplete (differing resources), needs work */
1125                                 /* fprintf(stderr, "Support for language %s is incomplete (differing resources) for %s.\n", get_language_name(i), res_names[res_type]); */
1126                                 printf("x");
1127                         } else if(!complete && partial && !needs_work) {
1128                                 /* Support is incomplete (missing resources), needs work */
1129                                 /* fprintf(stderr, "Support for language %s is incomplete (missing resources) for %s.\n", get_language_name(i), res_names[res_type]); */
1130                                 printf("-");
1131                         } else if(!complete && partial && needs_work) {
1132                                 /* Support is incomplete (missing and differing resources), needs work */
1133                                 /* fprintf(stderr, "Support for language %s is incomplete (missing and differing resources) for %s.\n", get_language_name(i), res_names[res_type]); */
1134                                 printf("+");
1135                         } else if(!complete && !partial) {
1136                                 /* Support is totally absent, might be interesting to do */
1137                                 /* fprintf(stderr, "Support for language %s is absent for %s.\n", get_language_name(i), res_names[res_type]); */
1138                                 printf(" ");
1139                         } else {
1140                                 /* Support is not relevant, no need to do anything */
1141                                 /* fprintf(stderr, "Support for language %s is not relevant for %s.\n", get_language_name(i), res_names[res_type]); */
1142                                 printf("n");
1143                         }
1144                 }
1145                 printf("\n");
1146                 for(i = 1; i <= nb_problems; i++) {
1147                         printf("%s\n", problems[i]);
1148                         free(problems[i]);
1149                 }
1150                 free(problems[0]);
1151                 free(problems);
1152                 for(i = 0; i < nb_resources[res_type][lang_type_master]; i++)
1153                         free(presence[i]);
1154                 free(presence);
1155         }
1156 }