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 2010 Nexenta Systems, Inc.  All rights reserved.
  14  * Copyright 2013 David Hoeppner.  All rights reserved.
  15  */
  16 
  17 /*
  18  * Character map handling for iconv.
  19  */
  20 
  21 #include <sys/avl.h>
  22 
  23 #include <stddef.h>
  24 
  25 #include "iconv.h"
  26 #include "parser.tab.h"
  27 
  28 /*
  29  * AVL trees for the from and to charmaps.
  30  */
  31 static avl_tree_t       from_cmap_sym;
  32 static avl_tree_t       from_cmap_wc;
  33 static avl_tree_t       to_cmap_sym;
  34 static avl_tree_t       to_cmap_wc;
  35 
  36 static avl_tree_t       *current_cmap_sym = &from_cmap_sym;
  37 static avl_tree_t       *current_cmap_wc = &from_cmap_wc;
  38 
  39 typedef struct charmap {
  40         const char      *name;
  41         wchar_t         wc;
  42         avl_node_t      avl_sym;
  43         avl_node_t      avl_wc;
  44 } charmap_t;
  45 
  46 static int
  47 cmap_compare_sym(const void *n1, const void *n2)
  48 {
  49         const charmap_t *c1 = n1;
  50         const charmap_t *c2 = n2;
  51         int     rv;
  52 
  53         rv = strcmp(c1->name, c2->name);
  54         return ((rv < 0) ? -1 : (rv > 0) ? 1 : 0);
  55 }
  56 
  57 static int
  58 cmap_compare_wc(const void *n1, const void *n2)
  59 {
  60         const charmap_t *c1 = n1;
  61         const charmap_t *c2 = n2;
  62 
  63         return ((c1->wc < c2->wc) ? -1 : (c1->wc > c2->wc) ? 1 : 0);
  64 }
  65 
  66 void
  67 init_charmap(void)
  68 {
  69         avl_create(&from_cmap_sym, cmap_compare_sym, sizeof (charmap_t),
  70             offsetof(charmap_t, avl_sym));
  71 
  72         avl_create(&from_cmap_wc, cmap_compare_wc, sizeof (charmap_t),
  73             offsetof(charmap_t, avl_wc));
  74 
  75         avl_create(&to_cmap_sym, cmap_compare_sym, sizeof (charmap_t),
  76             offsetof(charmap_t, avl_sym));
  77 
  78         avl_create(&to_cmap_wc, cmap_compare_wc, sizeof (charmap_t),
  79             offsetof(charmap_t, avl_wc));
  80 }
  81 
  82 /*
  83  * Switches from fromcharmap to tocharmap.
  84  */
  85 void
  86 switch_charmap(void)
  87 {
  88         current_cmap_sym = &to_cmap_sym;
  89         current_cmap_wc = &to_cmap_wc;
  90 }
  91 
  92 static void
  93 add_charmap_impl(char *sym, wchar_t wc, int nodups)
  94 {
  95         charmap_t       srch;
  96         charmap_t       *n = NULL;
  97         avl_index_t     where;
  98 
  99         srch.wc = wc;
 100         srch.name = sym;
 101 
 102         /*
 103          * Also possibly insert the wide mapping, although note that there
 104          * can only be one of these per wide character code.
 105          */
 106         if ((wc != -1) && ((avl_find(current_cmap_wc, &srch, &where)) == NULL)) {
 107                 if ((n = calloc(1, sizeof (*n))) == NULL) {
 108                         errf(_("out of memory"));
 109                         return;
 110                 }
 111 
 112                 n->wc = wc;
 113                 avl_insert(current_cmap_wc, n, where);
 114         }
 115 
 116         if (sym != NULL) {
 117                 if (avl_find(current_cmap_sym, &srch, &where) != NULL) {
 118                         if (nodups == 1) {
 119                                 errf(_("duplicate character definition"));
 120                         }
 121 
 122                         return;
 123                 }
 124 
 125                 if ((n == NULL) && ((n = calloc(1, sizeof (*n))) == NULL)) {
 126                         errf(_("out of memory"));
 127                         return;
 128                 }
 129 
 130                 n->wc = wc;
 131                 n->name = sym;
 132 printf("ADDING %s\n", sym);
 133                 avl_insert(current_cmap_sym, n, where);
 134         }
 135 }
 136 
 137 void
 138 add_charmap(char *sym, int c)
 139 {
 140         add_charmap_impl(sym, c, 1);
 141 }
 142 
 143 void
 144 add_charmap_range(char *s, char *e, int wc)
 145 {
 146 
 147 }