summaryrefslogtreecommitdiff
path: root/src/lib/ecore_input/ecore_input_compose.c
blob: 13b90bca09098e95704327150aad0b81351ddd2c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <stdio.h>
#include <string.h>

#include "Ecore.h"
#include "ecore_private.h"

#include "Ecore_Input.h"
#include "ecore_input_private.h"

// some info on a big big big compose table
// http://cgit.freedesktop.org/xorg/lib/libX11/plain/nls/en_US.UTF-8/Compose.pre
// isolate compose tree into its own file - hand crafted into static const c
#include "ecore_input_compose.h"

EAPI Ecore_Compose_State
ecore_compose_get(const Eina_List *seq, char **seqstr_ret)
{
   const char *p, *pend;
   const unsigned char *psz;
   Eina_List *l;
   const char *s;
   int i = 0;
   static int complen = 0;

   if (!seq) return ECORE_COMPOSE_NONE;
   l = (Eina_List *)seq;
   s = l->data;

   // calc comp string len first time around
   if (complen == 0)
     {
        int zeros = 0;

        for (p = comp; ; p++)
          {
             if (!(*p)) zeros++;
             else zeros = 0;
             // end marker - 4 0 bytes in a row
             if (zeros == 4)
               {
                  complen = p - comp - 3;
                  break;
               }
          }
     }
   // walk special comp string/byte array looking for our match
   pend = comp + complen;
   for (p = comp; (p < pend) && s;)
     {
        int len, jump = -1, bsize = -1;
        
        len = strlen(p);
        psz = (unsigned char *)(p + len + 1);
        // decode jump amount to next entry
        if (!(psz[0] & 0x80)) // < 0x80
          {
             jump = psz[0];
             bsize = 1;
          }
        else if ((psz[0] & 0xc0) == 0xc0) // < 0x200000
          {
             jump = (((psz[0] & 0x1f) << 16) | (psz[1] << 8) | (psz[2]));
             bsize = 3;
          }
        else // >= 0x4000
          {
             jump = (((psz[0] & 0x3f) << 8) | (psz[1]));
             bsize = 2;
          }

        // doesn't match -> jump to next level entry
        if (!(!strcmp(s, p)))
          {
             p = p + jump;
             if (p >= pend) return ECORE_COMPOSE_NONE;
          }
        // matches
        else
          {
             pend = p + jump;
             // advance to next sequence member
             l = l->next;
             i++;
             if (l) s = l->data;
             else s = NULL;
             p = p + len + 1 + bsize;
             len = strlen(p);
             psz = (unsigned char *)(p + len + 1);
             // leaf nodes all are short so psz[0] has the full value
             if ((len + 2) == psz[0])
               {
                  // final leaf node, so return string here
                  if (seqstr_ret) *seqstr_ret = strdup(p);
                  return ECORE_COMPOSE_DONE;
               }
          }
     }
   if (i == 0) return ECORE_COMPOSE_NONE;
   return ECORE_COMPOSE_MIDDLE;
}