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