[augeas-devel] [PATCH 1/6] Switch to C locale on API entry on systems that have uselocale
David Lutterkort
lutter at redhat.com
Fri Oct 23 17:30:08 UTC 2009
Since we need to do all our operations (especially regexp matching) in the
C locale, we switch to that on API entry, and switch back to the user's
locale on API exit.
That also makes it necessary that aug_init wraps the bulk of its work
inside an api_entry/api_exit.
Fixes ticket #35 for systems that have uselocale
---
configure.ac | 2 +-
src/augeas.c | 90 +++++++++++++++++++++++++++++++++++++------------------
src/internal.h | 11 +++++++
3 files changed, 72 insertions(+), 31 deletions(-)
diff --git a/configure.ac b/configure.ac
index 4184785..3da7a0a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -83,7 +83,7 @@ AUGEAS_CFLAGS=-std=gnu99
AC_SUBST(AUGEAS_CFLAGS)
AUGEAS_CHECK_READLINE
-AC_CHECK_FUNCS([open_memstream])
+AC_CHECK_FUNCS([open_memstream uselocale])
VERSION_SCRIPT_FLAGS=
$(/usr/bin/ld --help 2>&1 | grep -- --version-script >/dev/null) && \
diff --git a/src/augeas.c b/src/augeas.c
index 37faee3..f29dbb7 100644
--- a/src/augeas.c
+++ b/src/augeas.c
@@ -32,6 +32,7 @@
#include <argz.h>
#include <string.h>
#include <stdarg.h>
+#include <locale.h>
/* Some popular labels that we use in /augeas */
static const char *const s_augeas = "augeas";
@@ -229,13 +230,66 @@ static struct tree *tree_from_transform(struct augeas *aug,
return NULL;
}
+/* Save user locale and switch to C locale */
+#if HAVE_USELOCALE
+static void save_locale(struct augeas *aug) {
+ if (aug->c_locale == NULL) {
+ aug->c_locale = newlocale(LC_ALL_MASK, "C", NULL);
+ ERR_NOMEM(aug->c_locale == NULL, aug);
+ }
+
+ aug->user_locale = uselocale(aug->c_locale);
+ error:
+ return;
+}
+#else
+static void save_locale(ATTRIBUTE_UNUSED struct augeas *aug) { }
+#endif
+
+#if HAVE_USELOCALE
+static void restore_locale(struct augeas *aug) {
+ uselocale(aug->user_locale);
+ aug->user_locale = NULL;
+}
+#else
+static void restore_locale(ATTRIBUTE_UNUSED struct augeas *aug) { }
+#endif
+
+/* Clean up old error messages every time we enter through the public
+ * API. Since we make internal calls through the public API, we keep a
+ * count of how many times a public API call was made, and only reset when
+ * that count is 0. That requires that all public functions enclose their
+ * work within a matching pair of api_entry/api_exit calls.
+ */
+static void api_entry(const struct augeas *aug) {
+ struct error *err = ((struct augeas *) aug)->error;
+
+ ((struct augeas *) aug)->api_entries += 1;
+
+ if (aug->api_entries > 1)
+ return;
+
+ err->code = AUG_NOERROR;
+ err->minor = 0;
+ FREE(err->details);
+ err->minor_details = NULL;
+ save_locale((struct augeas *) aug);
+}
+
+static void api_exit(const struct augeas *aug) {
+ assert(aug->api_entries > 0);
+ ((struct augeas *) aug)->api_entries -= 1;
+ if (aug->api_entries == 0) {
+ store_pathx_error(aug);
+ restore_locale((struct augeas *) aug);
+ }
+}
+
struct augeas *aug_init(const char *root, const char *loadpath,
unsigned int flags) {
struct augeas *result;
struct tree *tree_root = make_tree(NULL, NULL, NULL, NULL);
- /* There's no point in bothering with api_entry/api_exit here */
-
if (tree_root == NULL)
return NULL;
@@ -249,6 +303,8 @@ struct augeas *aug_init(const char *root, const char *loadpath,
goto error;
}
+ api_entry(result);
+
result->flags = flags;
result->root = init_root(root);
@@ -327,9 +383,11 @@ struct augeas *aug_init(const char *root, const char *loadpath,
if (aug_load(result) < 0)
goto error;
+ api_exit(result);
return result;
error:
+ api_exit(result);
aug_close(result);
return NULL;
}
@@ -344,34 +402,6 @@ static void tree_unlink_children(struct augeas *aug, struct tree *tree) {
tree_unlink(tree->children);
}
-/* Clean up old error messages every time we enter through the public
- * API. Since we make internal calls through the public API, we keep a
- * count of how many times a public API call was made, and only reset when
- * that count is 0. That requires that all public functions enclose their
- * work within a matching pair of api_entry/api_exit calls.
- */
-static void api_entry(const struct augeas *aug) {
- struct error *err = ((struct augeas *) aug)->error;
-
- ((struct augeas *) aug)->api_entries += 1;
-
- if (aug->api_entries > 1)
- return;
-
- err->code = AUG_NOERROR;
- err->minor = 0;
- FREE(err->details);
- err->minor_details = NULL;
-}
-
-static void api_exit(const struct augeas *aug) {
- assert(aug->api_entries > 0);
- ((struct augeas *) aug)->api_entries -= 1;
- if (aug->api_entries == 0) {
- store_pathx_error(aug);
- }
-}
-
int aug_load(struct augeas *aug) {
struct tree *meta = tree_child_cr(aug->origin, s_augeas);
struct tree *meta_files = tree_child_cr(meta, s_files);
diff --git a/src/internal.h b/src/internal.h
index 9ea668a..fa286bb 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -35,6 +35,7 @@
#include <unistd.h>
#include <errno.h>
#include <assert.h>
+#include <locale.h>
/*
* Various parameters about env vars, special tree nodes etc.
@@ -285,6 +286,16 @@ struct augeas {
struct error *error;
uint api_entries; /* Number of entries through a public
* API, 0 when called from outside */
+#if HAVE_USELOCALE
+ /* On systems that have a uselocale call, we switch to the C locale
+ * on entry into API functions, and back to the old user locale
+ * on exit.
+ * FIXME: We need some solution for systems without uselocale, like
+ * setlocale + critical section, though that is very heavy-handed
+ */
+ locale_t c_locale;
+ locale_t user_locale;
+#endif
};
static inline struct error *err_of_aug(const struct augeas *aug) {
--
1.6.2.5
More information about the augeas-devel
mailing list