X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=cups%2Flanguage.c;h=e0641699035d7d7bb3be705d92273bf900e6a2c4;hb=HEAD;hp=69e391f2a8df96b084894a273faf197ee20c3fb6;hpb=3647435025e7db95f6239edf21e377566b23be64;p=thirdparty%2Fcups.git diff --git a/cups/language.c b/cups/language.c index 69e391f2a..e06416990 100644 --- a/cups/language.c +++ b/cups/language.c @@ -1,18 +1,10 @@ /* - * "$Id$" - * * I18N/language support for CUPS. * - * Copyright 2007-2015 by Apple Inc. + * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * - * These coded instructions, statements, and computer programs are the - * property of Apple Inc. and are protected by Federal copyright - * law. Distribution and use rights are outlined in the file "LICENSE.txt" - * which should have been included with this file. If this file is - * file is missing or damaged, see the license at "http://www.cups.org/". - * - * This file is subject to the Apple OS-Developed Software exception. + * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* @@ -20,14 +12,15 @@ */ #include "cups-private.h" +#include "debug-internal.h" #ifdef HAVE_LANGINFO_H # include #endif /* HAVE_LANGINFO_H */ -#ifdef WIN32 +#ifdef _WIN32 # include #else # include -#endif /* WIN32 */ +#endif /* _WIN32 */ #ifdef HAVE_COREFOUNDATION_H # include #endif /* HAVE_COREFOUNDATION_H */ @@ -120,11 +113,15 @@ typedef struct } _apple_language_locale_t; static const _apple_language_locale_t apple_language_locale[] = -{ /* Locale to language ID LUT */ - { "en", "en_US" }, - { "nb", "no" }, - { "zh-Hans", "zh_CN" }, - { "zh-Hant", "zh_TW" } +{ /* Language to locale ID LUT */ + { "en", "en_US" }, + { "nb", "no" }, + { "nb_NO", "no" }, + { "zh-Hans", "zh_CN" }, + { "zh_HANS", "zh_CN" }, + { "zh-Hant", "zh_TW" }, + { "zh_HANT", "zh_TW" }, + { "zh-Hant_CN", "zh_TW" } }; #endif /* __APPLE__ */ @@ -144,16 +141,15 @@ static const char *appleLangDefault(void); # define CF_RETURNS_RETAINED # endif /* __has_feature(attribute_cf_returns_retained) */ # endif /* !CF_RETURNED_RETAINED */ -static cups_array_t *appleMessageLoad(const char *locale) - CF_RETURNS_RETAINED; +static cups_array_t *appleMessageLoad(const char *locale) CF_RETURNS_RETAINED; # endif /* CUPS_BUNDLEDIR */ #endif /* __APPLE__ */ -static cups_lang_t *cups_cache_lookup(const char *name, - cups_encoding_t encoding); -static int cups_message_compare(_cups_message_t *m1, - _cups_message_t *m2); +static cups_lang_t *cups_cache_lookup(const char *name, cups_encoding_t encoding); +static int cups_message_compare(_cups_message_t *m1, _cups_message_t *m2); static void cups_message_free(_cups_message_t *m); static void cups_message_load(cups_lang_t *lang); +static void cups_message_puts(cups_file_t *fp, const char *s); +static int cups_read_strings(cups_file_t *fp, int flags, cups_array_t *a); static void cups_unquote(char *d, const char *s); @@ -241,6 +237,96 @@ _cupsAppleLanguage(const char *locale, /* I - Locale ID */ return (language); } + + +/* + * '_cupsAppleLocale()' - Get the locale associated with an Apple language ID. + */ + +const char * /* O - Locale */ +_cupsAppleLocale(CFStringRef languageName, /* I - Apple language ID */ + char *locale, /* I - Buffer for locale */ + size_t localesize) /* I - Size of buffer */ +{ + int i; /* Looping var */ + CFStringRef localeName; /* Locale as a CF string */ +#ifdef DEBUG + char temp[1024]; /* Temporary string */ + + + if (!CFStringGetCString(languageName, temp, (CFIndex)sizeof(temp), kCFStringEncodingASCII)) + temp[0] = '\0'; + + DEBUG_printf(("_cupsAppleLocale(languageName=%p(%s), locale=%p, localsize=%d)", (void *)languageName, temp, (void *)locale, (int)localesize)); +#endif /* DEBUG */ + + localeName = CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorDefault, languageName); + + if (localeName) + { + /* + * Copy the locale name and tweak as needed... + */ + + if (!CFStringGetCString(localeName, locale, (CFIndex)localesize, kCFStringEncodingASCII)) + *locale = '\0'; + + DEBUG_printf(("_cupsAppleLocale: locale=\"%s\"", locale)); + + CFRelease(localeName); + + /* + * Map new language identifiers to locales... + */ + + for (i = 0; + i < (int)(sizeof(apple_language_locale) / + sizeof(apple_language_locale[0])); + i ++) + { + size_t len = strlen(apple_language_locale[i].language); + + if (!strcmp(locale, apple_language_locale[i].language) || + (!strncmp(locale, apple_language_locale[i].language, len) && (locale[len] == '_' || locale[len] == '-'))) + { + DEBUG_printf(("_cupsAppleLocale: Updating locale to \"%s\".", apple_language_locale[i].locale)); + strlcpy(locale, apple_language_locale[i].locale, localesize); + break; + } + } + } + else + { + /* + * Just try the Apple language name... + */ + + if (!CFStringGetCString(languageName, locale, (CFIndex)localesize, kCFStringEncodingASCII)) + *locale = '\0'; + } + + if (!*locale) + { + DEBUG_puts("_cupsAppleLocale: Returning NULL."); + return (NULL); + } + + /* + * Convert language subtag into region subtag... + */ + + if (locale[2] == '-') + locale[2] = '_'; + else if (locale[3] == '-') + locale[3] = '_'; + + if (!strchr(locale, '.')) + strlcat(locale, ".UTF-8", localesize); + + DEBUG_printf(("_cupsAppleLocale: Returning \"%s\".", locale)); + + return (locale); +} #endif /* __APPLE__ */ @@ -600,6 +686,15 @@ cupsLangGet(const char *language) /* I - Language or locale */ *ptr++ = (char)toupper(*language & 255); *ptr = '\0'; + + /* + * Map Chinese region codes to legacy country codes. + */ + + if (!strcmp(language, "zh") && !strcmp(country, "HANS")) + strlcpy(country, "CN", sizeof(country)); + if (!strcmp(language, "zh") && !strcmp(country, "HANT")) + strlcpy(country, "TW", sizeof(country)); } if (*language == '.' && !charset[0]) @@ -619,7 +714,7 @@ cupsLangGet(const char *language) /* I - Language or locale */ * Force a POSIX locale for an invalid language name... */ - if (strlen(langname) != 2) + if (strlen(langname) != 2 && strlen(langname) != 3) { strlcpy(langname, "C", sizeof(langname)); country[0] = '\0'; @@ -759,6 +854,9 @@ _cupsLangString(cups_lang_t *lang, /* I - Language */ { const char *s; /* Localized message */ + + DEBUG_printf(("_cupsLangString(lang=%p, message=\"%s\")", (void *)lang, message)); + /* * Range check input... */ @@ -808,12 +906,12 @@ _cupsMessageFree(cups_array_t *a) /* I - Message array */ /* - * '_cupsMessageLoad()' - Load a .po file into a messages array. + * '_cupsMessageLoad()' - Load a .po or .strings file into a messages array. */ cups_array_t * /* O - New message array */ _cupsMessageLoad(const char *filename, /* I - Message catalog to load */ - int unquote) /* I - Unescape \foo in strings? */ + int flags) /* I - Load flags */ { cups_file_t *fp; /* Message file */ cups_array_t *a; /* Message array */ @@ -848,187 +946,189 @@ _cupsMessageLoad(const char *filename, /* I - Message catalog to load */ return (a); } - /* - * Read messages from the catalog file until EOF... - * - * The format is the GNU gettext .po format, which is fairly simple: - * - * msgid "some text" - * msgstr "localized text" - * - * The ID and localized text can span multiple lines using the form: - * - * msgid "" - * "some long text" - * msgstr "" - * "localized text spanning " - * "multiple lines" - */ - - m = NULL; - - while (cupsFileGets(fp, s, sizeof(s)) != NULL) + if (flags & _CUPS_MESSAGE_STRINGS) + { + while (cups_read_strings(fp, flags, a)); + } + else { /* - * Skip blank and comment lines... - */ - - if (s[0] == '#' || !s[0]) - continue; - - /* - * Strip the trailing quote... + * Read messages from the catalog file until EOF... + * + * The format is the GNU gettext .po format, which is fairly simple: + * + * msgid "some text" + * msgstr "localized text" + * + * The ID and localized text can span multiple lines using the form: + * + * msgid "" + * "some long text" + * msgstr "" + * "localized text spanning " + * "multiple lines" */ - if ((ptr = strrchr(s, '\"')) == NULL) - continue; - - *ptr = '\0'; - - /* - * Find start of value... - */ + m = NULL; - if ((ptr = strchr(s, '\"')) == NULL) - continue; + while (cupsFileGets(fp, s, sizeof(s)) != NULL) + { + /* + * Skip blank and comment lines... + */ - ptr ++; + if (s[0] == '#' || !s[0]) + continue; - /* - * Unquote the text... - */ + /* + * Strip the trailing quote... + */ - if (unquote) - cups_unquote(ptr, ptr); + if ((ptr = strrchr(s, '\"')) == NULL) + continue; - /* - * Create or add to a message... - */ + *ptr = '\0'; - if (!strncmp(s, "msgid", 5)) - { /* - * Add previous message as needed... + * Find start of value... */ - if (m) - { - if (m->str && m->str[0]) - { - cupsArrayAdd(a, m); - } - else - { - /* - * Translation is empty, don't add it... (STR #4033) - */ - - free(m->id); - if (m->str) - free(m->str); - free(m); - } - } + if ((ptr = strchr(s, '\"')) == NULL) + continue; + + ptr ++; /* - * Create a new message with the given msgid string... + * Unquote the text... */ - if ((m = (_cups_message_t *)calloc(1, sizeof(_cups_message_t))) == NULL) - { - cupsFileClose(fp); - return (a); - } + if (flags & _CUPS_MESSAGE_UNQUOTE) + cups_unquote(ptr, ptr); - if ((m->id = strdup(ptr)) == NULL) - { - free(m); - cupsFileClose(fp); - return (a); - } - } - else if (s[0] == '\"' && m) - { /* - * Append to current string... + * Create or add to a message... */ - length = strlen(m->str ? m->str : m->id); - ptrlen = strlen(ptr); - - if ((temp = realloc(m->str ? m->str : m->id, length + ptrlen + 1)) == NULL) + if (!strncmp(s, "msgid", 5)) { - if (m->str) - free(m->str); - free(m->id); - free(m); + /* + * Add previous message as needed... + */ - cupsFileClose(fp); - return (a); - } + if (m) + { + if (m->str && (m->str[0] || (flags & _CUPS_MESSAGE_EMPTY))) + { + cupsArrayAdd(a, m); + } + else + { + /* + * Translation is empty, don't add it... (STR #4033) + */ + + free(m->msg); + if (m->str) + free(m->str); + free(m); + } + } - if (m->str) - { /* - * Copy the new portion to the end of the msgstr string - safe - * to use memcpy because the buffer is allocated to the correct - * size... + * Create a new message with the given msgid string... */ - m->str = temp; + if ((m = (_cups_message_t *)calloc(1, sizeof(_cups_message_t))) == NULL) + break; - memcpy(m->str + length, ptr, ptrlen + 1); + if ((m->msg = strdup(ptr)) == NULL) + { + free(m); + m = NULL; + break; + } } - else + else if (s[0] == '\"' && m) { /* - * Copy the new portion to the end of the msgid string - safe - * to use memcpy because the buffer is allocated to the correct - * size... + * Append to current string... */ - m->id = temp; + length = strlen(m->str ? m->str : m->msg); + ptrlen = strlen(ptr); - memcpy(m->id + length, ptr, ptrlen + 1); - } - } - else if (!strncmp(s, "msgstr", 6) && m) - { - /* - * Set the string... - */ + if ((temp = realloc(m->str ? m->str : m->msg, length + ptrlen + 1)) == NULL) + { + if (m->str) + free(m->str); + free(m->msg); + free(m); + m = NULL; + break; + } + + if (m->str) + { + /* + * Copy the new portion to the end of the msgstr string - safe + * to use memcpy because the buffer is allocated to the correct + * size... + */ + + m->str = temp; + + memcpy(m->str + length, ptr, ptrlen + 1); + } + else + { + /* + * Copy the new portion to the end of the msgid string - safe + * to use memcpy because the buffer is allocated to the correct + * size... + */ + + m->msg = temp; - if ((m->str = strdup(ptr)) == NULL) + memcpy(m->msg + length, ptr, ptrlen + 1); + } + } + else if (!strncmp(s, "msgstr", 6) && m) { - free(m->id); - free(m); + /* + * Set the string... + */ - cupsFileClose(fp); - return (a); + if ((m->str = strdup(ptr)) == NULL) + { + free(m->msg); + free(m); + m = NULL; + break; + } } } - } - /* - * Add the last message string to the array as needed... - */ + /* + * Add the last message string to the array as needed... + */ - if (m) - { - if (m->str && m->str[0]) - { - cupsArrayAdd(a, m); - } - else + if (m) { - /* - * Translation is empty, don't add it... (STR #4033) - */ + if (m->str && (m->str[0] || (flags & _CUPS_MESSAGE_EMPTY))) + { + cupsArrayAdd(a, m); + } + else + { + /* + * Translation is empty, don't add it... (STR #4033) + */ - free(m->id); - if (m->str) - free(m->str); - free(m); + free(m->msg); + if (m->str) + free(m->str); + free(m); + } } } @@ -1038,8 +1138,7 @@ _cupsMessageLoad(const char *filename, /* I - Message catalog to load */ cupsFileClose(fp); - DEBUG_printf(("5_cupsMessageLoad: Returning %d messages...", - cupsArrayCount(a))); + DEBUG_printf(("5_cupsMessageLoad: Returning %d messages...", cupsArrayCount(a))); return (a); } @@ -1057,13 +1156,15 @@ _cupsMessageLookup(cups_array_t *a, /* I - Message array */ *match; /* Matching message */ + DEBUG_printf(("_cupsMessageLookup(a=%p, m=\"%s\")", (void *)a, m)); + /* * Lookup the message string; if it doesn't exist in the catalog, * then return the message that was passed to us... */ - key.id = (char *)m; - match = (_cups_message_t *)cupsArrayFind(a, &key); + key.msg = (char *)m; + match = (_cups_message_t *)cupsArrayFind(a, &key); #if defined(__APPLE__) && defined(CUPS_BUNDLEDIR) if (!match && cupsArrayUserData(a)) @@ -1076,12 +1177,11 @@ _cupsMessageLookup(cups_array_t *a, /* I - Message array */ CFStringRef cfm, /* Message as a CF string */ cfstr; /* Localized text as a CF string */ - dict = (CFDictionaryRef)cupsArrayUserData(a); - cfm = CFStringCreateWithCString(kCFAllocatorDefault, m, - kCFStringEncodingUTF8); - match = calloc(1, sizeof(_cups_message_t)); - match->id = strdup(m); - cfstr = cfm ? CFDictionaryGetValue(dict, cfm) : NULL; + dict = (CFDictionaryRef)cupsArrayUserData(a); + cfm = CFStringCreateWithCString(kCFAllocatorDefault, m, kCFStringEncodingUTF8); + match = calloc(1, sizeof(_cups_message_t)); + match->msg = strdup(m); + cfstr = cfm ? CFDictionaryGetValue(dict, cfm) : NULL; if (cfstr) { @@ -1090,8 +1190,7 @@ _cupsMessageLookup(cups_array_t *a, /* I - Message array */ CFStringGetCString(cfstr, buffer, sizeof(buffer), kCFStringEncodingUTF8); match->str = strdup(buffer); - DEBUG_printf(("1_cupsMessageLookup: Found \"%s\" as \"%s\"...", - m, buffer)); + DEBUG_printf(("1_cupsMessageLookup: Found \"%s\" as \"%s\"...", m, buffer)); } else { @@ -1128,6 +1227,57 @@ _cupsMessageNew(void *context) /* I - User data */ } +/* + * '_cupsMessageSave()' - Save a message catalog array. + */ + +int /* O - 0 on success, -1 on failure */ +_cupsMessageSave(const char *filename,/* I - Output filename */ + int flags, /* I - Format flags */ + cups_array_t *a) /* I - Message array */ +{ + cups_file_t *fp; /* Output file */ + _cups_message_t *m; /* Current message */ + + + /* + * Output message catalog file... + */ + + if ((fp = cupsFileOpen(filename, "w")) == NULL) + return (-1); + + /* + * Write each message... + */ + + if (flags & _CUPS_MESSAGE_STRINGS) + { + for (m = (_cups_message_t *)cupsArrayFirst(a); m; m = (_cups_message_t *)cupsArrayNext(a)) + { + cupsFilePuts(fp, "\""); + cups_message_puts(fp, m->msg); + cupsFilePuts(fp, "\" = \""); + cups_message_puts(fp, m->str); + cupsFilePuts(fp, "\";\n"); + } + } + else + { + for (m = (_cups_message_t *)cupsArrayFirst(a); m; m = (_cups_message_t *)cupsArrayNext(a)) + { + cupsFilePuts(fp, "msgid \""); + cups_message_puts(fp, m->msg); + cupsFilePuts(fp, "\"\nmsgstr \""); + cups_message_puts(fp, m->str); + cupsFilePuts(fp, "\"\n"); + } + } + + return (cupsFileClose(fp)); +} + + #ifdef __APPLE__ /* * 'appleLangDefault()' - Get the default locale string. @@ -1136,13 +1286,11 @@ _cupsMessageNew(void *context) /* I - User data */ static const char * /* O - Locale string */ appleLangDefault(void) { - int i; /* Looping var */ CFBundleRef bundle; /* Main bundle (if any) */ CFArrayRef bundleList; /* List of localizations in bundle */ CFPropertyListRef localizationList = NULL; /* List of localization data */ CFStringRef languageName; /* Current name */ - CFStringRef localeName; /* Canonical from of name */ char *lang; /* LANG environment variable */ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ @@ -1227,49 +1375,11 @@ appleLangDefault(void) if (languageName && CFGetTypeID(languageName) == CFStringGetTypeID()) { - localeName = CFLocaleCreateCanonicalLocaleIdentifierFromString( - kCFAllocatorDefault, languageName); - - if (localeName) - { - CFStringGetCString(localeName, cg->language, sizeof(cg->language), - kCFStringEncodingASCII); - CFRelease(localeName); - + if (_cupsAppleLocale(languageName, cg->language, sizeof(cg->language))) DEBUG_printf(("3appleLangDefault: cg->language=\"%s\"", cg->language)); - - /* - * Map new language identifiers to locales... - */ - - for (i = 0; - i < (int)(sizeof(apple_language_locale) / - sizeof(apple_language_locale[0])); - i ++) - { - if (!strcmp(cg->language, apple_language_locale[i].language)) - { - DEBUG_printf(("3appleLangDefault: mapping \"%s\" to \"%s\"...", - cg->language, apple_language_locale[i].locale)); - strlcpy(cg->language, apple_language_locale[i].locale, - sizeof(cg->language)); - break; - } - } - - /* - * Convert language subtag into region subtag... - */ - - if (cg->language[2] == '-') - cg->language[2] = '_'; - - if (!strchr(cg->language, '.')) - strlcat(cg->language, ".UTF-8", sizeof(cg->language)); - } else - DEBUG_puts("3appleLangDefault: Unable to get localeName."); + DEBUG_puts("3appleLangDefault: Unable to get locale."); } } @@ -1307,11 +1417,13 @@ appleMessageLoad(const char *locale) /* I - Locale ID */ { char filename[1024], /* Path to cups.strings file */ applelang[256], /* Apple language ID */ - baselang[3]; /* Base language */ + baselang[4]; /* Base language */ CFURLRef url; /* URL to cups.strings file */ CFReadStreamRef stream = NULL; /* File stream */ CFPropertyListRef plist = NULL; /* Localization file */ #ifdef DEBUG + const char *cups_strings = getenv("CUPS_STRINGS"); + /* Test strings file */ CFErrorRef error = NULL; /* Error when opening file */ #endif /* DEBUG */ @@ -1322,6 +1434,15 @@ appleMessageLoad(const char *locale) /* I - Locale ID */ * Load the cups.strings file... */ +#ifdef DEBUG + if (cups_strings) + { + DEBUG_puts("1appleMessageLoad: Using debug CUPS_STRINGS file."); + strlcpy(filename, cups_strings, sizeof(filename)); + } + else +#endif /* DEBUG */ + snprintf(filename, sizeof(filename), CUPS_BUNDLEDIR "/Resources/%s.lproj/cups.strings", _cupsAppleLanguage(locale, applelang, sizeof(applelang))); @@ -1334,10 +1455,26 @@ appleMessageLoad(const char *locale) /* I - Locale ID */ * Try with original locale string... */ + DEBUG_printf(("1appleMessageLoad: \"%s\": %s", filename, strerror(errno))); snprintf(filename, sizeof(filename), CUPS_BUNDLEDIR "/Resources/%s.lproj/cups.strings", locale); } - DEBUG_printf(("1appleMessageLoad: filename=\"%s\"", filename)); + if (access(filename, 0)) + { + /* + * + * + * Try with just the language code... + */ + + DEBUG_printf(("1appleMessageLoad: \"%s\": %s", filename, strerror(errno))); + + strlcpy(baselang, locale, sizeof(baselang)); + if (baselang[3] == '-' || baselang[3] == '_') + baselang[3] = '\0'; + + snprintf(filename, sizeof(filename), CUPS_BUNDLEDIR "/Resources/%s.lproj/cups.strings", baselang); + } if (access(filename, 0)) { @@ -1345,9 +1482,13 @@ appleMessageLoad(const char *locale) /* I - Locale ID */ * Try alternate lproj directory names... */ + DEBUG_printf(("1appleMessageLoad: \"%s\": %s", filename, strerror(errno))); + if (!strncmp(locale, "en", 2)) locale = "English"; - else if (!strncmp(locale, "nb", 2) || !strncmp(locale, "nl", 2)) + else if (!strncmp(locale, "nb", 2)) + locale = "no"; + else if (!strncmp(locale, "nl", 2)) locale = "Dutch"; else if (!strncmp(locale, "fr", 2)) locale = "French"; @@ -1359,10 +1500,11 @@ appleMessageLoad(const char *locale) /* I - Locale ID */ locale = "Japanese"; else if (!strncmp(locale, "es", 2)) locale = "Spanish"; - else if (!strcmp(locale, "zh_HK")) + else if (!strcmp(locale, "zh_HK") || !strncasecmp(locale, "zh-Hant", 7) || !strncasecmp(locale, "zh_Hant", 7)) { /* * + * * * Try zh_TW first, then zh... Sigh... */ @@ -1379,14 +1521,18 @@ appleMessageLoad(const char *locale) /* I - Locale ID */ */ strlcpy(baselang, locale, sizeof(baselang)); + if (baselang[2] == '-' || baselang[2] == '_') + baselang[2] = '\0'; + locale = baselang; } snprintf(filename, sizeof(filename), CUPS_BUNDLEDIR "/Resources/%s.lproj/cups.strings", locale); - DEBUG_printf(("1appleMessageLoad: alternate filename=\"%s\"", filename)); } + DEBUG_printf(("1appleMessageLoad: filename=\"%s\"", filename)); + url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8 *)filename, (CFIndex)strlen(filename), false); @@ -1476,7 +1622,7 @@ cups_cache_lookup( for (lang = lang_cache; lang != NULL; lang = lang->next) { DEBUG_printf(("9cups_cache_lookup: lang=%p, language=\"%s\", " - "encoding=%d(%s)", lang, lang->language, lang->encoding, + "encoding=%d(%s)", (void *)lang, lang->language, lang->encoding, lang_encodings[lang->encoding])); if (!strcmp(lang->language, name) && @@ -1505,7 +1651,7 @@ cups_message_compare( _cups_message_t *m1, /* I - First message */ _cups_message_t *m2) /* I - Second message */ { - return (strcmp(m1->id, m2->id)); + return (strcmp(m1->msg, m2->msg)); } @@ -1516,8 +1662,8 @@ cups_message_compare( static void cups_message_free(_cups_message_t *m) /* I - Message */ { - if (m->id) - free(m->id); + if (m->msg) + free(m->msg); if (m->str) free(m->str); @@ -1571,11 +1717,166 @@ cups_message_load(cups_lang_t *lang) /* I - Language */ * Read the strings from the file... */ - lang->strings = _cupsMessageLoad(filename, 1); + lang->strings = _cupsMessageLoad(filename, _CUPS_MESSAGE_UNQUOTE); #endif /* __APPLE__ && CUPS_BUNDLEDIR */ } +/* + * 'cups_message_puts()' - Write a message string with quoting. + */ + +static void +cups_message_puts(cups_file_t *fp, /* I - File to write to */ + const char *s) /* I - String to write */ +{ + const char *start, /* Start of substring */ + *ptr; /* Pointer into string */ + + + for (start = s, ptr = s; *ptr; ptr ++) + { + if (strchr("\\\"\n\t", *ptr)) + { + if (ptr > start) + { + cupsFileWrite(fp, start, (size_t)(ptr - start)); + start = ptr + 1; + } + + if (*ptr == '\\') + cupsFileWrite(fp, "\\\\", 2); + else if (*ptr == '\"') + cupsFileWrite(fp, "\\\"", 2); + else if (*ptr == '\n') + cupsFileWrite(fp, "\\n", 2); + else /* if (*ptr == '\t') */ + cupsFileWrite(fp, "\\t", 2); + } + } + + if (ptr > start) + cupsFileWrite(fp, start, (size_t)(ptr - start)); +} + + +/* + * 'cups_read_strings()' - Read a pair of strings from a .strings file. + */ + +static int /* O - 1 on success, 0 on failure */ +cups_read_strings(cups_file_t *fp, /* I - .strings file */ + int flags, /* I - CUPS_MESSAGE_xxx flags */ + cups_array_t *a) /* I - Message catalog array */ +{ + char buffer[8192], /* Line buffer */ + *bufptr, /* Pointer into buffer */ + *msg, /* Pointer to start of message */ + *str; /* Pointer to start of translation string */ + _cups_message_t *m; /* New message */ + + + while (cupsFileGets(fp, buffer, sizeof(buffer))) + { + /* + * Skip any line (comments, blanks, etc.) that isn't: + * + * "message" = "translation"; + */ + + for (bufptr = buffer; *bufptr && isspace(*bufptr & 255); bufptr ++); + + if (*bufptr != '\"') + continue; + + /* + * Find the end of the message... + */ + + bufptr ++; + for (msg = bufptr; *bufptr && *bufptr != '\"'; bufptr ++) + if (*bufptr == '\\' && bufptr[1]) + bufptr ++; + + if (!*bufptr) + continue; + + *bufptr++ = '\0'; + + if (flags & _CUPS_MESSAGE_UNQUOTE) + cups_unquote(msg, msg); + + /* + * Find the start of the translation... + */ + + while (*bufptr && isspace(*bufptr & 255)) + bufptr ++; + + if (*bufptr != '=') + continue; + + bufptr ++; + while (*bufptr && isspace(*bufptr & 255)) + bufptr ++; + + if (*bufptr != '\"') + continue; + + /* + * Find the end of the translation... + */ + + bufptr ++; + for (str = bufptr; *bufptr && *bufptr != '\"'; bufptr ++) + if (*bufptr == '\\' && bufptr[1]) + bufptr ++; + + if (!*bufptr) + continue; + + *bufptr++ = '\0'; + + if (flags & _CUPS_MESSAGE_UNQUOTE) + cups_unquote(str, str); + + /* + * If we get this far we have a valid pair of strings, add them... + */ + + if ((m = malloc(sizeof(_cups_message_t))) == NULL) + break; + + m->msg = strdup(msg); + m->str = strdup(str); + + if (m->msg && m->str) + { + cupsArrayAdd(a, m); + } + else + { + if (m->msg) + free(m->msg); + + if (m->str) + free(m->str); + + free(m); + break; + } + + return (1); + } + + /* + * No more strings... + */ + + return (0); +} + + /* * 'cups_unquote()' - Unquote characters in strings... */ @@ -1621,8 +1922,3 @@ cups_unquote(char *d, /* O - Unquoted string */ *d = '\0'; } - - -/* - * End of "$Id$". - */