diff options
author | Anas Nashif <anas.nashif@intel.com> | 2012-10-11 12:26:20 -0700 |
---|---|---|
committer | Anas Nashif <anas.nashif@intel.com> | 2013-02-02 16:44:14 -0800 |
commit | ff412beb0fbd5eab906b52a9905bd8c06b1608e7 (patch) | |
tree | 728099902393a0895e629b272f3a2625f3e223de /lib | |
parent | 0b8a3c4e3afbb517fd47e06bacee034ac455ed10 (diff) | |
download | rpm-ff412beb0fbd5eab906b52a9905bd8c06b1608e7.tar.gz rpm-ff412beb0fbd5eab906b52a9905bd8c06b1608e7.tar.bz2 rpm-ff412beb0fbd5eab906b52a9905bd8c06b1608e7.zip |
Convert output to the current locale.
Assumes utf8 input if the decoding works, otherwise iso-8859-1.
(imported from suse rpm)
Diffstat (limited to 'lib')
-rw-r--r-- | lib/tagexts.c | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/lib/tagexts.c b/lib/tagexts.c index 29b2bae9f..563c1b43c 100644 --- a/lib/tagexts.c +++ b/lib/tagexts.c @@ -2,6 +2,7 @@ * \file lib/formats.c */ +#include <wchar.h> #include "system.h" #include <rpm/rpmtypes.h> @@ -191,6 +192,114 @@ exit: return rc; } +static char * strtolocale(char *str) +{ + wchar_t *wstr, *wp; + const unsigned char *cp; + char *cc; + int state = 0; + int c; + int ccl, cca, mb_cur_max; + size_t l; + mbstate_t ps; + int strisutf8 = 1; + int locisutf8 = 1; + + if (!str) + return 0; + if (!*str) + return str; + wstr = (wchar_t *)xmalloc((strlen(str) + 1) * sizeof(*wstr)); + wp = wstr; + cp = (const unsigned char *)str; + while ((c = *cp++) != 0) { + if (state) { + if ((c & 0xc0) != 0x80) { + /* encoding error */ + break; + } + c = (c & 0x3f) | (state << 6); + if (!(state & 0x40000000)) { + /* check for overlong sequences */ + if ((c & 0x820823e0) == 0x80000000) + c = 0xfdffffff; + else if ((c & 0x020821f0) == 0x02000000) + c = 0xfff7ffff; + else if ((c & 0x000820f8) == 0x00080000) + c = 0xffffd000; + else if ((c & 0x0000207c) == 0x00002000) + c = 0xffffff70; + } + } else { + /* new sequence */ + if (c >= 0xfe) + c = 0xfffd; + else if (c >= 0xfc) + c = (c & 0x01) | 0xbffffffc; /* 5 bytes to follow */ + else if (c >= 0xf8) + c = (c & 0x03) | 0xbfffff00; /* 4 */ + else if (c >= 0xf0) + c = (c & 0x07) | 0xbfffc000; /* 3 */ + else if (c >= 0xe0) + c = (c & 0x0f) | 0xbff00000; /* 2 */ + else if (c >= 0xc2) + c = (c & 0x1f) | 0xfc000000; /* 1 */ + else if (c >= 0xc0) + c = 0xfdffffff; /* overlong */ + else if (c >= 0x80) + c = 0xfffd; + } + state = (c & 0x80000000) ? c : 0; + if (state) + continue; + *wp++ = (wchar_t)c; + } + if (state) { + /* encoding error, assume latin1 */ + strisutf8 = 0; + cp = (const unsigned char *)str; + wp = wstr; + while ((c = *cp++) != 0) { + *wp++ = (wchar_t)c; + } + } + *wp = 0; + mb_cur_max = MB_CUR_MAX; + memset(&ps, 0, sizeof(ps)); + cc = xmalloc(mb_cur_max); + /* test locale encoding */ + if (wcrtomb(cc, 0x20ac, &ps) != 3 || memcmp(cc, "\342\202\254", 3)) + locisutf8 = 0; + if (locisutf8 == strisutf8) { + wstr = _free(wstr); + return str; + } + str = _free((char *)str); + memset(&ps, 0, sizeof(ps)); + ccl = cca = 0; + for (wp = wstr; ; wp++) { + l = wcrtomb(cc + ccl, *wp, &ps); + if (*wp == 0) + break; + if (l == (size_t)-1) { + if (*wp < (wchar_t)256 && mbsinit(&ps)) { + cc[ccl] = *wp; + l = 1; + } else + l = wcrtomb(cc + ccl, (wchar_t)'?', &ps); + } + if (l == 0 || l == (size_t)-1) + continue; + ccl += l; + if (ccl > cca) { + cca = ccl + 16; + cc = xrealloc(cc, cca + mb_cur_max); + } + } + wstr = _free(wstr); + return (char *)cc; +} + /** * Retrieve trigger info. * @param h header @@ -508,10 +617,41 @@ static int i18nTag(Header h, rpmTag tag, rpmtd td, headerGetFlags hgflags) #endif rc = headerGet(h, tag, td, HEADERGET_ALLOC); + if (rc && td->data) { + td->data = strtolocale(td->data); + } return rc; } /** + * Retrieve text and convert to locale. + */ +static int localeTag(Header h, rpmTag tag, rpmtd td) +{ + int rc; + rc = headerGet(h, tag, td, HEADERGET_ALLOC); + if (!rc) + return 0; + if (td->type == RPM_STRING_TYPE) { + td->data = strtolocale(td->data); + td->count = 1; + } else if (td->type == RPM_STRING_ARRAY_TYPE) { + char **arr; + int i; + arr = xmalloc(td->count * sizeof(*arr)); + for (i = 0; i < td->count; i++) { + arr[i] = xstrdup(((char **)td->data)[i]); + arr[i] = strtolocale(arr[i]); + } + _free(td->data); + td->data = arr; + td->flags = RPMTD_ALLOCED | RPMTD_PTR_ALLOCED; + } + return rc; +} + + +/** * Retrieve summary text. * @param h header * @retval td tag data container @@ -533,6 +673,16 @@ static int descriptionTag(Header h, rpmtd td, headerGetFlags hgflags) return i18nTag(h, RPMTAG_DESCRIPTION, td, hgflags); } +static int changelognameTag(Header h, rpmtd td) +{ + return localeTag(h, RPMTAG_CHANGELOGNAME, td); +} + +static int changelogtextTag(Header h, rpmtd td) +{ + return localeTag(h, RPMTAG_CHANGELOGTEXT, td); +} + /** * Retrieve group text. * @param h header @@ -812,6 +962,8 @@ static const struct headerTagFunc_s rpmHeaderTagExtensions[] = { { RPMTAG_LONGARCHIVESIZE, longarchivesizeTag }, { RPMTAG_LONGSIZE, longsizeTag }, { RPMTAG_LONGSIGSIZE, longsigsizeTag }, + { RPMTAG_CHANGELOGNAME, changelognameTag }, + { RPMTAG_CHANGELOGTEXT, changelogtextTag }, { RPMTAG_DBINSTANCE, dbinstanceTag }, { RPMTAG_EVR, evrTag }, { RPMTAG_NVR, nvrTag }, |