Every internationalized program must set the current locale using the setlocale subroutine. This subroutine allows a process to change or query the current locale by accessing locale databases.
When a process is started, its current locale is set to the C or POSIX locale. A program that depends on locale data not defined in the C or POSIX locale must invoke the setlocale subroutine in the following manner before using any of the locale-specific information:
setlocale(LC_ALL, "");
The following subroutines provide access to information defined in the current locale as determined by the most recent call to the setlocale subroutine:
The localeconv and nl_langinfo subroutines do not provide access to all LC_* categories.
The current locale setting for a category can be obtained by: setlocale(Category, (char*)0). The return value is a string specifying the current locale for Category. The following example determines the current locale setting for the LC_CTYPE category:
char *ctype_locale; ctype_locale = setlocale(LC_CTYPE, (char*)0);
#include <locale.h> main() { char *p; p = setlocale(LC_ALL, ""); /* ** The program will have the locale as set by the ** LC_* and LANG variables. */ }
#include <stdio.h> #include <locale.h> main() { char *p; /* set the current locale to what is specified */ p = setlocale(LC_ALL, ""); /* The current locale settings for all the ** categories is pointed to by p */ /* ** Find the current setting for the ** LC_COLLATE category */ p = setlocale(LC_COLLATE, NULL); /* ** p points to a string containing the current locale ** setting for the LC_COLLATE category. */ }
#include <stdio.h> #include <locale.h> #include <string.h> #define NEW_LOCALE "MY_LOCALE" main() { char *p, *save_locale; p = setlocale(LC_ALL, ""); /* ** Initiate locale. p points to the current locale ** setting for all the categories */ save_locale = (char *)malloc(strlen(p) +1); strcpy(save_locale, p); /* Save the current locale setting */ p = setlocale(LC_ALL, NEW_LOCALE); /* Change to new locale */ /* ** Do processing ... */ /* Change back to old locale */ p = setlocale(LC_ALL, save_locale); /* Restore old locale */ free(save_locale); /* Free the memory */ }
#include <locale.h> main() { char *p; /* ** The program starts in the C locale for all categories. */ p = setlocale(LC_MESSAGES, ""); /* ** At this time the LC_COLLATE, LC_CTYPE, LC_NUMERIC, ** LC_MONETARY, LC_TIME will be in the C locale. ** LC_MESSAGES will be set to the current locale setting ** as determined by the environment variables. */ }
#include <locale.h> main() { struct lconv *ptr; char *decimal; (void)setlocale(LC_ALL, ""); ptr = localeconv(); /* ** Access the data obtained. For example, ** obtain the current decimal point setting. */ decimal = ptr->decimal_point; }
#include <langinfo.h> #include <locale.h> main() { char *ptr; (void)setlocale(LC_ALL, ""); ptr = nl_langinfo(D_T_FMT); }
#include <langinfo.h> #include <locale.h> main() { char *ptr; (void)setlocale(LC_ALL, ""); /* Set the program's locale */ ptr = nl_langinfo(RADIXCHAR); /* Obtain the radix character*/ }
#include <langinfo.h> #include <locale.h> main() { char *ptr; (void)setlocale(LC_ALL, ""); /* Set the program's locale */ ptr = nl_langinfo(CRNCYSTR); /* Obtain the currency string*/ /* The currency string will be "-$" in the U. S. locale. */ }
The affirmative and negative responses as specified in the locale database are no longer simple strings; they can be regular expressions. For example, the yesexpr can be the following regular expression, which will accept an upper or lower case letter y, followed by zero or more alphabetic characters; or the character O followed by K. Thus, yesexpr may be the following regular expression:
([yY][:alpha:]*|OK)
The standards do not contain a subroutine to retrieve and compare this information. You can use the AIX-specific rpmatch(const char *response) subroutine.
#include <stdio.h> #include <langinfo.h> #include <locale.h> #include <regex.h> int rpmatch(const char *); /* ** Returns 1 if yes response, 0 if no response, ** -1 otherwise */ main() { int ret; char *resp; (void)setlocale(LC_ALL, ""); do { /* ** Obtain the response to the query for yes/no strings. ** The string pointer resp points to this response. ** Check if the string is yes. */ ret = rpmatch(resp); if(ret == 1){ /* Response was yes. */ /* Process accordingly. */ }else if(ret == 0){ /* Response was negative. */ /* Process negative response. */ }else if(ret<0){ /* No match with yes/no occurred. */ continue; } }while(ret <0); }
Note that nl_langinfo(YESEXPR) and nl_langinfo(NOEXPR) are used to obtain the regular expressions for the affirmative and negative responses respectively.
#include <langinfo.h> #include <regex.h> /* ** rpmatch() performs comparison of a string to a regular expression ** using the POSIX.2 defined regular expression compile and match ** functions. The first argument is the response from the user and the ** second string is the current locale setting of the regular expression. */ int rpmatch( const char *string) { int status; int retval; regex_t re; char *pattern; pattern = nl_langinfo(YESEXPR); /* Compile the regular expression pointed to by pattern. */ if( ( status = regcomp( &re, pattern, REG_EXTENDED | REG_NOSUB )) != 0 ){ retval = -2; /*-2 indicates yes expr compile error */ return(retval); } /* Match the string with the compiled regular expression. */ status = regexec( &re, string, (size_t)0, (regmatch_t *)NULL, 0); if(status == 0){ retval = 1; /* Yes match found */ }else{ /* Check for negative response */ pattern = nl_langinfo(NOEXPR); if( ( status = regcomp( &re, pattern, REG_EXTENDED | REG_NOSUB )) != 0 ){ retval = -3;/*-3 indicates no compile error */ return(retval); } status = regexec( &re, string, (size_t)0, (regmatch_t *)NULL, 0); if(status == 0) retval = 0;/* Negative response match found */ }else retval = -1; /* The string did not match yes or no response */ regfree(&re); return(retval); }
Programs that need to format time into wide character code strings can use the wcsftime subroutine. Programs that need to convert multibyte strings into an internal time format can use the strptime subroutine.
In addition to the strftime subroutine defined in the C programming language standard, X/Open Portability Guide Issue 4 defines the following time formatting subroutines:
#include <stdio.h> #include <langinfo.h> #include <locale.h> #include <time.h> main() { wchar_t timebuf[BUFSIZE]; time_t clock = time( (time_t*) NULL); struct tim *tmptr = localetime(&clock); (void)setlocale(LC_ALL, ""); wcsftime( timebuf, /* Time string output buffer */ BUFSIZ, /*Maximum size of output string */ nl_langinfo(D_T_FMT), /* Date/time format */ tmptr /* Pointer to tm structure */ ); printf("%S\n", timebuf); }
#include <langinfo.h> #include <locale.h> #include <time.h> main(int argc, char **argv) { struct tm tm; (void)setlocale(LC_ALL, ""); if (argc != 2) { ... /* Error handling */ } if (strptime( argv[1], /* Formatted time string */ nl_langinfo(D_T_FMT), /* Date/time format */ &tm /* Address of tm structure */ ) == NULL) { ... /* Error handling */ } else { ... /* Other Processing */ } }
Programs that need to specify or access monetary quantities can call the strfmon subroutine.
Although the C programming language standard in conjunction with POSIX provides a means of specifying and accessing monetary information, these standards do not define a subroutine that formats monetary quantities. The XPG4 strfmon subroutine provides the facilities to format monetary quantities. No defined subroutine converts a formatted monetary string into a numeric quantity suitable for arithmetic. Applications that need to do arithmetic on monetary quantities may do so after processing the locale-dependent monetary string into a number. The culture-specific monetary formatting information is specified by the LC_MONETARY category. An application can obtain information pertaining to the monetary format and the currency symbol by calling the localeconv subroutine.