1#include "confusables.h"
2
3#include <base/str.h>
4
5#include <cstddef>
6
7static int str_utf8_skeleton(int ch, const int **skeleton, int *skeleton_len)
8{
9 for(size_t i = 0; i < NUM_DECOMPS; i++)
10 {
11 if(ch == decomp_chars[i])
12 {
13 int offset = decomp_slices[i].offset;
14 int length = decomp_lengths[decomp_slices[i].length];
15
16 *skeleton = &decomp_data[offset];
17 *skeleton_len = length;
18 return 1;
19 }
20 else if(ch < decomp_chars[i])
21 {
22 break;
23 }
24 }
25 *skeleton = nullptr;
26 *skeleton_len = 1;
27 return 0;
28}
29
30struct SKELETON
31{
32 const int *skeleton;
33 int skeleton_len;
34 const char *str;
35};
36
37static void str_utf8_skeleton_begin(struct SKELETON *skel, const char *str)
38{
39 skel->skeleton = nullptr;
40 skel->skeleton_len = 0;
41 skel->str = str;
42}
43
44static int str_utf8_skeleton_next(struct SKELETON *skel)
45{
46 int ch = 0;
47 while(skel->skeleton_len == 0)
48 {
49 ch = str_utf8_decode(ptr: &skel->str);
50 if(ch == 0)
51 {
52 return 0;
53 }
54 str_utf8_skeleton(ch, skeleton: &skel->skeleton, skeleton_len: &skel->skeleton_len);
55 }
56 skel->skeleton_len--;
57 if(skel->skeleton != nullptr)
58 {
59 ch = *skel->skeleton;
60 skel->skeleton++;
61 }
62 return ch;
63}
64
65int str_utf8_to_skeleton(const char *str, int *buf, int buf_len)
66{
67 int i;
68 struct SKELETON skel;
69 str_utf8_skeleton_begin(skel: &skel, str);
70 for(i = 0; i < buf_len; i++)
71 {
72 int ch = str_utf8_skeleton_next(skel: &skel);
73 if(ch == 0)
74 {
75 break;
76 }
77 buf[i] = ch;
78 }
79 return i;
80}
81
82int str_utf8_comp_confusable(const char *str1, const char *str2)
83{
84 struct SKELETON skel1;
85 struct SKELETON skel2;
86
87 str_utf8_skeleton_begin(skel: &skel1, str: str1);
88 str_utf8_skeleton_begin(skel: &skel2, str: str2);
89
90 while(true)
91 {
92 int ch1 = str_utf8_skeleton_next(skel: &skel1);
93 int ch2 = str_utf8_skeleton_next(skel: &skel2);
94
95 if(ch1 == 0 || ch2 == 0)
96 return ch1 != ch2;
97
98 if(ch1 != ch2)
99 return 1;
100 }
101}
102