fixes for Power64
[tridge/junkcode.git] / charset_test.c
1 #include <stdio.h>
2 #include <iconv.h>
3
4 #define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
5 #define SVAL(buf, pos) (CVAL(buf, pos) | CVAL(buf, pos+1)<<8)
6
7 typedef unsigned short uint16;
8 #define smb_ucs2_t unsigned short
9 #define UNI_UPPER    0x1
10 #define UNI_LOWER    0x2
11 #define UNI_DIGIT    0x4
12 #define UNI_XDIGIT   0x8
13 #define UNI_SPACE    0x10
14
15 typedef struct {
16         smb_ucs2_t lower;
17         smb_ucs2_t upper;
18         unsigned char flags;
19 } smb_unicode_table_t;
20
21 smb_unicode_table_t map_table[] = {
22 #include "unicode_map_table.h"
23 };
24
25 static int zero_len;
26 static int error_count;
27
28 /* check if a converted character contains a null */
29 static void check_null(iconv_t cd_in, iconv_t cd_out, smb_ucs2_t uc)
30 {
31         char buf[10];
32         int inlen=2, outlen=10;
33         char *p = (char *)&uc;
34         char *q = buf;
35         int i, len;
36
37         iconv(cd_in, &p, &inlen, &q, &outlen);
38         
39         if (outlen == 10) {
40                 zero_len++;
41                 return;
42         }
43
44         len = (10-outlen);
45
46         for (i=0;i<len;i++) {
47                 if (buf[i] == 0) {
48                         printf("NULL at pos %d in ucs2 char %04x\n",
49                                i, uc);
50                 }
51         }
52 }
53
54 /* check if a uppercase or lowercase version of a char is longer than
55    the original */
56 static void check_case(iconv_t cd_in, iconv_t cd_out, smb_ucs2_t uc)
57 {
58         char buf[10];
59         int inlen=2, outlen=10;
60         char *p = (char *)&uc;
61         char *q = buf;
62         int len1, len2, len3;
63         smb_ucs2_t uc2;
64
65         iconv(cd_in, &p, &inlen, &q, &outlen);
66         len1 = (10-outlen);
67
68         if (len1 == 0) return;
69
70         uc2 = map_table[uc].upper;
71         p = (char *)&uc2;
72         q = buf;
73         inlen = 2;
74         outlen = 10;
75
76         iconv(cd_in, &p, &inlen, &q, &outlen);
77         len2 = (10-outlen);
78
79         uc2 = map_table[uc].lower;
80         p = (char *)&uc2;
81         q = buf;
82         inlen = 2;
83         outlen = 10;
84
85         iconv(cd_in, &p, &inlen, &q, &outlen);
86         len3 = (10-outlen);
87
88         if (len2 > len1 || len3 > len1) {
89                 printf("case expansion for ucs2 char %04x (%d/%d/%d)\n",
90                        uc, len1, len2, len3);
91                 error_count++;
92         }
93 }
94
95
96 /* check if a character is C compatible */
97 static void check_compat(iconv_t cd_in, iconv_t cd_out, smb_ucs2_t uc)
98 {
99         char buf[10];
100         int inlen, outlen;
101         char *p, *q;
102         smb_ucs2_t uc2;
103
104         /* only care about 7 bit chars */
105         if (SVAL(&uc, 0) & 0xFF80) return;
106
107         inlen = 2; outlen = 10;
108         p = (char *)&uc;
109         q = buf;
110         iconv(cd_in, &p, &inlen, &q, &outlen);
111
112         if (outlen != 9) {
113                 printf("ucs2 char %04x not C compatible (len=%d)\n",
114                        uc, 10-outlen);
115                 return;
116         }
117
118         if (buf[0] != SVAL(&uc, 0)) {
119                 printf("ucs2 char %04x not C compatible (c=0x%x)\n",
120                        uc, buf[0]);
121                 error_count++;
122                 return;
123         }
124
125         inlen = 1; outlen = 2;
126         p = (char *)&uc2;
127         q = buf;
128         iconv(cd_out, &q, &inlen, &p, &outlen);
129         
130         if (uc2 != uc) {
131                 printf("ucs2 char %04x not C compatible (uc2=0x%x len=%d): %s\n",
132                        uc, uc2, 2-outlen, strerror(errno));
133                 error_count++;
134         }
135 }
136
137 /* check if a character is strchr compatible */
138 static void check_strchr_compat(iconv_t cd_in, iconv_t cd_out, smb_ucs2_t uc)
139 {
140         char buf[10];
141         int inlen=2, outlen=10;
142         int i;
143         char *p = (char *)&uc;
144         char *q = buf;
145
146         iconv(cd_in, &p, &inlen, &q, &outlen);
147
148         if (10 - outlen <= 1) return;
149
150         for (i=0; i<10-outlen; i++) {
151                 if (! (buf[i] & 0x80)) {
152                         printf("ucs2 char %04x not strchr compatible\n",
153                                uc);
154                         error_count++;
155                 }
156         }
157 }
158
159 int main(int argc, char *argv[])
160 {
161         int i;
162         iconv_t cd_in, cd_out;
163
164         if (argc < 2) {
165                 printf("Usage: charset_test <CHARSET>\n");
166                 exit(1);
167         }
168
169         cd_in = iconv_open(argv[1], "UCS-2LE");
170         cd_out = iconv_open("UCS-2LE", argv[1]);
171
172         if (cd_in == (iconv_t)-1 || cd_out == (iconv_t)-1) {
173                 perror(argv[1]);
174                 return -1;
175         }
176
177         for (i=1;i<0x10000;i++) {
178                 iconv(cd_in, NULL, NULL, NULL, NULL);
179                 iconv(cd_out, NULL, NULL, NULL, NULL);
180                 check_null(cd_in, cd_out, i);
181                 check_case(cd_in, cd_out, i);
182                 check_compat(cd_in, cd_out, i);
183                 /* check_strchr_compat(cd_in, cd_out, i); */
184         }
185
186         printf("%d chars convertible\n", 0x10000 - zero_len);
187         if (error_count == 0) {
188                 printf("character set %s OK for Samba\n", argv[1]);
189         } else {
190                 printf("%d errors in character set\n", error_count);
191                 return -1;
192         }
193         return 0;
194 }