1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2017 Nexenta Systems, Inc. 14 */ 15 16 /* 17 * LC_COLLATE database generation routines for localedef. 18 */ 19 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <errno.h> 23 #include <string.h> 24 #include <sys/types.h> 25 #include <sys/avl.h> 26 #include <string.h> 27 #include <unistd.h> 28 #include <wchar.h> 29 #include <widec.h> 30 #include <limits.h> 31 #include "localedef.h" 32 #include "parser.tab.h" 33 #include "collatefile.h" 34 35 /* 36 * Design notes. 37 * 38 * It will be extremely helpful to the reader if they have access to 39 * the localedef and locale file format specifications available. 40 * Latest versions of these are available from www.opengroup.org. 41 * 42 * The design for the collation code is a bit complex. The goal is a 43 * single collation database as described in collate.h (in 44 * libc/port/locale). However, there are some other tidbits: 45 * 46 * a) The substitution entries are now a directly indexable array. A 47 * priority elsewhere in the table is taken as an index into the 48 * substitution table if it has a high bit (COLLATE_SUBST_PRIORITY) 49 * set. (The bit is cleared and the result is the index into the 50 * table. 51 * 52 * b) We eliminate duplicate entries into the substitution table. 53 * This saves a lot of space. 54 * 55 * c) The priorities for each level are "compressed", so that each 56 * sorting level has consecutively numbered priorities starting at 1. 57 * (O is reserved for the ignore priority.) This means sort levels 58 * which only have a few distinct priorities can represent the 59 * priority level in fewer bits, which makes the strxfrm output 60 * smaller. 61 * 62 * d) We record the total number of priorities so that strxfrm can 63 * figure out how many bytes to expand a numeric priority into. 64 * 65 * e) For the UNDEFINED pass (the last pass), we record the maximum 66 * number of bits needed to uniquely prioritize these entries, so that 67 * the last pass can also use smaller strxfrm output when possible. 68 * 69 * f) Priorities with the sign bit set are verboten. This works out 70 * because no active character set needs that bit to carry significant 71 * information once the character is in wide form. 72 * 73 * To process the entire data to make the database, we actually run 74 * multiple passes over the data. 75 * 76 * The first pass, which is done at parse time, identifies elements, 77 * substitutions, and such, and records them in priority order. As 78 * some priorities can refer to other priorities, using forward 79 * references, we use a table of references indicating whether the 80 * priority's value has been resolved, or whether it is still a 81 * reference. 82 * 83 * The second pass walks over all the items in priority order, noting 84 * that they are used directly, and not just an indirect reference. 85 * This is done by creating a "weight" structure for the item. The 86 * weights are stashed in an AVL tree sorted by relative "priority". 87 * 88 * The third pass walks over all the weight structures, in priority 89 * order, and assigns a new monotonically increasing (per sort level) 90 * weight value to them. These are the values that will actually be 91 * written to the file. 92 * 93 * The fourth pass just writes the data out. 94 */ 95 96 /* 97 * In order to resolve the priorities, we create a table of priorities. 98 * Entries in the table can be in one of three states. 99 * 100 * UNKNOWN is for newly allocated entries, and indicates that nothing 101 * is known about the priority. (For example, when new entries are created 102 * for collating-symbols, this is the value assigned for them until the 103 * collating symbol's order has been determined. 104 * 105 * RESOLVED is used for an entry where the priority indicates the final 106 * numeric weight. 107 * 108 * REFER is used for entries that reference other entries. Typically 109 * this is used for forward references. A collating-symbol can never 110 * have this value. 111 * 112 * The "pass" field is used during final resolution to aid in detection 113 * of referencing loops. (For example <A> depends on <B>, but <B> has its 114 * priority dependent on <A>.) 115 */ 116 typedef enum { 117 UNKNOWN, /* priority is totally unknown */ 118 RESOLVED, /* priority value fully resolved */ 119 REFER /* priority is a reference (index) */ 120 } res_t; 121 122 typedef struct weight { 123 int32_t pri; 124 int opt; 125 avl_node_t avl; 126 } weight_t; 127 128 typedef struct priority { 129 res_t res; 130 int32_t pri; 131 int pass; 132 int lineno; 133 } collpri_t; 134 135 #define NUM_WT collinfo.directive_count 136 137 /* 138 * These are the abstract collating symbols, which are just a symbolic 139 * way to reference a priority. 140 */ 141 struct collsym { 142 char *name; 143 int32_t ref; 144 avl_node_t avl; 145 }; 146 147 /* 148 * These are also abstract collating symbols, but we allow them to have 149 * different priorities at different levels. 150 */ 151 typedef struct collundef { 152 char *name; 153 int32_t ref[COLL_WEIGHTS_MAX]; 154 avl_node_t avl; 155 } collundef_t; 156 157 /* 158 * These are called "chains" in libc. This records the fact that two 159 * more characters should be treated as a single collating entity when 160 * they appear together. For example, in Spanish <C><h> gets collated 161 * as a character between <C> and <D>. 162 */ 163 struct collelem { 164 char *symbol; 165 wchar_t *expand; 166 int32_t ref[COLL_WEIGHTS_MAX]; 167 avl_node_t avl_bysymbol; 168 avl_node_t avl_byexpand; 169 }; 170 171 /* 172 * Individual characters have a sequence of weights as well. 173 */ 174 typedef struct collchar { 175 wchar_t wc; 176 int32_t ref[COLL_WEIGHTS_MAX]; 177 avl_node_t avl; 178 } collchar_t; 179 180 /* 181 * Substitution entries. The key is itself a priority. Note that 182 * when we create one of these, we *automatically* wind up with a 183 * fully resolved priority for the key, because creation of 184 * substitutions creates a resolved priority at the same time. 185 */ 186 typedef struct { 187 int32_t key; 188 int32_t ref[COLLATE_STR_LEN]; 189 avl_node_t avl; 190 avl_node_t avl_ref; 191 } subst_t; 192 193 static avl_tree_t collsyms; 194 static avl_tree_t collundefs; 195 static avl_tree_t elem_by_symbol; 196 static avl_tree_t elem_by_expand; 197 static avl_tree_t collchars; 198 static avl_tree_t substs[COLL_WEIGHTS_MAX]; 199 static avl_tree_t substs_ref[COLL_WEIGHTS_MAX]; 200 static avl_tree_t weights[COLL_WEIGHTS_MAX]; 201 static int32_t nweight[COLL_WEIGHTS_MAX]; 202 203 /* 204 * This is state tracking for the ellipsis token. Note that we start 205 * the initial values so that the ellipsis logic will think we got a 206 * magic starting value of NUL. It starts at minus one because the 207 * starting point is exclusive -- i.e. the starting point is not 208 * itself handled by the ellipsis code. 209 */ 210 static int currorder = EOF; 211 static int lastorder = EOF; 212 static collelem_t *currelem; 213 static collchar_t *currchar; 214 static collundef_t *currundef; 215 static wchar_t ellipsis_start = 0; 216 static int32_t ellipsis_weights[COLL_WEIGHTS_MAX]; 217 218 /* 219 * We keep a running tally of weights. 220 */ 221 static int nextpri = 1; 222 static int nextsubst[COLL_WEIGHTS_MAX] = { 0 }; 223 224 /* 225 * This array collects up the weights for each level. 226 */ 227 static int32_t order_weights[COLL_WEIGHTS_MAX]; 228 static int curr_weight = 0; 229 static int32_t subst_weights[COLLATE_STR_LEN]; 230 static int curr_subst = 0; 231 232 /* 233 * Some initial priority values. 234 */ 235 static int32_t pri_undefined[COLL_WEIGHTS_MAX]; 236 static int32_t pri_ignore; 237 238 static collate_info_t collinfo; 239 240 static collpri_t *prilist = NULL; 241 static int numpri = 0; 242 static int maxpri = 0; 243 244 static void start_order(int); 245 246 static int32_t 247 new_pri(void) 248 { 249 int i; 250 251 if (numpri >= maxpri) { 252 maxpri = maxpri ? maxpri * 2 : 1024; 253 prilist = realloc(prilist, sizeof (collpri_t) * maxpri); 254 if (prilist == NULL) { 255 errf(_("out of memory")); 256 return (-1); 257 } 258 for (i = numpri; i < maxpri; i++) { 259 prilist[i].res = UNKNOWN; 260 prilist[i].pri = 0; 261 prilist[i].pass = 0; 262 } 263 } 264 return (numpri++); 265 } 266 267 static collpri_t * 268 get_pri(int32_t ref) 269 { 270 if ((ref < 0) || (ref > numpri)) { 271 INTERR; 272 return (NULL); 273 } 274 return (&prilist[ref]); 275 } 276 277 static void 278 set_pri(int32_t ref, int32_t v, res_t res) 279 { 280 collpri_t *pri; 281 282 pri = get_pri(ref); 283 284 if ((res == REFER) && ((v < 0) || (v >= numpri))) { 285 INTERR; 286 } 287 288 /* Resolve self references */ 289 if ((res == REFER) && (ref == v)) { 290 v = nextpri; 291 res = RESOLVED; 292 } 293 294 if (pri->res != UNKNOWN) { 295 warn(_("repeated item in order list (first on %d)"), 296 pri->lineno); 297 return; 298 } 299 pri->lineno = lineno; 300 pri->pri = v; 301 pri->res = res; 302 } 303 304 static int32_t 305 resolve_pri(int32_t ref) 306 { 307 collpri_t *pri; 308 static int32_t pass = 0; 309 310 pri = get_pri(ref); 311 pass++; 312 while (pri->res == REFER) { 313 if (pri->pass == pass) { 314 /* report a line with the circular symbol */ 315 lineno = pri->lineno; 316 errf(_("circular reference in order list")); 317 return (-1); 318 } 319 if ((pri->pri < 0) || (pri->pri >= numpri)) { 320 INTERR; 321 return (-1); 322 } 323 pri->pass = pass; 324 pri = &prilist[pri->pri]; 325 } 326 327 if (pri->res == UNKNOWN) { 328 return (-1); 329 } 330 if (pri->res != RESOLVED) 331 INTERR; 332 333 return (pri->pri); 334 } 335 336 static int 337 weight_compare(const void *n1, const void *n2) 338 { 339 int32_t k1 = ((const weight_t *)n1)->pri; 340 int32_t k2 = ((const weight_t *)n2)->pri; 341 342 return (k1 < k2 ? -1 : k1 > k2 ? 1 : 0); 343 } 344 345 static int 346 collsym_compare(const void *n1, const void *n2) 347 { 348 const collsym_t *c1 = n1; 349 const collsym_t *c2 = n2; 350 int rv; 351 352 rv = strcmp(c1->name, c2->name); 353 return ((rv < 0) ? -1 : (rv > 0) ? 1 : 0); 354 } 355 356 static int 357 collundef_compare(const void *n1, const void *n2) 358 { 359 const collundef_t *c1 = n1; 360 const collundef_t *c2 = n2; 361 int rv; 362 363 rv = strcmp(c1->name, c2->name); 364 return ((rv < 0) ? -1 : (rv > 0) ? 1 : 0); 365 } 366 367 static int 368 element_compare_symbol(const void *n1, const void *n2) 369 { 370 const collelem_t *c1 = n1; 371 const collelem_t *c2 = n2; 372 int rv; 373 374 rv = strcmp(c1->symbol, c2->symbol); 375 return ((rv < 0) ? -1 : (rv > 0) ? 1 : 0); 376 } 377 378 static int 379 element_compare_expand(const void *n1, const void *n2) 380 { 381 const collelem_t *c1 = n1; 382 const collelem_t *c2 = n2; 383 int rv; 384 385 rv = wcscmp(c1->expand, c2->expand); 386 return ((rv < 0) ? -1 : (rv > 0) ? 1 : 0); 387 } 388 389 static int 390 collchar_compare(const void *n1, const void *n2) 391 { 392 wchar_t k1 = ((const collchar_t *)n1)->wc; 393 wchar_t k2 = ((const collchar_t *)n2)->wc; 394 395 return (k1 < k2 ? -1 : k1 > k2 ? 1 : 0); 396 } 397 398 static int 399 subst_compare(const void *n1, const void *n2) 400 { 401 int32_t k1 = ((const subst_t *)n1)->key; 402 int32_t k2 = ((const subst_t *)n2)->key; 403 404 return (k1 < k2 ? -1 : k1 > k2 ? 1 : 0); 405 } 406 407 static int 408 subst_compare_ref(const void *n1, const void *n2) 409 { 410 int32_t *c1 = ((subst_t *)n1)->ref; 411 int32_t *c2 = ((subst_t *)n2)->ref; 412 int rv; 413 414 rv = wcscmp((wchar_t *)c1, (wchar_t *)c2); 415 return ((rv < 0) ? -1 : (rv > 0) ? 1 : 0); 416 } 417 418 void 419 init_collate(void) 420 { 421 int i; 422 423 avl_create(&collsyms, collsym_compare, sizeof (collsym_t), 424 offsetof(collsym_t, avl)); 425 426 avl_create(&collundefs, collundef_compare, sizeof (collsym_t), 427 offsetof(collundef_t, avl)); 428 429 avl_create(&elem_by_symbol, element_compare_symbol, sizeof (collelem_t), 430 offsetof(collelem_t, avl_bysymbol)); 431 avl_create(&elem_by_expand, element_compare_expand, sizeof (collelem_t), 432 offsetof(collelem_t, avl_byexpand)); 433 434 avl_create(&collchars, collchar_compare, sizeof (collchar_t), 435 offsetof(collchar_t, avl)); 436 437 for (i = 0; i < COLL_WEIGHTS_MAX; i++) { 438 avl_create(&substs[i], subst_compare, sizeof (subst_t), 439 offsetof(subst_t, avl)); 440 avl_create(&substs_ref[i], subst_compare_ref, 441 sizeof (subst_t), offsetof(subst_t, avl_ref)); 442 avl_create(&weights[i], weight_compare, sizeof (weight_t), 443 offsetof(weight_t, avl)); 444 nweight[i] = 1; 445 } 446 447 (void) memset(&collinfo, 0, sizeof (collinfo)); 448 449 /* allocate some initial priorities */ 450 pri_ignore = new_pri(); 451 452 set_pri(pri_ignore, 0, RESOLVED); 453 454 for (i = 0; i < COLL_WEIGHTS_MAX; i++) { 455 pri_undefined[i] = new_pri(); 456 457 /* we will override this later */ 458 set_pri(pri_undefined[i], COLLATE_MAX_PRIORITY, UNKNOWN); 459 } 460 } 461 462 void 463 define_collsym(char *name) 464 { 465 collsym_t *sym; 466 avl_index_t where; 467 468 if ((sym = calloc(1, sizeof (*sym))) == NULL) { 469 errf(_("out of memory")); 470 return; 471 } 472 sym->name = name; 473 sym->ref = new_pri(); 474 475 if (avl_find(&collsyms, sym, &where) != NULL) { 476 /* 477 * This should never happen because we are only called 478 * for undefined symbols. 479 */ 480 free(sym); 481 INTERR; 482 return; 483 } 484 avl_insert(&collsyms, sym, where); 485 } 486 487 collsym_t * 488 lookup_collsym(char *name) 489 { 490 collsym_t srch; 491 492 srch.name = name; 493 return (avl_find(&collsyms, &srch, NULL)); 494 } 495 496 collelem_t * 497 lookup_collelem(char *symbol) 498 { 499 collelem_t srch; 500 501 srch.symbol = symbol; 502 return (avl_find(&elem_by_symbol, &srch, NULL)); 503 } 504 505 static collundef_t * 506 get_collundef(char *name) 507 { 508 collundef_t srch; 509 collundef_t *ud; 510 avl_index_t where; 511 int i; 512 513 srch.name = name; 514 if ((ud = avl_find(&collundefs, &srch, &where)) == NULL) { 515 if (((ud = calloc(1, sizeof (*ud))) == NULL) || 516 ((ud->name = strdup(name)) == NULL)) { 517 errf(_("out of memory")); 518 free(ud); 519 return (NULL); 520 } 521 for (i = 0; i < NUM_WT; i++) { 522 ud->ref[i] = new_pri(); 523 } 524 avl_insert(&collundefs, ud, where); 525 } 526 add_charmap_undefined(name); 527 return (ud); 528 } 529 530 static collchar_t * 531 get_collchar(wchar_t wc, int create) 532 { 533 collchar_t srch; 534 collchar_t *cc; 535 avl_index_t where; 536 int i; 537 538 srch.wc = wc; 539 cc = avl_find(&collchars, &srch, &where); 540 if ((cc == NULL) && create) { 541 if ((cc = calloc(1, sizeof (*cc))) == NULL) { 542 errf(_("out of memory")); 543 return (NULL); 544 } 545 for (i = 0; i < NUM_WT; i++) { 546 cc->ref[i] = new_pri(); 547 } 548 cc->wc = wc; 549 avl_insert(&collchars, cc, where); 550 } 551 return (cc); 552 } 553 554 void 555 end_order_collsym(collsym_t *sym) 556 { 557 start_order(T_COLLSYM); 558 /* update the weight */ 559 560 set_pri(sym->ref, nextpri, RESOLVED); 561 nextpri++; 562 } 563 564 void 565 end_order(void) 566 { 567 int i; 568 int32_t pri; 569 int32_t ref; 570 collpri_t *p; 571 572 /* advance the priority/weight */ 573 pri = nextpri; 574 575 switch (currorder) { 576 case T_CHAR: 577 for (i = 0; i < NUM_WT; i++) { 578 if (((ref = order_weights[i]) < 0) || 579 ((p = get_pri(ref)) == NULL) || 580 (p->pri == -1)) { 581 /* unspecified weight is a self reference */ 582 set_pri(currchar->ref[i], pri, RESOLVED); 583 } else { 584 set_pri(currchar->ref[i], ref, REFER); 585 } 586 order_weights[i] = -1; 587 } 588 589 /* leave a cookie trail in case next symbol is ellipsis */ 590 ellipsis_start = currchar->wc + 1; 591 currchar = NULL; 592 break; 593 594 case T_ELLIPSIS: 595 /* save off the weights were we can find them */ 596 for (i = 0; i < NUM_WT; i++) { 597 ellipsis_weights[i] = order_weights[i]; 598 order_weights[i] = -1; 599 } 600 break; 601 602 case T_COLLELEM: 603 if (currelem == NULL) { 604 INTERR; 605 } else { 606 for (i = 0; i < NUM_WT; i++) { 607 608 if (((ref = order_weights[i]) < 0) || 609 ((p = get_pri(ref)) == NULL) || 610 (p->pri == -1)) { 611 set_pri(currelem->ref[i], pri, 612 RESOLVED); 613 } else { 614 set_pri(currelem->ref[i], ref, REFER); 615 } 616 order_weights[i] = -1; 617 } 618 } 619 break; 620 621 case T_UNDEFINED: 622 for (i = 0; i < NUM_WT; i++) { 623 if (((ref = order_weights[i]) < 0) || 624 ((p = get_pri(ref)) == NULL) || 625 (p->pri == -1)) { 626 set_pri(pri_undefined[i], -1, RESOLVED); 627 } else { 628 set_pri(pri_undefined[i], ref, REFER); 629 } 630 order_weights[i] = -1; 631 } 632 break; 633 634 case T_SYMBOL: 635 for (i = 0; i < NUM_WT; i++) { 636 if (((ref = order_weights[i]) < 0) || 637 ((p = get_pri(ref)) == NULL) || 638 (p->pri == -1)) { 639 set_pri(currundef->ref[i], pri, RESOLVED); 640 } else { 641 set_pri(currundef->ref[i], ref, REFER); 642 } 643 order_weights[i] = -1; 644 } 645 break; 646 647 default: 648 INTERR; 649 } 650 651 nextpri++; 652 } 653 654 static void 655 start_order(int type) 656 { 657 int i; 658 659 lastorder = currorder; 660 currorder = type; 661 662 /* this is used to protect ELLIPSIS processing */ 663 if ((lastorder == T_ELLIPSIS) && (type != T_CHAR)) { 664 errf(_("character value expected")); 665 } 666 667 for (i = 0; i < COLL_WEIGHTS_MAX; i++) { 668 order_weights[i] = -1; 669 } 670 curr_weight = 0; 671 } 672 673 void 674 start_order_undefined(void) 675 { 676 start_order(T_UNDEFINED); 677 } 678 679 void 680 start_order_symbol(char *name) 681 { 682 currundef = get_collundef(name); 683 start_order(T_SYMBOL); 684 } 685 686 void 687 start_order_char(wchar_t wc) 688 { 689 collchar_t *cc; 690 int32_t ref; 691 692 start_order(T_CHAR); 693 694 /* 695 * If we last saw an ellipsis, then we need to close the range. 696 * Handle that here. Note that we have to be careful because the 697 * items *inside* the range are treated exclusiveley to the items 698 * outside of the range. The ends of the range can have quite 699 * different weights than the range members. 700 */ 701 if (lastorder == T_ELLIPSIS) { 702 int i; 703 704 if (wc < ellipsis_start) { 705 errf(_("malformed range!")); 706 return; 707 } 708 while (ellipsis_start < wc) { 709 /* 710 * pick all of the saved weights for the 711 * ellipsis. note that -1 encodes for the 712 * ellipsis itself, which means to take the 713 * current relative priority. 714 */ 715 if ((cc = get_collchar(ellipsis_start, 1)) == NULL) { 716 INTERR; 717 return; 718 } 719 for (i = 0; i < NUM_WT; i++) { 720 collpri_t *p; 721 if (((ref = ellipsis_weights[i]) == -1) || 722 ((p = get_pri(ref)) == NULL) || 723 (p->pri == -1)) { 724 set_pri(cc->ref[i], nextpri, RESOLVED); 725 } else { 726 set_pri(cc->ref[i], ref, REFER); 727 } 728 ellipsis_weights[i] = 0; 729 } 730 ellipsis_start++; 731 nextpri++; 732 } 733 } 734 735 currchar = get_collchar(wc, 1); 736 } 737 738 void 739 start_order_collelem(collelem_t *e) 740 { 741 start_order(T_COLLELEM); 742 currelem = e; 743 } 744 745 void 746 start_order_ellipsis(void) 747 { 748 int i; 749 750 start_order(T_ELLIPSIS); 751 752 if (lastorder != T_CHAR) { 753 errf(_("illegal starting point for range")); 754 return; 755 } 756 757 for (i = 0; i < NUM_WT; i++) { 758 ellipsis_weights[i] = order_weights[i]; 759 } 760 } 761 762 void 763 define_collelem(char *name, wchar_t *wcs) 764 { 765 collelem_t *e; 766 avl_index_t where1; 767 avl_index_t where2; 768 int i; 769 770 if (wcslen(wcs) >= COLLATE_STR_LEN) { 771 errf(_("expanded collation element too long")); 772 return; 773 } 774 775 if ((e = calloc(1, sizeof (*e))) == NULL) { 776 errf(_("out of memory")); 777 return; 778 } 779 e->expand = wcs; 780 e->symbol = name; 781 782 /* 783 * This is executed before the order statement, so we don't 784 * know how many priorities we *really* need. We allocate one 785 * for each possible weight. Not a big deal, as collating-elements 786 * prove to be quite rare. 787 */ 788 for (i = 0; i < COLL_WEIGHTS_MAX; i++) { 789 e->ref[i] = new_pri(); 790 } 791 792 /* A character sequence can only reduce to one element. */ 793 if ((avl_find(&elem_by_symbol, e, &where1) != NULL) || 794 (avl_find(&elem_by_expand, e, &where2) != NULL)) { 795 errf(_("duplicate collating element definition")); 796 free(e); 797 return; 798 } 799 avl_insert(&elem_by_symbol, e, where1); 800 avl_insert(&elem_by_expand, e, where2); 801 } 802 803 void 804 add_order_bit(int kw) 805 { 806 uint8_t bit = DIRECTIVE_UNDEF; 807 808 switch (kw) { 809 case T_FORWARD: 810 bit = DIRECTIVE_FORWARD; 811 break; 812 case T_BACKWARD: 813 bit = DIRECTIVE_BACKWARD; 814 break; 815 case T_POSITION: 816 bit = DIRECTIVE_POSITION; 817 break; 818 default: 819 INTERR; 820 break; 821 } 822 collinfo.directive[collinfo.directive_count] |= bit; 823 } 824 825 void 826 add_order_directive(void) 827 { 828 if (collinfo.directive_count >= COLL_WEIGHTS_MAX) { 829 errf(_("too many directives (max %d)"), COLL_WEIGHTS_MAX); 830 } 831 collinfo.directive_count++; 832 } 833 834 static void 835 add_order_pri(int32_t ref) 836 { 837 if (curr_weight >= NUM_WT) { 838 errf(_("too many weights (max %d)"), NUM_WT); 839 return; 840 } 841 order_weights[curr_weight] = ref; 842 curr_weight++; 843 } 844 845 void 846 add_order_collsym(collsym_t *s) 847 { 848 add_order_pri(s->ref); 849 } 850 851 void 852 add_order_char(wchar_t wc) 853 { 854 collchar_t *cc; 855 856 if ((cc = get_collchar(wc, 1)) == NULL) { 857 INTERR; 858 return; 859 } 860 861 add_order_pri(cc->ref[curr_weight]); 862 } 863 864 void 865 add_order_collelem(collelem_t *e) 866 { 867 add_order_pri(e->ref[curr_weight]); 868 } 869 870 void 871 add_order_ignore(void) 872 { 873 add_order_pri(pri_ignore); 874 } 875 876 void 877 add_order_symbol(char *sym) 878 { 879 collundef_t *c; 880 if ((c = get_collundef(sym)) == NULL) { 881 INTERR; 882 return; 883 } 884 add_order_pri(c->ref[curr_weight]); 885 } 886 887 void 888 add_order_ellipsis(void) 889 { 890 /* special 0 value indicates self reference */ 891 add_order_pri(0); 892 } 893 894 void 895 add_order_subst(void) 896 { 897 subst_t srch; 898 subst_t *s; 899 avl_index_t where; 900 int i; 901 902 (void) memset(&srch, 0, sizeof (srch)); 903 for (i = 0; i < curr_subst; i++) { 904 srch.ref[i] = subst_weights[i]; 905 subst_weights[i] = 0; 906 } 907 s = avl_find(&substs_ref[curr_weight], &srch, &where); 908 909 if (s == NULL) { 910 if ((s = calloc(1, sizeof (*s))) == NULL) { 911 errf(_("out of memory")); 912 return; 913 } 914 s->key = new_pri(); 915 916 /* 917 * We use a self reference for our key, but we set a 918 * high bit to indicate that this is a substitution 919 * reference. This will expedite table lookups later, 920 * and prevent table lookups for situations that don't 921 * require it. (In short, its a big win, because we 922 * can skip a lot of binary searching.) 923 */ 924 set_pri(s->key, 925 (nextsubst[curr_weight] | COLLATE_SUBST_PRIORITY), 926 RESOLVED); 927 nextsubst[curr_weight] += 1; 928 929 for (i = 0; i < curr_subst; i++) { 930 s->ref[i] = srch.ref[i]; 931 } 932 933 avl_insert(&substs_ref[curr_weight], s, where); 934 935 if (avl_find(&substs[curr_weight], s, &where) != NULL) { 936 INTERR; 937 return; 938 } 939 avl_insert(&substs[curr_weight], s, where); 940 } 941 curr_subst = 0; 942 943 944 /* 945 * We are using the current (unique) priority as a search key 946 * in the substitution table. 947 */ 948 add_order_pri(s->key); 949 } 950 951 static void 952 add_subst_pri(int32_t ref) 953 { 954 if (curr_subst >= COLLATE_STR_LEN) { 955 errf(_("substitution string is too long")); 956 return; 957 } 958 subst_weights[curr_subst] = ref; 959 curr_subst++; 960 } 961 962 void 963 add_subst_char(wchar_t wc) 964 { 965 collchar_t *cc; 966 967 968 if (((cc = get_collchar(wc, 1)) == NULL) || 969 (cc->wc != wc)) { 970 INTERR; 971 return; 972 } 973 /* we take the weight for the character at that position */ 974 add_subst_pri(cc->ref[curr_weight]); 975 } 976 977 void 978 add_subst_collelem(collelem_t *e) 979 { 980 add_subst_pri(e->ref[curr_weight]); 981 } 982 983 void 984 add_subst_collsym(collsym_t *s) 985 { 986 add_subst_pri(s->ref); 987 } 988 989 void 990 add_subst_symbol(char *ptr) 991 { 992 collundef_t *cu; 993 994 if ((cu = get_collundef(ptr)) != NULL) { 995 add_subst_pri(cu->ref[curr_weight]); 996 } 997 } 998 999 void 1000 add_weight(int32_t ref, int pass) 1001 { 1002 weight_t srch; 1003 weight_t *w; 1004 avl_index_t where; 1005 1006 srch.pri = resolve_pri(ref); 1007 1008 /* No translation of ignores */ 1009 if (srch.pri == 0) 1010 return; 1011 1012 /* Substitution priorities are not weights */ 1013 if (srch.pri & COLLATE_SUBST_PRIORITY) 1014 return; 1015 1016 if (avl_find(&weights[pass], &srch, &where) != NULL) 1017 return; 1018 1019 if ((w = calloc(1, sizeof (*w))) == NULL) { 1020 errf(_("out of memory")); 1021 return; 1022 } 1023 w->pri = srch.pri; 1024 avl_insert(&weights[pass], w, where); 1025 } 1026 1027 void 1028 add_weights(int32_t *refs) 1029 { 1030 int i; 1031 for (i = 0; i < NUM_WT; i++) { 1032 add_weight(refs[i], i); 1033 } 1034 } 1035 1036 int32_t 1037 get_weight(int32_t ref, int pass) 1038 { 1039 weight_t srch; 1040 weight_t *w; 1041 int32_t pri; 1042 1043 pri = resolve_pri(ref); 1044 if (pri & COLLATE_SUBST_PRIORITY) { 1045 return (pri); 1046 } 1047 if (pri <= 0) { 1048 return (pri); 1049 } 1050 srch.pri = pri; 1051 if ((w = avl_find(&weights[pass], &srch, NULL)) == NULL) { 1052 INTERR; 1053 return (-1); 1054 } 1055 return (w->opt); 1056 } 1057 1058 void 1059 dump_collate(void) 1060 { 1061 FILE *f; 1062 int i, j, n; 1063 size_t sz; 1064 int32_t pri; 1065 collelem_t *ce; 1066 collchar_t *cc; 1067 subst_t *sb; 1068 char vers[COLLATE_STR_LEN]; 1069 collate_char_t chars[UCHAR_MAX + 1]; 1070 collate_large_t *large; 1071 collate_subst_t *subst[COLL_WEIGHTS_MAX]; 1072 collate_chain_t *chain; 1073 1074 /* 1075 * We have to run through a preliminary pass to identify all the 1076 * weights that we use for each sorting level. 1077 */ 1078 for (i = 0; i < NUM_WT; i++) { 1079 add_weight(pri_ignore, i); 1080 } 1081 for (i = 0; i < NUM_WT; i++) { 1082 for (sb = avl_first(&substs[i]); sb; 1083 sb = AVL_NEXT(&substs[i], sb)) { 1084 for (j = 0; sb->ref[j]; j++) { 1085 add_weight(sb->ref[j], i); 1086 } 1087 } 1088 } 1089 for (ce = avl_first(&elem_by_expand); 1090 ce != NULL; 1091 ce = AVL_NEXT(&elem_by_expand, ce)) { 1092 add_weights(ce->ref); 1093 } 1094 for (cc = avl_first(&collchars); cc; cc = AVL_NEXT(&collchars, cc)) { 1095 add_weights(cc->ref); 1096 } 1097 1098 /* 1099 * Now we walk the entire set of weights, removing the gaps 1100 * in the weights. This gives us optimum usage. The walk 1101 * occurs in priority. 1102 */ 1103 for (i = 0; i < NUM_WT; i++) { 1104 weight_t *w; 1105 for (w = avl_first(&weights[i]); w; 1106 w = AVL_NEXT(&weights[i], w)) { 1107 w->opt = nweight[i]; 1108 nweight[i] += 1; 1109 } 1110 } 1111 1112 (void) memset(&chars, 0, sizeof (chars)); 1113 (void) memset(vers, 0, COLLATE_STR_LEN); 1114 (void) strlcpy(vers, COLLATE_VERSION, sizeof (vers)); 1115 1116 /* 1117 * We need to make sure we arrange for the UNDEFINED field 1118 * to show up. Also, set the total weight counts. 1119 */ 1120 for (i = 0; i < NUM_WT; i++) { 1121 if (resolve_pri(pri_undefined[i]) == -1) { 1122 set_pri(pri_undefined[i], -1, RESOLVED); 1123 /* they collate at the end of everything else */ 1124 collinfo.undef_pri[i] = COLLATE_MAX_PRIORITY; 1125 } 1126 collinfo.pri_count[i] = nweight[i]; 1127 } 1128 1129 collinfo.pri_count[NUM_WT] = max_wide(); 1130 collinfo.undef_pri[NUM_WT] = COLLATE_MAX_PRIORITY; 1131 collinfo.directive[NUM_WT] = DIRECTIVE_UNDEFINED; 1132 1133 /* 1134 * Ordinary character priorities 1135 */ 1136 for (i = 0; i <= UCHAR_MAX; i++) { 1137 if ((cc = get_collchar(i, 0)) != NULL) { 1138 for (j = 0; j < NUM_WT; j++) { 1139 chars[i].pri[j] = get_weight(cc->ref[j], j); 1140 } 1141 } else { 1142 for (j = 0; j < NUM_WT; j++) { 1143 chars[i].pri[j] = 1144 get_weight(pri_undefined[j], j); 1145 } 1146 /* 1147 * Per POSIX, for undefined characters, we 1148 * also have to add a last item, which is the 1149 * character code. 1150 */ 1151 chars[i].pri[NUM_WT] = i; 1152 } 1153 } 1154 1155 /* 1156 * Substitution tables 1157 */ 1158 for (i = 0; i < NUM_WT; i++) { 1159 collate_subst_t *st = NULL; 1160 n = collinfo.subst_count[i] = avl_numnodes(&substs[i]); 1161 if ((st = calloc(n, sizeof (collate_subst_t))) == NULL) { 1162 errf(_("out of memory")); 1163 return; 1164 } 1165 n = 0; 1166 for (sb = avl_first(&substs[i]); sb; 1167 sb = AVL_NEXT(&substs[i], sb)) { 1168 if ((st[n].key = resolve_pri(sb->key)) < 0) { 1169 /* by definition these resolve! */ 1170 INTERR; 1171 } 1172 if (st[n].key != (n | COLLATE_SUBST_PRIORITY)) { 1173 INTERR; 1174 } 1175 for (j = 0; sb->ref[j]; j++) { 1176 st[n].pri[j] = get_weight(sb->ref[j], i); 1177 } 1178 n++; 1179 } 1180 if (n != collinfo.subst_count[i]) 1181 INTERR; 1182 subst[i] = st; 1183 } 1184 1185 1186 /* 1187 * Chains, i.e. collating elements 1188 */ 1189 collinfo.chain_count = avl_numnodes(&elem_by_expand); 1190 chain = calloc(collinfo.chain_count, sizeof (collate_chain_t)); 1191 if (chain == NULL) { 1192 errf(_("out of memory")); 1193 return; 1194 } 1195 for (n = 0, ce = avl_first(&elem_by_expand); 1196 ce != NULL; 1197 ce = AVL_NEXT(&elem_by_expand, ce), n++) { 1198 (void) wsncpy(chain[n].str, ce->expand, COLLATE_STR_LEN); 1199 for (i = 0; i < NUM_WT; i++) { 1200 chain[n].pri[i] = get_weight(ce->ref[i], i); 1201 } 1202 } 1203 if (n != collinfo.chain_count) 1204 INTERR; 1205 1206 /* 1207 * Large (> UCHAR_MAX) character priorities 1208 */ 1209 large = calloc(avl_numnodes(&collchars), sizeof (collate_large_t)); 1210 if (large == NULL) { 1211 errf(_("out of memory")); 1212 return; 1213 } 1214 1215 i = 0; 1216 for (cc = avl_first(&collchars); cc; cc = AVL_NEXT(&collchars, cc)) { 1217 int undef = 0; 1218 /* we already gathered those */ 1219 if (cc->wc <= UCHAR_MAX) 1220 continue; 1221 for (j = 0; j < NUM_WT; j++) { 1222 if ((pri = get_weight(cc->ref[j], j)) < 0) { 1223 undef = 1; 1224 } 1225 if (undef && (pri >= 0)) { 1226 /* if undefined, then all priorities are */ 1227 INTERR; 1228 } else { 1229 large[i].pri.pri[j] = pri; 1230 } 1231 } 1232 if (!undef) { 1233 large[i].val = cc->wc; 1234 collinfo.large_count = i++; 1235 } 1236 } 1237 1238 if ((f = open_category()) == NULL) { 1239 return; 1240 } 1241 1242 /* Time to write the entire data set out */ 1243 1244 if ((wr_category(vers, COLLATE_STR_LEN, f) < 0) || 1245 (wr_category(&collinfo, sizeof (collinfo), f) < 0) || 1246 (wr_category(&chars, sizeof (chars), f) < 0)) { 1247 delete_category(f); 1248 return; 1249 } 1250 1251 for (i = 0; i < NUM_WT; i++) { 1252 sz = sizeof (collate_subst_t) * collinfo.subst_count[i]; 1253 if (wr_category(subst[i], sz, f) < 0) { 1254 delete_category(f); 1255 return; 1256 } 1257 } 1258 sz = sizeof (collate_chain_t) * collinfo.chain_count; 1259 if (wr_category(chain, sz, f) < 0) { 1260 delete_category(f); 1261 return; 1262 } 1263 sz = sizeof (collate_large_t) * collinfo.large_count; 1264 if (wr_category(large, sz, f) < 0) { 1265 delete_category(f); 1266 return; 1267 } 1268 1269 close_category(f); 1270 } 1271