new file mode 100644
@@ -0,0 +1,24 @@
+/* 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/>. */
+
+#ifndef _XASPRINTF_H
+#define _XASPRINTF_H 1
+
+extern char *xasprintf (const char *format, ...)
+ __attribute__ ((__format__ (__printf__, 1, 2), __warn_unused_result__));
+
+#endif /* xasprintf.h */
@@ -56,7 +56,7 @@
localedef-aux := md5
locale-modules := locale locale-spec
lib-modules := charmap-dir simple-hash xmalloc xstrdup \
- record-status
+ record-status xasprintf
GPERF = gperf
@@ -434,20 +434,16 @@
{
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 +473,13 @@
}
-/* 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 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 const char *
construct_output_path (char *path)
{
- const char *normal = NULL;
char *result;
- char *endp;
if (strchr (path, '/') == NULL)
{
@@ -493,50 +487,44 @@
contains a reference to the codeset. This should be
normalized. */
char *startp;
+ char *endp = NULL;
+ const 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 ((char *) 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,24 +534,40 @@
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. */
+/* 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 cahracters.
+ - 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 const char *
normalize_codeset (const char *codeset, size_t name_len)
{
@@ -573,6 +577,7 @@
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,6 +587,8 @@
only_digit = 0;
}
+ /* If there were only digits we assume it's an ISO standard and we will
+ prefix with 'iso' so include space for that. */
retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
if (retval != NULL)
@@ -592,6 +599,7 @@
wp = retval;
for (cnt = 0; cnt < name_len; ++cnt)
+ /* Lowercase all characters. */
if (isalpha (codeset[cnt]))
*wp++ = tolower (codeset[cnt]);
else if (isdigit (codeset[cnt]))
@@ -600,6 +608,7 @@
*wp = '\0';
}
+ /* Return allocated and converted name for caller to free. */
return (const char *) retval;
}
@@ -123,6 +123,7 @@
/* Prototypes for a few program-wide used functions. */
#include <programs/xmalloc.h>
+#include <programs/xasprintf.h>
/* Mark given locale as to be read. */
new file mode 100644
@@ -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;
+}