diff options
Diffstat (limited to 'tools/po2c')
-rwxr-xr-x | tools/po2c | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/tools/po2c b/tools/po2c new file mode 100755 index 0000000000..9dbc5e0fb7 --- /dev/null +++ b/tools/po2c @@ -0,0 +1,260 @@ +#!/usr/bin/perl + +# +# po2c - Converts .po files to C code +# +# Copyright (C) 2004 Angel Ortega <angel@triptico.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# http://www.triptico.com +# + +$VERSION = "1.0.2-scummvm"; + +if(scalar(@ARGV) == 0) +{ + print "Usage: po2c {po file[s]}\n"; + exit 1; +} + +%msgs = (); +%msgids = (); + +# stage 1: loading + +# arguments are .po files +foreach my $f (@ARGV) +{ + my ($lang); + my ($langDesc); + + next unless(($lang) = ($f =~ /([^\/]+)\.po$/)); + + if(open F, $f) + { + my ($msgid, $val, %a); + + while(<F>) + { + chomp; + + # ignore blank lines or comments + next if /^$/ or /^#/; + + if(/^msgid\s+\"(.*)\"\s*$/) + { + # store previous msgid + if(defined($msgid)) + { + $a{$msgid} = $val; + $msgids{$msgid} ++; + } + + # start of msgid + $val = $1; + } + elsif(/^msgstr\s+\"(.*)\"\s*$/) + { + # store previous msgid + $msgid = $val; + + # start of msgstr + $val = $1; + } + elsif(/^\"(.*)\"\s*$/) + { + # add to current value + $val .= $1; + } + } + + # store previous msgid + if(defined($msgid)) + { + $a{$msgid} = $val; + $msgids{$msgid} ++; + } + + close F; + + # add to the global message pool + $msgs{$lang} = \%a; + } +} + +# stage 2: convert the data + +# stores all sorted msgids into @msgids +@msgids = sort(keys(%msgids)); + +# travels again, storing indexes into %msgids +for(my $n = 0;$n < scalar(@msgids);$n++) +{ + $msgids{$msgids[$n]} = $n; +} + +# stage 3: dump as C++ code + +print "// generated by po2c $VERSION - Do not modify\n\n"; + +# dump first the msgid array +print "static const char * const _messageIds[] = {\n"; + +for(my $n = 0;$n < scalar(@msgids);$n++) +{ + print "\t/* $n */ \"" . $msgids[$n] . "\",\n"; +} + +print "\tNULL\n};\n\n"; + +# dump the lang structure +print "struct PoMessageEntry {\n"; +print "\tint msgid;\n"; +print "\tconst char *msgstr;\n"; +print "};\n\n"; + +# dump now each language + +foreach my $l (keys(%msgs)) +{ + print "static const PoMessageEntry _translation_${l}\[\] = {\n"; + + # get the translation table for the language $l + my ($m) = $msgs{$l}; + +# while (my ($msgstr, $msgid) = each (%$m)) + foreach my $msgid (sort(keys(%$m))) + { + my ($msgstr) = ""; + + # make it 7-bit safe + foreach $c (split(//, $m->{$msgid})) { + if (ord($c) > 0x7f) { + $msgstr .= sprintf("\\%o", ord($c)); + } else { + $msgstr .= $c; + } + } + + print "\t{ " . $msgids{$msgid} . ", \"" . $msgstr . "\" },\n" + if $msgstr; + } + + print "\t{ -1, NULL }\n};\n\n"; +} + +# finally, dump the languages + +print "struct PoLangEntry {\n"; +print "\tconst char *lang;\n"; +print "\tconst char *charset;\n"; +print "\tconst PoMessageEntry *msgs;\n"; +print "};\n\n"; +print "const PoLangEntry _translations[] = {\n"; + +foreach my $l (keys(%msgs)) +{ + $header = $msgs{$l}->{""}; + $header =~ /charset=([^\\]+)/; + $charset = $1; + print "\t{ \"" . $l . "\", \"" . $charset . "\", _translation_${l} },\n"; +} + +print "\t{ NULL, NULL, NULL }\n};\n\n"; + +print "// code\n"; +print << 'EOF'; + +static const PoMessageEntry *_currentTranslation = NULL; +static int _currentTranslationMessageEntryCount = 0; +static const char *_currentTranslationCharset = NULL; + +void po2c_setlang(const char *lang) { + _currentTranslation = NULL; + _currentTranslationMessageEntryCount = 0; + _currentTranslationCharset = NULL; + + // if lang is NULL or "", deactivate it + if (lang == NULL || *lang == '\0') + return; + + // searches for a valid language array + for (int i = 0; _currentTranslation == NULL && _translations[i].lang != NULL; ++i) { + if (strcmp(lang, _translations[i].lang) == 0) { + _currentTranslation = _translations[i].msgs; + _currentTranslationCharset = _translations[i].charset; + } + } + + // try partial searches + for (int i = 0; _currentTranslation == NULL && _translations[i].lang != NULL; ++i) { + if (strncmp(lang, _translations[i].lang, 2) == 0) { + _currentTranslation = _translations[i].msgs; + _currentTranslationCharset = _translations[i].charset; + } + } + + // if found, count entries + if (_currentTranslation != NULL) { + for (const PoMessageEntry *m = _currentTranslation; m->msgid != -1; ++m) + ++_currentTranslationMessageEntryCount; + } +} + +const char *po2c_gettext(const char *msgid) { + // if no language is set or msgid is empty, return msgid as is + if (_currentTranslation == NULL || *msgid == '\0') + return msgid; + + // binary-search for the msgid + int leftIndex = 0; + int rightIndex = _currentTranslationMessageEntryCount - 1; + + while (rightIndex >= leftIndex) { + const int midIndex = (leftIndex + rightIndex) / 2; + const PoMessageEntry * const m = &_currentTranslation[midIndex]; + + const int compareResult = strcmp(msgid, _messageIds[m->msgid]); + + if (compareResult == 0) + return m->msgstr; + else if (compareResult < 0) + rightIndex = midIndex - 1; + else + leftIndex = midIndex + 1; + } + + return msgid; +} + +const char *po2c_getcharset(void) { + if (_currentTranslationCharset) + return _currentTranslationCharset; + else + return "ASCII"; +} + +int po2c_getnumlangs(void) { + return ARRAYSIZE(_translations) - 1; +} + +const char *po2c_getlang(const int num) { + assert(num < ARRAYSIZE(_translations)); + return _translations[num].lang; +} +EOF + +exit 0; |