1*6b5e5868SGarrett D'Amore /* 2*6b5e5868SGarrett D'Amore * This file and its contents are supplied under the terms of the 3*6b5e5868SGarrett D'Amore * Common Development and Distribution License ("CDDL"), version 1.0. 4*6b5e5868SGarrett D'Amore * You may only use this file in accordance with the terms version 1.0 5*6b5e5868SGarrett D'Amore * of the CDDL. 6*6b5e5868SGarrett D'Amore * 7*6b5e5868SGarrett D'Amore * A full copy of the text of the CDDL should have accompanied this 8*6b5e5868SGarrett D'Amore * source. A copy of the CDDL is also available via the Internet at 9*6b5e5868SGarrett D'Amore * http://www.illumos.org/license/CDDL. 10*6b5e5868SGarrett D'Amore */ 11*6b5e5868SGarrett D'Amore 12*6b5e5868SGarrett D'Amore /* 13*6b5e5868SGarrett D'Amore * Copyright 2010 Nexenta Systems, Inc. All rights reserved. 14*6b5e5868SGarrett D'Amore */ 15*6b5e5868SGarrett D'Amore 16*6b5e5868SGarrett D'Amore /* 17*6b5e5868SGarrett D'Amore * CHARMAP file handling for localedef. 18*6b5e5868SGarrett D'Amore */ 19*6b5e5868SGarrett D'Amore 20*6b5e5868SGarrett D'Amore #include <stdio.h> 21*6b5e5868SGarrett D'Amore #include <stdlib.h> 22*6b5e5868SGarrett D'Amore #include <string.h> 23*6b5e5868SGarrett D'Amore #include <limits.h> 24*6b5e5868SGarrett D'Amore #include <unistd.h> 25*6b5e5868SGarrett D'Amore #include <alloca.h> 26*6b5e5868SGarrett D'Amore #include <sys/avl.h> 27*6b5e5868SGarrett D'Amore #include <stddef.h> 28*6b5e5868SGarrett D'Amore #include <unistd.h> 29*6b5e5868SGarrett D'Amore #include "localedef.h" 30*6b5e5868SGarrett D'Amore #include "parser.tab.h" 31*6b5e5868SGarrett D'Amore 32*6b5e5868SGarrett D'Amore static avl_tree_t cmap_sym; 33*6b5e5868SGarrett D'Amore static avl_tree_t cmap_wc; 34*6b5e5868SGarrett D'Amore 35*6b5e5868SGarrett D'Amore typedef struct charmap { 36*6b5e5868SGarrett D'Amore const char *name; 37*6b5e5868SGarrett D'Amore wchar_t wc; 38*6b5e5868SGarrett D'Amore avl_node_t avl_sym; 39*6b5e5868SGarrett D'Amore avl_node_t avl_wc; 40*6b5e5868SGarrett D'Amore } charmap_t; 41*6b5e5868SGarrett D'Amore 42*6b5e5868SGarrett D'Amore /* 43*6b5e5868SGarrett D'Amore * Array of POSIX specific portable characters. 44*6b5e5868SGarrett D'Amore */ 45*6b5e5868SGarrett D'Amore static const struct { 46*6b5e5868SGarrett D'Amore char *name; 47*6b5e5868SGarrett D'Amore int ch; 48*6b5e5868SGarrett D'Amore } portable_chars[] = { 49*6b5e5868SGarrett D'Amore { "NUL", '\0' }, 50*6b5e5868SGarrett D'Amore { "alert", '\a' }, 51*6b5e5868SGarrett D'Amore { "backspace", '\b' }, 52*6b5e5868SGarrett D'Amore { "tab", '\t' }, 53*6b5e5868SGarrett D'Amore { "carriage-return", '\r' }, 54*6b5e5868SGarrett D'Amore { "newline", '\n' }, 55*6b5e5868SGarrett D'Amore { "vertical-tab", '\v' }, 56*6b5e5868SGarrett D'Amore { "form-feed", '\f' }, 57*6b5e5868SGarrett D'Amore { "space", ' ' }, 58*6b5e5868SGarrett D'Amore { "exclamation-mark", '!' }, 59*6b5e5868SGarrett D'Amore { "quotation-mark", '"' }, 60*6b5e5868SGarrett D'Amore { "number-sign", '#' }, 61*6b5e5868SGarrett D'Amore { "dollar-sign", '$' }, 62*6b5e5868SGarrett D'Amore { "percent-sign", '%' }, 63*6b5e5868SGarrett D'Amore { "ampersand", '&' }, 64*6b5e5868SGarrett D'Amore { "apostrophe", '\'' }, 65*6b5e5868SGarrett D'Amore { "left-parenthesis", '(' }, 66*6b5e5868SGarrett D'Amore { "right-parenthesis", '(' }, 67*6b5e5868SGarrett D'Amore { "asterisk", '*' }, 68*6b5e5868SGarrett D'Amore { "plus-sign", '+' }, 69*6b5e5868SGarrett D'Amore { "comma", ','}, 70*6b5e5868SGarrett D'Amore { "hyphen-minus", '-' }, 71*6b5e5868SGarrett D'Amore { "hyphen", '-' }, 72*6b5e5868SGarrett D'Amore { "full-stop", '.' }, 73*6b5e5868SGarrett D'Amore { "period", '.' }, 74*6b5e5868SGarrett D'Amore { "slash", '/' }, 75*6b5e5868SGarrett D'Amore { "solidus", '/' }, 76*6b5e5868SGarrett D'Amore { "zero", '0' }, 77*6b5e5868SGarrett D'Amore { "one", '1' }, 78*6b5e5868SGarrett D'Amore { "two", '2' }, 79*6b5e5868SGarrett D'Amore { "three", '3' }, 80*6b5e5868SGarrett D'Amore { "four", '4' }, 81*6b5e5868SGarrett D'Amore { "five", '5' }, 82*6b5e5868SGarrett D'Amore { "six", '6' }, 83*6b5e5868SGarrett D'Amore { "seven", '7' }, 84*6b5e5868SGarrett D'Amore { "eight", '8' }, 85*6b5e5868SGarrett D'Amore { "nine", '9' }, 86*6b5e5868SGarrett D'Amore { "colon", ':' }, 87*6b5e5868SGarrett D'Amore { "semicolon", ';' }, 88*6b5e5868SGarrett D'Amore { "less-than-sign", '<' }, 89*6b5e5868SGarrett D'Amore { "equals-sign", '=' }, 90*6b5e5868SGarrett D'Amore { "greater-than-sign", '>' }, 91*6b5e5868SGarrett D'Amore { "question-mark", '?' }, 92*6b5e5868SGarrett D'Amore { "commercial-at", '@' }, 93*6b5e5868SGarrett D'Amore { "left-square-bracket", '[' }, 94*6b5e5868SGarrett D'Amore { "backslash", '\\' }, 95*6b5e5868SGarrett D'Amore { "reverse-solidus", '\\' }, 96*6b5e5868SGarrett D'Amore { "right-square-bracket", ']' }, 97*6b5e5868SGarrett D'Amore { "circumflex", '^' }, 98*6b5e5868SGarrett D'Amore { "circumflex-accent", '^' }, 99*6b5e5868SGarrett D'Amore { "low-line", '_' }, 100*6b5e5868SGarrett D'Amore { "underscore", '_' }, 101*6b5e5868SGarrett D'Amore { "grave-accent", '`' }, 102*6b5e5868SGarrett D'Amore { "left-brace", '{' }, 103*6b5e5868SGarrett D'Amore { "left-curly-bracket", '{' }, 104*6b5e5868SGarrett D'Amore { "vertical-line", '|' }, 105*6b5e5868SGarrett D'Amore { "right-brace", '}' }, 106*6b5e5868SGarrett D'Amore { "right-curly-bracket", '}' }, 107*6b5e5868SGarrett D'Amore { "tilde", '~' }, 108*6b5e5868SGarrett D'Amore { "A", 'A' }, 109*6b5e5868SGarrett D'Amore { "B", 'B' }, 110*6b5e5868SGarrett D'Amore { "C", 'C' }, 111*6b5e5868SGarrett D'Amore { "D", 'D' }, 112*6b5e5868SGarrett D'Amore { "E", 'E' }, 113*6b5e5868SGarrett D'Amore { "F", 'F' }, 114*6b5e5868SGarrett D'Amore { "G", 'G' }, 115*6b5e5868SGarrett D'Amore { "H", 'H' }, 116*6b5e5868SGarrett D'Amore { "I", 'I' }, 117*6b5e5868SGarrett D'Amore { "J", 'J' }, 118*6b5e5868SGarrett D'Amore { "K", 'K' }, 119*6b5e5868SGarrett D'Amore { "L", 'L' }, 120*6b5e5868SGarrett D'Amore { "M", 'M' }, 121*6b5e5868SGarrett D'Amore { "N", 'N' }, 122*6b5e5868SGarrett D'Amore { "O", 'O' }, 123*6b5e5868SGarrett D'Amore { "P", 'P' }, 124*6b5e5868SGarrett D'Amore { "Q", 'Q' }, 125*6b5e5868SGarrett D'Amore { "R", 'R' }, 126*6b5e5868SGarrett D'Amore { "S", 'S' }, 127*6b5e5868SGarrett D'Amore { "T", 'T' }, 128*6b5e5868SGarrett D'Amore { "U", 'U' }, 129*6b5e5868SGarrett D'Amore { "V", 'V' }, 130*6b5e5868SGarrett D'Amore { "W", 'W' }, 131*6b5e5868SGarrett D'Amore { "X", 'X' }, 132*6b5e5868SGarrett D'Amore { "Y", 'Y' }, 133*6b5e5868SGarrett D'Amore { "Z", 'Z' }, 134*6b5e5868SGarrett D'Amore { "a", 'a' }, 135*6b5e5868SGarrett D'Amore { "b", 'b' }, 136*6b5e5868SGarrett D'Amore { "c", 'c' }, 137*6b5e5868SGarrett D'Amore { "d", 'd' }, 138*6b5e5868SGarrett D'Amore { "e", 'e' }, 139*6b5e5868SGarrett D'Amore { "f", 'f' }, 140*6b5e5868SGarrett D'Amore { "g", 'g' }, 141*6b5e5868SGarrett D'Amore { "h", 'h' }, 142*6b5e5868SGarrett D'Amore { "i", 'i' }, 143*6b5e5868SGarrett D'Amore { "j", 'j' }, 144*6b5e5868SGarrett D'Amore { "k", 'k' }, 145*6b5e5868SGarrett D'Amore { "l", 'l' }, 146*6b5e5868SGarrett D'Amore { "m", 'm' }, 147*6b5e5868SGarrett D'Amore { "n", 'n' }, 148*6b5e5868SGarrett D'Amore { "o", 'o' }, 149*6b5e5868SGarrett D'Amore { "p", 'p' }, 150*6b5e5868SGarrett D'Amore { "q", 'q' }, 151*6b5e5868SGarrett D'Amore { "r", 'r' }, 152*6b5e5868SGarrett D'Amore { "s", 's' }, 153*6b5e5868SGarrett D'Amore { "t", 't' }, 154*6b5e5868SGarrett D'Amore { "u", 'u' }, 155*6b5e5868SGarrett D'Amore { "v", 'v' }, 156*6b5e5868SGarrett D'Amore { "w", 'w' }, 157*6b5e5868SGarrett D'Amore { "x", 'x' }, 158*6b5e5868SGarrett D'Amore { "y", 'y' }, 159*6b5e5868SGarrett D'Amore { "z", 'z' }, 160*6b5e5868SGarrett D'Amore { NULL, 0 } 161*6b5e5868SGarrett D'Amore }; 162*6b5e5868SGarrett D'Amore 163*6b5e5868SGarrett D'Amore static int 164*6b5e5868SGarrett D'Amore cmap_compare_sym(const void *n1, const void *n2) 165*6b5e5868SGarrett D'Amore { 166*6b5e5868SGarrett D'Amore const charmap_t *c1 = n1; 167*6b5e5868SGarrett D'Amore const charmap_t *c2 = n2; 168*6b5e5868SGarrett D'Amore int rv; 169*6b5e5868SGarrett D'Amore 170*6b5e5868SGarrett D'Amore rv = strcmp(c1->name, c2->name); 171*6b5e5868SGarrett D'Amore return ((rv < 0) ? -1 : (rv > 0) ? 1 : 0); 172*6b5e5868SGarrett D'Amore } 173*6b5e5868SGarrett D'Amore 174*6b5e5868SGarrett D'Amore static int 175*6b5e5868SGarrett D'Amore cmap_compare_wc(const void *n1, const void *n2) 176*6b5e5868SGarrett D'Amore { 177*6b5e5868SGarrett D'Amore const charmap_t *c1 = n1; 178*6b5e5868SGarrett D'Amore const charmap_t *c2 = n2; 179*6b5e5868SGarrett D'Amore 180*6b5e5868SGarrett D'Amore return ((c1->wc < c2->wc) ? -1 : (c1->wc > c2->wc) ? 1 : 0); 181*6b5e5868SGarrett D'Amore } 182*6b5e5868SGarrett D'Amore 183*6b5e5868SGarrett D'Amore void 184*6b5e5868SGarrett D'Amore init_charmap(void) 185*6b5e5868SGarrett D'Amore { 186*6b5e5868SGarrett D'Amore avl_create(&cmap_sym, cmap_compare_sym, sizeof (charmap_t), 187*6b5e5868SGarrett D'Amore offsetof(charmap_t, avl_sym)); 188*6b5e5868SGarrett D'Amore 189*6b5e5868SGarrett D'Amore avl_create(&cmap_wc, cmap_compare_wc, sizeof (charmap_t), 190*6b5e5868SGarrett D'Amore offsetof(charmap_t, avl_wc)); 191*6b5e5868SGarrett D'Amore } 192*6b5e5868SGarrett D'Amore 193*6b5e5868SGarrett D'Amore static void 194*6b5e5868SGarrett D'Amore add_charmap_impl(char *sym, wchar_t wc, int nodups) 195*6b5e5868SGarrett D'Amore { 196*6b5e5868SGarrett D'Amore charmap_t srch; 197*6b5e5868SGarrett D'Amore charmap_t *n = NULL; 198*6b5e5868SGarrett D'Amore avl_index_t where; 199*6b5e5868SGarrett D'Amore 200*6b5e5868SGarrett D'Amore srch.wc = wc; 201*6b5e5868SGarrett D'Amore srch.name = sym; 202*6b5e5868SGarrett D'Amore 203*6b5e5868SGarrett D'Amore /* 204*6b5e5868SGarrett D'Amore * also possibly insert the wide mapping, although note that there 205*6b5e5868SGarrett D'Amore * can only be one of these per wide character code. 206*6b5e5868SGarrett D'Amore */ 207*6b5e5868SGarrett D'Amore if ((wc != -1) && ((avl_find(&cmap_wc, &srch, &where)) == NULL)) { 208*6b5e5868SGarrett D'Amore if ((n = calloc(1, sizeof (*n))) == NULL) { 209*6b5e5868SGarrett D'Amore errf(_("out of memory")); 210*6b5e5868SGarrett D'Amore return; 211*6b5e5868SGarrett D'Amore } 212*6b5e5868SGarrett D'Amore n->wc = wc; 213*6b5e5868SGarrett D'Amore avl_insert(&cmap_wc, n, where); 214*6b5e5868SGarrett D'Amore } 215*6b5e5868SGarrett D'Amore 216*6b5e5868SGarrett D'Amore if (sym) { 217*6b5e5868SGarrett D'Amore if (avl_find(&cmap_sym, &srch, &where) != NULL) { 218*6b5e5868SGarrett D'Amore if (nodups) { 219*6b5e5868SGarrett D'Amore errf(_("duplicate character definition")); 220*6b5e5868SGarrett D'Amore } 221*6b5e5868SGarrett D'Amore return; 222*6b5e5868SGarrett D'Amore } 223*6b5e5868SGarrett D'Amore if ((n == NULL) && ((n = calloc(1, sizeof (*n))) == NULL)) { 224*6b5e5868SGarrett D'Amore errf(_("out of memory")); 225*6b5e5868SGarrett D'Amore return; 226*6b5e5868SGarrett D'Amore } 227*6b5e5868SGarrett D'Amore n->wc = wc; 228*6b5e5868SGarrett D'Amore n->name = sym; 229*6b5e5868SGarrett D'Amore 230*6b5e5868SGarrett D'Amore avl_insert(&cmap_sym, n, where); 231*6b5e5868SGarrett D'Amore } 232*6b5e5868SGarrett D'Amore } 233*6b5e5868SGarrett D'Amore 234*6b5e5868SGarrett D'Amore void 235*6b5e5868SGarrett D'Amore add_charmap(char *sym, int c) 236*6b5e5868SGarrett D'Amore { 237*6b5e5868SGarrett D'Amore add_charmap_impl(sym, c, 1); 238*6b5e5868SGarrett D'Amore } 239*6b5e5868SGarrett D'Amore 240*6b5e5868SGarrett D'Amore void 241*6b5e5868SGarrett D'Amore add_charmap_undefined(char *sym) 242*6b5e5868SGarrett D'Amore { 243*6b5e5868SGarrett D'Amore charmap_t srch; 244*6b5e5868SGarrett D'Amore charmap_t *cm = NULL; 245*6b5e5868SGarrett D'Amore 246*6b5e5868SGarrett D'Amore srch.name = sym; 247*6b5e5868SGarrett D'Amore cm = avl_find(&cmap_sym, &srch, NULL); 248*6b5e5868SGarrett D'Amore 249*6b5e5868SGarrett D'Amore if ((undefok == 0) && ((cm == NULL) || (cm->wc == -1))) { 250*6b5e5868SGarrett D'Amore warn(_("undefined symbol <%s>"), sym); 251*6b5e5868SGarrett D'Amore add_charmap_impl(sym, -1, 0); 252*6b5e5868SGarrett D'Amore } else { 253*6b5e5868SGarrett D'Amore free(sym); 254*6b5e5868SGarrett D'Amore } 255*6b5e5868SGarrett D'Amore } 256*6b5e5868SGarrett D'Amore 257*6b5e5868SGarrett D'Amore void 258*6b5e5868SGarrett D'Amore add_charmap_range(char *s, char *e, int wc) 259*6b5e5868SGarrett D'Amore { 260*6b5e5868SGarrett D'Amore int ls, le; 261*6b5e5868SGarrett D'Amore int si; 262*6b5e5868SGarrett D'Amore int sn, en; 263*6b5e5868SGarrett D'Amore int i; 264*6b5e5868SGarrett D'Amore 265*6b5e5868SGarrett D'Amore static const char *digits = "0123456789"; 266*6b5e5868SGarrett D'Amore 267*6b5e5868SGarrett D'Amore ls = strlen(s); 268*6b5e5868SGarrett D'Amore le = strlen(e); 269*6b5e5868SGarrett D'Amore 270*6b5e5868SGarrett D'Amore if (((si = strcspn(s, digits)) == 0) || (si == ls) || 271*6b5e5868SGarrett D'Amore (strncmp(s, e, si) != 0) || 272*6b5e5868SGarrett D'Amore (strspn(s + si, digits) != (ls - si)) || 273*6b5e5868SGarrett D'Amore (strspn(e + si, digits) != (le - si)) || 274*6b5e5868SGarrett D'Amore ((sn = atoi(s + si)) > ((en = atoi(e + si))))) { 275*6b5e5868SGarrett D'Amore errf(_("malformed charmap range")); 276*6b5e5868SGarrett D'Amore return; 277*6b5e5868SGarrett D'Amore } 278*6b5e5868SGarrett D'Amore 279*6b5e5868SGarrett D'Amore s[si] = 0; 280*6b5e5868SGarrett D'Amore 281*6b5e5868SGarrett D'Amore for (i = sn; i <= en; i++) { 282*6b5e5868SGarrett D'Amore char *nn; 283*6b5e5868SGarrett D'Amore (void) asprintf(&nn, "%s%0*u", s, ls - si, i); 284*6b5e5868SGarrett D'Amore if (nn == NULL) { 285*6b5e5868SGarrett D'Amore errf(_("out of memory")); 286*6b5e5868SGarrett D'Amore return; 287*6b5e5868SGarrett D'Amore } 288*6b5e5868SGarrett D'Amore 289*6b5e5868SGarrett D'Amore add_charmap_impl(nn, wc, 1); 290*6b5e5868SGarrett D'Amore wc++; 291*6b5e5868SGarrett D'Amore } 292*6b5e5868SGarrett D'Amore free(s); 293*6b5e5868SGarrett D'Amore free(e); 294*6b5e5868SGarrett D'Amore } 295*6b5e5868SGarrett D'Amore 296*6b5e5868SGarrett D'Amore void 297*6b5e5868SGarrett D'Amore add_charmap_char(char *name, int val) 298*6b5e5868SGarrett D'Amore { 299*6b5e5868SGarrett D'Amore add_charmap_impl(name, val, 0); 300*6b5e5868SGarrett D'Amore } 301*6b5e5868SGarrett D'Amore 302*6b5e5868SGarrett D'Amore /* 303*6b5e5868SGarrett D'Amore * POSIX insists that certain entries be present, even when not in the 304*6b5e5868SGarrett D'Amore * orginal charmap file. 305*6b5e5868SGarrett D'Amore */ 306*6b5e5868SGarrett D'Amore void 307*6b5e5868SGarrett D'Amore add_charmap_posix(void) 308*6b5e5868SGarrett D'Amore { 309*6b5e5868SGarrett D'Amore char i; 310*6b5e5868SGarrett D'Amore 311*6b5e5868SGarrett D'Amore for (i = 0; portable_chars[i].name; i++) { 312*6b5e5868SGarrett D'Amore add_charmap_char(portable_chars[i].name, portable_chars[i].ch); 313*6b5e5868SGarrett D'Amore } 314*6b5e5868SGarrett D'Amore } 315*6b5e5868SGarrett D'Amore 316*6b5e5868SGarrett D'Amore int 317*6b5e5868SGarrett D'Amore lookup_charmap(const char *sym, wchar_t *wc) 318*6b5e5868SGarrett D'Amore { 319*6b5e5868SGarrett D'Amore charmap_t srch; 320*6b5e5868SGarrett D'Amore charmap_t *n; 321*6b5e5868SGarrett D'Amore 322*6b5e5868SGarrett D'Amore srch.name = sym; 323*6b5e5868SGarrett D'Amore n = avl_find(&cmap_sym, &srch, NULL); 324*6b5e5868SGarrett D'Amore if (n && n->wc != -1) { 325*6b5e5868SGarrett D'Amore if (wc) 326*6b5e5868SGarrett D'Amore *wc = n->wc; 327*6b5e5868SGarrett D'Amore return (0); 328*6b5e5868SGarrett D'Amore } 329*6b5e5868SGarrett D'Amore return (-1); 330*6b5e5868SGarrett D'Amore } 331*6b5e5868SGarrett D'Amore 332*6b5e5868SGarrett D'Amore int 333*6b5e5868SGarrett D'Amore check_charmap(wchar_t wc) 334*6b5e5868SGarrett D'Amore { 335*6b5e5868SGarrett D'Amore charmap_t srch; 336*6b5e5868SGarrett D'Amore 337*6b5e5868SGarrett D'Amore srch.wc = wc; 338*6b5e5868SGarrett D'Amore return (avl_find(&cmap_wc, &srch, NULL) ? 0 : -1); 339*6b5e5868SGarrett D'Amore } 340