Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/std/locale.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1989-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
22
/*
23
* locale command
24
*/
25
26
static const char usage[] =
27
"[-?\n@(#)$Id: locale (AT&T Research) 2009-10-21 $\n]"
28
USAGE_LICENSE
29
"[+NAME?locale - get locale-specific information]"
30
"[+DESCRIPTION?\blocale\b writes information about the current locale to"
31
" the standard output. If no options or operands are specified then the"
32
" environment for each locale category is summarized. If operands are"
33
" spcified then information is written about each operand: a locale"
34
" category name operand (\fcategories\f) selects all keywords in that"
35
" category; other operands name keywords within a category. Keyword"
36
" names are unique across all categories, so there is no ambiguity."
37
" \acategory=value\a operands set the corresponding locale \acategory\a"
38
" to \avalue\a by a call to \bsetlocale\b(3). A \avalue\a of \b-\b is"
39
" interpreted as \bNULL\b, allowing \acategory\a to be queried. The"
40
" \bTEST\b category converts the \avalue\a locale name to a canonical"
41
" form and lists the converted name on the standard output.]"
42
"[+?If the \b--all\b or \b--undefined\b options are specified and no operands"
43
" are specified then the names of all defined locales are listed on the"
44
" standard output. A \adefined\a locale name should work as an argument"
45
" to \bsetlocale\b(3). An \aundefined\a name is valid but not supported"
46
" on the local system. Locale names have the general form"
47
" \alanguage\a_\aterritory\a.\acharset\a@\aattribute\a[,\aattribute\a]]*"
48
" At least one of \alanguage\a or \aterritory\a is always specified, the"
49
" other parts are optional. The \b--abbreviated\b, \b--qualified\b,"
50
" \b--verbose\b and \b--local\b options determine the locale name"
51
" listing style. The default is \b--abbreviated\b. If multiple styles"
52
" are specified then the names are listed in columns in this order:"
53
" \babbreviated\b, \bqualified\b, \bverbose\b and \blocal\b.]"
54
55
"[a:all?List all defined locale names on the standard output.]"
56
"[b:abbreviated?List abbreviated locale names: \alanguage\a and \aterritory\a"
57
" as the two character ISO codes; non-default \acharset\a and"
58
" \aattributes\a. This is the default.]"
59
"[c:category?List the category names for each operand on the standard output.]"
60
"[e:element?The operands are interpreted as collation elements. Each element"
61
" name is listed on the standard output followed by a \btab\b character"
62
" and the space separated list of \bstrxfrm\b(3) collation weights.]"
63
"[i:indent?Indent keyword output lines for readability.]"
64
"[k:keyword?List the keyword name for each operand on the standard output.]"
65
"[l:local?List the locale names returned by the local system \bsetlocale\b(3)."
66
" NOTE: these names may contain embedded space.]"
67
"[m:charmaps?List the names of available charmaps.]"
68
"[q:qualified?List qualified locale names: \alanguage\a and \aterritory\a"
69
" as the two character ISO codes; default and non-default \acharset\a and"
70
" \aattributes\a.]"
71
"[t:composite?List the composite value of LC_ALL on the standard output.]"
72
"[u:undefined?List all undefined locale names on the standard output.]"
73
"[v:verbose?List verbose locale names: \alanguage\a and \aterritory\a"
74
" as the long English strings; non-default \acharset\a and"
75
" \aattributes\a.]"
76
"[x:transform?The operands are interpreted as strings. Each string is listed"
77
" on the standard output followed by a \btab\b character and the"
78
" space separated list of \bstrxfrm\b(3) collation weights.]"
79
80
"\n"
81
"\n[ name | name=value ... ]\n"
82
"\n"
83
84
"[+SEE ALSO?\blocaleconv\b(3), \bnl_langinfo\b(3), \bsetlocale\b(3)]"
85
;
86
87
#include <ast.h>
88
#include <cdt.h>
89
#include <ctype.h>
90
#include <error.h>
91
#include <lc.h>
92
#include <tm.h>
93
#include <regex.h>
94
#include <proc.h>
95
96
#include "FEATURE/locales"
97
98
#define TEST (AST_LC_COUNT+1)
99
100
#if _hdr_nl_types && _hdr_langinfo
101
102
#include <nl_types.h>
103
#include <langinfo.h>
104
105
#else
106
107
#undef _hdr_nl_types
108
#undef _hdr_langinfo
109
110
#endif
111
112
typedef struct Keyword_s
113
{
114
const char* name;
115
int index;
116
int type;
117
int elements;
118
long offset;
119
Dtlink_t link;
120
} Keyword_t;
121
122
#define LC_category (LC_user<<1)
123
#define LC_indent (LC_user<<2)
124
#define LC_keyword (LC_user<<3)
125
#define LC_proper (LC_user<<4)
126
#define LC_quote (LC_user<<5)
127
#define LC_recursive (LC_user<<6)
128
#define LC_upper (LC_user<<7)
129
130
#define C 1
131
#define I 4
132
#define N 3
133
#define S 0
134
#define X 5
135
136
#define CV_collate 1
137
138
#define CV_charset 1
139
#define CV_mb_cur_max 2
140
#define CV_mb_cur_min 3
141
142
#ifdef NOEXPR
143
#define CV_noexpr NOEXPR
144
#else
145
#define CV_noexpr (-1)
146
#endif
147
#ifdef NOSTR
148
#define CV_nostr NOSTR
149
#else
150
#define CV_nostr (-1)
151
#endif
152
#ifdef YESEXPR
153
#define CV_yesexpr YESEXPR
154
#else
155
#define CV_yesexpr (-1)
156
#endif
157
#ifdef YESSTR
158
#define CV_yesstr YESSTR
159
#else
160
#define CV_yesstr (-1)
161
#endif
162
163
#if _mem_credit_sign_lconv
164
#define CV_credit_sign offsetof(struct lconv,credit_sign)
165
#else
166
#define CV_credit_sign (-1)
167
#endif
168
#if _mem_currency_symbol_lconv
169
#define CV_currency_symbol offsetof(struct lconv,currency_symbol)
170
#else
171
#define CV_currency_symbol (-1)
172
#endif
173
#if _mem_debit_sign_lconv
174
#define CV_debit_sign offsetof(struct lconv,debit_sign)
175
#else
176
#define CV_debit_sign (-1)
177
#endif
178
#if _mem_frac_digits_lconv
179
#define CV_frac_digits offsetof(struct lconv,frac_digits)
180
#else
181
#define CV_frac_digits (-1)
182
#endif
183
#if _mem_int_curr_symbol_lconv
184
#define CV_int_curr_symbol offsetof(struct lconv,int_curr_symbol)
185
#else
186
#define CV_int_curr_symbol (-1)
187
#endif
188
#if _mem_int_frac_digits_lconv
189
#define CV_int_frac_digits offsetof(struct lconv,int_frac_digits)
190
#else
191
#define CV_int_frac_digits (-1)
192
#endif
193
#if _mem_left_parenthesis_lconv
194
#define CV_left_parenthesis offsetof(struct lconv,left_parenthesis)
195
#else
196
#define CV_left_parenthesis (-1)
197
#endif
198
#if _mem_mon_decimal_point_lconv
199
#define CV_mon_decimal_point offsetof(struct lconv,mon_decimal_point)
200
#else
201
#define CV_mon_decimal_point (-1)
202
#endif
203
#if _mem_mon_grouping_lconv
204
#define CV_mon_grouping offsetof(struct lconv,mon_grouping)
205
#else
206
#define CV_mon_grouping (-1)
207
#endif
208
#if _mem_mon_thousands_sep_lconv
209
#define CV_mon_thousands_sep offsetof(struct lconv,mon_thousands_sep)
210
#else
211
#define CV_mon_thousands_sep (-1)
212
#endif
213
#if _mem_n_cs_precedes_lconv
214
#define CV_n_cs_precedes offsetof(struct lconv,n_cs_precedes)
215
#else
216
#define CV_n_cs_precedes (-1)
217
#endif
218
#if _mem_n_sep_by_space_lconv
219
#define CV_n_sep_by_space offsetof(struct lconv,n_sep_by_space)
220
#else
221
#define CV_n_sep_by_space (-1)
222
#endif
223
#if _mem_n_sign_posn_lconv
224
#define CV_n_sign_posn offsetof(struct lconv,n_sign_posn)
225
#else
226
#define CV_n_sign_posn (-1)
227
#endif
228
#if _mem_negative_sign_lconv
229
#define CV_negative_sign offsetof(struct lconv,negative_sign)
230
#else
231
#define CV_negative_sign (-1)
232
#endif
233
#if _mem_p_cs_precedes_lconv
234
#define CV_p_cs_precedes offsetof(struct lconv,p_cs_precedes)
235
#else
236
#define CV_p_cs_precedes (-1)
237
#endif
238
#if _mem_p_sep_by_space_lconv
239
#define CV_p_sep_by_space offsetof(struct lconv,p_sep_by_space)
240
#else
241
#define CV_p_sep_by_space (-1)
242
#endif
243
#if _mem_p_sign_posn_lconv
244
#define CV_p_sign_posn offsetof(struct lconv,p_sign_posn)
245
#else
246
#define CV_p_sign_posn (-1)
247
#endif
248
#if _mem_positive_sign_lconv
249
#define CV_positive_sign offsetof(struct lconv,positive_sign)
250
#else
251
#define CV_positive_sign (-1)
252
#endif
253
#if _mem_right_parenthesis_lconv
254
#define CV_right_parenthesis offsetof(struct lconv,right_parenthesis)
255
#else
256
#define CV_right_parenthesis (-1)
257
#endif
258
259
#if _mem_decimal_point_lconv
260
#define CV_decimal_point offsetof(struct lconv,decimal_point)
261
#else
262
#define CV_decimal_point (-1)
263
#endif
264
#if _mem_grouping_lconv
265
#define CV_grouping offsetof(struct lconv,grouping)
266
#else
267
#define CV_grouping (-1)
268
#endif
269
#if _mem_thousands_sep_lconv
270
#define CV_thousands_sep offsetof(struct lconv,thousands_sep)
271
#else
272
#define CV_thousands_sep (-1)
273
#endif
274
275
#if _num__NL_ADDRESS_POSTAL_FMT
276
#define CV_postal_fmt _NL_ADDRESS_POSTAL_FMT
277
#else
278
#define CV_postal_fmt (-1)
279
#endif
280
#if _num__NL_ADDRESS_COUNTRY_NAME
281
#define CV_country_name _NL_ADDRESS_COUNTRY_NAME
282
#else
283
#define CV_country_name (-1)
284
#endif
285
#if _num__NL_ADDRESS_COUNTRY_POST
286
#define CV_country_post _NL_ADDRESS_COUNTRY_POST
287
#else
288
#define CV_country_post (-1)
289
#endif
290
#if _num__NL_ADDRESS_COUNTRY_AB2
291
#define CV_country_ab2 _NL_ADDRESS_COUNTRY_AB2
292
#else
293
#define CV_country_ab2 (-1)
294
#endif
295
#if _num__NL_ADDRESS_COUNTRY_AB3
296
#define CV_country_ab3 _NL_ADDRESS_COUNTRY_AB3
297
#else
298
#define CV_country_ab3 (-1)
299
#endif
300
#if _num__NL_ADDRESS_COUNTRY_NUM
301
#define CV_country_num _NL_ADDRESS_COUNTRY_NUM
302
#else
303
#define CV_country_num (-1)
304
#endif
305
#if _num__NL_ADDRESS_COUNTRY_CAR
306
#define CV_country_car _NL_ADDRESS_COUNTRY_CAR
307
#else
308
#define CV_country_car (-1)
309
#endif
310
#if _num__NL_ADDRESS_COUNTRY_ISBN
311
#define CV_country_isbn _NL_ADDRESS_COUNTRY_ISBN
312
#else
313
#define CV_country_isbn (-1)
314
#endif
315
#if _num__NL_ADDRESS_LANG_NAME
316
#define CV_lang_name _NL_ADDRESS_LANG_NAME
317
#else
318
#define CV_lang_name (-1)
319
#endif
320
#if _num__NL_ADDRESS_LANG_AB
321
#define CV_lang_ab _NL_ADDRESS_LANG_AB
322
#else
323
#define CV_lang_ab (-1)
324
#endif
325
#if _num__NL_ADDRESS_LANG_TERM
326
#define CV_lang_term _NL_ADDRESS_LANG_TERM
327
#else
328
#define CV_lang_term (-1)
329
#endif
330
#if _num__NL_ADDRESS_LANG_LIB
331
#define CV_lang_lib _NL_ADDRESS_LANG_LIB
332
#else
333
#define CV_lang_lib (-1)
334
#endif
335
336
#if _num__NL_IDENTIFICATION_TITLE
337
#define CV_title _NL_IDENTIFICATION_TITLE
338
#else
339
#define CV_title (-1)
340
#endif
341
#if _num__NL_IDENTIFICATION_SOURCE
342
#define CV_source _NL_IDENTIFICATION_SOURCE
343
#else
344
#define CV_source (-1)
345
#endif
346
#if _num__NL_IDENTIFICATION_ADDRESS
347
#define CV_address _NL_IDENTIFICATION_ADDRESS
348
#else
349
#define CV_address (-1)
350
#endif
351
#if _num__NL_IDENTIFICATION_CONTACT
352
#define CV_contact _NL_IDENTIFICATION_CONTACT
353
#else
354
#define CV_contact (-1)
355
#endif
356
#if _num__NL_IDENTIFICATION_EMAIL
357
#define CV_email _NL_IDENTIFICATION_EMAIL
358
#else
359
#define CV_email (-1)
360
#endif
361
#if _num__NL_IDENTIFICATION_TEL
362
#define CV_tel _NL_IDENTIFICATION_TEL
363
#else
364
#define CV_tel (-1)
365
#endif
366
#if _num__NL_IDENTIFICATION_FAX
367
#define CV_fax _NL_IDENTIFICATION_FAX
368
#else
369
#define CV_fax (-1)
370
#endif
371
#if _num__NL_IDENTIFICATION_LANGUAGE
372
#define CV_language _NL_IDENTIFICATION_LANGUAGE
373
#define T_language N
374
#else
375
#define CV_language (-2)
376
#define T_language X
377
#endif
378
#if _num__NL_IDENTIFICATION_TERRITORY
379
#define CV_territory _NL_IDENTIFICATION_TERRITORY
380
#define T_territory N
381
#else
382
#define CV_territory (-3)
383
#define T_territory X
384
#endif
385
#if _num__NL_IDENTIFICATION_ATTRIBUTES
386
#define CV_attributes _NL_IDENTIFICATION_ATTRIBUTES
387
#define T_attributes N
388
#else
389
#define CV_attributes (-4)
390
#define T_attributes X
391
#endif
392
#if _num__NL_IDENTIFICATION_REVISION
393
#define CV_revision _NL_IDENTIFICATION_REVISION
394
#else
395
#define CV_revision (-1)
396
#endif
397
#if _num__NL_IDENTIFICATION_DATE
398
#define CV_date _NL_IDENTIFICATION_DATE
399
#else
400
#define CV_date (-1)
401
#endif
402
403
#if _num__NL_MEASUREMENT_MEASUREMENT
404
#define CV_measurement _NL_MEASUREMENT_MEASUREMENT
405
#else
406
#define CV_measurement (-1)
407
#endif
408
409
#if _num__NL_NAME_NAME_FMT
410
#define CV_name_fmt _NL_NAME_NAME_FMT
411
#else
412
#define CV_name_fmt (-1)
413
#endif
414
#if _num__NL_NAME_NAME_MISS
415
#define CV_name_miss _NL_NAME_NAME_MISS
416
#else
417
#define CV_name_miss (-1)
418
#endif
419
#if _num__NL_NAME_NAME_MR
420
#define CV_name_mr _NL_NAME_NAME_MR
421
#else
422
#define CV_name_mr (-1)
423
#endif
424
#if _num__NL_NAME_NAME_MRS
425
#define CV_name_mrs _NL_NAME_NAME_MRS
426
#else
427
#define CV_name_mrs (-1)
428
#endif
429
#if _num__NL_NAME_NAME_MS
430
#define CV_name_ms _NL_NAME_NAME_MS
431
#else
432
#define CV_name_ms (-1)
433
#endif
434
435
#if _num__NL_PAPER_HEIGHT
436
#define CV_height _NL_PAPER_HEIGHT
437
#else
438
#define CV_height (-1)
439
#endif
440
#if _num__NL_PAPER_WIDTH
441
#define CV_width _NL_PAPER_WIDTH
442
#else
443
#define CV_width (-1)
444
#endif
445
446
#if _num__NL_TELEPHONE_TEL_INT_FMT
447
#define CV_tel_int_fmt _NL_TELEPHONE_TEL_INT_FMT
448
#else
449
#define CV_tel_int_fmt (-1)
450
#endif
451
#if _num__NL_TELEPHONE_TEL_DOM_FMT
452
#define CV_tel_dom_fmt _NL_TELEPHONE_TEL_DOM_FMT
453
#else
454
#define CV_tel_dom_fmt (-1)
455
#endif
456
#if _num__NL_TELEPHONE_INT_SELECT
457
#define CV_int_select _NL_TELEPHONE_INT_SELECT
458
#else
459
#define CV_int_select (-1)
460
#endif
461
#if _num__NL_TELEPHONE_INT_PREFIX
462
#define CV_int_prefix _NL_TELEPHONE_INT_PREFIX
463
#else
464
#define CV_int_prefix (-1)
465
#endif
466
467
#ifndef MB_CUR_MIN
468
#define MB_CUR_MIN 1
469
#endif
470
471
static const char defer[] = "/usr/bin/locale";
472
473
static Keyword_t keywords[] =
474
{
475
{"TEST", TEST, S,1,0},
476
{"postal_fmt", AST_LC_ADDRESS, N,1,CV_postal_fmt},
477
{"country_name", AST_LC_ADDRESS, N,1,CV_country_name},
478
{"country_post", AST_LC_ADDRESS, N,1,CV_country_post},
479
{"country_ab2", AST_LC_ADDRESS, N,1,CV_country_ab2},
480
{"country_ab3", AST_LC_ADDRESS, N,1,CV_country_ab3},
481
{"country_num", AST_LC_ADDRESS, N,1,CV_country_num},
482
{"country_car", AST_LC_ADDRESS, N,1,CV_country_car},
483
{"country_isbn", AST_LC_ADDRESS, N,1,CV_country_isbn},
484
{"lang_name", AST_LC_ADDRESS, N,1,CV_lang_name},
485
{"lang_ab", AST_LC_ADDRESS, N,1,CV_lang_ab},
486
{"lang_term", AST_LC_ADDRESS, N,1,CV_lang_term},
487
{"lang_lib", AST_LC_ADDRESS, N,1,CV_lang_lib},
488
{"collate", AST_LC_COLLATE, S,1,CV_collate},
489
{"charset", AST_LC_CTYPE, S,1,CV_charset},
490
{"mb_cur_max", AST_LC_CTYPE, I,1,CV_mb_cur_max},
491
{"mb_cur_min", AST_LC_CTYPE, I,1,CV_mb_cur_min},
492
{"title", AST_LC_IDENTIFICATION,N,1,CV_title},
493
{"source", AST_LC_IDENTIFICATION,N,1,CV_source},
494
{"address", AST_LC_IDENTIFICATION,N,1,CV_address},
495
{"contact", AST_LC_IDENTIFICATION,N,1,CV_contact},
496
{"email", AST_LC_IDENTIFICATION,N,1,CV_email},
497
{"tel", AST_LC_IDENTIFICATION,N,1,CV_tel},
498
{"fax", AST_LC_IDENTIFICATION,N,1,CV_fax},
499
{"language", AST_LC_IDENTIFICATION,T_language,1,CV_language},
500
{"territory", AST_LC_IDENTIFICATION,T_territory,1,CV_territory},
501
{"attributes", AST_LC_IDENTIFICATION,T_attributes,1,CV_attributes},
502
{"revision", AST_LC_IDENTIFICATION,N,1,CV_revision},
503
{"date", AST_LC_IDENTIFICATION,N,1,CV_date},
504
{"measurement", AST_LC_MEASUREMENT,N,1,CV_measurement},
505
{"yesexpr", AST_LC_MESSAGES, N,1,CV_yesexpr},
506
{"noexpr", AST_LC_MESSAGES, N,1,CV_noexpr},
507
{"yesstr", AST_LC_MESSAGES, N,1,CV_yesstr},
508
{"nostr", AST_LC_MESSAGES, N,1,CV_nostr},
509
{"credit_sign", AST_LC_MONETARY, S,1,CV_credit_sign},
510
{"currency_symbol", AST_LC_MONETARY, S,1,CV_currency_symbol},
511
{"debit_sign", AST_LC_MONETARY, S,1,CV_debit_sign},
512
{"frac_digits", AST_LC_MONETARY, C,1,CV_frac_digits},
513
{"int_curr_symbol", AST_LC_MONETARY, S,1,CV_int_curr_symbol},
514
{"int_frac_digits", AST_LC_MONETARY, C,1,CV_int_frac_digits},
515
{"left_parenthesis", AST_LC_MONETARY, S,1,CV_left_parenthesis},
516
{"mon_decimal_point", AST_LC_MONETARY, S,1,CV_mon_decimal_point},
517
{"mon_grouping", AST_LC_MONETARY, S,1,CV_mon_grouping},
518
{"mon_thousands_sep", AST_LC_MONETARY, S,1,CV_mon_thousands_sep},
519
{"n_cs_precedes", AST_LC_MONETARY, C,1,CV_n_cs_precedes},
520
{"n_sep_by_space", AST_LC_MONETARY, C,1,CV_n_sep_by_space},
521
{"n_sign_posn", AST_LC_MONETARY, C,1,CV_n_sign_posn},
522
{"negative_sign", AST_LC_MONETARY, S,1,CV_negative_sign},
523
{"p_cs_precedes", AST_LC_MONETARY, C,1,CV_p_cs_precedes},
524
{"p_sep_by_space", AST_LC_MONETARY, C,1,CV_p_sep_by_space},
525
{"p_sign_posn", AST_LC_MONETARY, C,1,CV_p_sign_posn},
526
{"positive_sign", AST_LC_MONETARY, S,1,CV_positive_sign},
527
{"right_parenthesis", AST_LC_MONETARY, S,1,CV_right_parenthesis},
528
{"name_fmt", AST_LC_NAME, N,1,CV_name_fmt},
529
{"name_miss", AST_LC_NAME, N,1,CV_name_miss},
530
{"name_mr", AST_LC_NAME, N,1,CV_name_mr},
531
{"name_mrs", AST_LC_NAME, N,1,CV_name_mrs},
532
{"name_ms", AST_LC_NAME, N,1,CV_name_ms},
533
{"decimal_point", AST_LC_NUMERIC, S,1,CV_decimal_point},
534
{"grouping", AST_LC_NUMERIC, S,1,CV_grouping},
535
{"thousands_sep", AST_LC_NUMERIC, S,1,CV_thousands_sep},
536
{"height", AST_LC_PAPER, N,1,CV_height},
537
{"width", AST_LC_PAPER, N,1,CV_width},
538
{"tel_int_fmt", AST_LC_TELEPHONE, N,1,CV_tel_int_fmt},
539
{"tel_dom_fmt", AST_LC_TELEPHONE, N,1,CV_tel_dom_fmt},
540
{"int_select", AST_LC_TELEPHONE, N,1,CV_int_select},
541
{"int_prefix", AST_LC_TELEPHONE, N,1,CV_int_prefix},
542
{"abday", AST_LC_TIME, S,7,TM_DAY_ABBREV*sizeof(char*)},
543
{"abmon", AST_LC_TIME, S,12,TM_MONTH_ABBREV*sizeof(char*)},
544
{"alt_digits", AST_LC_TIME, S,10,TM_DIGITS*sizeof(char*)},
545
{"am_pm", AST_LC_TIME, S,2,TM_MERIDIAN*sizeof(char*)},
546
{"d_fmt", AST_LC_TIME, S,1,TM_DATE*sizeof(char*)},
547
{"d_t_fmt", AST_LC_TIME, S,1,TM_DEFAULT*sizeof(char*)},
548
{"day", AST_LC_TIME, S,7,TM_DAY*sizeof(char*)},
549
{"era", AST_LC_TIME, S,1,TM_ERA*sizeof(char*)},
550
{"era_d_fmt", AST_LC_TIME, S,1,TM_ERA_DATE*sizeof(char*)},
551
{"era_d_t_fmt", AST_LC_TIME, S,1,TM_ERA_DEFAULT*sizeof(char*)},
552
{"era_t_fmt", AST_LC_TIME, S,1,TM_ERA_TIME*sizeof(char*)},
553
{"era_year", AST_LC_TIME, S,1,TM_ERA_YEAR*sizeof(char*)},
554
{"m_d_old", AST_LC_TIME, S,1,TM_DISTANT*sizeof(char*)},
555
{"m_d_recent", AST_LC_TIME, S,1,TM_RECENT*sizeof(char*)},
556
{"mon", AST_LC_TIME, S,12,TM_MONTH*sizeof(char*)},
557
{"t_fmt", AST_LC_TIME, S,1,TM_TIME*sizeof(char*)},
558
{"t_fmt_ampm", AST_LC_TIME, S,1,TM_MERIDIAN_TIME*sizeof(char*)},
559
};
560
561
static struct State_s
562
{
563
Lc_category_t* categories;
564
struct lconv* conv;
565
Dt_t* dict;
566
Dtdisc_t disc;
567
int all;
568
int output;
569
int sep;
570
} state;
571
572
/*
573
* list the locale name(s) for lc according to flags
574
*/
575
576
static void
577
list_locale(Sfio_t* sp, Keyword_t* key, Lc_t* lc, unsigned int flags)
578
{
579
register int i;
580
int n;
581
char* fmt;
582
char* sep;
583
char buf[256];
584
585
static unsigned long types[] = { LC_abbreviated, LC_qualified, LC_verbose, LC_local };
586
587
n = 0;
588
for (i = 0; i < elementsof(types); i++)
589
if (flags & types[i])
590
n++;
591
if (!n)
592
{
593
n++;
594
flags |= LC_abbreviated;
595
}
596
n = n == 1;
597
if (key)
598
{
599
if (flags & LC_indent)
600
{
601
sfputc(sp, '\t');
602
n = 0;
603
}
604
if (flags & (LC_category|LC_keyword))
605
{
606
sfprintf(sp, "%s=", key->name);
607
n = 0;
608
}
609
}
610
fmt = n ? "%s%s" : "%s\"%s\"";
611
sep = "";
612
for (i = 0; i < elementsof(types); i++)
613
if (flags & types[i])
614
{
615
lccanon(lc, types[i], buf, sizeof(buf));
616
if (n && streq(buf, "-"))
617
return;
618
sfprintf(sp, fmt, sep, buf);
619
sep = ";";
620
}
621
sfputc(sp, '\n');
622
}
623
624
/*
625
* print the numeric value i for key
626
*/
627
628
static void
629
number(Sfio_t* sp, register Keyword_t* key, int i, unsigned int flags)
630
{
631
state.output = 1;
632
if (flags & LC_indent)
633
sfputc(sp, '\t');
634
if (flags & LC_keyword)
635
sfprintf(sp, "%s=%d\n", key->name, i);
636
else
637
sfprintf(sp, "%d\n", i);
638
}
639
640
/*
641
* print one string value, possibly quoted and converted to upper case
642
*/
643
644
static void
645
value(Sfio_t* sp, register const char* s, register unsigned int flags)
646
{
647
register int c;
648
register int u;
649
650
state.output = 1;
651
if ((flags & (LC_quote|LC_proper|LC_upper)) == LC_quote)
652
{
653
sfprintf(sp, "%s", fmtquote(s, "\"", "\"", strlen(s), FMT_ALWAYS));
654
return;
655
}
656
if (flags & LC_quote)
657
sfputc(sp, '"');
658
if (flags & LC_upper)
659
while (c = *s++)
660
{
661
if (islower(c))
662
c = toupper(c);
663
sfputc(sp, c);
664
}
665
else if (flags & LC_proper)
666
{
667
u = 1;
668
while (c = *s++)
669
{
670
if (!isalnum(c))
671
u = 1;
672
else
673
{
674
if (u && islower(c))
675
c = toupper(c);
676
u = 0;
677
}
678
sfputc(sp, c);
679
}
680
}
681
else
682
sfprintf(sp, "%s", s);
683
if (flags & LC_quote)
684
sfputc(sp, '"');
685
}
686
687
/*
688
* print the string value(s) v[n] for key
689
*/
690
691
static void
692
string(Sfio_t* sp, register Keyword_t* key, char** v, int n, unsigned int flags)
693
{
694
char** e;
695
register const Lc_attribute_list_t* a;
696
697
if (flags & LC_indent)
698
sfputc(sp, '\t');
699
if (flags & LC_keyword)
700
sfprintf(sp, "%s=", key->name);
701
if ((flags & LC_keyword) || n != 1)
702
flags |= LC_quote;
703
if (n)
704
{
705
value(sp, *v, flags);
706
flags |= LC_quote;
707
e = v + n - 1;
708
while (v++ < e)
709
{
710
sfputc(sp, ';');
711
value(sp, *v, flags);
712
}
713
}
714
else if (v && (a = *((Lc_attribute_list_t**)v)))
715
{
716
value(sp, a->attribute->name, flags);
717
while (a = a->next)
718
{
719
sfputc(sp, ';');
720
value(sp, a->attribute->name, flags);
721
}
722
}
723
sfputc(sp, '\n');
724
}
725
726
/*
727
* extact and list info for key with base info at data
728
*/
729
730
static void
731
extract(Sfio_t* sp, register Keyword_t* key, void* data, unsigned int flags)
732
{
733
register int i;
734
char* s;
735
char** v;
736
Lc_t* lc;
737
738
switch (key->type)
739
{
740
case C:
741
if (key->offset >= 0)
742
i = *((char*)data + key->offset);
743
else
744
i = CHAR_MAX;
745
if (i == CHAR_MAX)
746
i = -1;
747
number(sp, key, i, flags);
748
break;
749
case I:
750
if (key->offset >= 0)
751
i = *(int*)((char*)data + key->offset);
752
else
753
i = -1;
754
number(sp, key, i, flags);
755
break;
756
case N:
757
#if _lib_nl_langinfo
758
if (key->offset >= 0)
759
{
760
s = nl_langinfo(key->offset);
761
762
#if _num__NL_PAPER_HEIGHT
763
764
/*
765
* redhat decided to change the nl_langinfo()
766
* return value after umpteen years of stability
767
* to optionally return an int for some numeric
768
* values -- botch botch botch
769
*/
770
771
if (((unsigned int)s) < 8196)
772
{
773
static char xxx[32];
774
775
sfsprintf(xxx, sizeof(xxx), "%d", (unsigned int)s);
776
s = xxx;
777
}
778
#endif
779
}
780
else
781
#endif
782
s = "";
783
string(sp, key, &s, 1, flags);
784
break;
785
case S:
786
if (key->offset >= 0)
787
{
788
v = (char**)((char*)data + key->offset);
789
i = key->elements;
790
}
791
else
792
{
793
s = "";
794
v = &s;
795
i = 1;
796
}
797
string(sp, key, v, i, flags);
798
break;
799
case X:
800
lc = (Lc_t*)lcinfo(state.categories[key->index].external)->lc;
801
i = 1;
802
if (key->offset == CV_language && lc->language)
803
{
804
s = (char*)lc->language->name;
805
flags |= LC_proper;
806
}
807
else if (key->offset == CV_territory && lc->territory)
808
{
809
s = (char*)lc->territory->name;
810
flags |= LC_proper;
811
}
812
else if (key->offset == CV_attributes && lc->attributes)
813
{
814
s = (char*)lc->attributes;
815
i = 0;
816
}
817
else
818
s = "";
819
string(sp, key, &s, i, flags);
820
break;
821
}
822
}
823
824
/*
825
* list LC_ALL info
826
*/
827
828
static void
829
list_all(Sfio_t* sp, register Lc_t* lc, unsigned long flags)
830
{
831
if (!lc)
832
lc = (Lc_t*)lcinfo(LC_CTYPE)->lc;
833
if (!state.sep)
834
state.sep = 1;
835
else
836
sfputc(sp, '\n');
837
if (flags & LC_category)
838
sfprintf(sp, "LC_ALL\n");
839
if (flags & LC_indent)
840
sfputc(sp, '\t');
841
if (flags & LC_keyword)
842
{
843
flags |= LC_quote;
844
sfprintf(sp, "locale=");
845
}
846
value(sp, lc->name, flags);
847
sfputc(sp, '\n');
848
}
849
850
static int scan(Sfio_t*, Keyword_t*, unsigned long);
851
852
/*
853
* list info for key
854
*/
855
856
static void
857
list_keyword(Sfio_t* sp, register Keyword_t* key, char* value, unsigned int flags)
858
{
859
register int i;
860
register int j;
861
register int n;
862
register unsigned int f;
863
char* s;
864
865
if ((flags & LC_category) && key->index != AST_LC_ALL)
866
sfprintf(sp, "%s\n", state.categories[key->index].name);
867
switch (key->index)
868
{
869
case AST_LC_COLLATE:
870
s = mbcoll() ? "strcoll" : "strcmp";
871
string(sp, key, &s, 1, flags);
872
break;
873
case AST_LC_CTYPE:
874
switch (key->offset)
875
{
876
case CV_charset:
877
s = (char*)lcinfo(LC_CTYPE)->lc->charset->code;
878
string(sp, key, &s, 1, flags|LC_upper);
879
break;
880
case CV_mb_cur_max:
881
number(sp, key, ast.mb_cur_max, flags);
882
break;
883
case CV_mb_cur_min:
884
number(sp, key, MB_CUR_MIN, flags);
885
break;
886
}
887
break;
888
case AST_LC_MONETARY:
889
case AST_LC_NUMERIC:
890
if (!state.conv)
891
state.conv = localeconv();
892
extract(sp, key, state.conv, flags);
893
break;
894
case AST_LC_ADDRESS:
895
case AST_LC_IDENTIFICATION:
896
case AST_LC_MEASUREMENT:
897
case AST_LC_MESSAGES:
898
case AST_LC_NAME:
899
case AST_LC_PAPER:
900
case AST_LC_TELEPHONE:
901
case AST_LC_TIME:
902
extract(sp, key, tmlocale(), flags);
903
break;
904
case AST_LC_ALL:
905
if (value)
906
{
907
if (streq(value, "-"))
908
value = 0;
909
if (!setlocale(key->offset, value))
910
error(1, "%s: invalid locale", value);
911
state.conv = 0;
912
}
913
else
914
{
915
if (key->type == AST_LC_ALL)
916
{
917
state.all = 1;
918
if ((flags & (LC_defined|LC_recursive)) == LC_defined)
919
{
920
scan(sp, key, flags|LC_recursive);
921
break;
922
}
923
i = 1;
924
n = AST_LC_COUNT - 1;
925
}
926
else
927
i = n = key->type;
928
if (state.all)
929
list_all(sp, NiL, flags);
930
for (; i <= n; i++)
931
{
932
f = flags;
933
for (j = 0; j < elementsof(keywords); j++)
934
if (keywords[j].index == i)
935
{
936
list_keyword(sp, &keywords[j], NiL, f);
937
f &= ~LC_category;
938
}
939
}
940
}
941
break;
942
case TEST:
943
state.output = 1;
944
if (!value)
945
error(2, "%s: value expected", key->name);
946
else
947
{
948
if (streq(value, "-"))
949
value = 0;
950
list_locale(sfstdout, key, lcmake(value), flags);
951
}
952
break;
953
}
954
}
955
956
/*
957
* scan all locales matching flags
958
*/
959
960
static int
961
scan(Sfio_t* sp, Keyword_t* key, unsigned long flags)
962
{
963
register Lc_t* lc = 0;
964
965
while (lc = lcscan(lc))
966
{
967
switch (flags & (LC_defined|LC_undefined))
968
{
969
case LC_defined:
970
if (!lc->index && !setlocale(LC_MONETARY, lc->name))
971
continue;
972
break;
973
case LC_undefined:
974
if (lc->index || setlocale(LC_MONETARY, lc->name))
975
continue;
976
break;
977
}
978
if (!key)
979
list_locale(sp, NiL, lc, flags);
980
else if (setlocale(LC_ALL, lc->name))
981
list_keyword(sp, key, NiL, flags&~LC_quote);
982
}
983
return 0;
984
}
985
986
int
987
main(int argc, char** argv)
988
{
989
register char* name;
990
register char* s;
991
register int i;
992
register unsigned int flags;
993
int collate;
994
int composite;
995
int transform;
996
int j;
997
char* value;
998
char** oargv;
999
Keyword_t* key;
1000
char buf[64];
1001
char col[1024];
1002
char dip[64];
1003
1004
error_info.id = "locale";
1005
oargv = argv;
1006
flags = 0;
1007
collate = 0;
1008
composite = 0;
1009
transform = 0;
1010
for (;;)
1011
{
1012
switch (optget(argv, usage))
1013
{
1014
case 'a':
1015
flags |= LC_defined;
1016
continue;
1017
case 'b':
1018
flags |= LC_abbreviated;
1019
continue;
1020
case 'c':
1021
flags |= LC_category;
1022
continue;
1023
case 'e':
1024
collate = 1;
1025
continue;
1026
case 'i':
1027
flags |= LC_indent;
1028
continue;
1029
case 'k':
1030
flags |= LC_keyword;
1031
continue;
1032
case 'l':
1033
flags |= LC_local;
1034
continue;
1035
case 'm':
1036
return execv(defer, argv);
1037
case 'q':
1038
flags |= LC_qualified;
1039
continue;
1040
case 't':
1041
composite = 1;
1042
continue;
1043
case 'u':
1044
flags |= LC_undefined;
1045
continue;
1046
case 'v':
1047
flags |= LC_verbose;
1048
continue;
1049
case 'x':
1050
transform = 1;
1051
continue;
1052
case '?':
1053
error(ERROR_USAGE|4, "%s", opt_info.arg);
1054
break;
1055
case ':':
1056
error(2, "%s", opt_info.arg);
1057
break;
1058
}
1059
break;
1060
}
1061
if (error_info.errors)
1062
error(ERROR_USAGE|4, "%s", optusage(NiL));
1063
argv += opt_info.index;
1064
if (collate)
1065
{
1066
while (name = *argv++)
1067
{
1068
sfprintf(sfstdout, "%s", name);
1069
sfsprintf(col, sizeof(col), ".%s.]", name);
1070
if ((i = regcollate(col, NiL, buf, sizeof(buf), NiL)) < 0)
1071
{
1072
sfprintf(sfstdout, "\tERROR\n");
1073
continue;
1074
}
1075
if (!(collate = mbxfrm(col, buf, sizeof(col))))
1076
{
1077
if (i > 1)
1078
{
1079
sfprintf(sfstdout, "\tINVALID\n");
1080
continue;
1081
}
1082
collate = i;
1083
memcpy(col, buf, i);
1084
}
1085
else if (i > 1)
1086
{
1087
buf[1] = 0;
1088
if (mbxfrm(dip, buf, sizeof(dip)) < collate)
1089
{
1090
sfprintf(sfstdout, "\tUNDEFINED\n");
1091
continue;
1092
}
1093
}
1094
for (i = 0, j = '\t'; i < collate; i++, j = ' ')
1095
sfprintf(sfstdout, "%c%02x", j, ((unsigned char*)col)[i]);
1096
sfputc(sfstdout, '\n');
1097
}
1098
return error_info.errors != 0;
1099
}
1100
if (composite)
1101
{
1102
sfprintf(sfstdout, "%s\n", setlocale(LC_ALL, NiL));
1103
return error_info.errors != 0;
1104
}
1105
if (transform)
1106
{
1107
while (name = *argv++)
1108
{
1109
sfprintf(sfstdout, "%s", name);
1110
collate = mbxfrm(col, name, sizeof(col));
1111
for (i = 0, j = '\t'; i < collate; i++, j = ' ')
1112
sfprintf(sfstdout, "%c%02x", j, ((unsigned char*)col)[i]);
1113
sfputc(sfstdout, '\n');
1114
}
1115
return error_info.errors != 0;
1116
}
1117
state.categories = lccategories();
1118
if (!*argv)
1119
{
1120
if (flags & (LC_undefined|LC_defined))
1121
{
1122
if (!(flags & (LC_abbreviated|LC_qualified|LC_local|LC_verbose)))
1123
flags |= LC_abbreviated;
1124
return scan(sfstdout, NiL, flags);
1125
}
1126
if (!flags)
1127
{
1128
name = "LANG";
1129
sfprintf(sfstdout, "%s=", name);
1130
if (!(s = getenv("LANG")))
1131
s = "POSIX";
1132
sfprintf(sfstdout, "%s\n", fmtquote(s, "'", NiL, strlen(s), 0));
1133
value = getenv(state.categories[AST_LC_ALL].name);
1134
for (i = 1; i < AST_LC_COUNT; i++)
1135
{
1136
s = setlocale(state.categories[i].external, NiL);
1137
sfprintf(sfstdout, "%s=%s\n", state.categories[i].name, fmtquote(s, "\"", "\"", strlen(s), (value || !getenv(state.categories[i].name)) ? FMT_ALWAYS : 0));
1138
}
1139
sfprintf(sfstdout, "%s=", state.categories[0].name);
1140
if (value)
1141
{
1142
s = setlocale(state.categories[0].external, NiL);
1143
sfprintf(sfstdout, "%s", fmtquote(s, "\"", "\"", strlen(s), 0));
1144
}
1145
sfputc(sfstdout, '\n');
1146
return 0;
1147
}
1148
}
1149
state.disc.key = offsetof(Keyword_t, name);
1150
state.disc.size = -1;
1151
state.disc.link = offsetof(Keyword_t, link);
1152
if (!(state.dict = dtopen(&state.disc, Dtoset)))
1153
error(3, "out of space [dictionary]");
1154
for (i = 0; i < elementsof(keywords); i++)
1155
dtinsert(state.dict, keywords + i);
1156
for (i = 0; i < AST_LC_COUNT; i++)
1157
{
1158
if (!(key = newof(0, Keyword_t, 1, 0)))
1159
error(3, "out of space [keyword]");
1160
key->name = state.categories[i].name;
1161
key->index = AST_LC_ALL;
1162
key->type = state.categories[i].internal;
1163
key->offset = state.categories[i].external;
1164
dtinsert(state.dict, key);
1165
}
1166
while (name = *argv++)
1167
{
1168
if (value = strchr(name, '='))
1169
*value++ = 0;
1170
if (!(key = (Keyword_t*)dtmatch(state.dict, name)))
1171
{
1172
if (name[0] == 'L' && name[1] == 'C' && name[2] == '_')
1173
error(2, "%s: unknown category", name);
1174
else if (oargv[0][0] != '/')
1175
{
1176
char* cmd[3];
1177
1178
cmd[0] = (char*)defer;
1179
cmd[1] = name;
1180
cmd[2] = 0;
1181
procrun(defer, cmd, 0);
1182
state.output = 1;
1183
}
1184
else
1185
error(2, "%s: unknown keyword", name);
1186
}
1187
else
1188
list_keyword(sfstdout, key, value, flags);
1189
}
1190
if (!error_info.errors && !state.output)
1191
list_keyword(sfstdout, (Keyword_t*)dtmatch(state.dict, state.categories[0].name), NiL, flags);
1192
return error_info.errors != 0;
1193
}
1194
1195