/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* locale -- get current locale information
*
* Copyright 1991, 1993 by Mortice Kern Systems Inc. All rights reserved.
*
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* locale: get locale-specific information
* usage: locale [-a|-m]
* locale [-ck] name ...
*/
/*
* New members added in the struct lconv by IEEE Std 1003.1-2001
* are always activated in the locale object.
* See <iso/locale_iso.h>.
*/
#define _LCONV_C99
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <dirent.h>
#include <ctype.h>
#include <stddef.h>
#include <nl_types.h>
#include <langinfo.h>
#include <locale.h>
#define GET_LOCALE 0
#ifndef isblank
#endif
enum types {
};
static void usage(void);
static void print_all_info(int);
static void print_cur_locale(void);
static void outstr(char *s);
static void outchar(int);
static void prt_ctp(char *);
static void prt_cnv(char *);
static void prt_collel(char *);
static char get_escapechar(void);
static char get_commentchar(void);
static char *save_loc;
/*
* We dummy up a new structure for purposes of the code below.
* If YESEXPR is available per XPG4, we use it.
* Otherwise, use YESSTR, the old method with less functionality from XPG3.
*/
struct yesno {
char *yes_expr;
char *no_expr;
char *yes_str;
char *no_str;
};
struct dtconv {
char *date_time_format;
char *date_format;
char *time_format;
char *time_format_ampm;
char *am_string;
char *pm_string;
char *era;
char *era_d_fmt;
char *era_d_t_fmt;
char *era_t_fmt;
char *alt_digits;
};
struct localedef {
char *charmap;
char *code_set_name;
char escape_char;
char comment_char;
int mb_cur_max;
int mb_cur_min;
};
static struct yesno *
getyesno(void)
{
static int loaded = 0;
if (loaded) {
return (&yn);
/* NOTREACHED */
}
loaded = 1;
return (&yn);
}
static struct dtconv *
localedtconv(void)
{
static int loaded = 0;
if (loaded) {
return (&_dtconv);
/* NOTREACHED */
}
loaded = 1;
return (&_dtconv);
}
static struct localedef *
localeldconv(void)
{
static int loaded = 0;
if (loaded) {
return (&_locdef);
/* NOTREACHED */
}
loaded = 1;
return (&_locdef);
}
/*
* The locale_name array also defines a canonical ordering for the categories.
* The function tocanon() translates the LC_* manifests to their canonical
* values.
*/
static struct locale_name {
char *name;
int category;
} locale_name[] = {
{"LC_CTYPE", LC_CTYPE},
{"LC_NUMERIC", LC_NUMERIC},
{"LC_TIME", LC_TIME},
{"LC_COLLATE", LC_COLLATE},
{"LC_MONETARY", LC_MONETARY},
{"LC_MESSAGES", LC_MESSAGES},
{"LC_ALL", LC_ALL},
};
/*
* The structure key contains all keywords string name,
* symbolic name, category, and type (STR INT ...)
* the type will decide the way the value of the item be printed out
*/
static struct key {
char *name;
void *(*structure)(void);
int offset;
int count;
int category;
} key[] = {
#define SPECIAL 0, 0, 0,
(void *(*)(void))localedtconv, \
count, \
LC_TIME, \
(void *(*)(void))localeconv, \
1, \
locale, \
(void *(*)(void))getyesno, \
1, \
LC_MESSAGES, \
/*
* Following keywords have no official method of obtaining them
*/
(void *(*)(void))localeldconv, \
1, \
locale, \
};
static char escapec;
int
{
int c;
int retval = 0;
#if !defined(TEXT_DOMAIN)
#endif
(void) textdomain(TEXT_DOMAIN);
switch (c) {
case 'a':
aflag = 1;
break;
case 'm':
mflag = 1;
break;
case 'c':
cflag = 1;
break;
case 'k':
kflag = 1;
break;
default:
usage();
/* NOTREACHED */
break;
}
}
usage();
/* NOTREACHED */
}
escapec = get_escapechar();
if (aflag) {
/* NOTREACHED */
}
if (mflag) {
/* NOTREACHED */
}
/* NOTREACHED */
}
usage();
/* NOTREACHED */
}
}
return (retval);
}
/*
* No options or operands.
* Print out the current locale names from the environment, or implied.
* Variables directly set in the environment are printed as-is, those
* implied are printed in quotes.
* The strings are printed ``appropriately quoted for possible later re-entry
* to the shell''. We use the routine outstr to do this -- however we
* want the shell escape character, the backslash, not the locale escape
* character, so we quietly save and restore the locale escape character.
*/
static void
print_cur_locale(void)
{
char *lc_allp;
int i;
} else {
(void) printf("LANG=\n");
}
for (i = 0; i < LC_ALL; i++) {
eff = "";
}
(void) putchar('"');
(void) putchar('"');
} else {
(void) putchar('"');
(void) putchar('"');
} else {
}
}
(void) putchar('\n');
}
(void) printf("LC_ALL=");
}
(void) putchar('\n');
exit(0);
}
static int num_of_loc = 0;
static int num_of_entries = 0;
static void
{
char *s;
if (num_of_loc >= num_of_entries) {
char **tmp;
/* restoring original locale */
gettext("locale: cannot allocate buffer"));
exit(1);
}
}
if (s == NULL) {
/* restoring original locale */
gettext("locale: cannot allocate buffer"));
exit(1);
}
entries[num_of_loc] = s;
num_of_loc++;
}
static int
{
}
static void
show_loc_entry(void)
{
int i;
(int (*)(const void *, const void *))loccmp);
for (i = 0; i < num_of_loc; i++) {
}
}
static void
{
int cat;
/* first, try LC_ALL */
/* succeeded */
return;
}
/*
* LC_ALL failed.
* try each category.
*/
/* succeeded */
return;
}
}
/* loc is not a valid locale */
}
/*
* print_all_info(): Print out all the locales and
* charmaps supported by the system
*/
static void
{
char *p;
gettext("locale: cannot allocate buffer"));
exit(1);
}
if (flag == GET_LOCALE) {
/* save the current locale */
add_loc_entry("POSIX");
} else { /* CHARMAP */
}
if (flag == GET_LOCALE)
exit(0);
else { /* CHARMAP */
"locale: charmap information not available.\n"));
exit(2);
}
}
continue;
}
if (flag == GET_LOCALE) {
/* "POSIX" has already been printed out */
}
} else { /* CHARMAP */
char *charmap;
char *c;
gettext("locale: cannot allocate buffer"));
exit(1);
}
exit(0);
}
*c++ = '/';
continue;
}
CHARMAP_NAME) == 0) &&
(void) printf("%s/%s\n",
}
}
}
}
}
if (flag == GET_LOCALE) {
/* restore the saved loc */
}
exit(0);
}
/*
* Print out the keyword value or category info.
* Call print_category() to print the entire locale category, if the name
* given is recognized as a category.
* Otherwise, assume that it is a keyword, and call print_keyword().
*/
static int
{
int i;
/*
* name is a category name
* print out all keywords in this category
*/
}
}
/* The name is a keyword name */
}
/*
* Print out the value of the keyword
*/
static int
{
int i, j;
int found = 0;
continue;
}
found = 1;
/* print out this category's name */
(void) printf("%s\n",
}
if (kflag) {
}
/*
* The grouping fields are a set of bytes, each of which
* is the numeric value of the next group size, terminated
* by a \0, or by CHAR_MAX
*/
case TYPE_GROUP:
{
void *s;
char *q;
/* LINTED */
if (*q == '\0') {
(void) printf("-1");
break;
}
while (*q != '\0' && *q != CHAR_MAX) {
if (!first) {
(void) putchar(';');
}
first = 0;
(void) printf("%u",
*(unsigned char *)q++);
}
/* CHAR_MAX: no further grouping performed. */
if (!first) {
(void) putchar(';');
}
if (*q == CHAR_MAX) {
(void) printf("-1");
} else {
(void) putchar('0');
}
}
break;
/*
* Entries like decimal_point states ``the decimal-point
* character...'' not string. However, it is a char *.
* This assumes single, narrow, character.
* Should it permit multibyte characters?
* Should it permit a whole string, in that case?
*/
case TYPE_STR:
{
void *s;
char **q;
/* LINTED */
if (j != 0) {
(void) printf(";");
}
if (kflag) {
(void) printf("\"");
outstr(q[j]);
(void) printf("\"");
} else {
(void) printf("%s", q[j]);
}
}
}
break;
case TYPE_INT:
{
void *s;
int *q;
/* LINTED */
(void) printf("%d", *q);
}
break;
/*
* TYPE_CHR: Single byte integer.
*/
case TYPE_CHR:
{
void *s;
char *q;
if (*q == CHAR_MAX) {
(void) printf("-1");
} else {
(void) printf("%u",
*(unsigned char *)q);
}
}
break;
/*
* TYPE_PCHR: Single byte, printed as a character if printable
*/
case TYPE_PCHR:
{
void *s;
char *q;
if (isprint(*(unsigned char *)q)) {
if (kflag) {
(void) printf("\"");
if ((*q == '\\') ||
(*q == ';') ||
(*q == '"')) {
(void) printf("%c",
*(unsigned char *)q);
} else {
(void) printf("%c",
*(unsigned char *)q);
}
(void) printf("\"");
} else {
(void) printf("%c",
*(unsigned char *)q);
}
} else if (*q == (char)-1) {
/* In case no signed chars */
(void) printf("-1");
} else {
(void) printf("%u",
*(unsigned char *)q);
}
}
break;
case TYPE_CTP:
{
}
break;
case TYPE_CNVU:
{
}
break;
case TYPE_CNVL:
{
}
break;
case TYPE_COLLEL:
{
}
break;
}
}
if (found) {
(void) printf("\n");
return (0);
} else {
return (1);
}
}
/*
* Strings being outputed have to use an unambiguous format -- escape
* any potentially bad output characters.
* The standard says that any control character shall be preceeded by
* the escape character. But it doesn't say that you can format that
* character at all.
* Question: If the multibyte character contains a quoting character,
* should that *byte* be escaped?
*/
static void
outstr(char *s)
{
int c;
while (*s != '\0') {
if (c < 0) {
s++;
} else if (c == 1) {
outchar(*s++);
} else {
for (; c > 0; c--) {
(void) putchar(*s++);
}
}
}
}
static void
outchar(int c)
{
unsigned char uc;
uc = (unsigned char) c;
} else {
}
}
/*
* print_category(): Print out all the keyword's value
* in the given category
*/
static int
{
int i;
int retval = 0;
} else {
if (cflag) {
(void) printf("%s\n",
}
}
}
}
return (retval);
}
/*
* usage message for locale
*/
static void
usage(void)
{
"Usage: locale [-a|-m]\n"
" locale [-ck] name ...\n"));
exit(2);
}
static void
{
static const char *reg_names[] = {
"upper", "lower", "alpha", "digit", "space", "cntrl",
};
break;
}
}
return;
}
for (i = 0; i < CSSIZE; i++) {
mem = 0;
switch (idx) {
case 0:
break;
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 7:
break;
case 8:
break;
case 9:
break;
case 10:
break;
}
if (mem) {
if (!first) {
(void) putchar(';');
}
first = 0;
(void) printf("\"");
outchar(i);
(void) printf("\"");
}
}
}
static void
{
int idx, i, q;
static const char *reg_names[] = {
};
break;
}
}
return;
}
for (i = 0; i < CSSIZE; i++) {
switch (idx) {
case 0:
q = toupper(i);
if (q == i) {
continue;
}
if (!first) {
(void) putchar(';');
}
first = 0;
/* BEGIN CSTYLED */
(void) printf("\"<'");
/* END CSTYLED */
outchar(i);
(void) printf("','");
outchar(q);
(void) printf("'>\"");
break;
case 1:
q = tolower(i);
if (q == i) {
continue;
}
if (!first) {
(void) putchar(';');
}
first = 0;
/* BEGIN CSTYLED */
(void) printf("\"<'");
/* END CSTYLED */
outchar(i);
(void) printf("','");
outchar(q);
(void) printf("'>\"");
break;
}
}
}
/*
* prt_collel(): Stub for the collate class which does nothing.
*/
/* ARGSUSED */
static void
{
}
static char
get_escapechar(void)
{
return ('\\');
}
static char
get_commentchar(void)
{
return ('#');
}