diff options
Diffstat (limited to 'locale/programs')
-rw-r--r-- | locale/programs/localedef.c | 151 | ||||
-rw-r--r-- | locale/programs/localedef.h | 1 | ||||
-rw-r--r-- | locale/programs/xasprintf.c | 34 |
3 files changed, 113 insertions, 73 deletions
diff --git a/locale/programs/localedef.c b/locale/programs/localedef.c index dbbb0145c0..b048bd05b9 100644 --- a/locale/programs/localedef.c +++ b/locale/programs/localedef.c @@ -180,14 +180,14 @@ static struct argp argp = /* Prototypes for local functions. */ static void error_print (void); -static const char *construct_output_path (char *path); -static const char *normalize_codeset (const char *codeset, size_t name_len); +static char *construct_output_path (char *path); +static char *normalize_codeset (const char *codeset, size_t name_len); int main (int argc, char *argv[]) { - const char *output_path; + char *output_path; int cannot_write_why; struct charmap_t *charmap; struct localedef_t global; @@ -232,7 +232,8 @@ main (int argc, char *argv[]) } /* The parameter describes the output path of the constructed files. - If the described files cannot be written return a NULL pointer. */ + If the described files cannot be written return a NULL pointer. + We don't free output_path because we will exit. */ output_path = construct_output_path (argv[remaining]); if (output_path == NULL && ! no_archive) error (4, errno, _("cannot create directory for output files")); @@ -434,20 +435,16 @@ more_help (int key, const char *text, void *input) { case ARGP_KEY_HELP_EXTRA: /* We print some extra information. */ - if (asprintf (&tp, gettext ("\ + tp = xasprintf (gettext ("\ For bug reporting instructions, please see:\n\ -%s.\n"), REPORT_BUGS_TO) < 0) - return NULL; - if (asprintf (&cp, gettext ("\ +%s.\n"), REPORT_BUGS_TO); + cp = xasprintf (gettext ("\ System's directory for character maps : %s\n\ repertoire maps: %s\n\ locale path : %s\n\ %s"), - CHARMAP_PATH, REPERTOIREMAP_PATH, LOCALE_PATH, tp) < 0) - { - free (tp); - return NULL; - } + CHARMAP_PATH, REPERTOIREMAP_PATH, LOCALE_PATH, tp); + free (tp); return cp; default: break; @@ -477,15 +474,13 @@ error_print (void) } -/* The parameter to localedef describes the output path. If it does - contain a '/' character it is a relative path. Otherwise it names the - locale this definition is for. */ -static const char * +/* The parameter to localedef describes the output path. If it does contain a + '/' character it is a relative path. Otherwise it names the locale this + definition is for. The returned path must be freed by the caller. */ +static char * construct_output_path (char *path) { - const char *normal = NULL; char *result; - char *endp; if (strchr (path, '/') == NULL) { @@ -493,50 +488,44 @@ construct_output_path (char *path) contains a reference to the codeset. This should be normalized. */ char *startp; + char *endp = NULL; + char *normal = NULL; startp = path; - /* We must be prepared for finding a CEN name or a location of - the introducing `.' where it is not possible anymore. */ + /* Either we have a '@' which starts a CEN name or '.' which starts the + codeset specification. The CEN name starts with '@' and may also have + a codeset specification, but we do not normalize the string after '@'. + If we only find the codeset specification then we normalize only the codeset + specification (but not anything after a subsequent '@'). */ while (*startp != '\0' && *startp != '@' && *startp != '.') ++startp; if (*startp == '.') { /* We found a codeset specification. Now find the end. */ endp = ++startp; + + /* Stop at the first '@', and don't normalize anything past that. */ while (*endp != '\0' && *endp != '@') ++endp; if (endp > startp) normal = normalize_codeset (startp, endp - startp); } - else - /* This is to keep gcc quiet. */ - endp = NULL; - /* We put an additional '\0' at the end of the string because at - the end of the function we need another byte for the trailing - '/'. */ - ssize_t n; if (normal == NULL) - n = asprintf (&result, "%s%s/%s%c", output_prefix ?: "", - COMPLOCALEDIR, path, '\0'); + result = xasprintf ("%s%s/%s/", output_prefix ?: "", + COMPLOCALEDIR, path); else - n = asprintf (&result, "%s%s/%.*s%s%s%c", - output_prefix ?: "", COMPLOCALEDIR, - (int) (startp - path), path, normal, endp, '\0'); - - if (n < 0) - return NULL; - - endp = result + n - 1; + result = xasprintf ("%s%s/%.*s%s%s/", + output_prefix ?: "", COMPLOCALEDIR, + (int) (startp - path), path, normal, endp ?: ""); + /* Free the allocated normalized codeset name. */ + free (normal); } else { - /* This is a user path. Please note the additional byte in the - memory allocation. */ - size_t len = strlen (path) + 1; - result = xmalloc (len + 1); - endp = mempcpy (result, path, len) - 1; + /* This is a user path. */ + result = xasprintf ("%s/", path); /* If the user specified an output path we cannot add the output to the archive. */ @@ -546,25 +535,41 @@ construct_output_path (char *path) errno = 0; if (no_archive && euidaccess (result, W_OK) == -1) - /* Perhaps the directory does not exist now. Try to create it. */ - if (errno == ENOENT) - { - errno = 0; - if (mkdir (result, 0777) < 0) - return NULL; - } - - *endp++ = '/'; - *endp = '\0'; + { + /* Perhaps the directory does not exist now. Try to create it. */ + if (errno == ENOENT) + { + errno = 0; + if (mkdir (result, 0777) < 0) + { + record_verbose (stderr, + _("cannot create output path \'%s\': %s"), + result, strerror (errno)); + free (result); + return NULL; + } + } + else + record_verbose (stderr, + _("no write permission to output path \'%s\': %s"), + result, strerror (errno)); + } return result; } -/* Normalize codeset name. There is no standard for the codeset - names. Normalization allows the user to use any of the common - names. */ -static const char * +/* Normalize codeset name. There is no standard for the codeset names. + Normalization allows the user to use any of the common names e.g. UTF-8, + utf-8, utf8, UTF8 etc. + + We normalize using the following rules: + - Remove all non-alpha-numeric characters + - Lowercase all characters. + - If there are only digits assume it's an ISO standard and prefix with 'iso' + + We return the normalized string which needs to be freed by free. */ +static char * normalize_codeset (const char *codeset, size_t name_len) { int len = 0; @@ -573,6 +578,7 @@ normalize_codeset (const char *codeset, size_t name_len) char *wp; size_t cnt; + /* Compute the length of only the alpha-numeric characters. */ for (cnt = 0; cnt < name_len; ++cnt) if (isalnum (codeset[cnt])) { @@ -582,25 +588,24 @@ normalize_codeset (const char *codeset, size_t name_len) only_digit = 0; } - retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1); + /* If there were only digits we assume it's an ISO standard and we will + prefix with 'iso' so include space for that. We fill in the required + space from codeset up to the converted length. */ + wp = retval = xasprintf ("%s%.*s", only_digit ? "iso" : "", len, codeset); - if (retval != NULL) - { - if (only_digit) - wp = stpcpy (retval, "iso"); - else - wp = retval; - - for (cnt = 0; cnt < name_len; ++cnt) - if (isalpha (codeset[cnt])) - *wp++ = tolower (codeset[cnt]); - else if (isdigit (codeset[cnt])) - *wp++ = codeset[cnt]; + /* Skip "iso". */ + if (only_digit) + wp += 3; - *wp = '\0'; - } + /* Lowercase all characters. */ + for (cnt = 0; cnt < name_len; ++cnt) + if (isalpha (codeset[cnt])) + *wp++ = tolower (codeset[cnt]); + else if (isdigit (codeset[cnt])) + *wp++ = codeset[cnt]; - return (const char *) retval; + /* Return allocated and converted name for caller to free. */ + return retval; } diff --git a/locale/programs/localedef.h b/locale/programs/localedef.h index 62ad717216..c98acf1bbe 100644 --- a/locale/programs/localedef.h +++ b/locale/programs/localedef.h @@ -123,6 +123,7 @@ extern bool hard_links; /* Prototypes for a few program-wide used functions. */ #include <programs/xmalloc.h> +#include <programs/xasprintf.h> /* Mark given locale as to be read. */ diff --git a/locale/programs/xasprintf.c b/locale/programs/xasprintf.c new file mode 100644 index 0000000000..efc91a9c34 --- /dev/null +++ b/locale/programs/xasprintf.c @@ -0,0 +1,34 @@ +/* asprintf with out of memory checking + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + 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; 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, see <https://www.gnu.org/licenses/>. */ + +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <libintl.h> +#include <error.h> + +char * +xasprintf (const char *format, ...) +{ + va_list ap; + va_start (ap, format); + char *result; + if (vasprintf (&result, format, ap) < 0) + error (EXIT_FAILURE, 0, _("memory exhausted")); + va_end (ap); + return result; +} |