[augeas-devel] augeas: master - Switch to C locale on API entry on systems that have uselocale

David Lutterkort lutter at fedoraproject.org
Tue Nov 10 17:24:29 UTC 2009


Gitweb:        http://git.fedorahosted.org/git/augeas.git?p=augeas.git;a=commitdiff;h=07b6a88064776e75f9c3296046cc05f9e4e1b405
Commit:        07b6a88064776e75f9c3296046cc05f9e4e1b405
Parent:        3d72cac6633f33d3ac301c8c5cac036105f1c3f3
Author:        David Lutterkort <lutter at redhat.com>
AuthorDate:    Thu Oct 22 16:21:41 2009 +0200
Committer:     David Lutterkort <lutter at redhat.com>
CommitterDate: Tue Nov 10 09:21:28 2009 -0800

Switch to C locale on API entry on systems that have uselocale

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) {




More information about the augeas-devel mailing list