Annotation of src/usr.bin/locale/locale.c, Revision 1.3.2.1
1.3.2.1 ! he 1: /* $NetBSD: locale.c,v 1.3 2004/01/05 23:23:35 jmmv Exp $ */
1.1 tshiozak 2:
3: /*-
4: * Copyright (c) 2002, 2003 Alexey Zelkin <phantom@FreeBSD.org>
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: *
16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26: * SUCH DAMAGE.
27: *
28: * FreeBSD: src/usr.bin/locale/locale.c,v 1.10 2003/06/26 11:05:56 phantom Exp
29: */
30:
31: #include <sys/cdefs.h>
32: #if defined(LIBC_SCCS) && !defined(lint)
1.3.2.1 ! he 33: __RCSID("$NetBSD: locale.c,v 1.3 2004/01/05 23:23:35 jmmv Exp $");
1.1 tshiozak 34: #endif /* LIBC_SCCS and not lint */
35:
36: /*
37: * XXX: implement missing era_* (LC_TIME) keywords (require libc &
38: * nl_langinfo(3) extensions)
39: *
40: * XXX: correctly handle reserved 'charmap' keyword and '-m' option (require
41: * localedef(1) implementation). Currently it's handled via
42: * nl_langinfo(CODESET).
43: */
44:
45: #include <sys/types.h>
46: #include <dirent.h>
47: #include <err.h>
48: #include <locale.h>
49: #include <langinfo.h>
50: #include <paths.h>
51: #include <stdio.h>
52: #include <stdlib.h>
53: #include <string.h>
54: #include <stringlist.h>
55: #include <unistd.h>
56:
57: /* Local prototypes */
58: void init_locales_list(void);
59: void list_charmaps(void);
60: void list_locales(void);
61: const char *lookup_localecat(int);
62: char *kwval_lconv(int);
63: int kwval_lookup(char *, char **, int *, int *);
64: void showdetails(char *);
65: void showkeywordslist(void);
66: void showlocale(void);
67: void usage(void);
68:
69: /* Global variables */
70: static StringList *locales = NULL;
71: extern char *_PathLocale;
72:
73: int all_locales = 0;
74: int all_charmaps = 0;
75: int prt_categories = 0;
76: int prt_keywords = 0;
77: int more_params = 0;
78:
79: struct _lcinfo {
80: const char *name;
81: int id;
82: } lcinfo [] = {
83: { "LC_CTYPE", LC_CTYPE },
84: { "LC_COLLATE", LC_COLLATE },
85: { "LC_TIME", LC_TIME },
86: { "LC_NUMERIC", LC_NUMERIC },
87: { "LC_MONETARY", LC_MONETARY },
88: { "LC_MESSAGES", LC_MESSAGES }
89: };
90: #define NLCINFO (sizeof(lcinfo)/sizeof(lcinfo[0]))
91:
92: /* ids for values not referenced by nl_langinfo() */
93: #define KW_ZERO 10000
94: #define KW_GROUPING (KW_ZERO+1)
95: #define KW_INT_CURR_SYMBOL (KW_ZERO+2)
96: #define KW_CURRENCY_SYMBOL (KW_ZERO+3)
97: #define KW_MON_DECIMAL_POINT (KW_ZERO+4)
98: #define KW_MON_THOUSANDS_SEP (KW_ZERO+5)
99: #define KW_MON_GROUPING (KW_ZERO+6)
100: #define KW_POSITIVE_SIGN (KW_ZERO+7)
101: #define KW_NEGATIVE_SIGN (KW_ZERO+8)
102: #define KW_INT_FRAC_DIGITS (KW_ZERO+9)
103: #define KW_FRAC_DIGITS (KW_ZERO+10)
104: #define KW_P_CS_PRECEDES (KW_ZERO+11)
105: #define KW_P_SEP_BY_SPACE (KW_ZERO+12)
106: #define KW_N_CS_PRECEDES (KW_ZERO+13)
107: #define KW_N_SEP_BY_SPACE (KW_ZERO+14)
108: #define KW_P_SIGN_POSN (KW_ZERO+15)
109: #define KW_N_SIGN_POSN (KW_ZERO+16)
110: #define KW_INT_P_CS_PRECEDES (KW_ZERO+17)
111: #define KW_INT_P_SEP_BY_SPACE (KW_ZERO+18)
112: #define KW_INT_N_CS_PRECEDES (KW_ZERO+19)
113: #define KW_INT_N_SEP_BY_SPACE (KW_ZERO+20)
114: #define KW_INT_P_SIGN_POSN (KW_ZERO+21)
115: #define KW_INT_N_SIGN_POSN (KW_ZERO+22)
116:
117: struct _kwinfo {
118: const char *name;
119: int isstr; /* true - string, false - number */
120: int catid; /* LC_* */
121: int value_ref;
122: const char *comment;
123: } kwinfo [] = {
124: { "charmap", 1, LC_CTYPE, CODESET, "" }, /* hack */
125:
126: { "decimal_point", 1, LC_NUMERIC, RADIXCHAR, "" },
127: { "thousands_sep", 1, LC_NUMERIC, THOUSEP, "" },
128: { "grouping", 1, LC_NUMERIC, KW_GROUPING, "" },
129: { "radixchar", 1, LC_NUMERIC, RADIXCHAR,
130: "Same as decimal_point (BSD only)" }, /* compat */
131: { "thousep", 1, LC_NUMERIC, THOUSEP,
132: "Same as thousands_sep (BSD only)" }, /* compat */
133:
134: { "int_curr_symbol", 1, LC_MONETARY, KW_INT_CURR_SYMBOL, "" },
135: { "currency_symbol", 1, LC_MONETARY, KW_CURRENCY_SYMBOL, "" },
136: { "mon_decimal_point", 1, LC_MONETARY, KW_MON_DECIMAL_POINT, "" },
137: { "mon_thousands_sep", 1, LC_MONETARY, KW_MON_THOUSANDS_SEP, "" },
138: { "mon_grouping", 1, LC_MONETARY, KW_MON_GROUPING, "" },
139: { "positive_sign", 1, LC_MONETARY, KW_POSITIVE_SIGN, "" },
140: { "negative_sign", 1, LC_MONETARY, KW_NEGATIVE_SIGN, "" },
141:
142: { "int_frac_digits", 0, LC_MONETARY, KW_INT_FRAC_DIGITS, "" },
143: { "frac_digits", 0, LC_MONETARY, KW_FRAC_DIGITS, "" },
144: { "p_cs_precedes", 0, LC_MONETARY, KW_P_CS_PRECEDES, "" },
145: { "p_sep_by_space", 0, LC_MONETARY, KW_P_SEP_BY_SPACE, "" },
146: { "n_cs_precedes", 0, LC_MONETARY, KW_N_CS_PRECEDES, "" },
147: { "n_sep_by_space", 0, LC_MONETARY, KW_N_SEP_BY_SPACE, "" },
148: { "p_sign_posn", 0, LC_MONETARY, KW_P_SIGN_POSN, "" },
149: { "n_sign_posn", 0, LC_MONETARY, KW_N_SIGN_POSN, "" },
150: { "int_p_cs_precedes", 0, LC_MONETARY, KW_INT_P_CS_PRECEDES, "" },
151: { "int_p_sep_by_space", 0, LC_MONETARY, KW_INT_P_SEP_BY_SPACE, "" },
152: { "int_n_cs_precedes", 0, LC_MONETARY, KW_INT_N_CS_PRECEDES, "" },
153: { "int_n_sep_by_space", 0, LC_MONETARY, KW_INT_N_SEP_BY_SPACE, "" },
154: { "int_p_sign_posn", 0, LC_MONETARY, KW_INT_P_SIGN_POSN, "" },
155: { "int_n_sign_posn", 0, LC_MONETARY, KW_INT_N_SIGN_POSN, "" },
156:
157: { "d_t_fmt", 1, LC_TIME, D_T_FMT, "" },
158: { "d_fmt", 1, LC_TIME, D_FMT, "" },
159: { "t_fmt", 1, LC_TIME, T_FMT, "" },
160: { "am_str", 1, LC_TIME, AM_STR, "" },
161: { "pm_str", 1, LC_TIME, PM_STR, "" },
162: { "t_fmt_ampm", 1, LC_TIME, T_FMT_AMPM, "" },
163: { "day_1", 1, LC_TIME, DAY_1, "" },
164: { "day_2", 1, LC_TIME, DAY_2, "" },
165: { "day_3", 1, LC_TIME, DAY_3, "" },
166: { "day_4", 1, LC_TIME, DAY_4, "" },
167: { "day_5", 1, LC_TIME, DAY_5, "" },
168: { "day_6", 1, LC_TIME, DAY_6, "" },
169: { "day_7", 1, LC_TIME, DAY_7, "" },
170: { "abday_1", 1, LC_TIME, ABDAY_1, "" },
171: { "abday_2", 1, LC_TIME, ABDAY_2, "" },
172: { "abday_3", 1, LC_TIME, ABDAY_3, "" },
173: { "abday_4", 1, LC_TIME, ABDAY_4, "" },
174: { "abday_5", 1, LC_TIME, ABDAY_5, "" },
175: { "abday_6", 1, LC_TIME, ABDAY_6, "" },
176: { "abday_7", 1, LC_TIME, ABDAY_7, "" },
177: { "mon_1", 1, LC_TIME, MON_1, "" },
178: { "mon_2", 1, LC_TIME, MON_2, "" },
179: { "mon_3", 1, LC_TIME, MON_3, "" },
180: { "mon_4", 1, LC_TIME, MON_4, "" },
181: { "mon_5", 1, LC_TIME, MON_5, "" },
182: { "mon_6", 1, LC_TIME, MON_6, "" },
183: { "mon_7", 1, LC_TIME, MON_7, "" },
184: { "mon_8", 1, LC_TIME, MON_8, "" },
185: { "mon_9", 1, LC_TIME, MON_9, "" },
186: { "mon_10", 1, LC_TIME, MON_10, "" },
187: { "mon_11", 1, LC_TIME, MON_11, "" },
188: { "mon_12", 1, LC_TIME, MON_12, "" },
189: { "abmon_1", 1, LC_TIME, ABMON_1, "" },
190: { "abmon_2", 1, LC_TIME, ABMON_2, "" },
191: { "abmon_3", 1, LC_TIME, ABMON_3, "" },
192: { "abmon_4", 1, LC_TIME, ABMON_4, "" },
193: { "abmon_5", 1, LC_TIME, ABMON_5, "" },
194: { "abmon_6", 1, LC_TIME, ABMON_6, "" },
195: { "abmon_7", 1, LC_TIME, ABMON_7, "" },
196: { "abmon_8", 1, LC_TIME, ABMON_8, "" },
197: { "abmon_9", 1, LC_TIME, ABMON_9, "" },
198: { "abmon_10", 1, LC_TIME, ABMON_10, "" },
199: { "abmon_11", 1, LC_TIME, ABMON_11, "" },
200: { "abmon_12", 1, LC_TIME, ABMON_12, "" },
201: { "era", 1, LC_TIME, ERA, "(unavailable)" },
202: { "era_d_fmt", 1, LC_TIME, ERA_D_FMT, "(unavailable)" },
203: { "era_d_t_fmt", 1, LC_TIME, ERA_D_T_FMT, "(unavailable)" },
204: { "era_t_fmt", 1, LC_TIME, ERA_T_FMT, "(unavailable)" },
205: { "alt_digits", 1, LC_TIME, ALT_DIGITS, "" },
206:
207: { "yesexpr", 1, LC_MESSAGES, YESEXPR, "" },
208: { "noexpr", 1, LC_MESSAGES, NOEXPR, "" },
209: { "yesstr", 1, LC_MESSAGES, YESSTR,
210: "(POSIX legacy)" }, /* compat */
211: { "nostr", 1, LC_MESSAGES, NOSTR,
212: "(POSIX legacy)" } /* compat */
213:
214: };
215: #define NKWINFO (sizeof(kwinfo)/sizeof(kwinfo[0]))
216:
217: int
218: main(int argc, char *argv[])
219: {
1.2 agc 220: int ch;
1.1 tshiozak 221: int tmp;
222:
223: while ((ch = getopt(argc, argv, "ackm")) != -1) {
224: switch (ch) {
225: case 'a':
226: all_locales = 1;
227: break;
228: case 'c':
229: prt_categories = 1;
230: break;
231: case 'k':
232: prt_keywords = 1;
233: break;
234: case 'm':
235: all_charmaps = 1;
236: break;
237: default:
238: usage();
239: }
240: }
241: argc -= optind;
242: argv += optind;
243:
244: /* validate arguments */
245: if (all_locales && all_charmaps)
246: usage();
247: if ((all_locales || all_charmaps) && argc > 0)
248: usage();
249: if ((all_locales || all_charmaps) && (prt_categories || prt_keywords))
250: usage();
251: if ((prt_categories || prt_keywords) && argc <= 0)
252: usage();
253:
254: /* process '-a' */
255: if (all_locales) {
256: list_locales();
257: exit(0);
258: }
259:
260: /* process '-m' */
261: if (all_charmaps) {
262: list_charmaps();
263: exit(0);
264: }
265:
266: /* check for special case '-k list' */
267: tmp = 0;
268: if (prt_keywords && argc > 0)
269: while (tmp < argc)
270: if (strcasecmp(argv[tmp++], "list") == 0) {
271: showkeywordslist();
272: exit(0);
273: }
274:
275: /* process '-c' and/or '-k' */
276: if (prt_categories || prt_keywords || argc > 0) {
277: setlocale(LC_ALL, "");
278: while (argc > 0) {
279: showdetails(*argv);
280: argv++;
281: argc--;
282: }
283: exit(0);
284: }
285:
286: /* no arguments, show current locale state */
287: showlocale();
288:
289: return (0);
290: }
291:
292: void
293: usage(void)
294: {
1.3 jmmv 295: printf("usage: locale [ -a | -m ]\n"
1.1 tshiozak 296: " locale [ -ck ] name ...\n");
297: exit(1);
298: }
299:
300: /*
301: * Output information about all available locales
302: *
303: * XXX actually output of this function does not guarantee that locale
304: * is really available to application, since it can be broken or
305: * inconsistent thus setlocale() will fail. Maybe add '-V' function to
306: * also validate these locales?
307: */
308: void
309: list_locales(void)
310: {
311: size_t i;
312:
313: init_locales_list();
314: for (i = 0; i < locales->sl_cur; i++) {
315: printf("%s\n", locales->sl_str[i]);
316: }
317: }
318:
319: /*
320: * qsort() helper function
321: */
322: static int
323: scmp(const void *s1, const void *s2)
324: {
325: return strcmp(*(const char **)s1, *(const char **)s2);
326: }
327:
328: /*
329: * Output information about all available charmaps
330: *
331: * XXX this function is doing a task in hackish way, i.e. by scaning
332: * list of locales, spliting their codeset part and building list of
333: * them.
334: */
335: void
336: list_charmaps(void)
337: {
338: size_t i;
339: char *s, *cs;
340: StringList *charmaps;
341:
342: /* initialize StringList */
343: charmaps = sl_init();
344: if (charmaps == NULL)
345: err(1, "could not allocate memory");
346:
347: /* fetch locales list */
348: init_locales_list();
349:
350: /* split codesets and build their list */
351: for (i = 0; i < locales->sl_cur; i++) {
352: s = locales->sl_str[i];
353: if ((cs = strchr(s, '.')) != NULL) {
354: cs++;
355: if (sl_find(charmaps, cs) == NULL)
356: sl_add(charmaps, cs);
357: }
358: }
359:
360: /* add US-ASCII, if not yet added */
361: if (sl_find(charmaps, "US-ASCII") == NULL)
362: sl_add(charmaps, "US-ASCII");
363:
364: /* sort the list */
365: qsort(charmaps->sl_str, charmaps->sl_cur, sizeof(char *), scmp);
366:
367: /* print results */
368: for (i = 0; i < charmaps->sl_cur; i++) {
369: printf("%s\n", charmaps->sl_str[i]);
370: }
371: }
372:
373: /*
374: * Retrieve sorted list of system locales (or user locales, if PATH_LOCALE
375: * environment variable is set)
376: */
377: void
378: init_locales_list(void)
379: {
380: DIR *dirp;
381: struct dirent *dp;
382:
383: /* why call this function twice ? */
384: if (locales != NULL)
385: return;
386:
387: /* initialize StringList */
388: locales = sl_init();
389: if (locales == NULL)
390: err(1, "could not allocate memory");
391:
392: /* get actual locales directory name */
393: setlocale(LC_CTYPE, "C");
394: if (_PathLocale == NULL)
395: errx(1, "unable to find locales storage");
396:
397: /* open locales directory */
398: dirp = opendir(_PathLocale);
399: if (dirp == NULL)
400: err(1, "could not open directory '%s'", _PathLocale);
401:
402: /* scan directory and store its contents except "." and ".." */
403: while ((dp = readdir(dirp)) != NULL) {
404: if (*(dp->d_name) == '.')
405: continue; /* exclude "." and ".." */
406: sl_add(locales, strdup(dp->d_name));
407: }
408: closedir(dirp);
409:
410: /* make sure that 'POSIX' and 'C' locales are present in the list.
411: * POSIX 1003.1-2001 requires presence of 'POSIX' name only here, but
412: * we also list 'C' for constistency
413: */
414: if (sl_find(locales, "POSIX") == NULL)
415: sl_add(locales, "POSIX");
416:
417: if (sl_find(locales, "C") == NULL)
418: sl_add(locales, "C");
419:
420: /* make output nicer, sort the list */
421: qsort(locales->sl_str, locales->sl_cur, sizeof(char *), scmp);
422: }
423:
424: /*
425: * Show current locale status, depending on environment variables
426: */
427: void
428: showlocale(void)
429: {
430: size_t i;
431: const char *lang, *vval, *eval;
432:
433: setlocale(LC_ALL, "");
434:
435: lang = getenv("LANG");
436: if (lang == NULL) {
437: lang = "";
438: }
1.3.2.1 ! he 439: printf("LANG=\"%s\"\n", lang);
1.1 tshiozak 440: /* XXX: if LANG is null, then set it to "C" to get implied values? */
441:
442: for (i = 0; i < NLCINFO; i++) {
443: vval = setlocale(lcinfo[i].id, NULL);
444: eval = getenv(lcinfo[i].name);
445: if (eval != NULL && !strcmp(eval, vval)
446: && strcmp(lang, vval)) {
447: /*
448: * Appropriate environment variable set, its value
449: * is valid and not overriden by LC_ALL
450: *
451: * XXX: possible side effect: if both LANG and
452: * overriden environment variable are set into same
453: * value, then it'll be assumed as 'implied'
454: */
1.3.2.1 ! he 455: printf("%s=\"%s\"\n", lcinfo[i].name, vval);
1.1 tshiozak 456: } else {
457: printf("%s=\"%s\"\n", lcinfo[i].name, vval);
458: }
459: }
460:
461: vval = getenv("LC_ALL");
462: if (vval == NULL) {
463: vval = "";
464: }
1.3.2.1 ! he 465: printf("LC_ALL=\"%s\"\n", vval);
1.1 tshiozak 466: }
467:
468: /*
469: * keyword value lookup helper (via localeconv())
470: */
471: char *
472: kwval_lconv(int id)
473: {
474: struct lconv *lc;
475: char *rval;
476:
477: rval = NULL;
478: lc = localeconv();
479: switch (id) {
480: case KW_GROUPING:
481: rval = lc->grouping;
482: break;
483: case KW_INT_CURR_SYMBOL:
484: rval = lc->int_curr_symbol;
485: break;
486: case KW_CURRENCY_SYMBOL:
487: rval = lc->currency_symbol;
488: break;
489: case KW_MON_DECIMAL_POINT:
490: rval = lc->mon_decimal_point;
491: break;
492: case KW_MON_THOUSANDS_SEP:
493: rval = lc->mon_thousands_sep;
494: break;
495: case KW_MON_GROUPING:
496: rval = lc->mon_grouping;
497: break;
498: case KW_POSITIVE_SIGN:
499: rval = lc->positive_sign;
500: break;
501: case KW_NEGATIVE_SIGN:
502: rval = lc->negative_sign;
503: break;
504: case KW_INT_FRAC_DIGITS:
505: rval = &(lc->int_frac_digits);
506: break;
507: case KW_FRAC_DIGITS:
508: rval = &(lc->frac_digits);
509: break;
510: case KW_P_CS_PRECEDES:
511: rval = &(lc->p_cs_precedes);
512: break;
513: case KW_P_SEP_BY_SPACE:
514: rval = &(lc->p_sep_by_space);
515: break;
516: case KW_N_CS_PRECEDES:
517: rval = &(lc->n_cs_precedes);
518: break;
519: case KW_N_SEP_BY_SPACE:
520: rval = &(lc->n_sep_by_space);
521: break;
522: case KW_P_SIGN_POSN:
523: rval = &(lc->p_sign_posn);
524: break;
525: case KW_N_SIGN_POSN:
526: rval = &(lc->n_sign_posn);
527: break;
528: case KW_INT_P_CS_PRECEDES:
529: rval = &(lc->int_p_cs_precedes);
530: break;
531: case KW_INT_P_SEP_BY_SPACE:
532: rval = &(lc->int_p_sep_by_space);
533: break;
534: case KW_INT_N_CS_PRECEDES:
535: rval = &(lc->int_n_cs_precedes);
536: break;
537: case KW_INT_N_SEP_BY_SPACE:
538: rval = &(lc->int_n_sep_by_space);
539: break;
540: case KW_INT_P_SIGN_POSN:
541: rval = &(lc->int_p_sign_posn);
542: break;
543: case KW_INT_N_SIGN_POSN:
544: rval = &(lc->int_n_sign_posn);
545: break;
546: default:
547: break;
548: }
549: return (rval);
550: }
551:
552: /*
553: * keyword value and properties lookup
554: */
555: int
556: kwval_lookup(char *kwname, char **kwval, int *cat, int *isstr)
557: {
558: int rval;
559: size_t i;
560:
561: rval = 0;
562: for (i = 0; i < NKWINFO; i++) {
563: if (strcasecmp(kwname, kwinfo[i].name) == 0) {
564: rval = 1;
565: *cat = kwinfo[i].catid;
566: *isstr = kwinfo[i].isstr;
567: if (kwinfo[i].value_ref < KW_ZERO) {
568: *kwval = nl_langinfo(kwinfo[i].value_ref);
569: } else {
570: *kwval = kwval_lconv(kwinfo[i].value_ref);
571: }
572: break;
573: }
574: }
575:
576: return (rval);
577: }
578:
579: /*
580: * Show details about requested keyword according to '-k' and/or '-c'
581: * command line options specified.
582: */
583: void
584: showdetails(char *kw)
585: {
586: int isstr, cat, tmpval;
587: char *kwval;
588:
589: if (kwval_lookup(kw, &kwval, &cat, &isstr) == 0) {
590: /*
591: * invalid keyword specified.
592: * XXX: any actions?
593: */
594: return;
595: }
596:
597: if (prt_categories) {
598: printf("%s\n", lookup_localecat(cat));
599: }
600:
601: if (prt_keywords) {
602: if (isstr) {
603: printf("%s=\"%s\"\n", kw, kwval);
604: } else {
605: tmpval = (char) *kwval;
606: printf("%s=%d\n", kw, tmpval);
607: }
608: }
609:
610: if (!prt_categories && !prt_keywords) {
611: if (isstr) {
612: printf("%s\n", kwval);
613: } else {
614: tmpval = (char) *kwval;
615: printf("%d\n", tmpval);
616: }
617: }
618: }
619:
620: /*
621: * Convert locale category id into string
622: */
623: const char *
624: lookup_localecat(int cat)
625: {
626: size_t i;
627:
628: for (i = 0; i < NLCINFO; i++)
629: if (lcinfo[i].id == cat) {
630: return (lcinfo[i].name);
631: }
632: return ("UNKNOWN");
633: }
634:
635: /*
636: * Show list of keywords
637: */
638: void
639: showkeywordslist(void)
640: {
641: size_t i;
642:
643: #define FMT "%-20s %-12s %-7s %-20s\n"
644:
645: printf("List of available keywords\n\n");
646: printf(FMT, "Keyword", "Category", "Type", "Comment");
647: printf("-------------------- ------------ ------- --------------------\n");
648: for (i = 0; i < NKWINFO; i++) {
649: printf(FMT,
650: kwinfo[i].name,
651: lookup_localecat(kwinfo[i].catid),
652: (kwinfo[i].isstr == 0) ? "number" : "string",
653: kwinfo[i].comment);
654: }
655: }
CVSweb <webmaster@jp.NetBSD.org>