Package init

This commit is contained in:
overweight 2019-09-30 10:40:17 -04:00
commit ab2b3c9d4d
8 changed files with 956 additions and 0 deletions

View File

@ -0,0 +1,136 @@
From dce3a16e5e9368245735e29bf498dcd5e3e474a4 Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Thu, 15 Sep 2016 13:57:24 +0200
Subject: [PATCH] xgettext: Fix crash with *.po file input
When xgettext was given two *.po files with the same msgid_plural, it
crashed with double-free. Problem reported by Davlet Panech in:
http://lists.gnu.org/archive/html/bug-gettext/2016-09/msg00001.html
* gettext-tools/src/po-gram-gen.y: Don't free msgid_pluralform after
calling do_callback_message, assuming that it takes ownership.
* gettext-tools/src/read-catalog.c (default_add_message): Free
msgid_plural after calling message_alloc.
* gettext-tools/tests/xgettext-po-2: New file.
* gettext-tools/tests/Makefile.am (TESTS): Add new test.
---
gettext-tools/src/po-gram-gen.y | 13 ++++-----
gettext-tools/src/read-catalog.c | 2 ++
gettext-tools/tests/Makefile.am | 2 +-
gettext-tools/tests/xgettext-po-2 | 55 +++++++++++++++++++++++++++++++++++++++
4 files changed, 63 insertions(+), 9 deletions(-)
create mode 100755 gettext-tools/tests/xgettext-po-2
diff --git a/gettext-tools/src/po-gram-gen.y b/gettext-tools/src/po-gram-gen.y
index becf5e6..4428e77 100644
--- a/gettext-tools/src/po-gram-gen.y
+++ b/gettext-tools/src/po-gram-gen.y
@@ -221,14 +221,11 @@ message
check_obsolete ($1, $3);
check_obsolete ($1, $4);
if (!$1.obsolete || pass_obsolete_entries)
- {
- do_callback_message ($1.ctxt, string2, &$1.pos, $3.string,
- $4.rhs.msgstr, $4.rhs.msgstr_len, &$4.pos,
- $1.prev_ctxt,
- $1.prev_id, $1.prev_id_plural,
- $1.obsolete);
- free ($3.string);
- }
+ do_callback_message ($1.ctxt, string2, &$1.pos, $3.string,
+ $4.rhs.msgstr, $4.rhs.msgstr_len, &$4.pos,
+ $1.prev_ctxt,
+ $1.prev_id, $1.prev_id_plural,
+ $1.obsolete);
else
{
free_message_intro ($1);
diff --git a/gettext-tools/src/read-catalog.c b/gettext-tools/src/read-catalog.c
index 571d18e..6af6d20 100644
--- a/gettext-tools/src/read-catalog.c
+++ b/gettext-tools/src/read-catalog.c
@@ -397,6 +397,8 @@ default_add_message (default_catalog_reader_ty *this,
appropriate. */
mp = message_alloc (msgctxt, msgid, msgid_plural, msgstr, msgstr_len,
msgstr_pos);
+ if (msgid_plural != NULL)
+ free (msgid_plural);
mp->prev_msgctxt = prev_msgctxt;
mp->prev_msgid = prev_msgid;
mp->prev_msgid_plural = prev_msgid_plural;
diff --git a/gettext-tools/tests/Makefile.am b/gettext-tools/tests/Makefile.am
index 23b09b1..0dfb4d8 100644
--- a/gettext-tools/tests/Makefile.am
+++ b/gettext-tools/tests/Makefile.am
@@ -95,7 +95,7 @@ TESTS = gettext-1 gettext-2 gettext-3 gettext-4 gettext-5 gettext-6 gettext-7 \
xgettext-perl-1 xgettext-perl-2 xgettext-perl-3 xgettext-perl-4 \
xgettext-perl-5 xgettext-perl-6 xgettext-perl-7 xgettext-perl-8 \
xgettext-php-1 xgettext-php-2 xgettext-php-3 xgettext-php-4 \
- xgettext-po-1 \
+ xgettext-po-1 xgettext-po-2 \
xgettext-properties-1 \
xgettext-python-1 xgettext-python-2 xgettext-python-3 \
xgettext-python-4 \
diff --git a/gettext-tools/tests/xgettext-po-2 b/gettext-tools/tests/xgettext-po-2
new file mode 100755
index 0000000..c4bd9d0
--- /dev/null
+++ b/gettext-tools/tests/xgettext-po-2
@@ -0,0 +1,55 @@
+#! /bin/sh
+. "${srcdir=.}/init.sh"; path_prepend_ . ../src
+
+# Test PO extractors with multiple input files.
+
+cat <<EOF > xg-po-2-1.po
+msgid "first msgid"
+msgid_plural "first msgid (plural)"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "second msgid"
+msgid_plural "second msgid (plural)"
+msgstr[0] ""
+msgstr[1] ""
+EOF
+
+cat <<EOF > xg-po-2-2.po
+msgid "third msgid"
+msgid_plural "third msgid (plural)"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "second msgid"
+msgid_plural "second msgid (plural)"
+msgstr[0] ""
+msgstr[1] ""
+EOF
+
+: ${XGETTEXT=xgettext}
+${XGETTEXT} --omit-header xg-po-2-1.po xg-po-2-2.po -o xg-po-2.tmp.po || Exit 1
+LC_ALL=C tr -d '\r' < xg-po-2.tmp.po > xg-po-2.po || Exit 1
+
+cat <<EOF > xg-po-2.ok
+msgid "first msgid"
+msgid_plural "first msgid (plural)"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "second msgid"
+msgid_plural "second msgid (plural)"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "third msgid"
+msgid_plural "third msgid (plural)"
+msgstr[0] ""
+msgstr[1] ""
+EOF
+
+: ${DIFF=diff}
+${DIFF} xg-po-2.ok xg-po-2.po
+result=$?
+
+exit $result
--
1.9.1

View File

@ -0,0 +1,47 @@
commit bd2c6ca2b7ae0be02d4bb85db79def454f3153fb
Author: rpm-build <rpm-build>
AuthorDate: Wed Dec 21 12:50:54 2016 +0100
Commit: rpm-build <rpm-build>
CommitDate: Wed Dec 21 12:52:36 2016 +0100
disable-gettext-runtime-test-lock.patch
diff --git a/gettext-runtime/tests/Makefile.am b/gettext-runtime/tests/Makefile.am
index 88a0684..3a27b79 100644
--- a/gettext-runtime/tests/Makefile.am
+++ b/gettext-runtime/tests/Makefile.am
@@ -19,7 +19,7 @@
AUTOMAKE_OPTIONS = 1.11 gnits no-dependencies color-tests subdir-objects
EXTRA_DIST =
-TESTS = test-lock
+TESTS =
AM_CPPFLAGS = \
-I.. \
diff --git a/gettext-runtime/tests/Makefile.in b/gettext-runtime/tests/Makefile.in
index 4327733..5879146 100644
--- a/gettext-runtime/tests/Makefile.in
+++ b/gettext-runtime/tests/Makefile.in
@@ -86,7 +86,7 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
-TESTS = test-lock$(EXEEXT)
+TESTS =
check_PROGRAMS = test-lock$(EXEEXT)
subdir = tests
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
diff --git a/gettext-tools/gnulib-tests/Makefile.in b/gettext-tools/gnulib-tests/Makefile.in
index 26becd9..4b9d0e4 100644
--- a/gettext-tools/gnulib-tests/Makefile.in
+++ b/gettext-tools/gnulib-tests/Makefile.in
@@ -143,7 +143,7 @@ TESTS = test-set-mode-acl.sh test-set-mode-acl-1.sh \
test-isnanl-nolibm$(EXEEXT) test-isnanl$(EXEEXT) \
test-iswblank$(EXEEXT) test-langinfo$(EXEEXT) \
test-linkedhash_list$(EXEEXT) test-locale$(EXEEXT) \
- test-localename$(EXEEXT) test-lock$(EXEEXT) \
+ test-localename$(EXEEXT) \
test-log10$(EXEEXT) test-lseek.sh test-lstat$(EXEEXT) \
test-malloca$(EXEEXT) test-math$(EXEEXT) test-mbrtowc1.sh \
test-mbrtowc2.sh test-mbrtowc3.sh test-mbrtowc4.sh \

View File

@ -0,0 +1,43 @@
From a0cab23332a254e3500cac2a3a984472d02180e5 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Fri, 9 Dec 2016 21:04:31 +0100
Subject: [PATCH] Fix crash of xgettext with --its option.
* gettext-tools/src/xgettext.c (main): Free contents of its_dirs only when it
was initialized. Fixes bug introduced on 2016-05-16.
---
gettext-tools/src/xgettext.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/gettext-tools/src/xgettext.c b/gettext-tools/src/xgettext.c
index f848d76d1..a80ee51ac 100644
--- a/gettext-tools/src/xgettext.c
+++ b/gettext-tools/src/xgettext.c
@@ -330,7 +330,7 @@ main (int argc, char *argv[])
bool sort_by_msgid = false;
bool sort_by_filepos = false;
char **dirs;
- char **its_dirs;
+ char **its_dirs = NULL;
char *explicit_its_filename = NULL;
const char *file_name;
const char *files_from = NULL;
@@ -1016,9 +1016,12 @@ warning: file '%s' extension '%s' is unknown; will try C"), filename, extension)
if (its_locating_rules)
locating_rule_list_free (its_locating_rules);
- for (i = 0; its_dirs[i] != NULL; i++)
- free (its_dirs[i]);
- free (its_dirs);
+ if (its_dirs != NULL)
+ {
+ for (i = 0; its_dirs[i] != NULL; i++)
+ free (its_dirs[i]);
+ free (its_dirs);
+ }
exit (EXIT_SUCCESS);
}
--
2.14.3

BIN
gettext-0.19.8.1.tar.xz Normal file

Binary file not shown.

View File

@ -0,0 +1,21 @@
Index: gettext-0.19.8.1/gettext-tools/misc/po-mode.el
===================================================================
--- gettext-0.19.8.1.orig/gettext-tools/misc/po-mode.el
+++ gettext-0.19.8.1/gettext-tools/misc/po-mode.el
@@ -3518,10 +3518,12 @@ Write to your team? ('n' if writing to
(re-search-forward
(concat "^" (regexp-quote mail-header-separator) "\n"))
(save-excursion
- (insert-buffer-substring buffer)
- (shell-command-on-region
- (region-beginning) (region-end)
- (concat po-gzip-uuencode-command " " name ".gz") t t))))))
+ (save-restriction
+ (narrow-to-region (point) (point))
+ (insert-buffer-substring buffer)
+ (shell-command-on-region
+ (point-min) (point-max)
+ (concat po-gzip-uuencode-command " " name ".gz") t t)))))))
(message ""))
(defun po-confirm-and-quit ()

247
gettext.spec Normal file
View File

@ -0,0 +1,247 @@
%bcond_with jar
%bcond_with java
%bcond_without check
%global archiveversion 0.19.8
Name: gettext
Version: 0.19.8.1
Release: 19
License: GPLv3+ and LGPLv2+
Summary: GNU gettext utilities are a set of tools that provides a framework to help other GNU packages produce multi-lingual messages.
URL: https://www.gnu.org/software/gettext/
Source: ftp://ftp.gnu.org/gnu/gettext/%{name}-%{version}.tar.xz
Patch0: disable-gettext-runtime-test-lock.patch
Patch1: gettext-po-send-mail.patch
Patch2: gettext-0.19.8-its-segfault.patch
Patch6000: backport-CVE-2018-18751.patch
Source2: msghack.py
Source3: msghack.1
BuildRequires: gcc-c++, emacs, git, xz, chrpath, autoconf
BuildRequires: ncurses-devel, libxml2-devel, glib2-devel, libcroco-devel, libunistring-devel
%if %{with java}
BuildRequires: gcc-java, libgcj
BuildRequires: java-1.6.0-openjdk-devel
%if %{with jar}
BuildRequires: %{_bindir}/fastjar
BuildRequires: zip, unzip
%endif
%endif
# Requires: %{name}-libs%{_isa} = %{version}-%{release}
Conflicts: filesystem < 3
Provides: /bin/gettext
Provides: bundled(gnulib)
Provides: %{name}-libs
Obsoletes: %{name}-libs
%description
GNU gettext is an important step for the GNU Translation Project, as it
is an asset on which we may build many other steps. This package offers
to programmers, translators, and even users, a well integrated set of
tools and documentation. Specifically, the GNU gettext utilities are a
set of tools that provides a framework to help other GNU packages
produce multi-lingual messages. These tools include a set of conventions
about how programs should be written to support message catalogs, a
directory and file naming organization for the message catalogs themselves,
a runtime library supporting the retrieval of translated messages, and
a few stand-alone programs to massage in various ways the sets of
translatable strings, or already translated strings. A special GNU Emacs
mode also helps interested parties in preparing these sets, or bringing
them up to date.
%package devel
Summary: Development files for %{name}
License: LGPLv2+ and GPLv3+
Requires: %{name} = %{version}-%{release}
Requires(post): info
Requires(preun): info
Requires: xz
Obsoletes: gettext-autopoint < 0.18.1.1-3
Provides: gettext-autopoint = %{version}-%{release}
Obsoletes: %{name}-common-devel
Provides: %{name}-common-devel
Provides: emacs-po-mode
Requires: emacs(bin) >= %{_emacs_version}
Provides: emacs-%{name}-el = %{version}-%{release}
Provides: emacs-%{name}
Obsoletes: emacs-%{name}
Obsoletes: emacs-%{name}-el < %{version}-%{release}
Obsoletes: msghack
Provides: msghack
%description devel
This package provides development files and tools which help edit/alter
po files, if you need to compile gettext related application/library or
edit/alter po files, you should install this package.
want to add gettext support for your project.
%package help
Summary: help info for %{name}
%description help
This package contains man, license, info, readme, copyright, license.
%prep
%autosetup -n %{name}-%{version} -S git
%build
%if %{with java}
export JAVAC=gcj
%if %{with jar}
export JAR=fastjar
%endif
%endif
%ifarch ppc ppc64 ppc64le
export CFLAGS="$RPM_OPT_FLAGS -D__SUPPORT_SNAN__"
%endif
autoreconf
%configure --without-included-gettext --enable-nls --disable-static \
--enable-shared --with-pic --disable-csharp --disable-rpath \
%if %{with java}
--enable-java \
%else
--disable-java --disable-native-java \
%endif
--with-xz
make %{?_smp_mflags} %{?with_java:GCJFLAGS="-findirect-dispatch"}
%install
make install DESTDIR=${RPM_BUILD_ROOT} INSTALL="%{__install} -p" \
lispdir=%{_datadir}/emacs/site-lisp/gettext \
aclocaldir=%{_datadir}/aclocal EXAMPLESFILES=""
install -pm 755 %SOURCE2 ${RPM_BUILD_ROOT}/%{_bindir}/msghack
install -pm 644 %SOURCE3 ${RPM_BUILD_ROOT}/%{_mandir}/man1/msghack.1
# make preloadable_libintl.so executable
chmod 755 ${RPM_BUILD_ROOT}%{_libdir}/preloadable_libintl.so
rm -f ${RPM_BUILD_ROOT}%{_infodir}/dir
# doc relocations
for i in gettext-runtime/man/*.html; do
rm ${RPM_BUILD_ROOT}%{_datadir}/doc/gettext/`basename $i`
done
rm -r ${RPM_BUILD_ROOT}%{_datadir}/doc/gettext/javadoc*
rm -rf ${RPM_BUILD_ROOT}%{_datadir}/doc/gettext/examples
rm -rf htmldoc
mkdir htmldoc
mv ${RPM_BUILD_ROOT}%{_datadir}/doc/gettext/* ${RPM_BUILD_ROOT}/%{_datadir}/doc/libasprintf/* htmldoc
rm -r ${RPM_BUILD_ROOT}%{_datadir}/doc/libasprintf
rm -r ${RPM_BUILD_ROOT}%{_datadir}/doc/gettext
%if %{with jar}
%else
rm -f ${RPM_BUILD_ROOT}%{_datadir}/%{name}/libintl.jar
%endif
rm -f ${RPM_BUILD_ROOT}%{_datadir}/%{name}/gettext.jar
mkdir -p $RPM_BUILD_ROOT%{_datadir}/%{name}/its
rm ${RPM_BUILD_ROOT}%{_libdir}/lib*.la
rm ${RPM_BUILD_ROOT}%{_libdir}/libgettext{src,lib}.so
install -d ${RPM_BUILD_ROOT}%{_emacs_sitestartdir}
mv ${RPM_BUILD_ROOT}%{_emacs_sitelispdir}/%{name}/start-po.el ${RPM_BUILD_ROOT}%{_emacs_sitestartdir}
rm ${RPM_BUILD_ROOT}%{_emacs_sitelispdir}/%{name}/start-po.elc
%find_lang %{name}-runtime
%find_lang %{name}-tools
cat %{name}-*.lang > %{name}.lang
# cleanup rpaths
for i in $RPM_BUILD_ROOT%{_bindir}/* `find $RPM_BUILD_ROOT%{_libdir} -type f`; do
if file $i | grep "ELF 64-bit" >/dev/null; then
chrpath -l $i && chrpath --delete $i
fi
done
%if %{with check}
%check
make check LIBUNISTRING=-lunistring
%endif
%ldconfig_scriptlets libs
%files -f %{name}.lang
%doc AUTHORS gettext-runtime/BUGS
%doc COPYING gettext-tools/misc/DISCLAIM README
%doc NEWS THANKS
%doc gettext-runtime/man/*.1.html
%doc gettext-runtime/intl/COPYING*
%{_bindir}/*
%exclude %{_bindir}/autopoint
%exclude %{_bindir}/gettextize
%exclude %{_bindir}/msghack
%{_libdir}/%{name}
%if %{with java}
%exclude %{_libdir}/%{name}/gnu.gettext.*
%endif
%dir %{_datadir}/%{name}
%dir %{_datadir}/%{name}/its
%{_datadir}/%{name}/ABOUT-NLS
%{_datadir}/%{name}/po
%{_datadir}/%{name}/styles
%dir %{_datadir}/%{name}-%{archiveversion}
%{_datadir}/%{name}-%{archiveversion}/its
%{_libdir}/libasprintf.so.0*
%{_libdir}/libgettextpo.so.0*
%{_libdir}/libgettextlib-0.*.so
%{_libdir}/libgettextsrc-0.*.so
%if %{with jar}
%{_datadir}/%{name}/libintl.jar
%endif
%files devel
%doc gettext-runtime/man/*.3.html ChangeLog
%{_bindir}/autopoint
%{_bindir}/gettextize
%{_datadir}/%{name}/projects/
%{_datadir}/%{name}/config.rpath
%{_datadir}/%{name}/*.h
%{_datadir}/%{name}/msgunfmt.tcl
%{_datadir}/aclocal/*
%{_includedir}/*
%{_infodir}/autosprintf*
%{_libdir}/libasprintf.so
%{_libdir}/libgettextpo.so
%{_libdir}/preloadable_libintl.so
%{_mandir}/man1/autopoint.1*
%{_mandir}/man3/*
%{_datadir}/%{name}/intl
%{_datadir}/%{name}/javaversion.class
%doc gettext-runtime/intl-java/javadoc*
%if %{with java}
%{_libdir}/%{name}/gnu.gettext.*
%endif
%{_datadir}/%{name}/archive.*.tar.xz
%dir %{_emacs_sitelispdir}/%{name}
%{_emacs_sitelispdir}/%{name}/*.elc
%{_emacs_sitelispdir}/%{name}/*.el
%{_emacs_sitestartdir}/*.el
%license COPYING
%{_bindir}/msghack
%{_mandir}/man1/msghack.1*
%files help
%{_infodir}/gettext*
%{_mandir}/man1/*
%exclude %{_mandir}/man1/autopoint.1*
%exclude %{_mandir}/man1/msghack.1*
%changelog
* Fri Sep 27 2019 openEuler Buildteam <buildteam@openeuler.org> - 0.19.8.1-19
- fix CVE-2018-18751
* Tue Sep 17 2019 openEuler Buildteam <buildteam@openeuler.org> - 0.19.8.1-18
- Package init

45
msghack.1 Normal file
View File

@ -0,0 +1,45 @@
.TH MSGHACK "1" "June 2013" "msghack" "User Commands"
.SH NAME
msghack \- alter PO files in ways
.SH SYNOPSIS
.B msghack
[\fIOPTION\fR] \fIfile.po \fR[\fIref.po\fR]
.SH DESCRIPTION
.PP
This program can be used to alter .po files in ways no sane mind would think about.
.TP
\fB\-o\fR
result will be written to FILE
.TP
\fB\-\-invert\fR
invert a po file by switching msgid and msgstr
.TP
\fB\-\-master\fR
join any number of files in a master\-formatted catalog
.TP
\fB\-\-empty\fR
empty the contents of the .po file, creating a .pot
.TP
\fB\-\-append\fR
append entries from ref.po that don't exist in file.po
.PP
Note: It is just a replacement of msghack for backward support.
.PP
This program can be used to alter .po files in ways no sane mind would think about.
.TP
\fB\-o\fR
result will be written to FILE
.TP
\fB\-\-invert\fR
invert a po file by switching msgid and msgstr
.TP
\fB\-\-master\fR
join any number of files in a master\-formatted catalog
.TP
\fB\-\-empty\fR
empty the contents of the .po file, creating a .pot
.TP
\fB\-\-append\fR
append entries from ref.po that don't exist in file.po
.PP
Note: It is just a replacement of msghack for backward support.

417
msghack.py Executable file
View File

@ -0,0 +1,417 @@
#!/usr/bin/python3
## -*- coding: utf-8 -*-
## Copyright (C) 2001, 2004, 2008, 2012 Red Hat, Inc.
## Copyright (C) 2001 Trond Eivind Glomsrød <teg@redhat.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 3 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, see <http://www.gnu.org/licenses/>.
"""
A msghack replacement
"""
import sys
class GTMessage:
"""
A class containing a message, its msgid and various references pointing at it
"""
def __init__(self,id=None,message=None,refs=[]):
"""
The constructor for the GTMessage class
@self The object instance
@message The message
@id The messageid associated with the object
"""
self._message=message.strip()
self._id=id.strip()
self._refs=[]
for ref in refs:
self._refs.append(ref)
def __str__(self):
"""
Return a string representation of the object
@self The object instance
"""
res=""
for ref in self._refs:
res=res+ref+"\n"
res=res+"msgid %s\nmsgstr %s\n" % (self._id,self._message)
return res
def invertedStrings(self):
"""
Returns a string representation, but with msgid and msgstr inverted.
Note: Don't invert the "" string
@self The object instance
"""
res=""
for ref in self._refs:
res=res+ref+"\n"
if not self._id=="\"\"":
res=res+"msgid %s\nmsgstr %s\n" % (self._message,self._id)
else:
res=res+"msgid %s\nmsgstr %s\n" % (self._id,self._message)
return res
def emptyMsgStrings(self):
"""
Return a string representation of the object, but leave the msgstr
empty - create a pot file from a po file
Note: Won't remove the "" string
@self The object instance
"""
res=""
for ref in self._refs:
res=res+ref+"\n"
if not self._id=="\"\"":
res=res+"msgid %s\nmsgstr \"\"\n" % (self._id)
else:
res=res+"msgid %s\nmsgstr %s\n" % (self._id,self._message)
return res
def compareMessage(self,msg):
"""
Return if the messages have identical msgids, 0 otherwise
@self The object instance
@msg The message to compare to
"""
if self._id == msg._id:
return 1
return 0
class GTMasterMessage:
"""
A class containing a message, its msgid and various references pointing at it
The difference between GTMessage and GTMasterMessage is that this class
can do less operations, but is able to store multiple msgstrs with identifiers
(usually language, like 'msgst(no)'
"""
def __init__(self,id=None,refs=[]):
"""
The constructor for the GTMessage class
@self The object instance
@id The messageid associated with the object
"""
self._id=id
self._refs=[]
self._messages=[]
for ref in refs:
self._refs.append(ref)
def addMessage(self,message,identifier):
"""
Add a new message and identifier to the GTMasterMessage object
@self The object instance
@message The message to append
@identifier The identifier of the message
"""
self._messages.append((identifier,message))
def __str__(self):
"""
Return a string representation of the object
@self The object instance
"""
res=""
for ref in self._refs:
res=res+ref+"\n"
res=res+"msgid %s\n" % self._id
for message in self._messages:
res=res+"msgstr(%s) %s\n" %(message[0],message[1])
res=res+"\n"
return res
class GTFile:
"""
A class containing the GTMessages contained in a file
"""
def __init__(self,filename):
"""
The constructor of the GTMFile class
@self The object instance
@filename The file to initialize from
"""
self._filename=filename
self._messages=[]
self.readFile(filename)
def __str__(self):
"""
Return a string representation of the object
@self The object instance
"""
res=""
for message in self._messages:
res=res+str(message)+"\n"
return res
def invertedStrings(self):
"""
Return a string representation of the object, with msgid and msgstr
swapped. Will remove duplicates...
@self The object instance
"""
msght={}
msgar=[]
for message in self._messages:
if message._id=='""' and len(msgar)==0:
msgar.append(GTMessage(message._id,message._message,message._refs))
continue
msg=GTMessage(message._message,message._id,message._refs)
if msg._id not in msght:
msght[msg._id]=msg
msgar.append(msg)
else:
msg2=msght[msg._id]
for ref in msg._refs:
msg2._refs.append(ref)
res=""
for message in msgar:
res=res+str(message)+"\n"
return res
def msgidDupes(self):
"""
Search for duplicates in the msgids.
@self The object instance
"""
msgids={}
res=""
for message in self._messages:
msgid=message._id
if msgid in msgids:
res=res+"Duplicate: %s\n" % (msgid)
else:
msgids[msgid]=1
return res
def getMsgstr(self,msgid):
"""
Return the msgstr matching the given id. 'None' if missing
@self The object instance
@msgid The msgid key
"""
for message in self._messages:
if msgid == message._id:
return message._message
return None
def emptyMsgStrings(self):
"""
Return a string representation of the object, but leave the msgstr
empty - create a pot file from a po file
@self The object instance
"""
res=""
for message in self._messages:
res=res+message.emptyMsgStrings()+"\n"
return res
def append(self,B):
"""
Append entries from dictionary B which aren't
already present in this dictionary
@self The object instance
@B the dictionary to append messages from
"""
for message in B._messages:
if not self.getMsgstr(message._id):
self._messages.append(message)
def readFile(self,filename):
"""
Read the contents of a file into the GTFile object
@self The object instance
@filename The name of the file to read
"""
file=open(filename,"r")
msgid=""
msgstr=""
refs=[]
lines=[]
inmsgid=0
inmsgstr=0
templines=file.readlines()
for line in templines:
lines.append(line.strip())
for line in lines:
pos=line.find('"')
pos2=line.rfind('"')
if line and line[0]=="#":
refs.append(line.strip())
if inmsgstr==0 and line[:6]=="msgstr":
msgstr=""
inmsgstr=1
inmsgid=0
if inmsgstr==1:
if pos==-1:
inmsgstr=0
#Handle entries with and without "" consistently
if msgid[:2]=='""' and len(msgid)>4:
msgid=msgid[2:]
if msgstr[:2]=='""' and len(msgstr)>4:
msgstr=msgstr[2:]
message=GTMessage(msgid,msgstr,refs)
self._messages.append(message)
msgstr=""
msgid=""
refs=[]
else:
msgstr=msgstr+line[pos:pos2+1]+"\n"
if inmsgid==0 and line[:5]=="msgid":
msgid=""
inmsgid=1
if inmsgid==1:
if pos==-1:
inmsgid=0
else:
msgid=msgid+line[pos:pos2+1]+"\n"
if msgstr and msgid:
message=GTMessage(msgid,msgstr,refs)
self._messages.append(message)
class GTMaster:
"""
A class containing a master catalogue of gettext dictionaries
"""
def __init__(self,dicts):
"""
The constructor for the GTMaster class
@self The object instance
@dicts An array of dictionaries to merge
"""
self._messages=[]
self.createMaster(dicts)
def createMaster(self,dicts):
"""
Create the master catalogue
@self The object instance
@dicts An array of dictionaries to merge
"""
self._master=dicts[0]
self._dicts=dicts[1:]
for message in self._master._messages:
gtm=GTMasterMessage(message._id,message._refs)
gtm.addMessage(message._message,self._master._filename[:-3])
for dict in self._dicts:
res=dict.getMsgstr(message._id)
if(res):
gtm.addMessage(res,dict._filename[:-3])
self._messages.append(gtm)
def __str__(self):
"""
Return a string representation of the object
@self The object instance
"""
res=""
for message in self._messages:
res=res+str(message)+"\n"
return res
def printUsage():
"Print the usage messages"
print("Usage: " + str(sys.argv[0]) + " [OPTION] file.po [ref.po]\n\
This program can be used to alter .po files in ways no sane mind would think about.\n\
-o result will be written to FILE\n\
--invert invert a po file by switching msgid and msgstr\n\
--master join any number of files in a master-formatted catalog\n\
--empty empty the contents of the .po file, creating a .pot\n\
--append append entries from ref.po that don't exist in file.po\n\
\n\
Note: It is just a replacement of msghack for backward support.\n")
if __name__=="__main__":
output=None
res=None
if("-o") in sys.argv:
if (len(sys.argv)<=sys.argv.index("-o")+1):
print("file.po and ref.po are not specified!\n")
printUsage()
exit(1)
output=sys.argv[sys.argv.index("-o")+1]
sys.argv.remove("-o")
sys.argv.remove(output)
if("--invert") in sys.argv:
if (len(sys.argv)<=sys.argv.index("--invert")+1):
print("file.po is not specified!\n")
printUsage()
exit(1)
file=sys.argv[sys.argv.index("--invert")+1]
gtf=GTFile(file)
res1=gtf.msgidDupes()
if res1:
sys.stderr.write(res1)
sys.exit(1)
res=str(gtf.invertedStrings())
elif("--empty") in sys.argv:
if (len(sys.argv)<=sys.argv.index("--empty")+1):
print("file.po is not specified!\n")
printUsage()
exit(1)
file=sys.argv[sys.argv.index("--empty")+1]
gtf=GTFile(file)
res=str(gtf.emptyMsgStrings())
elif("--master") in sys.argv:
if (len(sys.argv)<=sys.argv.index("--master")+1):
print("file.po is not specified!\n")
printUsage()
exit(1)
loc=sys.argv.index("--master")+1
gtfs=[]
for file in sys.argv[loc:]:
gtfs.append(GTFile(file))
master=GTMaster(gtfs)
res=str(master)
elif("--append") in sys.argv:
if (len(sys.argv)<=sys.argv.index("--append")+2):
print("file.po and/or ref.po are not specified!\n")
printUsage()
exit(1)
file=sys.argv[sys.argv.index("--append")+1]
file2=sys.argv[sys.argv.index("--append")+2]
gtf=GTFile(file)
gtf2=GTFile(file2)
gtf.append(gtf2)
res=str(gtf)
else:
#print("Not implemented: "+str(sys.argv))
printUsage()
sys.exit(1)
if not output:
print(res)
else:
file=open(output,"w")
file.write(res)
sys.exit(0)