wrc: Add support for generating .po files from existing resources.

This commit is contained in:
Alexandre Julliard 2011-01-04 11:18:10 +01:00
parent 0e79c5c1c3
commit 10700bf6b2
5 changed files with 758 additions and 19 deletions

View File

@ -1,11 +1,13 @@
DEFS = -D__WINESRC__ -DINCLUDEDIR="\"$(includedir)\"" $(EXTRADEFS)
PROGRAMS = wrc$(EXEEXT) wrc-installed
MANPAGE = wrc.man
ALL_LIBS = @LIBGETTEXTPO@ $(LIBWPP) $(LIBWINE) $(LIBPORT)
C_SRCS = \
dumpres.c \
genres.c \
newstruc.c \
po.c \
readres.c \
translation.c \
utils.c \
@ -22,10 +24,10 @@ all: $(PROGRAMS)
@MAKE_RULES@
wrc$(EXEEXT): $(OBJS) $(LIBWPP)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBWPP) $(LIBWINE) $(LIBPORT) $(LDFLAGS) $(LDRPATH_LOCAL)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(ALL_LIBS) $(LDFLAGS) $(LDRPATH_LOCAL)
wrc-installed: $(OBJS) $(LIBWPP)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBWPP) $(LIBWINE) $(LIBPORT) $(LDFLAGS) $(LDRPATH_INSTALL)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(ALL_LIBS) $(LDFLAGS) $(LDRPATH_INSTALL)
install:: wrc-installed $(DESTDIR)$(bindir)
$(INSTALL_PROGRAM) wrc-installed $(DESTDIR)$(bindir)/wrc$(EXEEXT)

716
tools/wrc/po.c Normal file
View File

@ -0,0 +1,716 @@
/*
* Support for po files
*
* Copyright 2010 Alexandre Julliard
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <assert.h>
#include <ctype.h>
#ifdef HAVE_GETTEXT_PO_H
#include <gettext-po.h>
#endif
#include "wrc.h"
#include "genres.h"
#include "newstruc.h"
#include "utils.h"
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "wine/list.h"
#include "wine/unicode.h"
#ifdef HAVE_LIBGETTEXTPO
static const struct
{
unsigned int id, sub;
const char *name;
} languages[] =
{
{ LANG_ARABIC, SUBLANG_NEUTRAL, "ar" },
{ LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA, "ar_SA" },
{ LANG_ARABIC, SUBLANG_ARABIC_IRAQ, "ar_IQ" },
{ LANG_ARABIC, SUBLANG_ARABIC_EGYPT, "ar_EG" },
{ LANG_ARABIC, SUBLANG_ARABIC_LIBYA, "ar_LY" },
{ LANG_ARABIC, SUBLANG_ARABIC_ALGERIA, "ar_DZ" },
{ LANG_ARABIC, SUBLANG_ARABIC_MOROCCO, "ar_MA" },
{ LANG_ARABIC, SUBLANG_ARABIC_TUNISIA, "ar_TN" },
{ LANG_ARABIC, SUBLANG_ARABIC_OMAN, "ar_OM" },
{ LANG_ARABIC, SUBLANG_ARABIC_YEMEN, "ar_YE" },
{ LANG_ARABIC, SUBLANG_ARABIC_SYRIA, "ar_SY" },
{ LANG_ARABIC, SUBLANG_ARABIC_JORDAN, "ar_JO" },
{ LANG_ARABIC, SUBLANG_ARABIC_LEBANON, "ar_LB" },
{ LANG_ARABIC, SUBLANG_ARABIC_KUWAIT, "ar_KW" },
{ LANG_ARABIC, SUBLANG_ARABIC_UAE, "ar_AE" },
{ LANG_ARABIC, SUBLANG_ARABIC_BAHRAIN, "ar_BH" },
{ LANG_ARABIC, SUBLANG_ARABIC_QATAR, "ar_QA" },
{ LANG_BULGARIAN, SUBLANG_NEUTRAL, "bg" },
{ LANG_BULGARIAN, SUBLANG_BULGARIAN_BULGARIA, "bg_BG" },
{ LANG_CATALAN, SUBLANG_NEUTRAL, "ca" },
{ LANG_CATALAN, SUBLANG_CATALAN_CATALAN, "ca_ES" },
{ LANG_CHINESE, SUBLANG_NEUTRAL, "zh" },
{ LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL, "zh_TW" },
{ LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED, "zh_CN" },
{ LANG_CHINESE, SUBLANG_CHINESE_HONGKONG, "zh_HK" },
{ LANG_CHINESE, SUBLANG_CHINESE_SINGAPORE, "zh_SG" },
{ LANG_CHINESE, SUBLANG_CHINESE_MACAU, "zh_MO" },
{ LANG_CZECH, SUBLANG_NEUTRAL, "cs" },
{ LANG_CZECH, SUBLANG_CZECH_CZECH_REPUBLIC, "cs_CZ" },
{ LANG_DANISH, SUBLANG_NEUTRAL, "da" },
{ LANG_DANISH, SUBLANG_DANISH_DENMARK, "da_DK" },
{ LANG_GERMAN, SUBLANG_NEUTRAL, "de" },
{ LANG_GERMAN, SUBLANG_GERMAN, "de_DE" },
{ LANG_GERMAN, SUBLANG_GERMAN_SWISS, "de_CH" },
{ LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN, "de_AT" },
{ LANG_GERMAN, SUBLANG_GERMAN_LUXEMBOURG, "de_LU" },
{ LANG_GERMAN, SUBLANG_GERMAN_LIECHTENSTEIN, "de_LI" },
{ LANG_GREEK, SUBLANG_NEUTRAL, "el" },
{ LANG_GREEK, SUBLANG_GREEK_GREECE, "el_GR" },
{ LANG_ENGLISH, SUBLANG_NEUTRAL, "en" },
{ LANG_ENGLISH, SUBLANG_ENGLISH_US, "en_US" },
{ LANG_ENGLISH, SUBLANG_ENGLISH_UK, "en_GB" },
{ LANG_ENGLISH, SUBLANG_ENGLISH_AUS, "en_AU" },
{ LANG_ENGLISH, SUBLANG_ENGLISH_CAN, "en_CA" },
{ LANG_ENGLISH, SUBLANG_ENGLISH_NZ, "en_NZ" },
{ LANG_ENGLISH, SUBLANG_ENGLISH_EIRE, "en_IE" },
{ LANG_ENGLISH, SUBLANG_ENGLISH_SOUTH_AFRICA, "en_ZA" },
{ LANG_ENGLISH, SUBLANG_ENGLISH_JAMAICA, "en_JM" },
{ LANG_ENGLISH, SUBLANG_ENGLISH_CARIBBEAN, "en_CB" },
{ LANG_ENGLISH, SUBLANG_ENGLISH_BELIZE, "en_BZ" },
{ LANG_ENGLISH, SUBLANG_ENGLISH_TRINIDAD, "en_TT" },
{ LANG_ENGLISH, SUBLANG_ENGLISH_ZIMBABWE, "en_ZW" },
{ LANG_ENGLISH, SUBLANG_ENGLISH_PHILIPPINES, "en_PH" },
{ LANG_SPANISH, SUBLANG_NEUTRAL, "es" },
{ LANG_SPANISH, SUBLANG_SPANISH, "es_ES" },
{ LANG_SPANISH, SUBLANG_SPANISH_MEXICAN, "es_MX" },
{ LANG_SPANISH, SUBLANG_SPANISH_MODERN, "es_ES_modern" },
{ LANG_SPANISH, SUBLANG_SPANISH_GUATEMALA, "es_GT" },
{ LANG_SPANISH, SUBLANG_SPANISH_COSTA_RICA, "es_CR" },
{ LANG_SPANISH, SUBLANG_SPANISH_PANAMA, "es_PA" },
{ LANG_SPANISH, SUBLANG_SPANISH_DOMINICAN_REPUBLIC, "es_DO" },
{ LANG_SPANISH, SUBLANG_SPANISH_VENEZUELA, "es_VE" },
{ LANG_SPANISH, SUBLANG_SPANISH_COLOMBIA, "es_CO" },
{ LANG_SPANISH, SUBLANG_SPANISH_PERU, "es_PE" },
{ LANG_SPANISH, SUBLANG_SPANISH_ARGENTINA, "es_AR" },
{ LANG_SPANISH, SUBLANG_SPANISH_ECUADOR, "es_EC" },
{ LANG_SPANISH, SUBLANG_SPANISH_CHILE, "es_CL" },
{ LANG_SPANISH, SUBLANG_SPANISH_URUGUAY, "es_UY" },
{ LANG_SPANISH, SUBLANG_SPANISH_PARAGUAY, "es_PY" },
{ LANG_SPANISH, SUBLANG_SPANISH_BOLIVIA, "es_BO" },
{ LANG_SPANISH, SUBLANG_SPANISH_EL_SALVADOR, "es_SV" },
{ LANG_SPANISH, SUBLANG_SPANISH_HONDURAS, "es_HN" },
{ LANG_SPANISH, SUBLANG_SPANISH_NICARAGUA, "es_NI" },
{ LANG_SPANISH, SUBLANG_SPANISH_PUERTO_RICO, "es_PR" },
{ LANG_FINNISH, SUBLANG_NEUTRAL, "fi" },
{ LANG_FINNISH, SUBLANG_FINNISH_FINLAND, "fi_FI" },
{ LANG_FRENCH, SUBLANG_NEUTRAL, "fr" },
{ LANG_FRENCH, SUBLANG_FRENCH, "fr_FR" },
{ LANG_FRENCH, SUBLANG_FRENCH_BELGIAN, "fr_BE" },
{ LANG_FRENCH, SUBLANG_FRENCH_CANADIAN, "fr_CA" },
{ LANG_FRENCH, SUBLANG_FRENCH_SWISS, "fr_CH" },
{ LANG_FRENCH, SUBLANG_FRENCH_LUXEMBOURG, "fr_LU" },
{ LANG_FRENCH, SUBLANG_FRENCH_MONACO, "fr_MC" },
{ LANG_HEBREW, SUBLANG_NEUTRAL, "he" },
{ LANG_HEBREW, SUBLANG_HEBREW_ISRAEL, "he_IL" },
{ LANG_HUNGARIAN, SUBLANG_NEUTRAL, "hu" },
{ LANG_HUNGARIAN, SUBLANG_HUNGARIAN_HUNGARY, "hu_HU" },
{ LANG_ICELANDIC, SUBLANG_NEUTRAL, "is" },
{ LANG_ICELANDIC, SUBLANG_ICELANDIC_ICELAND, "is_IS" },
{ LANG_ITALIAN, SUBLANG_NEUTRAL, "it" },
{ LANG_ITALIAN, SUBLANG_ITALIAN, "it_IT" },
{ LANG_ITALIAN, SUBLANG_ITALIAN_SWISS, "it_CH" },
{ LANG_JAPANESE, SUBLANG_NEUTRAL, "ja" },
{ LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN, "ja_JP" },
{ LANG_KOREAN, SUBLANG_NEUTRAL, "ko" },
{ LANG_KOREAN, SUBLANG_KOREAN, "ko_KR" },
{ LANG_DUTCH, SUBLANG_NEUTRAL, "nl" },
{ LANG_DUTCH, SUBLANG_DUTCH, "nl_NL" },
{ LANG_DUTCH, SUBLANG_DUTCH_BELGIAN, "nl_BE" },
{ LANG_DUTCH, SUBLANG_DUTCH_SURINAM, "nl_SR" },
{ LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL, "nb_NO" },
{ LANG_NORWEGIAN, SUBLANG_NORWEGIAN_NYNORSK, "nn_NO" },
{ LANG_POLISH, SUBLANG_NEUTRAL, "pl" },
{ LANG_POLISH, SUBLANG_POLISH_POLAND, "pl_PL" },
{ LANG_PORTUGUESE, SUBLANG_NEUTRAL, "pt" },
{ LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN, "pt_BR" },
{ LANG_PORTUGUESE, SUBLANG_PORTUGUESE_PORTUGAL, "pt_PT" },
{ LANG_ROMANSH, SUBLANG_NEUTRAL, "rm" },
{ LANG_ROMANSH, SUBLANG_ROMANSH_SWITZERLAND, "rm_CH" },
{ LANG_ROMANIAN, SUBLANG_NEUTRAL, "ro" },
{ LANG_ROMANIAN, SUBLANG_ROMANIAN_ROMANIA, "ro_RO" },
{ LANG_RUSSIAN, SUBLANG_NEUTRAL, "ru" },
{ LANG_RUSSIAN, SUBLANG_RUSSIAN_RUSSIA, "ru_RU" },
{ LANG_SERBIAN, SUBLANG_NEUTRAL, "hr" },
{ LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA, "hr_HR" },
{ LANG_SERBIAN, SUBLANG_SERBIAN_LATIN, "sr_Latn_SP" },
{ LANG_SERBIAN, SUBLANG_SERBIAN_CYRILLIC, "sr_SP" },
{ LANG_SLOVAK, SUBLANG_NEUTRAL, "sk" },
{ LANG_SLOVAK, SUBLANG_SLOVAK_SLOVAKIA, "sk_SK" },
{ LANG_ALBANIAN, SUBLANG_NEUTRAL, "sq" },
{ LANG_ALBANIAN, SUBLANG_ALBANIAN_ALBANIA, "sq_AL" },
{ LANG_SWEDISH, SUBLANG_NEUTRAL, "sv" },
{ LANG_SWEDISH, SUBLANG_SWEDISH_SWEDEN, "sv_SE" },
{ LANG_SWEDISH, SUBLANG_SWEDISH_FINLAND, "sv_FI" },
{ LANG_THAI, SUBLANG_NEUTRAL, "th" },
{ LANG_THAI, SUBLANG_THAI_THAILAND, "th_TH" },
{ LANG_TURKISH, SUBLANG_NEUTRAL, "tr" },
{ LANG_TURKISH, SUBLANG_TURKISH_TURKEY, "tr_TR" },
{ LANG_URDU, SUBLANG_NEUTRAL, "ur" },
{ LANG_URDU, SUBLANG_URDU_PAKISTAN, "ur_PK" },
{ LANG_INDONESIAN, SUBLANG_NEUTRAL, "id" },
{ LANG_INDONESIAN, SUBLANG_INDONESIAN_INDONESIA, "id_ID" },
{ LANG_UKRAINIAN, SUBLANG_NEUTRAL, "uk" },
{ LANG_UKRAINIAN, SUBLANG_UKRAINIAN_UKRAINE, "uk_UA" },
{ LANG_BELARUSIAN, SUBLANG_NEUTRAL, "be" },
{ LANG_BELARUSIAN, SUBLANG_BELARUSIAN_BELARUS, "be_BY" },
{ LANG_SLOVENIAN, SUBLANG_NEUTRAL, "sl" },
{ LANG_SLOVENIAN, SUBLANG_SLOVENIAN_SLOVENIA, "sl_SI" },
{ LANG_ESTONIAN, SUBLANG_NEUTRAL, "et" },
{ LANG_ESTONIAN, SUBLANG_ESTONIAN_ESTONIA, "et_EE" },
{ LANG_LATVIAN, SUBLANG_NEUTRAL, "lv" },
{ LANG_LATVIAN, SUBLANG_LATVIAN_LATVIA, "lv_LV" },
{ LANG_LITHUANIAN, SUBLANG_NEUTRAL, "lt" },
{ LANG_LITHUANIAN, SUBLANG_LITHUANIAN_LITHUANIA, "lt_LT" },
{ LANG_PERSIAN, SUBLANG_NEUTRAL, "fa" },
{ LANG_PERSIAN, SUBLANG_PERSIAN_IRAN, "fa_IR" },
{ LANG_ARMENIAN, SUBLANG_NEUTRAL, "hy" },
{ LANG_ARMENIAN, SUBLANG_ARMENIAN_ARMENIA, "hy_AM" },
{ LANG_AZERI, SUBLANG_NEUTRAL, "az" },
{ LANG_AZERI, SUBLANG_AZERI_LATIN, "az_Latn_AZ" },
{ LANG_AZERI, SUBLANG_AZERI_CYRILLIC, "az_AZ" },
{ LANG_BASQUE, SUBLANG_NEUTRAL, "eu" },
{ LANG_BASQUE, SUBLANG_BASQUE_BASQUE, "eu_ES" },
{ LANG_MACEDONIAN, SUBLANG_NEUTRAL, "mk" },
{ LANG_MACEDONIAN, SUBLANG_MACEDONIAN_MACEDONIA, "mk_MK" },
{ LANG_AFRIKAANS, SUBLANG_NEUTRAL, "af" },
{ LANG_AFRIKAANS, SUBLANG_AFRIKAANS_SOUTH_AFRICA, "af_ZA" },
{ LANG_GEORGIAN, SUBLANG_NEUTRAL, "ka" },
{ LANG_GEORGIAN, SUBLANG_GEORGIAN_GEORGIA, "ka_GE" },
{ LANG_FAEROESE, SUBLANG_NEUTRAL, "fo" },
{ LANG_FAEROESE, SUBLANG_FAEROESE_FAROE_ISLANDS, "fo_FO" },
{ LANG_HINDI, SUBLANG_NEUTRAL, "hi" },
{ LANG_HINDI, SUBLANG_HINDI_INDIA, "hi_IN" },
{ LANG_MALAY, SUBLANG_NEUTRAL, "ms" },
{ LANG_MALAY, SUBLANG_MALAY_MALAYSIA, "ms_MY" },
{ LANG_MALAY, SUBLANG_MALAY_BRUNEI_DARUSSALAM, "ms_BN" },
{ LANG_KAZAK, SUBLANG_NEUTRAL, "kk" },
{ LANG_KAZAK, SUBLANG_KAZAK_KAZAKHSTAN, "kk_KZ" },
{ LANG_KYRGYZ, SUBLANG_NEUTRAL, "ky" },
{ LANG_KYRGYZ, SUBLANG_KYRGYZ_KYRGYZSTAN, "ky_KG" },
{ LANG_SWAHILI, SUBLANG_NEUTRAL, "sw" },
{ LANG_SWAHILI, SUBLANG_SWAHILI_KENYA, "sw_KE" },
{ LANG_UZBEK, SUBLANG_NEUTRAL, "uz" },
{ LANG_UZBEK, SUBLANG_UZBEK_LATIN, "uz_Latn_UZ" },
{ LANG_UZBEK, SUBLANG_UZBEK_CYRILLIC, "uz_UZ" },
{ LANG_TATAR, SUBLANG_NEUTRAL, "tt" },
{ LANG_TATAR, SUBLANG_TATAR_RUSSIA, "tt_TA" },
{ LANG_PUNJABI, SUBLANG_NEUTRAL, "pa" },
{ LANG_PUNJABI, SUBLANG_PUNJABI_INDIA, "pa_IN" },
{ LANG_GUJARATI, SUBLANG_NEUTRAL, "gu" },
{ LANG_GUJARATI, SUBLANG_GUJARATI_INDIA, "gu_IN" },
{ LANG_ORIYA, SUBLANG_NEUTRAL, "or" },
{ LANG_ORIYA, SUBLANG_ORIYA_INDIA, "or_IN" },
{ LANG_TAMIL, SUBLANG_NEUTRAL, "ta" },
{ LANG_TAMIL, SUBLANG_TAMIL_INDIA, "ta_IN" },
{ LANG_TELUGU, SUBLANG_NEUTRAL, "te" },
{ LANG_TELUGU, SUBLANG_TELUGU_INDIA, "te_IN" },
{ LANG_KANNADA, SUBLANG_NEUTRAL, "kn" },
{ LANG_KANNADA, SUBLANG_KANNADA_INDIA, "kn_IN" },
{ LANG_MALAYALAM, SUBLANG_NEUTRAL, "ml" },
{ LANG_MALAYALAM, SUBLANG_MALAYALAM_INDIA, "ml_IN" },
{ LANG_MARATHI, SUBLANG_NEUTRAL, "mr" },
{ LANG_MARATHI, SUBLANG_MARATHI_INDIA, "mr_IN" },
{ LANG_SANSKRIT, SUBLANG_NEUTRAL, "sa" },
{ LANG_SANSKRIT, SUBLANG_SANSKRIT_INDIA, "sa_IN" },
{ LANG_MONGOLIAN, SUBLANG_NEUTRAL, "mn" },
{ LANG_MONGOLIAN, SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA, "mn_MN" },
{ LANG_WELSH, SUBLANG_NEUTRAL, "cy" },
{ LANG_WELSH, SUBLANG_WELSH_UNITED_KINGDOM, "cy_GB" },
{ LANG_GALICIAN, SUBLANG_NEUTRAL, "gl" },
{ LANG_GALICIAN, SUBLANG_GALICIAN_GALICIAN, "gl_ES" },
{ LANG_KONKANI, SUBLANG_NEUTRAL, "kok" },
{ LANG_KONKANI, SUBLANG_KONKANI_INDIA, "kok_IN" },
{ LANG_DIVEHI, SUBLANG_NEUTRAL, "dv" },
{ LANG_DIVEHI, SUBLANG_DIVEHI_MALDIVES, "dv_MV" },
{ LANG_BRETON, SUBLANG_NEUTRAL, "br" },
{ LANG_BRETON, SUBLANG_BRETON_FRANCE, "br_FR" },
#ifdef LANG_ESPERANTO
{ LANG_ESPERANTO, SUBLANG_DEFAULT, "eo" },
#endif
#ifdef LANG_WALON
{ LANG_WALON, SUBLANG_NEUTRAL, "wa" },
{ LANG_WALON, SUBLANG_DEFAULT, "wa_BE" },
#endif
#ifdef LANG_CORNISH
{ LANG_CORNISH, SUBLANG_NEUTRAL, "kw" },
{ LANG_CORNISH, SUBLANG_DEFAULT, "kw_GB" },
#endif
#ifdef LANG_GAELIC
{ LANG_GAELIC, SUBLANG_NEUTRAL, "ga" },
{ LANG_GAELIC, SUBLANG_GAELIC, "ga_IE" },
{ LANG_GAELIC, SUBLANG_GAELIC_SCOTTISH, "gd_GB" },
{ LANG_GAELIC, SUBLANG_GAELIC_MANX, "gv_GB" },
#endif
};
static void po_xerror( int severity, po_message_t message,
const char *filename, size_t lineno, size_t column,
int multiline_p, const char *message_text )
{
fprintf( stderr, "%s:%u:%u: %s\n",
filename, (unsigned int)lineno, (unsigned int)column, message_text );
if (severity) exit(1);
}
static void po_xerror2( int severity, po_message_t message1,
const char *filename1, size_t lineno1, size_t column1,
int multiline_p1, const char *message_text1,
po_message_t message2,
const char *filename2, size_t lineno2, size_t column2,
int multiline_p2, const char *message_text2 )
{
fprintf( stderr, "%s:%u:%u: %s\n",
filename1, (unsigned int)lineno1, (unsigned int)column1, message_text1 );
fprintf( stderr, "%s:%u:%u: %s\n",
filename2, (unsigned int)lineno2, (unsigned int)column2, message_text2 );
if (severity) exit(1);
}
static const struct po_xerror_handler po_xerror_handler = { po_xerror, po_xerror2 };
static char *convert_string_utf8( const string_t *str, int codepage )
{
string_t *newstr = convert_string( str, str_unicode, codepage );
char *buffer = xmalloc( newstr->size * 4 + 1 );
int len = wine_utf8_wcstombs( 0, newstr->str.wstr, newstr->size, buffer, newstr->size * 4 );
buffer[len] = 0;
free_string( newstr );
return buffer;
}
static char *convert_msgid_ascii( const string_t *str, int error_on_invalid_char )
{
int i;
string_t *newstr = convert_string( str, str_unicode, 1252 );
char *buffer = xmalloc( newstr->size + 1 );
for (i = 0; i < newstr->size; i++)
{
buffer[i] = newstr->str.wstr[i];
if (newstr->str.wstr[i] >= 32 && newstr->str.wstr[i] <= 127) continue;
if (newstr->str.wstr[i] == '\t' || newstr->str.wstr[i] == '\n') continue;
if (error_on_invalid_char)
{
print_location( &newstr->loc );
error( "Invalid character %04x in source string\n", newstr->str.wstr[i] );
}
free_string( newstr );
return NULL;
}
buffer[i] = 0;
free_string( newstr );
return buffer;
}
static char *get_message_context( char **msgid )
{
static const char magic[] = "#msgctxt#";
char *id, *context;
if (strncmp( *msgid, magic, sizeof(magic) - 1 )) return NULL;
context = *msgid + sizeof(magic) - 1;
if (!(id = strchr( context, '#' ))) return NULL;
*id = 0;
*msgid = id + 1;
return context;
}
static po_message_t find_message( po_file_t po, const char *msgid, const char *msgctxt,
po_message_iterator_t *iterator )
{
po_message_t msg;
const char *context;
*iterator = po_message_iterator( po, NULL );
while ((msg = po_next_message( *iterator )))
{
if (strcmp( po_message_msgid( msg ), msgid )) continue;
if (!msgctxt) break;
if (!(context = po_message_msgctxt( msg ))) break;
if (!strcmp( context, msgctxt )) break;
}
return msg;
}
static void add_po_string( po_file_t po, const string_t *msgid, const string_t *msgstr,
const language_t *lang )
{
po_message_t msg;
po_message_iterator_t iterator;
int codepage;
char *id, *id_buffer, *context, *str_buffer = NULL;
if (!msgid->size) return;
id_buffer = id = convert_msgid_ascii( msgid, 1 );
context = get_message_context( &id );
if (msgstr)
{
if (lang) codepage = get_language_codepage( lang->id, lang->sub );
else codepage = get_language_codepage( 0, 0 );
assert( codepage != -1 );
str_buffer = convert_string_utf8( msgstr, codepage );
}
if (!(msg = find_message( po, id, context, &iterator )))
{
msg = po_message_create();
po_message_set_msgid( msg, id );
po_message_set_msgstr( msg, str_buffer ? str_buffer : "" );
if (context) po_message_set_msgctxt( msg, context );
po_message_insert( iterator, msg );
}
if (msgid->loc.file) po_message_add_filepos( msg, msgid->loc.file, msgid->loc.line );
po_message_iterator_free( iterator );
free( id_buffer );
free( str_buffer );
}
struct po_file_lang
{
struct list entry;
language_t lang;
po_file_t po;
};
static struct list po_file_langs = LIST_INIT( po_file_langs );
static po_file_t create_po_file(void)
{
po_file_t po;
po_message_t msg;
po_message_iterator_t iterator;
po = po_file_create();
iterator = po_message_iterator( po, NULL );
msg = po_message_create();
po_message_set_msgid( msg, "" );
po_message_set_msgstr( msg,
"Project-Id-Version: Wine\n"
"Report-Msgid-Bugs-To: http://bugs.winehq.org\n"
"POT-Creation-Date: N/A\n"
"PO-Revision-Date: N/A\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" );
po_message_insert( iterator, msg );
po_message_iterator_free( iterator );
return po;
}
static po_file_t get_po_file( const language_t *lang )
{
struct po_file_lang *po_file;
LIST_FOR_EACH_ENTRY( po_file, &po_file_langs, struct po_file_lang, entry )
if (po_file->lang.id == lang->id && po_file->lang.sub == lang->sub) return po_file->po;
/* create a new one */
po_file = xmalloc( sizeof(*po_file) );
po_file->lang = *lang;
po_file->po = create_po_file();
list_add_tail( &po_file_langs, &po_file->entry );
return po_file->po;
}
static char *get_po_file_name( const language_t *lang )
{
unsigned int i;
char name[40];
sprintf( name, "%02x-%02x", lang->id, lang->sub );
for (i = 0; i < sizeof(languages)/sizeof(languages[0]); i++)
{
if (languages[i].id == lang->id && languages[i].sub == lang->sub)
{
strcpy( name, languages[i].name );
break;
}
}
strcat( name, ".po" );
return xstrdup( name );
}
static unsigned int flush_po_files( const char *output_name )
{
struct po_file_lang *po_file, *next;
unsigned int count;
LIST_FOR_EACH_ENTRY_SAFE( po_file, next, &po_file_langs, struct po_file_lang, entry )
{
char *name = get_po_file_name( &po_file->lang );
if (output_name)
{
const char *p = strrchr( output_name, '/' );
if (p) p++;
else p = output_name;
if (!strcmp( p, name ))
{
po_file_write( po_file->po, name, &po_xerror_handler );
count++;
}
}
else /* no specified output name, output a file for every language found */
{
po_file_write( po_file->po, name, &po_xerror_handler );
count++;
fprintf( stderr, "created %s\n", name );
}
po_file_free( po_file->po );
list_remove( &po_file->entry );
free( po_file );
free( name );
}
return count;
}
static int control_has_title( const control_t *ctrl )
{
if (!ctrl->title) return 0;
if (ctrl->title->type != name_str) return 0;
/* check for text static control */
if (ctrl->ctlclass && ctrl->ctlclass->type == name_ord && ctrl->ctlclass->name.i_name == CT_STATIC)
{
switch (ctrl->style->or_mask & SS_TYPEMASK)
{
case SS_LEFT:
case SS_CENTER:
case SS_RIGHT:
return 1;
default:
return 0;
}
}
return 1;
}
static void add_pot_stringtable( po_file_t po, const resource_t *res )
{
const stringtable_t *stt = res->res.stt;
int i;
while (stt)
{
for (i = 0; i < stt->nentries; i++)
if (stt->entries[i].str) add_po_string( po, stt->entries[i].str, NULL, NULL );
stt = stt->next;
}
}
static void add_po_stringtable( const resource_t *english, const resource_t *res )
{
const stringtable_t *english_stt = english->res.stt;
const stringtable_t *stt = res->res.stt;
po_file_t po = get_po_file( stt->lvc.language );
int i;
while (english_stt && stt)
{
for (i = 0; i < stt->nentries; i++)
if (english_stt->entries[i].str && stt->entries[i].str)
add_po_string( po, english_stt->entries[i].str, stt->entries[i].str, stt->lvc.language );
stt = stt->next;
english_stt = english_stt->next;
}
}
static void add_pot_dialog_controls( po_file_t po, const control_t *ctrl )
{
while (ctrl)
{
if (control_has_title( ctrl )) add_po_string( po, ctrl->title->name.s_name, NULL, NULL );
ctrl = ctrl->next;
}
}
static void add_pot_dialog( po_file_t po, const resource_t *res )
{
const dialog_t *dlg = res->res.dlg;
if (dlg->title) add_po_string( po, dlg->title, NULL, NULL );
if (dlg->font) add_po_string( po, dlg->font->name, NULL, NULL );
add_pot_dialog_controls( po, dlg->controls );
}
static void add_po_dialog_controls( po_file_t po, const control_t *english_ctrl,
const control_t *ctrl, const language_t *lang )
{
while (english_ctrl && ctrl)
{
if (control_has_title( english_ctrl ) && control_has_title( ctrl ))
add_po_string( po, english_ctrl->title->name.s_name, ctrl->title->name.s_name, lang );
ctrl = ctrl->next;
english_ctrl = english_ctrl->next;
}
}
static void add_po_dialog( const resource_t *english, const resource_t *res )
{
const dialog_t *english_dlg = english->res.dlg;
const dialog_t *dlg = res->res.dlg;
po_file_t po = get_po_file( dlg->lvc.language );
if (english_dlg->title && dlg->title)
add_po_string( po, english_dlg->title, dlg->title, dlg->lvc.language );
if (english_dlg->font && dlg->font)
add_po_string( po, english_dlg->font->name, dlg->font->name, dlg->lvc.language );
add_po_dialog_controls( po, english_dlg->controls, dlg->controls, dlg->lvc.language );
}
static void add_pot_menu_items( po_file_t po, const menu_item_t *item )
{
while (item)
{
if (item->name) add_po_string( po, item->name, NULL, NULL );
if (item->popup) add_pot_menu_items( po, item->popup );
item = item->next;
}
}
static void add_pot_menu( po_file_t po, const resource_t *res )
{
add_pot_menu_items( po, res->res.men->items );
}
static void add_po_menu_items( po_file_t po, const menu_item_t *english_item,
const menu_item_t *item, const language_t *lang )
{
while (english_item && item)
{
if (english_item->name && item->name)
add_po_string( po, english_item->name, item->name, lang );
if (english_item->popup && item->popup)
add_po_menu_items( po, english_item->popup, item->popup, lang );
item = item->next;
english_item = english_item->next;
}
}
static void add_po_menu( const resource_t *english, const resource_t *res )
{
const menu_item_t *english_items = english->res.men->items;
const menu_item_t *items = res->res.men->items;
po_file_t po = get_po_file( res->res.men->lvc.language );
add_po_menu_items( po, english_items, items, res->res.men->lvc.language );
}
static int is_english( const language_t *lan )
{
return lan->id == LANG_ENGLISH && lan->sub == SUBLANG_DEFAULT;
}
static resource_t *find_english_resource( resource_t *res )
{
resource_t *ptr;
for (ptr = resource_top; ptr; ptr = ptr->next)
{
if (ptr->type != res->type) continue;
if (!ptr->lan) continue;
if (!is_english( ptr->lan )) continue;
if (compare_name_id( ptr->name, res->name )) continue;
return ptr;
}
return NULL;
}
void write_pot_file( const char *outname )
{
resource_t *res;
po_file_t po = create_po_file();
for (res = resource_top; res; res = res->next)
{
if (!is_english( res->lan )) continue;
switch (res->type)
{
case res_acc: break; /* FIXME */
case res_dlg: add_pot_dialog( po, res ); break;
case res_men: add_pot_menu( po, res ); break;
case res_stt: add_pot_stringtable( po, res ); break;
case res_msg: break; /* FIXME */
default: break;
}
}
po_file_write( po, outname, &po_xerror_handler );
po_file_free( po );
}
void write_po_files( const char *outname )
{
resource_t *res, *english;
po_file_t po;
for (res = resource_top; res; res = res->next)
{
if (!(english = find_english_resource( res ))) continue;
po = get_po_file( res->lan );
switch (res->type)
{
case res_acc: break; /* FIXME */
case res_dlg: add_po_dialog( english, res ); break;
case res_men: add_po_menu( english, res ); break;
case res_stt: add_po_stringtable( english, res ); break;
case res_msg: break; /* FIXME */
default: break;
}
}
if (!flush_po_files( outname ))
{
if (outname) error( "No translations found for %s\n", outname );
else error( "No translations found\n" );
}
}
#else /* HAVE_LIBGETTEXTPO */
void write_pot_file( const char *outname )
{
error( "PO files not supported in this wrc build\n" );
}
void write_po_files( const char *outname )
{
error( "PO files not supported in this wrc build\n" );
}
#endif

View File

@ -69,7 +69,7 @@ static const char usage[] =
" --no-use-temp-file Ignored for compatibility with windres\n"
" --nostdinc Disables searching the standard include path\n"
" -o, --output=FILE Output to file (default is infile.res)\n"
" -O, --output-format=FORMAT The output format (either `res' or `res16`)\n"
" -O, --output-format=FORMAT The output format (`po', `pot', `res', or `res16`)\n"
" --pedantic Enable pedantic warnings\n"
" --preprocessor Specifies the preprocessor to use, including arguments\n"
" -r Ignored for compatibility with rc\n"
@ -148,7 +148,7 @@ static int pointer_size = sizeof(void *);
static int verify_translations_mode;
char *output_name = NULL; /* The name given by the -o option */
static char *output_name; /* The name given by the -o option */
char *input_name = NULL; /* The name given on the command-line */
static char *temp_name = NULL; /* Temporary file for preprocess pipe */
@ -333,6 +333,7 @@ int main(int argc,char *argv[])
int nb_files = 0;
int i;
int cmdlen;
int po_mode = 0;
char **files = xmalloc( argc * sizeof(*files) );
signal(SIGSEGV, segvhandler);
@ -462,7 +463,9 @@ int main(int argc,char *argv[])
else error("Too many output files.\n");
break;
case 'O':
if (strcmp(optarg, "res16") == 0) win32 = 0;
if (strcmp(optarg, "po") == 0) po_mode = 1;
else if (strcmp(optarg, "pot") == 0) po_mode = 2;
else if (strcmp(optarg, "res16") == 0) win32 = 0;
else if (strcmp(optarg, "res")) warning("Output format %s not supported.\n", optarg);
break;
case 'r':
@ -524,20 +527,10 @@ int main(int argc,char *argv[])
for (i = 0; i < nb_files; i++)
{
input_name = files[i];
if(!output_name && !preprocess_only)
{
output_name = dup_basename(input_name, ".rc");
strcat(output_name, ".res");
}
if (load_file( input_name, output_name )) exit(1);
}
/* stdin special case. NULL means "stdin" for wpp. */
if (nb_files == 0)
{
if(!output_name && !preprocess_only)
output_name = strdup("wrc.tab.res");
if (load_file( NULL, output_name )) exit(1);
}
if (nb_files == 0 && load_file( NULL, output_name )) exit(1);
if(debuglevel & DEBUGLEVEL_DUMP)
dump_resources(resource_top);
@ -547,11 +540,31 @@ int main(int argc,char *argv[])
verify_translations(resource_top);
exit(0);
}
if (po_mode)
{
if (po_mode == 2) /* pot file */
{
if (!output_name)
{
output_name = dup_basename( nb_files ? files[0] : NULL, ".rc" );
strcat( output_name, ".pot" );
}
write_pot_file( output_name );
}
else write_po_files( output_name );
output_name = NULL;
exit(0);
}
/* Convert the internal lists to binary data */
resources2res(resource_top);
chat("Writing .res-file\n");
if (!output_name)
{
output_name = dup_basename( nb_files ? files[0] : NULL, ".rc" );
strcat(output_name, ".res");
}
write_resfile(output_name, resource_top);
output_name = NULL;

View File

@ -45,7 +45,6 @@ extern int preprocess_only;
extern int no_preprocess;
extern int check_utf8;
extern char *output_name;
extern char *input_name;
extern char *cmdline;
extern time_t now;
@ -57,6 +56,8 @@ extern resource_t *resource_top;
extern language_t *currentlanguage;
void verify_translations(resource_t *top);
void write_pot_file( const char *outname );
void write_po_files( const char *outname );
void write_resfile(char *outname, resource_t *top);
static inline void set_location( location_t *loc )

View File

@ -93,8 +93,15 @@ with \fB.rc\fR stripped or \fBwrc.tab.res\fR if input is read
from standard input.
.TP
.I \fB\-O\fR, \fB\-\-output\-format\fR=\fIformat\fR
Sets the output format. The supported formats are 'res' and 'res16'.
If this option is not specified, format defaults to 'res'.
Sets the output format. The supported formats are \fBpo\fR, \fBpot\fR,
\fBres\fR, and \fBres16\fR. If this option is not specified, the
format defaults to \fBres\fR.
.br
In \fBpo\fR mode, if an output file name is specified it must match a
known language name, like \fBen_US.po\fR; only resources for the
specified language are output. If no output file name is specified, a
separate .po file is created for every language encountered in the
input.
.TP
.I \fB\-\-pedantic\fR
Enable pedantic warnings. Notably redefinition of #define statements can