2 * Copyright (c) 2004 Tim J. Robbins.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $FreeBSD: head/usr.bin/tr/cmap.c 200462 2009-12-13 03:14:06Z delphij $
29 * "Character map" ADT. Stores mappings between pairs of characters in a
30 * splay tree, with a lookup table cache to simplify looking up the first
31 * bunch of characters (which are presumably more common than others).
41 static struct cmapnode
*cmap_splay(struct cmapnode
*, wint_t);
45 * Allocate a character map.
52 cm
= malloc(sizeof(*cm
));
56 cm
->cm_def
= CM_DEF_SELF
;
57 cm
->cm_havecache
= false;
58 cm
->cm_min
= cm
->cm_max
= 0;
64 * Add a mapping from "from" to "to" to the map.
67 cmap_add(struct cmap
*cm
, wint_t from
, wint_t to
)
69 struct cmapnode
*cmn
, *ncmn
;
71 cm
->cm_havecache
= false;
73 if (cm
->cm_root
== NULL
) {
74 cmn
= malloc(sizeof(*cmn
));
79 cmn
->cmn_left
= cmn
->cmn_right
= NULL
;
81 cm
->cm_min
= cm
->cm_max
= from
;
85 cmn
= cm
->cm_root
= cmap_splay(cm
->cm_root
, from
);
87 if (cmn
->cmn_from
== from
) {
92 ncmn
= malloc(sizeof(*ncmn
));
95 ncmn
->cmn_from
= from
;
97 if (from
< cmn
->cmn_from
) {
98 ncmn
->cmn_left
= cmn
->cmn_left
;
99 ncmn
->cmn_right
= cmn
;
100 cmn
->cmn_left
= NULL
;
102 ncmn
->cmn_right
= cmn
->cmn_right
;
103 ncmn
->cmn_left
= cmn
;
104 cmn
->cmn_right
= NULL
;
106 if (from
< cm
->cm_min
)
108 if (from
> cm
->cm_max
)
116 * cmap_lookup_hard --
117 * Look up the mapping for a character without using the cache.
120 cmap_lookup_hard(struct cmap
*cm
, wint_t ch
)
123 if (cm
->cm_root
!= NULL
) {
124 cm
->cm_root
= cmap_splay(cm
->cm_root
, ch
);
125 if (cm
->cm_root
->cmn_from
== ch
)
126 return (cm
->cm_root
->cmn_to
);
128 return (cm
->cm_def
== CM_DEF_SELF
? ch
: cm
->cm_def
);
136 cmap_cache(struct cmap
*cm
)
140 for (ch
= 0; ch
< CM_CACHE_SIZE
; ch
++)
141 cm
->cm_cache
[ch
] = cmap_lookup_hard(cm
, ch
);
143 cm
->cm_havecache
= true;
148 * Change the value that characters without mappings map to, and
149 * return the old value. The special character value CM_MAP_SELF
150 * means characters map to themselves.
153 cmap_default(struct cmap
*cm
, wint_t def
)
159 cm
->cm_havecache
= false;
163 static struct cmapnode
*
164 cmap_splay(struct cmapnode
*t
, wint_t ch
)
166 struct cmapnode N
, *l
, *r
, *y
;
169 * Based on public domain code from Sleator.
174 N
.cmn_left
= N
.cmn_right
= NULL
;
177 if (ch
< t
->cmn_from
) {
178 if (t
->cmn_left
!= NULL
&&
179 ch
< t
->cmn_left
->cmn_from
) {
181 t
->cmn_left
= y
->cmn_right
;
185 if (t
->cmn_left
== NULL
)
190 } else if (ch
> t
->cmn_from
) {
191 if (t
->cmn_right
!= NULL
&&
192 ch
> t
->cmn_right
->cmn_from
) {
194 t
->cmn_right
= y
->cmn_left
;
198 if (t
->cmn_right
== NULL
)
206 l
->cmn_right
= t
->cmn_left
;
207 r
->cmn_left
= t
->cmn_right
;
208 t
->cmn_left
= N
.cmn_right
;
209 t
->cmn_right
= N
.cmn_left
;