@@ -60,6 +60,24 @@
6060 */
6161
6262#include <HsFFI.h>
63+#include <stdlib.h>
64+#include <string.h>
65+
66+// The maximum size for a custom character width table is the total
67+// number of possible characters as dictated by the compiler.
68+#define MAX_CUSTOM_TABLE_SIZE (HS_CHAR_MAX + 1)
69+
70+// The pointer to the start of the custom character width table, if any.
71+// If this is NULL, the built-in tree search logic is used.
72+static uint8_t* custom_table = NULL;
73+
74+// The size of the custom table. This should only be set if custom_table
75+// is not NULL. Its value should be the size of the custom_table array.
76+static uint32_t custom_table_size = 0;
77+
78+// A flag indicating whether the custom table is ready for use. This
79+// should only be set once the table has been allocated and initialized.
80+static uint8_t custom_table_ready = 0;
6381
6482struct interval {
6583 int first;
@@ -119,7 +137,7 @@ static int vty_bisearch(HsChar ucs, const struct interval *table, int max) {
119137 * in ISO 10646.
120138 */
121139
122−HsInt vty_mk_wcwidth(HsChar ucs)
140+HsInt builtin_wcwidth(HsChar ucs)
123141{
124142 /* sorted list of non-overlapping intervals of non-spacing characters */
125143 /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
@@ -202,3 +220,99 @@ HsInt vty_mk_wcwidth(HsChar ucs)
202220 (ucs >= 0x20000 && ucs <= 0x2fffd) ||
203221 (ucs >= 0x30000 && ucs <= 0x3fffd)));
204222}
223+
224+// Return the width, in terminal cells, of the specified character.
225+//
226+// If the global custom width table is present, that table will be
227+// consulted for the character's width. If the character is not in
228+// the table, zero will be returned. If the custom width table is not
229+// present, the built-in width table will be used.
230+HsInt vty_mk_wcwidth(HsChar ch)
231+{
232+ if (custom_table != NULL) {
233+ if (ch >= 0 && ch < custom_table_size) {
234+ return custom_table[ch];
235+ } else {
236+ return 0;
237+ }
238+ } else {
239+ return builtin_wcwidth(ch);
240+ }
241+}
242+
243+// Initialize a custom character width table.
244+//
245+// This allocates a new character width table of the specified size
246+// (in characters). If a custom table has already been allocated, this
247+// returns 1. Otherwise it allocates a new table, initializes all of its
248+// entries to zero, and returns zero.
249+//
250+// Note that this does *not* mark the table as ready for use. Until the
251+// table is marked ready, it will not be used by vty_mk_wcwidth. To mark
252+// the table as ready, call vty_activate_custom_table() after the table
253+// has been set up with calls to vty_set_custom_table_range.
254+int vty_init_custom_table(int size)
255+{
256+ if (custom_table == NULL) {
257+ if (size > 0 && size <= MAX_CUSTOM_TABLE_SIZE) {
258+ custom_table_ready = 0;
259+ custom_table = malloc(size);
260+ bzero(custom_table, size);
261+ custom_table_size = size;
262+ return 0;
263+ } else {
264+ return 1;
265+ }
266+ } else {
267+ return 1;
268+ }
269+}
270+
271+// Set the specified character range in the custom width table to the
272+// specified width.
273+//
274+// This function sets 'width' as the character width for all entries
275+// in the custom character table starting at the 'start' entry and
276+// including all entries up to and including 'start + size - 1'.
277+//
278+// If this succeeds, it returns zero. If it fails, it returns 1. It
279+// fails if the table is not allocated, marked as ready (i.e. it is in
280+// use and has already been populated), or if the start or size values
281+// are not in bounds for the table.
282+int vty_set_custom_table_range(uint32_t start, uint32_t size, uint8_t width)
283+{
284+ if (custom_table == NULL) {
285+ return 1;
286+ } else if ((start + size - 1) >= custom_table_size) {
287+ return 1;
288+ } else if (custom_table_ready) {
289+ return 1;
290+ } else {
291+ memset(custom_table + start, (uint8_t) width, size);
292+ return 0;
293+ }
294+}
295+
296+// Mark the allocated custom character width table as ready for use.
297+//
298+// After this call, further calls to vty_set_custom_table_range will
299+// fail.
300+//
301+// This function returns 0 if it succeeds. If it fails, it returns 1.
302+// It fails if the custom table is already ready or if it has not been
303+// allocated.
304+int vty_activate_custom_table()
305+{
306+ if (custom_table_ready || (custom_table == NULL)) {
307+ return 1;
308+ } else {
309+ custom_table_ready = 1;
310+ return 0;
311+ }
312+}
313+
314+// Returns whether a custom character width table has been marked ready.
315+int vty_custom_table_ready()
316+{
317+ return ((custom_table != NULL) && custom_table_ready);
318+}