Apply extremely trivial free() patch to WindowList.
[fvwm.git] / libs / BidiJoin.c
blob88bdbe785e87973ee006681afdbd44ed0a055b4d
1 /* -*-c-*- */
2 /* Copyright (C) 2002 Nadim Shaikli (arabeyes.org) */
3 /* This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * FBidiJoin.c
21 * A place holder for when fribidi finally implements character
22 * shaping/joining. This shaping/joining is a must for a variety of
23 * Bidi'ed languages such as Arabic, Farsi, as well as all the Syriacs
24 * (Urdu, Sindhi, Pashto, Kurdish, Baluchi, Kashmiri, Kazakh, Berber,
25 * Uighur, Kirghiz, etc).
28 #include "config.h"
30 #if HAVE_BIDI
32 #include "fvwmlib.h"
33 #include "BidiJoin.h"
35 /* ---------------------------- included header files ---------------------- */
37 #include <stdio.h>
39 /* ---------------------------- local types -------------------------------- */
41 typedef struct char_shaped
43 FriBidiChar base;
45 /* The various Arabic shaped permutations */
46 FriBidiChar isolated;
47 FriBidiChar initial;
48 FriBidiChar medial;
49 FriBidiChar final;
50 } char_shaped_t;
52 typedef struct char_shaped_comb
54 /* The Arabic exceptions - 2chars ==> 1char */
55 FriBidiChar first;
56 FriBidiChar second;
57 FriBidiChar comb_isolated;
58 FriBidiChar comb_joined;
59 } char_shaped_comb_t;
61 /* ---------------------------- static variables --------------------------- */
63 static const char_shaped_t shaped_table[] =
65 /* base s i m f */
66 { 0x0621, 0xFE80, 0x0000, 0x0000, 0x0000, }, /* HAMZA */
67 { 0x0622, 0xFE81, 0x0000, 0x0000, 0xFE82, }, /* ALEF_MADDA */
68 { 0x0623, 0xFE83, 0x0000, 0x0000, 0xFE84, }, /* ALEF_HAMZA_ABOVE */
69 { 0x0624, 0xFE85, 0x0000, 0x0000, 0xFE86, }, /* WAW_HAMZA */
70 { 0x0625, 0xFE87, 0x0000, 0x0000, 0xFE88, }, /* ALEF_HAMZA_BELOW */
71 { 0x0626, 0xFE89, 0xFE8B, 0xFE8C, 0xFE8A, }, /* YEH_HAMZA */
72 { 0x0627, 0xFE8D, 0x0000, 0x0000, 0xFE8E, }, /* ALEF */
73 { 0x0628, 0xFE8F, 0xFE91, 0xFE92, 0xFE90, }, /* BEH */
74 { 0x0629, 0xFE93, 0x0000, 0x0000, 0xFE94, }, /* TEH_MARBUTA */
75 { 0x062A, 0xFE95, 0xFE97, 0xFE98, 0xFE96, }, /* TEH */
76 { 0x062B, 0xFE99, 0xFE9B, 0xFE9C, 0xFE9A, }, /* THEH */
77 { 0x062C, 0xFE9D, 0xFE9F, 0xFEA0, 0xFE9E, }, /* JEEM */
78 { 0x062D, 0xFEA1, 0xFEA3, 0xFEA4, 0xFEA2, }, /* HAH */
79 { 0x062E, 0xFEA5, 0xFEA7, 0xFEA8, 0xFEA6, }, /* KHAH */
80 { 0x062F, 0xFEA9, 0x0000, 0x0000, 0xFEAA, }, /* DAL */
81 { 0x0630, 0xFEAB, 0x0000, 0x0000, 0xFEAC, }, /* THAL */
82 { 0x0631, 0xFEAD, 0x0000, 0x0000, 0xFEAE, }, /* REH */
83 { 0x0632, 0xFEAF, 0x0000, 0x0000, 0xFEB0, }, /* ZAIN */
84 { 0x0633, 0xFEB1, 0xFEB3, 0xFEB4, 0xFEB2, }, /* SEEN */
85 { 0x0634, 0xFEB5, 0xFEB7, 0xFEB8, 0xFEB6, }, /* SHEEN */
86 { 0x0635, 0xFEB9, 0xFEBB, 0xFEBC, 0xFEBA, }, /* SAD */
87 { 0x0636, 0xFEBD, 0xFEBF, 0xFEC0, 0xFEBE, }, /* DAD */
88 { 0x0637, 0xFEC1, 0xFEC3, 0xFEC4, 0xFEC2, }, /* TAH */
89 { 0x0638, 0xFEC5, 0xFEC7, 0xFEC8, 0xFEC6, }, /* ZAH */
90 { 0x0639, 0xFEC9, 0xFECB, 0xFECC, 0xFECA, }, /* AIN */
91 { 0x063A, 0xFECD, 0xFECF, 0xFED0, 0xFECE, }, /* GHAIN */
92 { 0x0640, 0x0640, 0x0640, 0x0640, 0x0640, }, /* TATWEEL */
93 { 0x0641, 0xFED1, 0xFED3, 0xFED4, 0xFED2, }, /* FEH */
94 { 0x0642, 0xFED5, 0xFED7, 0xFED8, 0xFED6, }, /* QAF */
95 { 0x0643, 0xFED9, 0xFEDB, 0xFEDC, 0xFEDA, }, /* KAF */
96 { 0x0644, 0xFEDD, 0xFEDF, 0xFEE0, 0xFEDE, }, /* LAM */
97 { 0x0645, 0xFEE1, 0xFEE3, 0xFEE4, 0xFEE2, }, /* MEEM */
98 { 0x0646, 0xFEE5, 0xFEE7, 0xFEE8, 0xFEE6, }, /* NOON */
99 { 0x0647, 0xFEE9, 0xFEEB, 0xFEEC, 0xFEEA, }, /* HEH */
100 { 0x0648, 0xFEED, 0x0000, 0x0000, 0xFEEE, }, /* WAW */
101 { 0x0649, 0xFEEF, 0xFBE8, 0xFBE9, 0xFEF0, }, /* ALEF_MAKSURA */
102 { 0x064A, 0xFEF1, 0xFEF3, 0xFEF4, 0xFEF2, }, /* YEH */
103 { 0x0671, 0xFB50, 0x0000, 0x0000, 0xFB51, },
104 { 0x0679, 0xFB66, 0xFB68, 0xFB69, 0xFB67, },
105 { 0x067A, 0xFB5E, 0xFB60, 0xFB61, 0xFB5F, },
106 { 0x067B, 0xFB52, 0xFB54, 0xFB55, 0xFB53, },
107 { 0x067E, 0xFB56, 0xFB58, 0xFB59, 0xFB57, },
108 { 0x067F, 0xFB62, 0xFB64, 0xFB65, 0xFB63, },
109 { 0x0680, 0xFB5A, 0xFB5C, 0xFB5D, 0xFB5B, },
110 { 0x0683, 0xFB76, 0xFB78, 0xFB79, 0xFB77, },
111 { 0x0684, 0xFB72, 0xFB74, 0xFB75, 0xFB73, },
112 { 0x0686, 0xFB7A, 0xFB7C, 0xFB7D, 0xFB7B, },
113 { 0x0687, 0xFB7E, 0xFB80, 0xFB81, 0xFB7F, },
114 { 0x0688, 0xFB88, 0x0000, 0x0000, 0xFB89, },
115 { 0x068C, 0xFB84, 0x0000, 0x0000, 0xFB85, },
116 { 0x068D, 0xFB82, 0x0000, 0x0000, 0xFB83, },
117 { 0x068E, 0xFB86, 0x0000, 0x0000, 0xFB87, },
118 { 0x0691, 0xFB8C, 0x0000, 0x0000, 0xFB8D, },
119 { 0x0698, 0xFB8A, 0x0000, 0x0000, 0xFB8B, },
120 { 0x06A4, 0xFB6A, 0xFB6C, 0xFB6D, 0xFB6B, },
121 { 0x06A6, 0xFB6E, 0xFB70, 0xFB71, 0xFB6F, },
122 { 0x06A9, 0xFB8E, 0xFB90, 0xFB91, 0xFB8F, },
123 { 0x06AD, 0xFBD3, 0xFBD5, 0xFBD6, 0xFBD4, },
124 { 0x06AF, 0xFB92, 0xFB94, 0xFB95, 0xFB93, },
125 { 0x06B1, 0xFB9A, 0xFB9C, 0xFB9D, 0xFB9B, },
126 { 0x06B3, 0xFB96, 0xFB98, 0xFB99, 0xFB97, },
127 { 0x06BB, 0xFBA0, 0xFBA2, 0xFBA3, 0xFBA1, },
128 { 0x06BE, 0xFBAA, 0xFBAC, 0xFBAD, 0xFBAB, },
129 { 0x06C0, 0xFBA4, 0x0000, 0x0000, 0xFBA5, },
130 { 0x06C1, 0xFBA6, 0xFBA8, 0xFBA9, 0xFBA7, },
131 { 0x06C5, 0xFBE0, 0x0000, 0x0000, 0xFBE1, },
132 { 0x06C6, 0xFBD9, 0x0000, 0x0000, 0xFBDA, },
133 { 0x06C7, 0xFBD7, 0x0000, 0x0000, 0xFBD8, },
134 { 0x06C8, 0xFBDB, 0x0000, 0x0000, 0xFBDC, },
135 { 0x06C9, 0xFBE2, 0x0000, 0x0000, 0xFBE3, },
136 { 0x06CB, 0xFBDE, 0x0000, 0x0000, 0xFBDF, },
137 { 0x06CC, 0xFBFC, 0xFBFE, 0xFBFF, 0xFBFD, },
138 { 0x06D0, 0xFBE4, 0xFBE6, 0xFBE7, 0xFBE5, },
139 { 0x06D2, 0xFBAE, 0x0000, 0x0000, 0xFBAF, },
140 { 0x06D3, 0xFBB0, 0x0000, 0x0000, 0xFBB1, },
141 /* special treatment for ligatures from combining phase */
142 { 0xFEF5, 0xFEF5, 0x0000, 0x0000, 0xFEF6, }, /* LAM_ALEF_MADDA */
143 { 0xFEF7, 0xFEF7, 0x0000, 0x0000, 0xFEF8, }, /* LAM_ALEF_HAMZA_ABOVE */
144 { 0xFEF9, 0xFEF9, 0x0000, 0x0000, 0xFEFA, }, /* LAM_ALEF_HAMZA_BELOW */
145 { 0xFEFB, 0xFEFB, 0x0000, 0x0000, 0xFEFC, }, /* LAM_ALEF */
148 static const char_shaped_comb_t shaped_comb_table[] =
150 { 0x0644, 0x0622, 0xFEF5, 0xFEF6, }, /* LAM_ALEF_MADDA */
151 { 0x0644, 0x0623, 0xFEF7, 0xFEF8, }, /* LAM_ALEF_HAMZA_ABOVE */
152 { 0x0644, 0x0625, 0xFEF9, 0xFEFA, }, /* LAM_ALEF_HAMZA_BELOW */
153 { 0x0644, 0x0627, 0xFEFB, 0xFEFC, }, /* LAM_ALEF */
156 /* -------------------------- local functions ------------------------------ */
158 static const char_shaped_t *
159 get_shaped_entry(FriBidiChar ch)
161 int count;
162 int table_size;
164 table_size = sizeof(shaped_table) / sizeof(shaped_table[0]);
166 for (count = 0; count < table_size; count++)
168 if (shaped_table[count].base == ch)
170 return &shaped_table[count];
174 return NULL;
177 /* ------------------------- interface functions --------------------------- */
180 shape_n_join(
181 FriBidiChar *str_visual, int str_len)
183 int i; /* counter of the input string */
184 int len; /* counter and the final length of the shaped string */
185 FriBidiChar *orig_str;
186 const char_shaped_t **list;
187 const char_shaped_t *prev;
188 const char_shaped_t *curr;
189 const char_shaped_t *next;
191 list = (const char_shaped_t **)safemalloc(
192 (str_len + 2) * sizeof(char_shaped_t *));
194 orig_str = (FriBidiChar *)safemalloc(
195 (str_len + 1) * sizeof(FriBidiChar));
197 /* head is NULL */
198 *list = NULL;
199 list++;
201 /* Populate with existent shaped characters */
202 for (i = 0; i < str_len; i++)
204 list[i] = get_shaped_entry(str_visual[i]);
207 /* tail is NULL */
208 list[i] = NULL;
210 /* Store-off non-shaped characters; start with a clean slate */
211 memcpy(orig_str, str_visual, (str_len * sizeof(str_visual[0])));
212 memset(str_visual, 0, (str_len * sizeof(str_visual[0])));
214 /* Traverse the line & build new content */
215 for (i = 0, len = 0; i <= str_len - 1; i++, len++)
217 /* Get previous, current, and next characters */
218 prev = list[i + 1];
219 curr = list[i];
220 next = list[i - 1];
222 /* Process current mapped characters */
223 if (curr)
225 if (next)
227 if (prev)
229 if (!prev->initial || !prev->medial)
231 str_visual[len] =
232 curr->initial?
233 curr->initial:
234 curr->isolated;
236 else
238 str_visual[len] = curr->medial?
239 curr->medial:
240 curr->final;
243 else
245 str_visual[len] = curr->initial?
246 curr->initial:
247 curr->isolated;
250 else
252 if (prev)
254 if (!prev->initial || !prev->medial)
256 str_visual[len] =
257 curr->isolated;
259 else
261 str_visual[len] = curr->final?
262 curr->final:
263 curr->isolated;
266 else
268 str_visual[len] = curr->isolated;
272 else
274 str_visual[len] = orig_str[i];
278 free(list-1);
279 free(orig_str);
281 /* return the length of the new string */
282 return len;
285 #endif /* HAVE_BIDI */