changeset 13166:40606e63445c

142 locale support not POSIX compliant Portions contributed by J. Schilling <joerg@schily.net> Reviewed by: joerg@schily.net Approved by: gwr@nexenta.com
author Garrett D'Amore <garrett@nexenta.com>
date Fri, 03 Sep 2010 11:20:34 -0700
parents 7ebf06c38a9d
children 5f6c3c121560
files usr/src/lib/libc/port/locale/setlocale.c
diffstat 1 files changed, 56 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/lib/libc/port/locale/setlocale.c	Thu Sep 02 21:55:52 2010 -0700
+++ b/usr/src/lib/libc/port/locale/setlocale.c	Fri Sep 03 11:20:34 2010 -0700
@@ -45,6 +45,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <alloca.h>
+#include <stdio.h>
 #include "collate.h"
 #include "lmonetary.h"	/* for __monetary_load_locale() */
 #include "lnumeric.h"	/* for __numeric_load_locale() */
@@ -54,12 +55,12 @@
 #include "timelocal.h" /* for __time_load_locale() */
 #include "../i18n/_loc_path.h"
 
-#define	NUM_CATS	7
 /*
  * Category names for getenv()  Note that this was modified
  * for Solaris.  See <iso/locale_iso.h>.
  */
-static char *categories[NUM_CATS] = {
+#define NUM_CATS	7
+static char *categories[7] = {
 	"LC_CTYPE",
 	"LC_NUMERIC",
 	"LC_TIME",
@@ -125,6 +126,8 @@
 	if (!*locale) {
 		if (category == LC_ALL) {
 			for (i = 0; i < NUM_CATS; ++i) {
+				if (i == LC_ALL)
+					continue;
 				env = __get_locale_env(i);
 				if (strlen(env) > ENCODING_LEN) {
 					errno = EINVAL;
@@ -152,21 +155,21 @@
 				errno = EINVAL;
 				return (NULL);
 			}
-			for (i = 1; i < NUM_CATS; ++i)
+			for (i = 0; i < NUM_CATS; ++i)
 				(void) strcpy(new_categories[i], locale);
 		} else {
 			char	*buf;
 			char	*save;
 
 			buf = alloca(strlen(locale) + 1);
+			(void) strcpy(buf, locale);
 
-			for (i = 0, save = NULL; i <= LC_ALL; i++) {
-				r = strtok_r(buf, "/", &save);
+			save = NULL;
+			r = strtok_r(buf, "/", &save);
+			for (i = 0;  i < NUM_CATS; i++) {
+				if (i == LC_ALL)
+					continue;
 				if (r == NULL) {
-					if (i == LC_ALL) {
-						/* Good!  Fully specified! */
-						break;
-					}
 					/*
 					 * Composite Locale is inadequately
 					 * specified!   (Or with empty fields.)
@@ -177,14 +180,17 @@
 					errno = EINVAL;
 					return (NULL);
 				}
-				if (i == LC_ALL) {
-					/* Too many components */
-					errno = EINVAL;
-					return (NULL);
-				}
 				(void) strlcpy(new_categories[i], r,
 				    ENCODING_LEN);
-				buf = NULL;	/* for strtok's benefit */
+				r = strtok_r(NULL, "/", &save);
+			}
+			if (r != NULL) {
+				/*
+				 * Too many components - we had left over
+				 * data in the LC_ALL.  It is malformed.
+				 */
+				errno = EINVAL;
+				return (NULL);
 			}
 		}
 	}
@@ -192,13 +198,17 @@
 	if (category != LC_ALL)
 		return (loadlocale(category));
 
-	for (i = 0; i < LC_ALL; ++i) {
+	for (i = 0; i < NUM_CATS; ++i) {
 		(void) strcpy(saved_categories[i], current_categories[i]);
+		if (i == LC_ALL)
+			continue;
 		if (loadlocale(i) == NULL) {
 			saverr = errno;
-			for (j = 1; j < i; j++) {
+			for (j = 0; j < i; j++) {
 				(void) strcpy(new_categories[j],
 				    saved_categories[j]);
+				if (i == LC_ALL)
+					continue;
 				if (loadlocale(j) == NULL) {
 					(void) strcpy(new_categories[j], "C");
 					(void) loadlocale(j);
@@ -215,18 +225,37 @@
 currentlocale(void)
 {
 	int i;
-
-	(void) strcpy(current_locale_string, current_categories[0]);
+	int composite = 0;
 
-	for (i = 1; i < LC_ALL; ++i)
-		if (strcmp(current_categories[1], current_categories[i])) {
-			for (i = 1; i < LC_ALL; ++i) {
-				(void) strcat(current_locale_string, "/");
-				(void) strcat(current_locale_string,
-				    current_categories[i]);
-			}
+	/* Look to see if any category is different */
+	for (i = 1; i < NUM_CATS; ++i) {
+		if (i == LC_ALL)
+			continue;
+		if (strcmp(current_categories[0], current_categories[i])) {
+			composite = 1;
 			break;
 		}
+	}
+
+	if (composite) {
+		/*
+		 * Note ordering of these follows the numeric order,
+		 * if the order is changed, then setlocale() will need
+		 * to be changed as well.
+		 */
+		(void) snprintf(current_locale_string,
+		    sizeof (current_locale_string),
+		    "%s/%s/%s/%s/%s/%s",
+		    current_categories[LC_CTYPE],
+		    current_categories[LC_NUMERIC],
+		    current_categories[LC_TIME],
+		    current_categories[LC_COLLATE],
+		    current_categories[LC_MONETARY],
+		    current_categories[LC_MESSAGES]);
+	} else {
+		(void) strlcpy(current_locale_string, current_categories[0],
+		    sizeof (current_locale_string));
+	}
 	return (current_locale_string);
 }
 
@@ -285,7 +314,7 @@
 	const char *env;
 
 	/* 1. check LC_ALL. */
-	env = getenv(categories[0]);
+	env = getenv(categories[LC_ALL]);
 
 	/* 2. check LC_* */
 	if (env == NULL || !*env)