Hi all,

Another version, this time implemented more intelligently.

Since wrc already knows how to parse the resource files, it makes sense
to hook in it rather than use a dump and parse it. I added a new debug
flag to wrc to do just that (0x40).

All the functionnality of the bash script is not yet there, there's
still 2-3 things to add, but the base is already in good shape. And it's
way way faster to use (as in a couple seconds rather than almost 10
minutes before).

Already done:
- Reading of resource files (hook into wrc);
- Comparison functions for Windows resources, targetted for translation;
- Checking of differences between different languages with said
comparison functions.

Missing things:
- Languages for which some resources are not localized yet do not appear
at all;
- If both the MASTER and LANG_NEUTRAL languages are found for a kind of
resources, they won't be compared between themselves;
- It'd be nice to output the name of the language rather than it's
number;
- Better incorporation in the build system (Makefiles);
- Summary thing, to put on WineHQ.

The included v5 script runs the new wrc on each .rc file mentionned in
Makefiles. Capture the output to a file (>foo 2>&1) to analyze it for
now.

Any comments before the last stretch?

(Oups, just noticed some TODO comments are in French rather than
English... ah well, they should be gone by Monday or Tuesday anyway)

Vincent
Index: tools/wrc/Makefile.in
===================================================================
RCS file: /home/wine/wine/tools/wrc/Makefile.in,v
retrieving revision 1.28
diff -u -r1.28 Makefile.in
--- tools/wrc/Makefile.in	1 Sep 2003 23:59:41 -0000	1.28
+++ tools/wrc/Makefile.in	5 Oct 2003 03:08:53 -0000
@@ -15,6 +15,7 @@
 	genres.c \
 	newstruc.c \
 	readres.c \
+	translation.c \
 	utils.c \
 	wrc.c \
 	writeres.c
Index: tools/wrc/wrc.c
===================================================================
RCS file: /home/wine/wine/tools/wrc/wrc.c,v
retrieving revision 1.36
diff -u -r1.36 wrc.c
--- tools/wrc/wrc.c	18 Aug 2003 19:48:58 -0000	1.36
+++ tools/wrc/wrc.c	5 Oct 2003 03:08:53 -0000
@@ -39,6 +39,7 @@
 #include "utils.h"
 #include "readres.h"
 #include "dumpres.h"
+#include "translation.h"
 #include "genres.h"
 #include "newstruc.h"
 #include "parser.h"
@@ -97,6 +98,7 @@
 	"    * 0x08 Preprocessor messages\n"
 	"    * 0x10 Preprocessor lex messages\n"
 	"    * 0x20 Preprocessor yacc trace\n"
+	"    * 0x40 Verify translations\n"
 	"If no input filename is given and the output name is not overridden\n"
 	"with -o, then the output is written to \"wrc.tab.res\"\n"
 	;
@@ -123,6 +125,7 @@
  * debuglevel & DEBUGLEVEL_PPMSG	Preprocessor messages
  * debuglevel & DEBUGLEVEL_PPLEX	Preprocessor lex trace
  * debuglevel & DEBUGLEVEL_PPTRACE	Preprocessor yacc trace
+ * debuglevel & DEBUGLEVEL_TRANSLATION	Verify translations
  */
 int debuglevel = DEBUGLEVEL_NONE;
 
@@ -453,6 +456,12 @@
 
 	if(debuglevel & DEBUGLEVEL_DUMP)
 		dump_resources(resource_top);
+
+	if(debuglevel & DEBUGLEVEL_TRANSLATION)
+	{
+		verify_translations(resource_top);
+		exit(0);
+	}
 
 	/* Convert the internal lists to binary data */
 	resources2res(resource_top);
Index: tools/wrc/wrc.h
===================================================================
RCS file: /home/wine/wine/tools/wrc/wrc.h,v
retrieving revision 1.31
diff -u -r1.31 wrc.h
--- tools/wrc/wrc.h	5 Sep 2003 23:15:40 -0000	1.31
+++ tools/wrc/wrc.h	5 Oct 2003 03:08:53 -0000
@@ -45,6 +45,7 @@
 #define DEBUGLEVEL_PPMSG	0x0008
 #define DEBUGLEVEL_PPLEX	0x0010
 #define DEBUGLEVEL_PPTRACE	0x0020
+#define DEBUGLEVEL_TRANSLATION	0x0040
 
 extern int win32;
 extern int create_res;
--- /dev/null	2002-08-30 19:31:37.000000000 -0400
+++ tools/wrc/translation.c	2003-10-04 22:21:48.000000000 -0400
@@ -0,0 +1,799 @@
+/*
+ * Copyright 2003 Vincent Béron
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "translation.h"
+
+int master_language = LANG_ENGLISH;
+
+KEEP_RESOURCE(accelerator)
+KEEP_RESOURCE_RAW(bitmap)
+KEEP_RESOURCE(cursor)
+KEEP_RESOURCE(cursor_group)
+KEEP_RESOURCE(dialog)
+KEEP_RESOURCE(dialogex)
+KEEP_RESOURCE_RAW(font)
+KEEP_RESOURCE(icon)
+KEEP_RESOURCE(icon_group)
+KEEP_RESOURCE(menu)
+KEEP_RESOURCE(menuex)
+KEEP_RESOURCE_RAW(rcdata)
+KEEP_RESOURCE(stringtable)
+KEEP_RESOURCE_RAW(user)
+KEEP_RESOURCE_RAW(messagetable)
+KEEP_RESOURCE(versioninfo)
+KEEP_RESOURCE_RAW(dlginit)
+KEEP_RESOURCE(toolbar)
+KEEP_RESOURCE_RAW(ani_curico)
+
+static int compare_accelerator(accelerator_t *accelerator1, accelerator_t *accelerator2) {
+	int different = 0;
+	event_t *ev1 = NULL, *ev2 = NULL;
+	if(!different &&
+	   ((accelerator1->memopt != accelerator2->memopt) ||
+	   (accelerator1->lvc.version != accelerator2->lvc.version) ||
+	   (accelerator1->lvc.characts != accelerator2->lvc.characts)))
+		different = 1;
+	ev1 = accelerator1->events;
+	ev2 = accelerator2->events;
+	while(!different && ev1 && ev2) {
+		if(!different &&
+		   ((ev1->id != ev2->id) ||
+		   (ev1->flags != ev2->flags)))
+			different = 1;
+		ev1 = ev1->next;
+		ev2 = ev2->next;
+	}
+	if(!different &&
+	   ((ev1 && !ev2) || (!ev1 && ev2)))
+		different = 1;
+	return different;
+}
+
+static int compare_bitmap(bitmap_t *bitmap1, bitmap_t *bitmap2) {
+	int different = 0;
+	if(!different &&
+	   ((bitmap1->memopt != bitmap2->memopt) ||
+	   (bitmap1->data->lvc.version != bitmap2->data->lvc.version) ||
+	   (bitmap1->data->lvc.characts != bitmap2->data->lvc.characts)))
+		different = 1;
+	return different;
+}
+
+static int compare_cursor(cursor_t *cursor1, cursor_t *cursor2) {
+	int different = 0;
+	if(!different &&
+	   ((cursor1->id != cursor2->id) ||
+	   (cursor1->width != cursor2->width) ||
+	   (cursor1->height != cursor2->height) ||
+	   (cursor1->xhot != cursor2->xhot) ||
+	   (cursor1->yhot != cursor2->yhot)))
+		different = 1;
+	if(!different &&
+	   ((cursor1->lvc.version != cursor2->lvc.version) ||
+	   (cursor1->lvc.characts != cursor2->lvc.characts)))
+		different = 1;
+	return different;
+}
+
+static int compare_cursor_group(cursor_group_t *cursor_group1, cursor_group_t *cursor_group2) {
+	int different = 0;
+	cursor_t *cursor1 = NULL, *cursor2 = NULL;
+	if(!different &&
+	   ((cursor_group1->memopt != cursor_group2->memopt) ||
+	   (cursor_group1->lvc.version != cursor_group2->lvc.version) ||
+	   (cursor_group1->lvc.characts != cursor_group2->lvc.characts)))
+		different = 1;
+	if(!different &&
+	   (cursor_group1->ncursor != cursor_group2->ncursor))
+		different = 1;
+	if(!different) {
+		cursor1 = cursor_group1->cursorlist;
+		cursor2 = cursor_group2->cursorlist;
+		while(!different && cursor1 && cursor2) {
+			different = compare_cursor(cursor1, cursor2);
+			cursor1 = cursor1->next;
+			cursor2 = cursor2->next;
+		}
+		if(!different &&
+		   ((cursor1 && !cursor2) ||
+		   (!cursor1 && cursor2)))
+			different = 1;
+	}
+	return different;
+}
+
+static int compare_control(control_t *control1, control_t *control2) {
+	int different = 0;
+	char *nameid = NULL;
+	if(!different &&
+		((control1 && !control2) ||
+		(!control1 && control2)))
+			different = 1;
+	if(different || !control1 || !control2)
+		return different;
+	nameid = strdup(get_nameid_str(control1->ctlclass));
+	if(!different && strcmp(nameid, get_nameid_str(control2->ctlclass)))
+		different = 1;
+	free(nameid);
+	if(!different && 
+	   (control1->id != control2->id))
+		different = 1;
+	if(!different && control1->gotstyle && control2->gotstyle) {
+		if((!control1->style || !control2->style) ||
+		   (control1->style->and_mask || control2->style->and_mask) ||
+		   (control1->style->or_mask != control2->style->or_mask))
+			different = 1;
+	} else if(!different &&
+		  ((control1->gotstyle && !control2->gotstyle) ||
+		  (!control1->gotstyle && control2->gotstyle)))
+			different = 1;
+	if(!different && control1->gotexstyle && control2->gotexstyle) {
+		if((!control1->exstyle || !control2->exstyle) ||
+		   (control1->exstyle->and_mask || control2->exstyle->and_mask) ||
+		   (control1->exstyle->or_mask != control2->exstyle->or_mask))
+			different = 1;
+	} else if(!different &&
+		  ((control1->gotexstyle && !control2->gotexstyle) ||
+		  (!control1->gotexstyle && control2->gotexstyle)))
+			different = 1;
+	if(!different && control1->gothelpid && control2->gothelpid) {
+		if(control1->helpid != control2->helpid)
+			different = 1;
+	} else if(!different &&
+		  ((control1->gothelpid && !control2->gothelpid) ||
+		  (!control1->gothelpid && control2->gothelpid)))
+			different = 1;
+	return different;
+}
+
+static int compare_dialog(dialog_t *dialog1, dialog_t *dialog2) {
+	int different = 0;
+	char *nameid = NULL;
+	if(!different &&
+	   ((dialog1->memopt != dialog2->memopt) ||
+	   (dialog1->lvc.version != dialog2->lvc.version) ||
+	   (dialog1->lvc.characts != dialog2->lvc.characts)))
+		different = 1;
+	if(!different && dialog1->gotstyle && dialog2->gotstyle) {
+		if((!dialog1->style || !dialog2->style) ||
+		   (dialog1->style->and_mask || dialog2->style->and_mask) ||
+		   (dialog1->style->or_mask != dialog2->style->or_mask))
+			different = 1;
+	} else if(!different &&
+		  ((dialog1->gotstyle && !dialog2->gotstyle) ||
+		  (!dialog1->gotstyle && dialog2->gotstyle)))
+			different = 1;
+	if(!different && dialog1->gotexstyle && dialog2->gotexstyle) {
+		if((!dialog1->exstyle || !dialog2->exstyle) ||
+		   (dialog1->exstyle->and_mask || dialog2->exstyle->and_mask) ||
+		   (dialog1->exstyle->or_mask != dialog2->exstyle->or_mask))
+			different = 1;
+	} else if(!different &&
+		  ((dialog1->gotexstyle && !dialog2->gotexstyle) ||
+		  (!dialog1->gotexstyle && dialog2->gotexstyle)))
+			different = 1;
+	nameid = strdup(get_nameid_str(dialog1->menu));
+	if(!different && strcmp(nameid, get_nameid_str(dialog2->menu)))
+		different = 1;
+	free(nameid);
+	nameid = strdup(get_nameid_str(dialog1->dlgclass));
+	if(!different && strcmp(nameid, get_nameid_str(dialog2->dlgclass)))
+		different = 1;
+	free(nameid);
+	if(!different)
+		different = compare_control(dialog1->controls, dialog2->controls);
+	return different;
+}
+
+static int compare_dialogex(dialogex_t *dialogex1, dialogex_t *dialogex2) {
+	int different = 0;
+	char *nameid = NULL;
+	if(!different &&
+	   ((dialogex1->memopt != dialogex2->memopt) ||
+	   (dialogex1->lvc.version != dialogex2->lvc.version) ||
+	   (dialogex1->lvc.characts != dialogex2->lvc.characts)))
+		different = 1;
+	if(!different && dialogex1->gotstyle && dialogex2->gotstyle) {
+		if((!dialogex1->style || !dialogex2->style) ||
+		   (dialogex1->style->and_mask || dialogex2->style->and_mask) ||
+		   (dialogex1->style->or_mask != dialogex2->style->or_mask))
+			different = 1;
+	} else if(!different &&
+		  ((dialogex1->gotstyle && !dialogex2->gotstyle) ||
+		  (!dialogex1->gotstyle && dialogex2->gotstyle)))
+			different = 1;
+	if(!different && dialogex1->gotexstyle && dialogex2->gotexstyle) {
+		if((!dialogex1->exstyle || !dialogex2->exstyle) ||
+		   (dialogex1->exstyle->and_mask || dialogex2->exstyle->and_mask) ||
+		   (dialogex1->exstyle->or_mask != dialogex2->exstyle->or_mask))
+			different = 1;
+	} else if(!different &&
+		  ((dialogex1->gotexstyle && !dialogex2->gotexstyle) ||
+		  (!dialogex1->gotexstyle && dialogex2->gotexstyle)))
+			different = 1;
+	if(!different && dialogex1->gothelpid && dialogex2->gothelpid) {
+		if(dialogex1->helpid != dialogex2->helpid)
+			different = 1;
+	} else if(!different &&
+		  ((dialogex1->gothelpid && !dialogex2->gothelpid) ||
+		  (!dialogex1->gothelpid && dialogex2->gothelpid)))
+			different = 1;
+	nameid = strdup(get_nameid_str(dialogex1->menu));
+	if(!different && strcmp(nameid, get_nameid_str(dialogex2->menu)))
+		different = 1;
+	free(nameid);
+	nameid = strdup(get_nameid_str(dialogex1->dlgclass));
+	if(!different && strcmp(nameid, get_nameid_str(dialogex2->dlgclass)))
+		different = 1;
+	free(nameid);
+	if(!different)
+		different = compare_control(dialogex1->controls, dialogex2->controls);
+	return different;
+}
+
+static int compare_font(font_t *font1, font_t *font2) {
+	int different = 0;
+	if(!different &&
+	   ((font1->memopt != font2->memopt) ||
+	   (font1->data->lvc.version != font2->data->lvc.version) ||
+	   (font1->data->lvc.characts != font2->data->lvc.characts)))
+		different = 1;
+	return different;
+}
+
+static int compare_icon(icon_t *icon1, icon_t *icon2) {
+	int different = 0;
+	if(!different &&
+	   ((icon1->id != icon2->id) ||
+	   (icon1->width != icon2->width) ||
+	   (icon1->height != icon2->height)))
+		different = 1;
+	if(!different &&
+	   ((icon1->lvc.version != icon2->lvc.version) ||
+	   (icon1->lvc.characts != icon2->lvc.characts)))
+		different = 1;
+	return different;
+}
+
+static int compare_icon_group(icon_group_t *icon_group1, icon_group_t *icon_group2) {
+	int different = 0;
+	icon_t *icon1 = NULL, *icon2 = NULL;
+	if(!different &&
+	   ((icon_group1->memopt != icon_group2->memopt) ||
+	   (icon_group1->lvc.version != icon_group2->lvc.version) ||
+	   (icon_group1->lvc.characts != icon_group2->lvc.characts)))
+		different = 1;
+	if(!different &&
+	   (icon_group1->nicon != icon_group2->nicon))
+		different = 1;
+	if(!different) {
+		icon1 = icon_group1->iconlist;
+		icon2 = icon_group2->iconlist;
+		while(!different && icon1 && icon2) {
+			different = compare_icon(icon1, icon2);
+			icon1 = icon1->next;
+			icon2 = icon2->next;
+		}
+		if(!different &&
+		   ((icon1 && !icon2) ||
+		   (!icon1 && icon2)))
+			different = 1;
+	}
+	return different;
+}
+
+static int compare_menu_item(menu_item_t *menu_item1, menu_item_t *menu_item2) {
+	int different = 0;
+	while(!different && menu_item1 && menu_item2) {
+		if(menu_item1->popup && menu_item2->popup)
+			different = compare_menu_item(menu_item1->popup, menu_item2->popup);
+		else if(!menu_item1->popup && !menu_item2->popup) {
+			if(menu_item1->name && menu_item2->name) {
+				if((menu_item1->id != menu_item2->id) ||
+				   (menu_item1->state != menu_item2->state))
+					different = 1;
+			} else if((menu_item1->name && !menu_item2->name) ||
+				  (!menu_item1->name && menu_item2->name))
+					different = 1;
+		} else
+			different = 1;
+		menu_item1 = menu_item1->next;
+		menu_item2 = menu_item2->next;
+	}
+	if(!different &&
+	   ((menu_item1 && !menu_item2) ||
+	   (!menu_item1 && menu_item2)))
+		different = 1;
+	return different;
+}
+
+static int compare_menu(menu_t *menu1, menu_t *menu2) {
+	int different = 0;
+	if(!different &&
+	   ((menu1->memopt != menu2->memopt) ||
+	   (menu1->lvc.version != menu2->lvc.version) ||
+	   (menu1->lvc.characts != menu2->lvc.characts)))
+		different = 1;
+	if(!different)
+		different = compare_menu_item(menu1->items, menu2->items);
+	return different;
+}
+
+static int compare_menuex_item(menuex_item_t *menuex_item1, menuex_item_t *menuex_item2) {
+	int different = 0;
+	while(!different && menuex_item1 && menuex_item2) {
+		if(menuex_item1->popup && menuex_item2->popup) {
+			if(!different && menuex_item1->gotid && menuex_item2->gotid) {
+				if(menuex_item1->id != menuex_item2->id)
+					different = 1;
+			} else if(!different &&
+				  ((menuex_item1->gotid && !menuex_item2->gotid) ||
+				  (!menuex_item2->gotid && menuex_item2->gotid)))
+					different = 1;
+			if(!different && menuex_item1->gottype && menuex_item2->gottype) {
+				if(menuex_item1->type != menuex_item2->type)
+					different = 1;
+			} else if(!different &&
+				  ((menuex_item1->gottype && !menuex_item2->gottype) ||
+				  (!menuex_item2->gottype && menuex_item2->gottype)))
+					different = 1;
+			if(!different && menuex_item1->gotstate && menuex_item2->gotstate) {
+				if(menuex_item1->state != menuex_item2->state)
+					different = 1;
+			} else if(!different &&
+				  ((menuex_item1->gotstate && !menuex_item2->gotstate) ||
+				  (!menuex_item2->gotstate && menuex_item2->gotstate)))
+					different = 1;
+			if(!different && menuex_item1->gothelpid && menuex_item2->gothelpid) {
+				if(menuex_item1->helpid != menuex_item2->helpid)
+					different = 1;
+			} else if(!different &&
+				  ((menuex_item1->gothelpid && !menuex_item2->gothelpid) ||
+				  (!menuex_item2->gothelpid && menuex_item2->gothelpid)))
+					different = 1;
+			if(!different)
+				different = compare_menuex_item(menuex_item1->popup, menuex_item2->popup);
+		} else if(!menuex_item1->popup && !menuex_item2->popup) {
+			if(menuex_item1->name && menuex_item2->name) {
+				if(!different && menuex_item1->gotid && menuex_item2->gotid) {
+					if(menuex_item1->id != menuex_item2->id)
+						different = 1;
+				} else if(!different &&
+					  ((menuex_item1->gotid && !menuex_item2->gotid) ||
+					  (!menuex_item2->gotid && menuex_item2->gotid)))
+						different = 1;
+				if(!different && menuex_item1->gottype && menuex_item2->gottype) {
+					if(menuex_item1->type != menuex_item2->type)
+						different = 1;
+				} else if(!different &&
+					  ((menuex_item1->gottype && !menuex_item2->gottype) ||
+					  (!menuex_item2->gottype && menuex_item2->gottype)))
+						different = 1;
+				if(!different && menuex_item1->gotstate && menuex_item2->gotstate) {
+					if(menuex_item1->state != menuex_item2->state)
+						different = 1;
+				} else if(!different &&
+					  ((menuex_item1->gotstate && !menuex_item2->gotstate) ||
+					  (!menuex_item2->gotstate && menuex_item2->gotstate)))
+						different = 1;
+				if(!different && menuex_item1->gothelpid && menuex_item2->gothelpid) {
+					if(menuex_item1->helpid != menuex_item2->helpid)
+						different = 1;
+				} else if(!different &&
+					  ((menuex_item1->gothelpid && !menuex_item2->gothelpid) ||
+					  (!menuex_item2->gothelpid && menuex_item2->gothelpid)))
+						different = 1;
+			} else if((menuex_item1->name && !menuex_item2->name) ||
+				  (!menuex_item1->name && menuex_item2->name))
+					different = 1;
+		} else
+			different = 1;
+		menuex_item1 = menuex_item1->next;
+		menuex_item2 = menuex_item2->next;
+	}
+	if(!different &&
+	   ((menuex_item1 && !menuex_item2) ||
+	   (!menuex_item1 && menuex_item2)))
+		different = 1;
+	return different;
+}
+
+static int compare_menuex(menuex_t *menuex1, menuex_t *menuex2) {
+	int different = 0;
+	if(!different &&
+	   ((menuex1->memopt != menuex2->memopt) ||
+	   (menuex1->lvc.version != menuex2->lvc.version) ||
+	   (menuex1->lvc.characts != menuex2->lvc.characts)))
+		different = 1;
+	if(!different)
+		different = compare_menuex_item(menuex1->items, menuex2->items);
+	return different;
+}
+
+static int compare_rcdata(rcdata_t *rcdata1, rcdata_t *rcdata2) {
+	int different = 0;
+	if(!different &&
+	   ((rcdata1->memopt != rcdata2->memopt) ||
+	   (rcdata1->data->lvc.version != rcdata2->data->lvc.version) ||
+	   (rcdata1->data->lvc.characts != rcdata2->data->lvc.characts)))
+		different = 1;
+	return different;
+}
+
+static int compare_stringtable(stringtable_t *stringtable1, stringtable_t *stringtable2) {
+	int different = 0;
+	int i;
+	while(!different && stringtable1 && stringtable2) {
+		if((stringtable1->memopt != stringtable2->memopt) ||
+		   (stringtable1->lvc.version != stringtable2->lvc.version) ||
+		   (stringtable1->lvc.characts != stringtable2->lvc.characts))
+			different = 1;
+		if(!different) {
+			if((stringtable1->nentries != stringtable2->nentries) ||
+			   (stringtable1->idbase != stringtable2->idbase))
+				different = 1;
+			else
+				for(i = 0 ; i < stringtable1->nentries; i++)
+					if((stringtable1->entries[i].id != stringtable2->entries[i].id) ||
+					   (stringtable1->entries[i].memopt != stringtable2->entries[i].memopt) ||
+					   (stringtable1->entries[i].str && !stringtable2->entries[i].str) ||
+					   (!stringtable1->entries[i].str && stringtable2->entries[i].str)) {
+						different = 1;
+						break;
+					}
+		}
+		stringtable1 = stringtable1->next;
+		stringtable2 = stringtable2->next;
+	}
+	return different;
+}
+
+static int compare_user(user_t *user1, user_t *user2) {
+	int different = 0;
+	char *nameid = NULL;
+	if(!different &&
+	   ((user1->memopt != user2->memopt) ||
+	   (user1->data->lvc.version != user2->data->lvc.version) ||
+	   (user1->data->lvc.characts != user2->data->lvc.characts)))
+		different = 1;
+	nameid = strdup(get_nameid_str(user1->type));
+	if(!different && strcmp(nameid, get_nameid_str(user2->type)))
+		different = 1;
+	free(nameid);
+	return different;
+}
+
+static int compare_messagetable(messagetable_t *messagetable1, messagetable_t *messagetable2) {
+	int different = 0;
+	if(!different &&
+	   ((messagetable1->memopt != messagetable2->memopt) ||
+	   (messagetable1->data->lvc.version != messagetable2->data->lvc.version) ||
+	   (messagetable1->data->lvc.characts != messagetable2->data->lvc.characts)))
+		different = 1;
+	return different;
+}
+
+static int compare_string(string_t *string1, string_t *string2) {
+	int different = 0;
+	if(!different &&
+	   ((string1->size != string2->size) ||
+	   (string1->type != string2->type)))
+		different = 1;
+	if(!different) {
+		if(string1->type == str_char)
+			different = memcmp(string1->str.cstr, string2->str.cstr, string1->size);
+		else if(string1->type == str_unicode)
+			different = memcmp(string1->str.wstr, string2->str.wstr, string1->size*sizeof(WCHAR));
+		else
+			different = 1;
+	}
+	return different;
+}
+
+static int compare_ver_block(ver_block_t *ver_block1, ver_block_t *ver_block2);
+
+static int compare_ver_value(ver_value_t *ver_value1, ver_value_t *ver_value2) {
+	int different = 0;
+	int i = 0;
+	if(!different &&
+	   (ver_value1->type == ver_value2->type)) {
+		switch(ver_value1->type) {
+			case val_str:
+				if(!different && ver_value1->key && ver_value2->key)
+					different = compare_string(ver_value1->key, ver_value2->key);
+				else if(!different &&
+					((ver_value1->key && !ver_value2->key) ||
+					(!ver_value1->key && ver_value2->key)))
+						different = 1;
+				break;
+			case val_words:
+				if(!different && ver_value1->key && ver_value2->key)
+					different = compare_string(ver_value1->key, ver_value2->key);
+				else if(!different &&
+					((ver_value1->key && !ver_value2->key) ||
+					(!ver_value1->key && ver_value2->key)))
+						different = 1;
+				if(!different && ver_value1->value.words && ver_value2->value.words) {
+					if(!different &&
+					   (ver_value1->value.words->nwords != ver_value2->value.words->nwords))
+						different = 1;
+					if(!different)
+						for(i = 0; i < ver_value1->value.words->nwords; i++) {
+							if(ver_value1->value.words->words[i] != ver_value2->value.words->words[i]) {
+								different = 1;
+								break;
+							}
+						}
+				} else if(!different &&
+					  ((ver_value1->value.words && !ver_value2->value.words) ||
+					  (!ver_value1->value.words && ver_value2->value.words)))
+						different = 1;
+				break;
+			case val_block:
+				if(!different && ver_value1->value.block && ver_value2->value.block)
+					different = compare_ver_block(ver_value1->value.block, ver_value2->value.block);
+				else if(!different &&
+					((ver_value1->value.block && !ver_value2->value.block) ||
+					(!ver_value1->value.block && ver_value2->value.block)))
+						different = 1;
+				break;
+			default:
+				different = 1;
+		}
+	} else
+		different = 1;
+	return different;
+}
+
+static int compare_ver_block(ver_block_t *ver_block1, ver_block_t *ver_block2) {
+	int different = 0;
+	ver_value_t *ver_value1 = NULL, *ver_value2 = NULL;
+	if(!different) {
+		ver_value1 = ver_block1->values;
+		ver_value2 = ver_block2->values;
+		while(!different && ver_value1 && ver_value2) {
+			different = compare_ver_value(ver_value1, ver_value2);
+			ver_value1 = ver_value1->next;
+			ver_value2 = ver_value2->next;
+		}
+		if(!different &&
+		   ((ver_value1 && !ver_value2) ||
+		   (!ver_value1 && ver_value2)))
+			different = 1;
+	}
+	return different;
+}
+
+static int compare_versioninfo(versioninfo_t *versioninfo1, versioninfo_t *versioninfo2) {
+	int different = 0;
+	ver_block_t *ver_block1 = NULL, *ver_block2 = NULL;
+	if(!different &&
+	   ((versioninfo1->memopt != versioninfo2->memopt) ||
+	   (versioninfo1->lvc.version != versioninfo2->lvc.version) ||
+	   (versioninfo1->lvc.characts != versioninfo2->lvc.characts)))
+		different = 1;
+	if(!different && versioninfo1->gotit.fv && versioninfo2->gotit.fv) {
+		if((versioninfo1->filever_maj1 != versioninfo2->filever_maj1) ||
+		   (versioninfo1->filever_maj2 != versioninfo2->filever_maj2) ||
+		   (versioninfo1->filever_min1 != versioninfo2->filever_min1) ||
+		   (versioninfo1->filever_min2 != versioninfo2->filever_min2))
+			different = 1;
+	} else if(!different &&
+		  ((versioninfo1->gotit.fv && !versioninfo2->gotit.fv) ||
+		  (!versioninfo1->gotit.fv && versioninfo2->gotit.fv)))
+			different = 1;
+	if(!different && versioninfo1->gotit.pv && versioninfo2->gotit.pv) {
+		if((versioninfo1->prodver_maj1 != versioninfo2->prodver_maj1) ||
+		   (versioninfo1->prodver_maj2 != versioninfo2->prodver_maj2) ||
+		   (versioninfo1->prodver_min1 != versioninfo2->prodver_min1) ||
+		   (versioninfo1->prodver_min2 != versioninfo2->prodver_min2))
+			different = 1;
+	} else if(!different &&
+		  ((versioninfo1->gotit.pv && !versioninfo2->gotit.pv) ||
+		  (!versioninfo1->gotit.pv && versioninfo2->gotit.pv)))
+			different = 1;
+	if(!different && versioninfo1->gotit.fo && versioninfo2->gotit.fo) {
+		if(versioninfo1->fileos != versioninfo2->fileos)
+			different = 1;
+	} else if(!different &&
+		  ((versioninfo1->gotit.fo && !versioninfo2->gotit.fo) ||
+		  (!versioninfo1->gotit.fo && versioninfo2->gotit.fo)))
+			different = 1;
+	if(!different && versioninfo1->gotit.ff && versioninfo2->gotit.ff) {
+		if(versioninfo1->fileflags != versioninfo2->fileflags)
+			different = 1;
+	} else if(!different &&
+		  ((versioninfo1->gotit.ff && !versioninfo2->gotit.ff) ||
+		  (!versioninfo1->gotit.ff && versioninfo2->gotit.ff)))
+			different = 1;
+	if(!different && versioninfo1->gotit.ffm && versioninfo2->gotit.ffm) {
+		if(versioninfo1->fileflagsmask != versioninfo2->fileflagsmask)
+			different = 1;
+	} else if(!different &&
+		  ((versioninfo1->gotit.ffm && !versioninfo2->gotit.ffm) ||
+		  (!versioninfo1->gotit.ffm && versioninfo2->gotit.ffm)))
+			different = 1;
+	if(!different && versioninfo1->gotit.ft && versioninfo2->gotit.ft) {
+		if(versioninfo1->filetype != versioninfo2->filetype)
+			different = 1;
+	} else if(!different &&
+		  ((versioninfo1->gotit.ft && !versioninfo2->gotit.ft) ||
+		  (!versioninfo1->gotit.ft && versioninfo2->gotit.ft)))
+			different = 1;
+	if(!different && versioninfo1->gotit.fst && versioninfo2->gotit.fst) {
+		if(versioninfo1->filesubtype != versioninfo2->filesubtype)
+			different = 1;
+	} else if(!different &&
+		  ((versioninfo1->gotit.fst && !versioninfo2->gotit.fst) ||
+		  (!versioninfo1->gotit.fst && versioninfo2->gotit.fst)))
+			different = 1;
+	if(!different) {
+		ver_block1 = versioninfo1->blocks;
+		ver_block2 = versioninfo2->blocks;
+		while(!different && ver_block1 && ver_block2) {
+			different = compare_ver_block(ver_block1, ver_block2);
+			ver_block1 = ver_block1->next;
+			ver_block2 = ver_block2->next;
+		}
+		if(!different &&
+		   ((ver_block1 && !ver_block2) ||
+		   (ver_block1 && !ver_block2)))
+			different = 1;
+	}
+	return different;
+}
+
+static int compare_dlginit(dlginit_t *dlginit1, dlginit_t *dlginit2) {
+	int different = 0;
+	if(!different &&
+	   ((dlginit1->memopt != dlginit2->memopt) ||
+	   (dlginit1->data->lvc.version != dlginit2->data->lvc.version) ||
+	   (dlginit1->data->lvc.characts != dlginit2->data->lvc.characts)))
+		different = 1;
+	return different;
+}
+
+static int compare_toolbar_item(toolbar_item_t *toolbar_item1, toolbar_item_t *toolbar_item2) {
+	int different = 0;
+	while(!different && toolbar_item1 && toolbar_item2) {
+		if((toolbar_item1->id && !toolbar_item2->id) ||
+		   (!toolbar_item1->id && toolbar_item2->id))
+			different = 1;
+		toolbar_item1 = toolbar_item1->next;
+		toolbar_item2 = toolbar_item2->next;
+	}
+	if(!different &&
+	   ((toolbar_item1 && !toolbar_item2) ||
+	   (!toolbar_item1 && toolbar_item2)))
+		different = 1;
+	return different;
+}
+
+static int compare_toolbar(toolbar_t *toolbar1, toolbar_t *toolbar2) {
+	int different = 0;
+	if(!different &&
+	   ((toolbar1->memopt != toolbar2->memopt) ||
+	   (toolbar1->lvc.version != toolbar2->lvc.version) ||
+	   (toolbar1->lvc.characts != toolbar2->lvc.characts)))
+		different = 1;
+	if(!different)
+		different = compare_toolbar_item(toolbar1->items, toolbar2->items);
+	return different;
+}
+
+static int compare_ani_curico(ani_curico_t *ani_curico1, ani_curico_t *ani_curico2) {
+	int different = 0;
+	if(!different &&
+	   ((ani_curico1->memopt != ani_curico2->memopt) ||
+	   (ani_curico1->data->lvc.version != ani_curico2->data->lvc.version) ||
+	   (ani_curico1->data->lvc.characts != ani_curico2->data->lvc.characts)))
+		different = 1;
+	return different;
+}
+
+void verify_translations(resource_t *top) {
+	DEFINE_VARIABLES_TRANSLATION
+	resource_t *next = top;
+	while(next) {
+		switch(next->type) {
+			case res_acc:
+				add_accelerator(next, next->res.acc);
+				break;
+			case res_bmp:
+				add_bitmap(next, next->res.bmp);
+				break;
+			case res_cur:
+				add_cursor(next, next->res.cur);
+				break;
+			case res_curg:
+				add_cursor_group(next, next->res.curg);
+				break;
+			case res_dlg:
+				add_dialog(next, next->res.dlg);
+				break;
+			case res_dlgex:
+				add_dialogex(next, next->res.dlgex);
+				break;
+			case res_fnt:
+				add_font(next, next->res.fnt);
+				break;
+			case res_ico:
+				add_icon(next, next->res.ico);
+				break;
+			case res_icog:
+				add_icon_group(next, next->res.icog);
+				break;
+			case res_men:
+				add_menu(next, next->res.men);
+				break;
+			case res_menex:
+				add_menuex(next, next->res.menex);
+				break;
+			case res_rdt:
+				add_rcdata(next, next->res.rdt);
+				break;
+			case res_stt:
+				add_stringtable(next, next->res.stt);
+				break;
+			case res_usr:
+				add_user(next, next->res.usr);
+				break;
+			case res_msg:
+				add_messagetable(next, next->res.msg);
+				break;
+			case res_ver:
+				add_versioninfo(next, next->res.ver);
+				break;
+			case res_dlginit:
+				add_dlginit(next, next->res.dlgi);
+				break;
+			case res_toolbar:
+				add_toolbar(next, next->res.tbt);
+				break;
+			case res_anicur:
+			case res_aniico:
+				add_ani_curico(next, next->res.ani);
+				break;
+			default:
+				fprintf(stderr, "Report this: unkown resource type parsed %08x\n", next->type);
+		}
+		next = next->next;
+	}
+	CHECK_TRANSLATION(accelerator)
+	CHECK_TRANSLATION_RAW(bitmap)
+	CHECK_TRANSLATION(cursor)
+	CHECK_TRANSLATION(cursor_group)
+	CHECK_TRANSLATION(dialog)
+	CHECK_TRANSLATION(dialogex)
+	CHECK_TRANSLATION_RAW(font)
+	CHECK_TRANSLATION(icon)
+	CHECK_TRANSLATION(icon_group)
+	CHECK_TRANSLATION(menu)
+	CHECK_TRANSLATION(menuex)
+	CHECK_TRANSLATION_RAW(rcdata)
+	CHECK_TRANSLATION(stringtable)
+	CHECK_TRANSLATION_RAW(user)
+	CHECK_TRANSLATION_RAW(messagetable)
+	CHECK_TRANSLATION(versioninfo)
+	CHECK_TRANSLATION_RAW(dlginit)
+	CHECK_TRANSLATION(toolbar)
+	CHECK_TRANSLATION_RAW(ani_curico)
+}
--- /dev/null	2002-08-30 19:31:37.000000000 -0400
+++ tools/wrc/translation.h	2003-10-04 22:25:02.000000000 -0400
@@ -0,0 +1,115 @@
+/*
+ * Verification of resources translations prototypes
+ *
+ * Copyright 2003 Vincent Béron
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __WRC_TRANSLATION_H
+#define __WRC_TRANSLATION_H
+
+#include <string.h>
+
+#include "dumpres.h"
+
+#define KEEP_RESOURCE_COMMON(type, lang_id) \
+	int nb_list_##type = 0; \
+	int nb_master_##type = 0; \
+	int nb_neutral_##type = 0; \
+	resource_t **list_resource_##type = NULL; \
+	resource_t **master_resource_##type = NULL; \
+	resource_t **neutral_resource_##type = NULL; \
+	type##_t **list_##type = NULL; \
+	type##_t **master_##type = NULL; \
+	type##_t **neutral_##type = NULL; \
+	static void add_##type(resource_t *resource, type##_t *type) { \
+		if(type lang_id->lvc.language->id == master_language) { \
+			ADD_RESOURCE(type, master) \
+		} else if(type lang_id->lvc.language->id == LANG_NEUTRAL) { \
+			ADD_RESOURCE(type, neutral) \
+		} else { \
+			ADD_RESOURCE(type, list) \
+		} \
+	}
+
+#define ADD_RESOURCE(type, list) { \
+	nb_##list##_##type++; \
+	list##_##type = realloc(list##_##type, nb_##list##_##type*sizeof(type##_t *)); \
+	list##_##type[nb_##list##_##type-1] = type; \
+	list##_resource_##type = realloc(list##_resource_##type, nb_##list##_##type*sizeof(resource_t *)); \
+	list##_resource_##type[nb_##list##_##type-1] = resource; \
+	}
+
+#define KEEP_RESOURCE(type) \
+	KEEP_RESOURCE_COMMON(type, )
+
+#define KEEP_RESOURCE_RAW(type) \
+	KEEP_RESOURCE_COMMON(type, ->data)
+
+#define DEFINE_VARIABLES_TRANSLATION \
+	int i, j; \
+	char *nameid;
+
+#define ENSURE_MASTER_PRESENT(type) \
+	if(nb_list_##type > 0) { \
+		if(nb_master_##type && nb_neutral_##type) { \
+			fprintf(stderr, "There are both a NEUTRAL and a MASTER versions for %s, along with additional localized versions.\n", #type); \
+		} else if(nb_neutral_##type) { \
+			fprintf(stderr, "There are no MASTER version, but there are some NEUTRAL versions for %s, so will use those instead of MASTER.\n", #type); \
+			master_resource_##type = neutral_resource_##type; \
+			master_##type = neutral_##type; \
+			nb_master_##type = nb_neutral_##type; \
+		} else if(!nb_master_##type) { \
+			fprintf(stderr, "There are no NEUTRAL nor MASTER version for %s, but there are some other localized versions.\n", #type); \
+		} \
+	} else { \
+		if(nb_master_##type && nb_neutral_##type) { \
+			fprintf(stderr, "There are both a NEUTRAL and a MASTER versions for %s, but no other localized version.\n", #type); \
+		} else if(nb_master_##type) { \
+			fprintf(stderr, "There are only MASTER versions for %s.\n", #type); \
+		} else if(nb_neutral_##type) { \
+			fprintf(stderr, "There are only NEUTRAL versions for %s.\n", #type); \
+		} \
+	}
+/*Ne pas juste flusher des ressources, les ajouter à une des listes*/
+
+#define CHECK_DIFFERENCES(type, lang_id) \
+	for(i = 0; i < nb_list_##type; i++) { \
+		for(j = 0; j < nb_master_##type; j++) { \
+			nameid = strdup(get_nameid_str(list_resource_##type[i]->name)); \
+			if(!strcmp(nameid, get_nameid_str(master_resource_##type[j]->name))) { \
+				if(compare_##type(list_##type[i], master_##type[j])) { \
+					fprintf(stderr, "Differences in type %s, ID %s, for language %x\n", #type, nameid, list_##type[i]lang_id->lvc.language->id); \
+				} \
+			} \
+			free(nameid); \
+		} \
+	}
+
+#define CHECK_TRANSLATION(type) \
+	ENSURE_MASTER_PRESENT(type) \
+	CHECK_DIFFERENCES(type, )
+
+#define CHECK_TRANSLATION_RAW(type) \
+	ENSURE_MASTER_PRESENT(type) \
+	CHECK_DIFFERENCES(type, ->data)
+/*Langues manquantes*/
+
+/*Afficher le nom des langues plutôt que le numéro*/
+
+void verify_translations(resource_t *top);
+
+#endif
#!/bin/sh

for MAKEFILE in `find . -name 'Makefile'`; do
	DIRECTORY="`dirname "${MAKEFILE}"`"
	pushd "${DIRECTORY}" >/dev/null
	MAKEFILECONTENTS="`sed -e '/^[[:space:]]/s/^[[:space:]]*\([^[:space:]]\)/ \1/' Makefile`"
	RC_SRCS="`echo "${MAKEFILECONTENTS}" |\
		sed -e '/^RC_SRCS[[:space:]]*=[[:space:]]*/s/^RC_SRCS[[:space:]]*=[[:space:]]*\([^[:space:]]*\)/RC_SRCS=\1/' |\
		sed -e '/^RC_SRCS=.*$/ {
			:join
			N
			s/[[:space:]]*\\\\\n//
			t join
			b next
			}
			:next' |\
		grep '^RC_SRCS=.*$' |\
		sed -e 's/^RC_SRCS=[[:space:]]*//'`"
	RC_SRCS16="`echo "${MAKEFILECONTENTS}" |\
		sed -e '/^RC_SRCS16[[:space:]]*=[[:space:]]*/s/^RC_SRCS16[[:space:]]*=[[:space:]]*\([^[:space:]]*\)/RC_SRCS16=\1/' |\
		sed -e '/^RC_SRCS16=.*$/ {
			:join
			N
			s/[[:space:]]*\\\\\n//
			t join
			b next
			}
			:next' |\
		grep '^RC_SRCS16=.*$' |\
		sed -e 's/^RC_SRCS16=[[:space:]]*//'`"
	TOPSRCDIR="`echo "${MAKEFILECONTENTS}" |\
		grep '^TOPSRCDIR[[:space:]]*=.*$' |\
		sed -e 's/^TOPSRCDIR[[:space:]]*=[[:space:]]*//'`"
	TOPOBJDIR="`echo "${MAKEFILECONTENTS}" |\
		grep '^TOPOBJDIR[[:space:]]*=.*$' |\
		sed -e 's/^TOPOBJDIR[[:space:]]*=[[:space:]]*//'`"
	SRCDIR="`echo "${MAKEFILECONTENTS}" |\
		grep '^SRCDIR[[:space:]]*=.*$' |\
		sed -e 's/^SRCDIR[[:space:]]*=[[:space:]]*//'`"
	EXTRARCFLAGS="`echo "${MAKEFILECONTENTS}" |\
		grep '^EXTRARCFLAGS[[:space:]]*=.*$' |\
		sed -e 's/^EXTRARCFLAGS[[:space:]]*=[[:space:]]*//'`"
	INCLUDES="-I${SRCDIR} -I. -I${TOPSRCDIR}/include -I${TOPOBJDIR}/include"
	LDPATH="${TOPOBJDIR}/libs/unicode:${LD_LIBRARY_PATH}"
	WRC="${TOPOBJDIR}/tools/wrc/wrc"
	RC="${WRC}"
	RC16="${WRC}"
	RCFLAGS="--nostdinc ${INCLUDES} --debug=0x40 ${EXTRARCFLAGS}"
	RC16FLAGS="-O res16 ${RCFLAGS}"
	if [ -n "${RC_SRCS}" ]; then
		for RCFILE in ${RC_SRCS}; do
			echo "File ${DIRECTORY}/${RCFILE}:"
			LD_LIBRARY_PATH="${LDPATH}" ${RC} ${RCFLAGS} -fo${RCFILE%.rc}.res ${RCFILE}
		done
	fi
	if [ -n "${RC16_SRCS}" ]; then
		for RCFILE in ${RC16_SRCS}; do
			echo "File ${DIRECTORY}/${RCFILE}:"
			LD_LIBRARY_PATH="${LDPATH}" ${RC16} ${RC16FLAGS} -fo${RCFILE%.rc}.res ${RCFILE}
		done
	fi
	popd >/dev/null
done

exit

Reply via email to