source: libcaca/trunk/cucul/transform.c @ 1788

Last change on this file since 1788 was 1788, checked in by Sam Hocevar, 14 years ago
  • Renamed cucul_left/cucul_right into cucul_rotate_left/cucul_rotate_right.
  • Renamed cucul_rotate into cucul_rotate_180.
  • Deprecated cucul_rotate and fix examples accordingly. Hope it all makes sense.
  • Property svn:keywords set to Id
File size: 21.3 KB
Line 
1/*
2 *  libcucul      Canvas for ultrafast compositing of Unicode letters
3 *  Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id: transform.c 1788 2007-06-28 16:29:00Z sam $
7 *
8 *  This library is free software. It comes without any warranty, to
9 *  the extent permitted by applicable law. You can redistribute it
10 *  and/or modify it under the terms of the Do What The Fuck You Want
11 *  To Public License, Version 2, as published by Sam Hocevar. See
12 *  http://sam.zoy.org/wtfpl/COPYING for more details.
13 */
14
15/*
16 *  This file contains horizontal and vertical flipping routines.
17 */
18
19#include "config.h"
20#include "common.h"
21
22#if !defined(__KERNEL__)
23#   include <stdlib.h>
24#endif
25
26#include "cucul.h"
27#include "cucul_internals.h"
28
29static uint32_t flipchar(uint32_t ch);
30static uint32_t flopchar(uint32_t ch);
31static uint32_t rotatechar(uint32_t ch);
32static uint32_t leftchar(uint32_t ch);
33static uint32_t rightchar(uint32_t ch);
34
35/** \brief Invert a canvas' colours.
36 *
37 *  Invert a canvas' colours (black becomes white, red becomes cyan, etc.)
38 *  without changing the characters in it.
39 *
40 *  This function never fails.
41 *
42 *  \param cv The canvas to invert.
43 *  \return This function always returns 0.
44 */
45int cucul_invert(cucul_canvas_t *cv)
46{
47    uint32_t *attrs = cv->attrs;
48    unsigned int i;
49
50    for(i = cv->height * cv->width; i--; )
51    {
52        *attrs = *attrs ^ 0x000f000f;
53        attrs++;
54    }
55
56    return 0;
57}
58
59/** \brief Flip a canvas horizontally.
60 *
61 *  Flip a canvas horizontally, choosing characters that look like the
62 *  mirrored version wherever possible. Some characters will stay
63 *  unchanged by the process, but the operation is guaranteed to be
64 *  involutive: performing it again gives back the original canvas.
65 *
66 *  This function never fails.
67 *
68 *  \param cv The canvas to flip.
69 *  \return This function always returns 0.
70 */
71int cucul_flip(cucul_canvas_t *cv)
72{
73    unsigned int y;
74
75    for(y = 0; y < cv->height; y++)
76    {
77        uint32_t *cleft = cv->chars + y * cv->width;
78        uint32_t *cright = cleft + cv->width - 1;
79        uint32_t *aleft = cv->attrs + y * cv->width;
80        uint32_t *aright = aleft + cv->width - 1;
81
82        while(cleft < cright)
83        {
84            uint32_t ch;
85            uint32_t attr;
86
87            /* Swap attributes */
88            attr = *aright;
89            *aright-- = *aleft;
90            *aleft++ = attr;
91
92            /* Swap characters */
93            ch = *cright;
94            *cright-- = flipchar(*cleft);
95            *cleft++ = flipchar(ch);
96        }
97
98        if(cleft == cright)
99            *cleft = flipchar(*cleft);
100
101        /* Fix fullwidth characters. Could it be done in one loop? */
102        cleft = cv->chars + y * cv->width;
103        cright = cleft + cv->width - 1;
104        for( ; cleft < cright; cleft++)
105        {
106            if(cleft[0] == CUCUL_MAGIC_FULLWIDTH)
107            {
108                cleft[0] = cleft[1];
109                cleft[1] = CUCUL_MAGIC_FULLWIDTH;
110                cleft++;
111            }
112        }
113    }
114
115    return 0;
116}
117
118/** \brief Flip a canvas vertically.
119 *
120 *  Flip a canvas vertically, choosing characters that look like the
121 *  mirrored version wherever possible. Some characters will stay
122 *  unchanged by the process, but the operation is guaranteed to be
123 *  involutive: performing it again gives back the original canvas.
124 *
125 *  This function never fails.
126 *
127 *  \param cv The canvas to flop.
128 *  \return This function always returns 0.
129 */
130int cucul_flop(cucul_canvas_t *cv)
131{
132    unsigned int x;
133
134    for(x = 0; x < cv->width; x++)
135    {
136        uint32_t *ctop = cv->chars + x;
137        uint32_t *cbottom = ctop + cv->width * (cv->height - 1);
138        uint32_t *atop = cv->attrs + x;
139        uint32_t *abottom = atop + cv->width * (cv->height - 1);
140
141        while(ctop < cbottom)
142        {
143            uint32_t ch;
144            uint32_t attr;
145
146            /* Swap attributes */
147            attr = *abottom; *abottom = *atop; *atop = attr;
148
149            /* Swap characters */
150            ch = *cbottom; *cbottom = flopchar(*ctop); *ctop = flopchar(ch);
151
152            ctop += cv->width; cbottom -= cv->width;
153            atop += cv->width; abottom -= cv->width;
154        }
155
156        if(ctop == cbottom)
157            *ctop = flopchar(*ctop);
158    }
159
160    return 0;
161}
162
163/** \brief Rotate a canvas.
164 *
165 *  Apply a 180-degree transformation to a canvas, choosing characters
166 *  that look like the upside-down version wherever possible. Some
167 *  characters will stay unchanged by the process, but the operation is
168 *  guaranteed to be involutive: performing it again gives back the
169 *  original canvas.
170 *
171 *  This function never fails.
172 *
173 *  \param cv The canvas to rotate.
174 *  \return This function always returns 0.
175 */
176int cucul_rotate_180(cucul_canvas_t *cv)
177{
178    uint32_t *cbegin = cv->chars;
179    uint32_t *cend = cbegin + cv->width * cv->height - 1;
180    uint32_t *abegin = cv->attrs;
181    uint32_t *aend = abegin + cv->width * cv->height - 1;
182    unsigned int y;
183
184    while(cbegin < cend)
185    {
186        uint32_t ch;
187        uint32_t attr;
188
189        /* Swap attributes */
190        attr = *aend; *aend = *abegin; *abegin = attr;
191
192        /* Swap characters */
193        ch = *cend; *cend = rotatechar(*cbegin); *cbegin = rotatechar(ch);
194
195        cbegin++; cend--; abegin++; aend--;
196    }
197
198    if(cbegin == cend)
199        *cbegin = rotatechar(*cbegin);
200
201    /* Fix fullwidth characters. Could it be done in one loop? */
202    for(y = 0; y < cv->height; y++)
203    {
204        cbegin = cv->chars + y * cv->width;
205        cend = cbegin + cv->width - 1;
206        for( ; cbegin < cend; cbegin++)
207        {
208            if(cbegin[0] == CUCUL_MAGIC_FULLWIDTH)
209            {
210                cbegin[0] = cbegin[1];
211                cbegin[1] = CUCUL_MAGIC_FULLWIDTH;
212                cbegin++;
213            }
214        }
215    }
216
217    return 0;
218}
219
220/** \brief Rotate a canvas, 90 degrees counterclockwise.
221 *
222 *  Apply a 90-degree transformation to a canvas, choosing characters
223 *  that look like the rotated version wherever possible. Some characters
224 *  will stay unchanged by the process, some others will be replaced by
225 *  close equivalents. Fullwidth characters will be lost. The operation is
226 *  not guaranteed to be reversible at all.
227 *
228 *  Note that the width and height of the canvas are swapped.
229 *
230 *  If an error occurs, -1 is returned and \b errno is set accordingly:
231 *  - \c EBUSY The canvas is in use by a display driver and cannot be rotated.
232 *  - \c ENOMEM Not enough memory to allocate the new canvas size. If this
233 *    happens, the previous canvas handle is still valid.
234 *
235 *  \param cv The canvas to rotate left.
236 *  \return 0 in case of success, -1 if an error occurred.
237 */
238int cucul_rotate_left(cucul_canvas_t *cv)
239{
240    uint32_t *newchars, *newattrs;
241    unsigned int x, y;
242
243    if(cv->refcount)
244    {
245        seterrno(EBUSY);
246        return -1;
247    }
248
249    /* Save the current frame shortcuts */
250    _cucul_save_frame_info(cv);
251
252    newchars = malloc(cv->width * cv->height * sizeof(uint32_t));
253    if(!newchars)
254        return -1;
255
256    newattrs = malloc(cv->width * cv->height * sizeof(uint32_t));
257    if(!newattrs)
258    {
259        free(newchars);
260        return -1;
261    }
262
263    for(y = 0; y < cv->height; y++)
264    {
265        for(x = 0; x < cv->width; x++)
266        {
267            uint32_t ch, attr;
268
269            ch = cv->chars[cv->width * y + x];
270            attr = cv->attrs[cv->width * y + x];
271
272            /* FIXME: do something about fullwidth characters */
273            ch = leftchar(ch);
274
275            newchars[cv->height * (cv->width - 1 - x) + y] = ch;
276            newattrs[cv->height * (cv->width - 1 - x) + y] = attr;
277        }
278    }
279
280    free(cv->chars);
281    free(cv->attrs);
282
283    /* Swap X and Y information */
284    x = cv->frames[cv->frame].x;
285    y = cv->frames[cv->frame].y;
286    cv->frames[cv->frame].x = y;
287    cv->frames[cv->frame].y = cv->width - 1 - x;
288
289    x = cv->frames[cv->frame].handlex;
290    y = cv->frames[cv->frame].handley;
291    cv->frames[cv->frame].handlex = y;
292    cv->frames[cv->frame].handley = cv->width - 1 - x;
293
294    cv->frames[cv->frame].width = cv->height;
295    cv->frames[cv->frame].height = cv->width;
296
297    cv->frames[cv->frame].chars = newchars;
298    cv->frames[cv->frame].attrs = newattrs;
299
300    /* Reset the current frame shortcuts */
301    _cucul_load_frame_info(cv);
302
303    return 0;
304}
305
306/** \brief Rotate a canvas, 90 degrees clockwise.
307 *
308 *  Apply a 270-degree transformation to a canvas, choosing characters
309 *  that look like the rotated version wherever possible. Some characters
310 *  will stay unchanged by the process, some others will be replaced by
311 *  close equivalents. Fullwidth characters will be lost. The operation is
312 *  not guaranteed to be reversible at all.
313 *
314 *  Note that the width and height of the canvas are swapped.
315 *
316 *  If an error occurs, -1 is returned and \b errno is set accordingly:
317 *  - \c EBUSY The canvas is in use by a display driver and cannot be rotated.
318 *  - \c ENOMEM Not enough memory to allocate the new canvas size. If this
319 *    happens, the previous canvas handle is still valid.
320 *
321 *  \param cv The canvas to rotate right.
322 *  \return 0 in case of success, -1 if an error occurred.
323 */
324int cucul_rotate_right(cucul_canvas_t *cv)
325{
326    uint32_t *newchars, *newattrs;
327    unsigned int x, y;
328
329    if(cv->refcount)
330    {
331        seterrno(EBUSY);
332        return -1;
333    }
334
335    /* Save the current frame shortcuts */
336    _cucul_save_frame_info(cv);
337
338    newchars = malloc(cv->width * cv->height * sizeof(uint32_t));
339    if(!newchars)
340    {
341        seterrno(ENOMEM);
342        return -1;
343    }
344
345    newattrs = malloc(cv->width * cv->height * sizeof(uint32_t));
346    if(!newattrs)
347    {
348        free(newchars);
349        seterrno(ENOMEM);
350        return -1;
351    }
352
353    for(y = 0; y < cv->height; y++)
354    {
355        for(x = 0; x < cv->width; x++)
356        {
357            uint32_t ch, attr;
358
359            ch = cv->chars[cv->width * y + x];
360            attr = cv->attrs[cv->width * y + x];
361
362            /* FIXME: do something about fullwidth characters */
363            ch = rightchar(ch);
364
365            newchars[cv->height * x + cv->height - 1 - y] = ch;
366            newattrs[cv->height * x + cv->height - 1 - y] = attr;
367        }
368    }
369
370    free(cv->chars);
371    free(cv->attrs);
372
373    /* Swap X and Y information */
374    x = cv->frames[cv->frame].x;
375    y = cv->frames[cv->frame].y;
376    cv->frames[cv->frame].x = cv->height - 1 - y;
377    cv->frames[cv->frame].y = x;
378
379    x = cv->frames[cv->frame].handlex;
380    y = cv->frames[cv->frame].handley;
381    cv->frames[cv->frame].handlex = cv->height - 1 - y;
382    cv->frames[cv->frame].handley = x;
383
384    cv->frames[cv->frame].width = cv->height;
385    cv->frames[cv->frame].height = cv->width;
386
387    cv->frames[cv->frame].chars = newchars;
388    cv->frames[cv->frame].attrs = newattrs;
389
390    /* Reset the current frame shortcuts */
391    _cucul_load_frame_info(cv);
392
393    return 0;
394}
395
396/* FIXME: as the lookup tables grow bigger, use a log(n) lookup instead
397 * of linear lookup. */
398static uint32_t flipchar(uint32_t ch)
399{
400    int i;
401
402    static uint32_t const noflip[] =
403    {
404         /* ASCII */
405         ' ', '"', '#', '\'', '-', '.', '*', '+', ':', '=', '0', '8',
406         'A', 'H', 'I', 'M', 'O', 'T', 'U', 'V', 'W', 'X', 'Y', '^',
407         '_', 'i', 'o', 'v', 'w', 'x', '|',
408         /* CP437 and box drawing */
409         0x2591, 0x2592, 0x2593, 0x2588, 0x2584, 0x2580, /* ░ ▒ ▓ █ ▄ ▀ */
410         0x2500, 0x2501, 0x2503, 0x2503, 0x253c, 0x254b, /* ─ ━ │ ┃ ┼ ╋ */
411         0x252c, 0x2534, 0x2533, 0x253b, 0x2566, 0x2569, /* ┬ ┴ ┳ ┻ ╦ ╩ */
412         0x2550, 0x2551, 0x256c, /* ═ ║ ╬ */
413         0x2575, 0x2577, 0x2579, 0x257b, /* ╵ ╷ ╹ ╻ */
414         0
415    };
416
417    static uint32_t const pairs[] =
418    {
419         /* ASCII */
420         '(', ')',
421         '/', '\\',
422         '<', '>',
423         '[', ']',
424         'b', 'd',
425         'p', 'q',
426         '{', '}',
427         /* ASCII-Unicode */
428         ';', 0x204f, /* ; ⁏ */
429         '`', 0x00b4, /* ` ´ */
430         ',', 0x02ce, /* , ˎ */
431         'C', 0x03fd, /* C Ͻ */
432         'E', 0x018e, /* E Ǝ */
433         'L', 0x2143, /* L ⅃ */
434         'N', 0x0418, /* N И */
435         'R', 0x042f, /* R Я */
436         'S', 0x01a7, /* S Ƨ */
437         'c', 0x0254, /* c ɔ */
438         'e', 0x0258, /* e ɘ */
439         /* CP437 */
440         0x258c, 0x2590, /* ▌ ▐ */
441         0x2596, 0x2597, /* ▖ ▗ */
442         0x2598, 0x259d, /* ▘ ▝ */
443         0x2599, 0x259f, /* ▙ ▟ */
444         0x259a, 0x259e, /* ▚ ▞ */
445         0x259b, 0x259c, /* ▛ ▜ */
446         0x25ba, 0x25c4, /* ► ◄ */
447         0x2192, 0x2190, /* → ← */
448         0x2310, 0xac,   /* ⌐ ¬ */
449         /* Box drawing */
450         0x250c, 0x2510, /* ┌ ┐ */
451         0x2514, 0x2518, /* └ ┘ */
452         0x251c, 0x2524, /* ├ ┤ */
453         0x250f, 0x2513, /* ┏ ┓ */
454         0x2517, 0x251b, /* ┗ ┛ */
455         0x2523, 0x252b, /* ┣ ┫ */
456         0x2552, 0x2555, /* ╒ ╕ */
457         0x2558, 0x255b, /* ╘ ╛ */
458         0x2553, 0x2556, /* ╓ ╖ */
459         0x2559, 0x255c, /* ╙ ╜ */
460         0x2554, 0x2557, /* ╔ ╗ */
461         0x255a, 0x255d, /* ╚ ╝ */
462         0x255e, 0x2561, /* ╞ ╡ */
463         0x255f, 0x2562, /* ╟ ╢ */
464         0x2560, 0x2563, /* ╠ ╣ */
465         0x2574, 0x2576, /* ╴ ╶ */
466         0x2578, 0x257a, /* ╸ ╺ */
467         0
468    };
469
470    for(i = 0; noflip[i]; i++)
471        if(ch == noflip[i])
472            return ch;
473
474    for(i = 0; pairs[i]; i++)
475        if(ch == pairs[i])
476            return pairs[i ^ 1];
477
478    return ch;
479}
480
481static uint32_t flopchar(uint32_t ch)
482{
483    int i;
484
485    static uint32_t const noflop[] =
486    {
487         /* ASCII */
488         ' ', '(', ')', '*', '+', '-', '0', '3', '8', ':', '<', '=',
489         '>', 'B', 'C', 'D', 'E', 'H', 'I', 'K', 'O', 'X', '[', ']',
490         'c', 'o', '{', '|', '}',
491         /* CP437 and box drawing */
492         0x2591, 0x2592, 0x2593, 0x2588, 0x258c, 0x2590, /* ░ ▒ ▓ █ ▌ ▐ */
493         0x2500, 0x2501, 0x2503, 0x2503, 0x253c, 0x254b, /* ─ ━ │ ┃ ┼ ╋ */
494         0x251c, 0x2524, 0x2523, 0x252b, 0x2560, 0x2563, /* ├ ┤ ┣ ┫ ╠ ╣ */
495         0x2550, 0x2551, 0x256c, /* ═ ║ ╬ */
496         0x2574, 0x2576, 0x2578, 0x257a, /* ╴ ╶ ╸ ╺ */
497         0
498    };
499
500    static uint32_t const pairs[] =
501    {
502         /* ASCII */
503         '/', '\\',
504         'M', 'W',
505         ',', '`',
506         'b', 'p',
507         'd', 'q',
508         'p', 'q',
509         'f', 't',
510         '.', '\'',
511         /* ASCII-Unicode */
512         '_', 0x203e, /* _ ‾ */
513         '!', 0x00a1, /* ! ¡ */
514         'L', 0x0413, /* L Г */
515         'N', 0x0418, /* N И */
516         'P', 0x042c, /* P Ь */
517         'R', 0x0281, /* R ʁ */
518         'S', 0x01a7, /* S Ƨ */
519         'U', 0x0548, /* U Ո */
520         'V', 0x039b, /* V Λ */
521         'Y', 0x2144, /* Y ⅄ */
522         'h', 0x03bc, /* h μ */
523         'i', 0x1d09, /* i ᴉ */
524         'v', 0x028c, /* v ʌ */
525         'w', 0x028d, /* w ʍ */
526         'y', 0x03bb, /* y λ */
527         /* Not perfect, but better than nothing */
528         '"', 0x201e, /* " „ */
529         'm', 0x026f, /* m ɯ */
530         'n', 'u',
531         /* CP437 */
532         0x2584, 0x2580, /* ▄ ▀ */
533         0x2596, 0x2598, /* ▖ ▘ */
534         0x2597, 0x259d, /* ▗ ▝ */
535         0x2599, 0x259b, /* ▙ ▛ */
536         0x259f, 0x259c, /* ▟ ▜ */
537         0x259a, 0x259e, /* ▚ ▞ */
538         /* Box drawing */
539         0x250c, 0x2514, /* ┌ └ */
540         0x2510, 0x2518, /* ┐ ┘ */
541         0x252c, 0x2534, /* ┬ ┴ */
542         0x250f, 0x2517, /* ┏ ┗ */
543         0x2513, 0x251b, /* ┓ ┛ */
544         0x2533, 0x253b, /* ┳ ┻ */
545         0x2554, 0x255a, /* ╔ ╚ */
546         0x2557, 0x255d, /* ╗ ╝ */
547         0x2566, 0x2569, /* ╦ ╩ */
548         0x2552, 0x2558, /* ╒ ╘ */
549         0x2555, 0x255b, /* ╕ ╛ */
550         0x2564, 0x2567, /* ╤ ╧ */
551         0x2553, 0x2559, /* ╓ ╙ */
552         0x2556, 0x255c, /* ╖ ╜ */
553         0x2565, 0x2568, /* ╥ ╨ */
554         0x2575, 0x2577, /* ╵ ╷ */
555         0x2579, 0x257b, /* ╹ ╻ */
556         0
557    };
558
559    for(i = 0; noflop[i]; i++)
560        if(ch == noflop[i])
561            return ch;
562
563    for(i = 0; pairs[i]; i++)
564        if(ch == pairs[i])
565            return pairs[i ^ 1];
566
567    return ch;
568}
569
570static uint32_t rotatechar(uint32_t ch)
571{
572    int i;
573
574    static uint32_t const norotate[] =
575    {
576         /* ASCII */
577         ' ', '*', '+', '-', '/', '0', '8', ':', '=', 'H', 'I', 'N',
578         'O', 'S', 'X', 'Z', '\\', 'l', 'o', 's', 'x', 'z', '|',
579         /* Unicode */
580         0x2591, 0x2592, 0x2593, 0x2588, 0x259a, 0x259e, /* ░ ▒ ▓ █ ▚ ▞ */
581         0x2500, 0x2501, 0x2503, 0x2503, 0x253c, 0x254b, /* ─ ━ │ ┃ ┼ ╋ */
582         0x2550, 0x2551, 0x256c, /* ═ ║ ╬ */
583         0
584    };
585
586    static uint32_t const pairs[] =
587    {
588         /* ASCII */
589         '(', ')',
590         '<', '>',
591         '[', ']',
592         '{', '}',
593         '.', '\'',
594         '6', '9',
595         'M', 'W',
596         'b', 'q',
597         'd', 'p',
598         'n', 'u',
599         /* ASCII-Unicode */
600         '_', 0x203e, /* _ ‾ */
601         ',', 0x00b4, /* , ´ */
602         '`', 0x02ce, /* ` ˎ */
603         '&', 0x214b, /* & ⅋ */
604         '!', 0x00a1, /* ! ¡ */
605         '?', 0x00bf, /* ? ¿ */
606         'C', 0x03fd, /* C Ͻ */
607         'E', 0x018e, /* E Ǝ */
608         'F', 0x2132, /* F Ⅎ */
609         'L', 0x2142, /* L ⅂ */
610         'U', 0x0548, /* U Ո */
611         'V', 0x039b, /* V Λ */
612         'Y', 0x2144, /* Y ⅄ */
613         'a', 0x0250, /* a ɐ */
614         'c', 0x0254, /* c ɔ */
615         'e', 0x0259, /* e ə */
616         'f', 0x025f, /* f ɟ */
617         'g', 0x1d77, /* g ᵷ */
618         'h', 0x0265, /* h ɥ */
619         'i', 0x1d09, /* i ᴉ */
620         'k', 0x029e, /* k ʞ */
621         'm', 0x026f, /* m ɯ */
622         'r', 0x0279, /* r ɹ */
623         't', 0x0287, /* t ʇ */
624         'v', 0x028c, /* v ʌ */
625         'w', 0x028d, /* w ʍ */
626         'y', 0x028e, /* y ʎ */
627         /* Not perfect, but better than nothing */
628         '"', 0x201e, /* " „ */
629         /* Misc Unicode */
630         0x00e6, 0x1d02, /* æ ᴂ */
631         0x0153, 0x1d14, /* œ ᴔ */
632         /* CP437 */
633         0x258c, 0x2590, /* ▌ ▐ */
634         0x2584, 0x2580, /* ▄ ▀ */
635         0x2596, 0x259d, /* ▖ ▝ */
636         0x2597, 0x2598, /* ▗ ▘ */
637         0x2599, 0x259c, /* ▙ ▜ */
638         0x259f, 0x259b, /* ▟ ▛ */
639         /* Box drawing */
640         0x250c, 0x2518, /* ┌ ┘ */
641         0x2510, 0x2514, /* ┐ └ */
642         0x251c, 0x2524, /* ├ ┤ */
643         0x252c, 0x2534, /* ┬ ┴ */
644         0x250f, 0x251b, /* ┏ ┛ */
645         0x2513, 0x2517, /* ┓ ┗ */
646         0x2523, 0x252b, /* ┣ ┫ */
647         0x2533, 0x253b, /* ┳ ┻ */
648         0x2554, 0x255d, /* ╔ ╝ */
649         0x2557, 0x255a, /* ╗ ╚ */
650         0x2560, 0x2563, /* ╠ ╣ */
651         0x2566, 0x2569, /* ╦ ╩ */
652         0x2552, 0x255b, /* ╒ ╛ */
653         0x2555, 0x2558, /* ╕ ╘ */
654         0x255e, 0x2561, /* ╞ ╡ */
655         0x2564, 0x2567, /* ╤ ╧ */
656         0x2553, 0x255c, /* ╓ ╜ */
657         0x2556, 0x2559, /* ╖ ╙ */
658         0x255f, 0x2562, /* ╟ ╢ */
659         0x2565, 0x2568, /* ╥ ╨ */
660         0x2574, 0x2576, /* ╴ ╶ */
661         0x2575, 0x2577, /* ╵ ╷ */
662         0x2578, 0x257a, /* ╸ ╺ */
663         0x2579, 0x257b, /* ╹ ╻ */
664         0
665    };
666
667    for(i = 0; norotate[i]; i++)
668        if(ch == norotate[i])
669            return ch;
670
671    for(i = 0; pairs[i]; i++)
672        if(ch == pairs[i])
673            return pairs[i ^ 1];
674
675    return ch;
676}
677
678static uint32_t const leftright2[] =
679{
680    /* ASCII */
681    '/', '\\',
682    '|', '-',
683    '|', '_', /* This is all right because there was already a '|' before */
684    /* ASCII-Unicode */
685    '|', 0x203e, /* | ‾ */
686    /* Misc Unicode */
687    0x2571, 0x2572, /* ╱ ╲ */
688    /* Box drawing */
689    0x2500, 0x2502, /* ─ │ */
690    0x2501, 0x2503, /* ━ ┃ */
691    0x2550, 0x2551, /* ═ ║ */
692    0, 0
693};
694
695static uint32_t const leftright4[] =
696{
697    /* ASCII */
698    '<', 'v', '>', '^',
699    ',', '.', '\'', '`',
700    /* Misc Unicode */
701    0x256d, 0x2570, 0x256f, 0x256e, /* ╭ ╰ ╯ ╮ */
702    /* CP437 */
703    0x258c, 0x2584, 0x2590, 0x2580, /* ▌ ▄ ▐ ▀ */
704    0x2596, 0x2597, 0x259d, 0x2598, /* ▖ ▗ ▝ ▘ */
705    0x2599, 0x259f, 0x259c, 0x259b, /* ▙ ▟ ▜ ▛ */
706    /* Box drawing */
707    0x250c, 0x2514, 0x2518, 0x2510, /* ┌ └ ┘ ┐ */
708    0x250f, 0x2517, 0x251b, 0x2513, /* ┏ ┗ ┛ ┓ */
709    0x251c, 0x2534, 0x2524, 0x252c, /* ├ ┴ ┤ ┬ */
710    0x2523, 0x253b, 0x252b, 0x2533, /* ┣ ┻ ┫ ┳ */
711    0x2552, 0x2559, 0x255b, 0x2556, /* ╒ ╙ ╛ ╖ */
712    0x2553, 0x2558, 0x255c, 0x2555, /* ╓ ╘ ╜ ╕ */
713    0x2554, 0x255a, 0x255d, 0x2557, /* ╔ ╚ ╝ ╗ */
714    0x255e, 0x2568, 0x2561, 0x2565, /* ╞ ╨ ╡ ╥ */
715    0x255f, 0x2567, 0x2562, 0x2564, /* ╟ ╧ ╢ ╤ */
716    0x2560, 0x2569, 0x2563, 0x2566, /* ╠ ╩ ╣ ╦ */
717    0x2574, 0x2577, 0x2576, 0x2575, /* ╴ ╷ ╶ ╵ */
718    0x2578, 0x257b, 0x257a, 0x2579, /* ╸ ╻ ╺ ╹ */
719    0, 0, 0, 0
720};
721
722static uint32_t leftchar(uint32_t ch)
723{
724    int i;
725
726    for(i = 0; leftright2[i]; i++)
727        if(ch == leftright2[i])
728            return leftright2[(i & ~1) | ((i + 1) & 1)];
729
730    for(i = 0; leftright4[i]; i++)
731        if(ch == leftright4[i])
732            return leftright4[(i & ~3) | ((i + 1) & 3)];
733
734    return ch;
735}
736
737static uint32_t rightchar(uint32_t ch)
738{
739    int i;
740
741    for(i = 0; leftright2[i]; i++)
742        if(ch == leftright2[i])
743            return leftright2[(i & ~1) | ((i - 1) & 1)];
744
745    for(i = 0; leftright4[i]; i++)
746        if(ch == leftright4[i])
747            return leftright4[(i & ~3) | ((i - 1) & 3)];
748
749    return ch;
750}
751
Note: See TracBrowser for help on using the repository browser.