/* setlocale.c * Load LC_CTYPE locale only special for uclibc * * Written by Vladimir Oleynik (c) vodz@usa.net * * This file is part of the uClibc C library and is distributed * under the GNU Library General Public License. * used ideas is part of the GNU C Library. */ /* * No-locale-support setlocale() added. */ #include #include /* NULL, fopen */ #include /* malloc */ #include #include /* PATH_MAX */ #include "../ctype/ctype.h" #undef TEST_LOCALE #ifdef __UCLIBC_HAS_LOCALE__ static char C_LOCALE_NAME[]="C"; #ifdef TEST_LOCALE static const char PATH_LOCALE[]="./"; #else static const char PATH_LOCALE[]=__UCLIBC_LOCALE_DIR; #endif static const char LC_CTYPE_STR[]="/LC_CTYPE"; struct SAV_LOADED_LOCALE { char *locale; const unsigned char *buf; struct SAV_LOADED_LOCALE *next; }; static struct SAV_LOADED_LOCALE sav_loaded_locale [1] = { { C_LOCALE_NAME, _uc_ctype_b_C, 0 } }; static struct SAV_LOADED_LOCALE * old_locale = sav_loaded_locale; static char *set_new_locale(struct SAV_LOADED_LOCALE * s_locale) { _uc_ctype_b = s_locale->buf; _uc_ctype_trans = s_locale->buf+LOCALE_BUF_SIZE/2; old_locale = s_locale; return s_locale->locale; } /* Current support only LC_CTYPE or LC_ALL category */ char *setlocale(int category, const char *locale) { FILE * fl; struct SAV_LOADED_LOCALE *cur; struct SAV_LOADED_LOCALE *bottom; char full_path[PATH_MAX]; char * buf = 0; int l; if(category!=LC_CTYPE && category!=LC_ALL) return NULL; if(locale==0) return set_new_locale(old_locale); if(strcmp(locale, "POSIX")==0) return set_new_locale(sav_loaded_locale); else if(*locale == '\0') { locale = getenv(LC_CTYPE_STR+1); if(locale == 0 || *locale == 0) locale = getenv("LANG"); if(locale == 0 || *locale == '\0') return set_new_locale(old_locale); if(strcmp(locale, "POSIX")==0) return set_new_locale(sav_loaded_locale); } for(cur = sav_loaded_locale; cur; cur = cur->next) if(strcmp(cur->locale, locale)==0) return set_new_locale(cur); l = strlen(locale); if((l+sizeof(PATH_LOCALE)+sizeof(LC_CTYPE_STR))>=PATH_MAX) return NULL; strcpy(full_path, PATH_LOCALE); strcat(full_path, locale); strcat(full_path, LC_CTYPE_STR); fl = fopen(full_path, "r"); if(fl==0) return NULL; cur = malloc(sizeof(struct SAV_LOADED_LOCALE)+LOCALE_BUF_SIZE+l); if(cur) { buf = (char *)(cur+1); if(fread(buf, 1, LOCALE_BUF_SIZE+1, fl)!=(LOCALE_BUF_SIZE)) { /* broken locale file */ free(cur); buf = 0; #ifdef TEST_LOCALE fprintf(stderr, "\nbroken locale file\n"); #endif } } fclose(fl); if(cur==0) /* not enough memory */ return NULL; if(buf==0) /* broken locale file, set to "C" */ return set_new_locale(sav_loaded_locale); cur->next = 0; strcpy(buf+LOCALE_BUF_SIZE, locale); bottom = sav_loaded_locale; while(bottom->next!=0) bottom = bottom->next; bottom->next = cur; /* next two line only pedantic */ cur->buf = buf; cur->locale = buf+LOCALE_BUF_SIZE; return set_new_locale(cur); } #else /* no locale support */ char *setlocale(int category, const char *locale) { /* Allow locales "C" and "" (native). Both are "C" for our purposes. */ if (locale) { if (*locale == 'C') { ++locale; } if (*locale) { /* locale wasn't "C" or ""!! */ return NULL; } } /* Allow any legal category for "C" or "" (native) locale. */ if((category < LC_CTYPE) || (category > LC_ALL)) { /* Illegal category! */ return NULL; } return "C"; } #endif