16b5e5868SGarrett D'Amore /* 26b5e5868SGarrett D'Amore * This file and its contents are supplied under the terms of the 36b5e5868SGarrett D'Amore * Common Development and Distribution License ("CDDL"), version 1.0. 4*5aec55ebSGarrett D'Amore * You may only use this file in accordance with the terms of version 5*5aec55ebSGarrett D'Amore * 1.0 of the CDDL. 66b5e5868SGarrett D'Amore * 76b5e5868SGarrett D'Amore * A full copy of the text of the CDDL should have accompanied this 86b5e5868SGarrett D'Amore * source. A copy of the CDDL is also available via the Internet at 96b5e5868SGarrett D'Amore * http://www.illumos.org/license/CDDL. 106b5e5868SGarrett D'Amore */ 116b5e5868SGarrett D'Amore 126b5e5868SGarrett D'Amore /* 136b5e5868SGarrett D'Amore * Copyright 2010 Nexenta Systems, Inc. All rights reserved. 146b5e5868SGarrett D'Amore */ 156b5e5868SGarrett D'Amore 166b5e5868SGarrett D'Amore /* 176b5e5868SGarrett D'Amore * CHARMAP file handling for localedef. 186b5e5868SGarrett D'Amore */ 196b5e5868SGarrett D'Amore 206b5e5868SGarrett D'Amore #include <stdio.h> 216b5e5868SGarrett D'Amore #include <stdlib.h> 226b5e5868SGarrett D'Amore #include <string.h> 236b5e5868SGarrett D'Amore #include <limits.h> 246b5e5868SGarrett D'Amore #include <unistd.h> 256b5e5868SGarrett D'Amore #include <alloca.h> 266b5e5868SGarrett D'Amore #include <sys/avl.h> 276b5e5868SGarrett D'Amore #include <stddef.h> 286b5e5868SGarrett D'Amore #include <unistd.h> 296b5e5868SGarrett D'Amore #include "localedef.h" 306b5e5868SGarrett D'Amore #include "parser.tab.h" 316b5e5868SGarrett D'Amore 326b5e5868SGarrett D'Amore static avl_tree_t cmap_sym; 336b5e5868SGarrett D'Amore static avl_tree_t cmap_wc; 346b5e5868SGarrett D'Amore 356b5e5868SGarrett D'Amore typedef struct charmap { 366b5e5868SGarrett D'Amore const char *name; 376b5e5868SGarrett D'Amore wchar_t wc; 386b5e5868SGarrett D'Amore avl_node_t avl_sym; 396b5e5868SGarrett D'Amore avl_node_t avl_wc; 406b5e5868SGarrett D'Amore } charmap_t; 416b5e5868SGarrett D'Amore 426b5e5868SGarrett D'Amore /* 436b5e5868SGarrett D'Amore * Array of POSIX specific portable characters. 446b5e5868SGarrett D'Amore */ 456b5e5868SGarrett D'Amore static const struct { 466b5e5868SGarrett D'Amore char *name; 476b5e5868SGarrett D'Amore int ch; 486b5e5868SGarrett D'Amore } portable_chars[] = { 496b5e5868SGarrett D'Amore { "NUL", '\0' }, 506b5e5868SGarrett D'Amore { "alert", '\a' }, 516b5e5868SGarrett D'Amore { "backspace", '\b' }, 526b5e5868SGarrett D'Amore { "tab", '\t' }, 536b5e5868SGarrett D'Amore { "carriage-return", '\r' }, 546b5e5868SGarrett D'Amore { "newline", '\n' }, 556b5e5868SGarrett D'Amore { "vertical-tab", '\v' }, 566b5e5868SGarrett D'Amore { "form-feed", '\f' }, 576b5e5868SGarrett D'Amore { "space", ' ' }, 586b5e5868SGarrett D'Amore { "exclamation-mark", '!' }, 596b5e5868SGarrett D'Amore { "quotation-mark", '"' }, 606b5e5868SGarrett D'Amore { "number-sign", '#' }, 616b5e5868SGarrett D'Amore { "dollar-sign", '$' }, 626b5e5868SGarrett D'Amore { "percent-sign", '%' }, 636b5e5868SGarrett D'Amore { "ampersand", '&' }, 646b5e5868SGarrett D'Amore { "apostrophe", '\'' }, 656b5e5868SGarrett D'Amore { "left-parenthesis", '(' }, 666b5e5868SGarrett D'Amore { "right-parenthesis", '(' }, 676b5e5868SGarrett D'Amore { "asterisk", '*' }, 686b5e5868SGarrett D'Amore { "plus-sign", '+' }, 696b5e5868SGarrett D'Amore { "comma", ','}, 706b5e5868SGarrett D'Amore { "hyphen-minus", '-' }, 716b5e5868SGarrett D'Amore { "hyphen", '-' }, 726b5e5868SGarrett D'Amore { "full-stop", '.' }, 736b5e5868SGarrett D'Amore { "period", '.' }, 746b5e5868SGarrett D'Amore { "slash", '/' }, 756b5e5868SGarrett D'Amore { "solidus", '/' }, 766b5e5868SGarrett D'Amore { "zero", '0' }, 776b5e5868SGarrett D'Amore { "one", '1' }, 786b5e5868SGarrett D'Amore { "two", '2' }, 796b5e5868SGarrett D'Amore { "three", '3' }, 806b5e5868SGarrett D'Amore { "four", '4' }, 816b5e5868SGarrett D'Amore { "five", '5' }, 826b5e5868SGarrett D'Amore { "six", '6' }, 836b5e5868SGarrett D'Amore { "seven", '7' }, 846b5e5868SGarrett D'Amore { "eight", '8' }, 856b5e5868SGarrett D'Amore { "nine", '9' }, 866b5e5868SGarrett D'Amore { "colon", ':' }, 876b5e5868SGarrett D'Amore { "semicolon", ';' }, 886b5e5868SGarrett D'Amore { "less-than-sign", '<' }, 896b5e5868SGarrett D'Amore { "equals-sign", '=' }, 906b5e5868SGarrett D'Amore { "greater-than-sign", '>' }, 916b5e5868SGarrett D'Amore { "question-mark", '?' }, 926b5e5868SGarrett D'Amore { "commercial-at", '@' }, 936b5e5868SGarrett D'Amore { "left-square-bracket", '[' }, 946b5e5868SGarrett D'Amore { "backslash", '\\' }, 956b5e5868SGarrett D'Amore { "reverse-solidus", '\\' }, 966b5e5868SGarrett D'Amore { "right-square-bracket", ']' }, 976b5e5868SGarrett D'Amore { "circumflex", '^' }, 986b5e5868SGarrett D'Amore { "circumflex-accent", '^' }, 996b5e5868SGarrett D'Amore { "low-line", '_' }, 1006b5e5868SGarrett D'Amore { "underscore", '_' }, 1016b5e5868SGarrett D'Amore { "grave-accent", '`' }, 1026b5e5868SGarrett D'Amore { "left-brace", '{' }, 1036b5e5868SGarrett D'Amore { "left-curly-bracket", '{' }, 1046b5e5868SGarrett D'Amore { "vertical-line", '|' }, 1056b5e5868SGarrett D'Amore { "right-brace", '}' }, 1066b5e5868SGarrett D'Amore { "right-curly-bracket", '}' }, 1076b5e5868SGarrett D'Amore { "tilde", '~' }, 1086b5e5868SGarrett D'Amore { "A", 'A' }, 1096b5e5868SGarrett D'Amore { "B", 'B' }, 1106b5e5868SGarrett D'Amore { "C", 'C' }, 1116b5e5868SGarrett D'Amore { "D", 'D' }, 1126b5e5868SGarrett D'Amore { "E", 'E' }, 1136b5e5868SGarrett D'Amore { "F", 'F' }, 1146b5e5868SGarrett D'Amore { "G", 'G' }, 1156b5e5868SGarrett D'Amore { "H", 'H' }, 1166b5e5868SGarrett D'Amore { "I", 'I' }, 1176b5e5868SGarrett D'Amore { "J", 'J' }, 1186b5e5868SGarrett D'Amore { "K", 'K' }, 1196b5e5868SGarrett D'Amore { "L", 'L' }, 1206b5e5868SGarrett D'Amore { "M", 'M' }, 1216b5e5868SGarrett D'Amore { "N", 'N' }, 1226b5e5868SGarrett D'Amore { "O", 'O' }, 1236b5e5868SGarrett D'Amore { "P", 'P' }, 1246b5e5868SGarrett D'Amore { "Q", 'Q' }, 1256b5e5868SGarrett D'Amore { "R", 'R' }, 1266b5e5868SGarrett D'Amore { "S", 'S' }, 1276b5e5868SGarrett D'Amore { "T", 'T' }, 1286b5e5868SGarrett D'Amore { "U", 'U' }, 1296b5e5868SGarrett D'Amore { "V", 'V' }, 1306b5e5868SGarrett D'Amore { "W", 'W' }, 1316b5e5868SGarrett D'Amore { "X", 'X' }, 1326b5e5868SGarrett D'Amore { "Y", 'Y' }, 1336b5e5868SGarrett D'Amore { "Z", 'Z' }, 1346b5e5868SGarrett D'Amore { "a", 'a' }, 1356b5e5868SGarrett D'Amore { "b", 'b' }, 1366b5e5868SGarrett D'Amore { "c", 'c' }, 1376b5e5868SGarrett D'Amore { "d", 'd' }, 1386b5e5868SGarrett D'Amore { "e", 'e' }, 1396b5e5868SGarrett D'Amore { "f", 'f' }, 1406b5e5868SGarrett D'Amore { "g", 'g' }, 1416b5e5868SGarrett D'Amore { "h", 'h' }, 1426b5e5868SGarrett D'Amore { "i", 'i' }, 1436b5e5868SGarrett D'Amore { "j", 'j' }, 1446b5e5868SGarrett D'Amore { "k", 'k' }, 1456b5e5868SGarrett D'Amore { "l", 'l' }, 1466b5e5868SGarrett D'Amore { "m", 'm' }, 1476b5e5868SGarrett D'Amore { "n", 'n' }, 1486b5e5868SGarrett D'Amore { "o", 'o' }, 1496b5e5868SGarrett D'Amore { "p", 'p' }, 1506b5e5868SGarrett D'Amore { "q", 'q' }, 1516b5e5868SGarrett D'Amore { "r", 'r' }, 1526b5e5868SGarrett D'Amore { "s", 's' }, 1536b5e5868SGarrett D'Amore { "t", 't' }, 1546b5e5868SGarrett D'Amore { "u", 'u' }, 1556b5e5868SGarrett D'Amore { "v", 'v' }, 1566b5e5868SGarrett D'Amore { "w", 'w' }, 1576b5e5868SGarrett D'Amore { "x", 'x' }, 1586b5e5868SGarrett D'Amore { "y", 'y' }, 1596b5e5868SGarrett D'Amore { "z", 'z' }, 1606b5e5868SGarrett D'Amore { NULL, 0 } 1616b5e5868SGarrett D'Amore }; 1626b5e5868SGarrett D'Amore 1636b5e5868SGarrett D'Amore static int 1646b5e5868SGarrett D'Amore cmap_compare_sym(const void *n1, const void *n2) 1656b5e5868SGarrett D'Amore { 1666b5e5868SGarrett D'Amore const charmap_t *c1 = n1; 1676b5e5868SGarrett D'Amore const charmap_t *c2 = n2; 1686b5e5868SGarrett D'Amore int rv; 1696b5e5868SGarrett D'Amore 1706b5e5868SGarrett D'Amore rv = strcmp(c1->name, c2->name); 1716b5e5868SGarrett D'Amore return ((rv < 0) ? -1 : (rv > 0) ? 1 : 0); 1726b5e5868SGarrett D'Amore } 1736b5e5868SGarrett D'Amore 1746b5e5868SGarrett D'Amore static int 1756b5e5868SGarrett D'Amore cmap_compare_wc(const void *n1, const void *n2) 1766b5e5868SGarrett D'Amore { 1776b5e5868SGarrett D'Amore const charmap_t *c1 = n1; 1786b5e5868SGarrett D'Amore const charmap_t *c2 = n2; 1796b5e5868SGarrett D'Amore 1806b5e5868SGarrett D'Amore return ((c1->wc < c2->wc) ? -1 : (c1->wc > c2->wc) ? 1 : 0); 1816b5e5868SGarrett D'Amore } 1826b5e5868SGarrett D'Amore 1836b5e5868SGarrett D'Amore void 1846b5e5868SGarrett D'Amore init_charmap(void) 1856b5e5868SGarrett D'Amore { 1866b5e5868SGarrett D'Amore avl_create(&cmap_sym, cmap_compare_sym, sizeof (charmap_t), 1876b5e5868SGarrett D'Amore offsetof(charmap_t, avl_sym)); 1886b5e5868SGarrett D'Amore 1896b5e5868SGarrett D'Amore avl_create(&cmap_wc, cmap_compare_wc, sizeof (charmap_t), 1906b5e5868SGarrett D'Amore offsetof(charmap_t, avl_wc)); 1916b5e5868SGarrett D'Amore } 1926b5e5868SGarrett D'Amore 1936b5e5868SGarrett D'Amore static void 1946b5e5868SGarrett D'Amore add_charmap_impl(char *sym, wchar_t wc, int nodups) 1956b5e5868SGarrett D'Amore { 1966b5e5868SGarrett D'Amore charmap_t srch; 1976b5e5868SGarrett D'Amore charmap_t *n = NULL; 1986b5e5868SGarrett D'Amore avl_index_t where; 1996b5e5868SGarrett D'Amore 2006b5e5868SGarrett D'Amore srch.wc = wc; 2016b5e5868SGarrett D'Amore srch.name = sym; 2026b5e5868SGarrett D'Amore 2036b5e5868SGarrett D'Amore /* 2046b5e5868SGarrett D'Amore * also possibly insert the wide mapping, although note that there 2056b5e5868SGarrett D'Amore * can only be one of these per wide character code. 2066b5e5868SGarrett D'Amore */ 2076b5e5868SGarrett D'Amore if ((wc != -1) && ((avl_find(&cmap_wc, &srch, &where)) == NULL)) { 2086b5e5868SGarrett D'Amore if ((n = calloc(1, sizeof (*n))) == NULL) { 2096b5e5868SGarrett D'Amore errf(_("out of memory")); 2106b5e5868SGarrett D'Amore return; 2116b5e5868SGarrett D'Amore } 2126b5e5868SGarrett D'Amore n->wc = wc; 2136b5e5868SGarrett D'Amore avl_insert(&cmap_wc, n, where); 2146b5e5868SGarrett D'Amore } 2156b5e5868SGarrett D'Amore 2166b5e5868SGarrett D'Amore if (sym) { 2176b5e5868SGarrett D'Amore if (avl_find(&cmap_sym, &srch, &where) != NULL) { 2186b5e5868SGarrett D'Amore if (nodups) { 2196b5e5868SGarrett D'Amore errf(_("duplicate character definition")); 2206b5e5868SGarrett D'Amore } 2216b5e5868SGarrett D'Amore return; 2226b5e5868SGarrett D'Amore } 2236b5e5868SGarrett D'Amore if ((n == NULL) && ((n = calloc(1, sizeof (*n))) == NULL)) { 2246b5e5868SGarrett D'Amore errf(_("out of memory")); 2256b5e5868SGarrett D'Amore return; 2266b5e5868SGarrett D'Amore } 2276b5e5868SGarrett D'Amore n->wc = wc; 2286b5e5868SGarrett D'Amore n->name = sym; 2296b5e5868SGarrett D'Amore 2306b5e5868SGarrett D'Amore avl_insert(&cmap_sym, n, where); 2316b5e5868SGarrett D'Amore } 2326b5e5868SGarrett D'Amore } 2336b5e5868SGarrett D'Amore 2346b5e5868SGarrett D'Amore void 2356b5e5868SGarrett D'Amore add_charmap(char *sym, int c) 2366b5e5868SGarrett D'Amore { 2376b5e5868SGarrett D'Amore add_charmap_impl(sym, c, 1); 2386b5e5868SGarrett D'Amore } 2396b5e5868SGarrett D'Amore 2406b5e5868SGarrett D'Amore void 2416b5e5868SGarrett D'Amore add_charmap_undefined(char *sym) 2426b5e5868SGarrett D'Amore { 2436b5e5868SGarrett D'Amore charmap_t srch; 2446b5e5868SGarrett D'Amore charmap_t *cm = NULL; 2456b5e5868SGarrett D'Amore 2466b5e5868SGarrett D'Amore srch.name = sym; 2476b5e5868SGarrett D'Amore cm = avl_find(&cmap_sym, &srch, NULL); 2486b5e5868SGarrett D'Amore 2496b5e5868SGarrett D'Amore if ((undefok == 0) && ((cm == NULL) || (cm->wc == -1))) { 2506b5e5868SGarrett D'Amore warn(_("undefined symbol <%s>"), sym); 2516b5e5868SGarrett D'Amore add_charmap_impl(sym, -1, 0); 2526b5e5868SGarrett D'Amore } else { 2536b5e5868SGarrett D'Amore free(sym); 2546b5e5868SGarrett D'Amore } 2556b5e5868SGarrett D'Amore } 2566b5e5868SGarrett D'Amore 2576b5e5868SGarrett D'Amore void 2586b5e5868SGarrett D'Amore add_charmap_range(char *s, char *e, int wc) 2596b5e5868SGarrett D'Amore { 2606b5e5868SGarrett D'Amore int ls, le; 2616b5e5868SGarrett D'Amore int si; 2626b5e5868SGarrett D'Amore int sn, en; 2636b5e5868SGarrett D'Amore int i; 2646b5e5868SGarrett D'Amore 2656b5e5868SGarrett D'Amore static const char *digits = "0123456789"; 2666b5e5868SGarrett D'Amore 2676b5e5868SGarrett D'Amore ls = strlen(s); 2686b5e5868SGarrett D'Amore le = strlen(e); 2696b5e5868SGarrett D'Amore 2706b5e5868SGarrett D'Amore if (((si = strcspn(s, digits)) == 0) || (si == ls) || 2716b5e5868SGarrett D'Amore (strncmp(s, e, si) != 0) || 2726b5e5868SGarrett D'Amore (strspn(s + si, digits) != (ls - si)) || 2736b5e5868SGarrett D'Amore (strspn(e + si, digits) != (le - si)) || 2746b5e5868SGarrett D'Amore ((sn = atoi(s + si)) > ((en = atoi(e + si))))) { 2756b5e5868SGarrett D'Amore errf(_("malformed charmap range")); 2766b5e5868SGarrett D'Amore return; 2776b5e5868SGarrett D'Amore } 2786b5e5868SGarrett D'Amore 2796b5e5868SGarrett D'Amore s[si] = 0; 2806b5e5868SGarrett D'Amore 2816b5e5868SGarrett D'Amore for (i = sn; i <= en; i++) { 2826b5e5868SGarrett D'Amore char *nn; 2836b5e5868SGarrett D'Amore (void) asprintf(&nn, "%s%0*u", s, ls - si, i); 2846b5e5868SGarrett D'Amore if (nn == NULL) { 2856b5e5868SGarrett D'Amore errf(_("out of memory")); 2866b5e5868SGarrett D'Amore return; 2876b5e5868SGarrett D'Amore } 2886b5e5868SGarrett D'Amore 2896b5e5868SGarrett D'Amore add_charmap_impl(nn, wc, 1); 2906b5e5868SGarrett D'Amore wc++; 2916b5e5868SGarrett D'Amore } 2926b5e5868SGarrett D'Amore free(s); 2936b5e5868SGarrett D'Amore free(e); 2946b5e5868SGarrett D'Amore } 2956b5e5868SGarrett D'Amore 2966b5e5868SGarrett D'Amore void 2976b5e5868SGarrett D'Amore add_charmap_char(char *name, int val) 2986b5e5868SGarrett D'Amore { 2996b5e5868SGarrett D'Amore add_charmap_impl(name, val, 0); 3006b5e5868SGarrett D'Amore } 3016b5e5868SGarrett D'Amore 3026b5e5868SGarrett D'Amore /* 3036b5e5868SGarrett D'Amore * POSIX insists that certain entries be present, even when not in the 3046b5e5868SGarrett D'Amore * orginal charmap file. 3056b5e5868SGarrett D'Amore */ 3066b5e5868SGarrett D'Amore void 3076b5e5868SGarrett D'Amore add_charmap_posix(void) 3086b5e5868SGarrett D'Amore { 3096b5e5868SGarrett D'Amore char i; 3106b5e5868SGarrett D'Amore 3116b5e5868SGarrett D'Amore for (i = 0; portable_chars[i].name; i++) { 3126b5e5868SGarrett D'Amore add_charmap_char(portable_chars[i].name, portable_chars[i].ch); 3136b5e5868SGarrett D'Amore } 3146b5e5868SGarrett D'Amore } 3156b5e5868SGarrett D'Amore 3166b5e5868SGarrett D'Amore int 3176b5e5868SGarrett D'Amore lookup_charmap(const char *sym, wchar_t *wc) 3186b5e5868SGarrett D'Amore { 3196b5e5868SGarrett D'Amore charmap_t srch; 3206b5e5868SGarrett D'Amore charmap_t *n; 3216b5e5868SGarrett D'Amore 3226b5e5868SGarrett D'Amore srch.name = sym; 3236b5e5868SGarrett D'Amore n = avl_find(&cmap_sym, &srch, NULL); 3246b5e5868SGarrett D'Amore if (n && n->wc != -1) { 3256b5e5868SGarrett D'Amore if (wc) 3266b5e5868SGarrett D'Amore *wc = n->wc; 3276b5e5868SGarrett D'Amore return (0); 3286b5e5868SGarrett D'Amore } 3296b5e5868SGarrett D'Amore return (-1); 3306b5e5868SGarrett D'Amore } 3316b5e5868SGarrett D'Amore 3326b5e5868SGarrett D'Amore int 3336b5e5868SGarrett D'Amore check_charmap(wchar_t wc) 3346b5e5868SGarrett D'Amore { 3356b5e5868SGarrett D'Amore charmap_t srch; 3366b5e5868SGarrett D'Amore 3376b5e5868SGarrett D'Amore srch.wc = wc; 3386b5e5868SGarrett D'Amore return (avl_find(&cmap_wc, &srch, NULL) ? 0 : -1); 3396b5e5868SGarrett D'Amore } 340