1 /* This file is part of GNU Dico
2    Copyright (C) 2012-2020 Sergey Poznyakoff
3 
4    GNU Dico is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3, or (at your option)
7    any later version.
8 
9    GNU Dico is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with GNU Dico.  If not, see <http://www.gnu.org/licenses/>. */
16 
17 #include <config.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <dico.h>
22 
23 typedef int (*opfn) (int argc, char **argv);
24 
25 struct optab {
26     char *name;
27     opfn fun;
28 };
29 
30 static unsigned *
strtowc(const char * str)31 strtowc(const char *str)
32 {
33     unsigned *buf;
34     if (utf8_mbstr_to_wc(str, &buf, NULL)) {
35 	dico_log(L_ERR, errno, "cannot convert \"%s\"", str);
36 	abort();
37     }
38     return buf;
39 }
40 
41 
42 static int
help(int argc,char ** argv)43 help(int argc, char **argv)
44 {
45     printf("No more help, sorry");
46     return 0;
47 }
48 
49 static int
op_strlen(int argc,char ** argv)50 op_strlen(int argc, char **argv)
51 {
52     char *opname = *argv++;
53     argc--;
54     if (argc != 1) {
55 	dico_log(L_ERR, 0, "%s requires one argument", opname);
56 	return 1;
57     }
58     printf("%lu\n", (unsigned long) utf8_strlen(argv[0]));
59     return 0;
60 }
61 
62 static int
op_strcasecmp(int argc,char ** argv)63 op_strcasecmp(int argc, char **argv)
64 {
65     char *opname = *argv++;
66     argc--;
67     if (argc != 2) {
68 	dico_log(L_ERR, 0, "%s requires two arguments", opname);
69 	return 1;
70     }
71     printf("%d\n", utf8_strcasecmp(argv[0], argv[1]));
72     return 0;
73 }
74 
75 static int
op_strncasecmp(int argc,char ** argv)76 op_strncasecmp(int argc, char **argv)
77 {
78     char *opname = *argv++;
79     argc--;
80     if (argc != 3) {
81 	dico_log(L_ERR, 0, "%s requires three arguments", opname);
82 	return 1;
83     }
84     printf("%d\n", utf8_strncasecmp(argv[0], argv[1], atoi(argv[2])));
85     return 0;
86 }
87 
88 static int
op_wc_strcmp(int argc,char ** argv)89 op_wc_strcmp(int argc, char **argv)
90 {
91     unsigned *wa, *wb;
92     char *opname = *argv++;
93     argc--;
94     if (argc != 2) {
95 	dico_log(L_ERR, 0, "%s requires two arguments", opname);
96 	return 1;
97     }
98 
99     wa = strtowc(argv[0]);
100     wb = strtowc(argv[1]);
101 
102     printf("%d\n", utf8_wc_strcmp(wa, wb));
103     return 0;
104 }
105 
106 static int
op_wc_strncmp(int argc,char ** argv)107 op_wc_strncmp(int argc, char **argv)
108 {
109     unsigned *wa, *wb;
110     char *opname = *argv++;
111     argc--;
112     if (argc != 3) {
113 	dico_log(L_ERR, 0, "%s requires three arguments", opname);
114 	return 1;
115     }
116 
117     wa = strtowc(argv[0]);
118     wb = strtowc(argv[1]);
119 
120     printf("%d\n", utf8_wc_strncmp(wa, wb, atoi(argv[2])));
121     return 0;
122 }
123 
124 static int
op_wc_strcasecmp(int argc,char ** argv)125 op_wc_strcasecmp(int argc, char **argv)
126 {
127     unsigned *wa, *wb;
128     char *opname = *argv++;
129     argc--;
130     if (argc != 2) {
131 	dico_log(L_ERR, 0, "%s requires two arguments", opname);
132 	return 1;
133     }
134 
135     wa = strtowc(argv[0]);
136     wb = strtowc(argv[1]);
137 
138     printf("%d\n", utf8_wc_strcasecmp(wa, wb));
139     return 0;
140 }
141 
142 static int
op_wc_strncasecmp(int argc,char ** argv)143 op_wc_strncasecmp(int argc, char **argv)
144 {
145     unsigned *wa, *wb;
146     char *opname = *argv++;
147     argc--;
148     if (argc != 3) {
149 	dico_log(L_ERR, 0, "%s requires three arguments", opname);
150 	return 1;
151     }
152 
153     wa = strtowc(argv[0]);
154     wb = strtowc(argv[1]);
155 
156     printf("%d\n", utf8_wc_strncasecmp(wa, wb, atoi(argv[2])));
157     return 0;
158 }
159 
160 static int
op_toupper(int argc,char ** argv)161 op_toupper(int argc, char **argv)
162 {
163     char *opname = *argv++;
164     argc--;
165     if (argc != 1) {
166 	dico_log(L_ERR, 0, "%s requires one arguments", opname);
167 	return 1;
168     }
169     if (utf8_toupper(argv[0]))
170 	abort();
171     printf("%s\n", argv[0]);
172     return 0;
173 }
174 
175 static int
op_tolower(int argc,char ** argv)176 op_tolower(int argc, char **argv)
177 {
178     char *opname = *argv++;
179     argc--;
180     if (argc != 1) {
181 	dico_log(L_ERR, 0, "%s requires one argument", opname);
182 	return 1;
183     }
184     if (utf8_tolower(argv[0]))
185 	abort();
186     printf("%s\n", argv[0]);
187     return 0;
188 }
189 
190 static int
op_wc_strchr(int argc,char ** argv)191 op_wc_strchr(int argc, char **argv)
192 {
193     unsigned *wa, *wb;
194     const unsigned *p;
195     char *opname = *argv++;
196     argc--;
197     if (argc != 2) {
198 	dico_log(L_ERR, 0, "%s requires two arguments", opname);
199 	return 1;
200     }
201 
202     wa = strtowc(argv[0]);
203     wb = strtowc(argv[1]);
204     p = utf8_wc_strchr(wa, wb[0]);
205     if (!p)
206 	return 2;
207     printf("%td\n", p - wa);
208     return 0;
209 }
210 
211 static int
op_wc_strchr_ci(int argc,char ** argv)212 op_wc_strchr_ci(int argc, char **argv)
213 {
214     unsigned *wa, *wb;
215     const unsigned *p;
216     char *opname = *argv++;
217     argc--;
218     if (argc != 2) {
219 	dico_log(L_ERR, 0, "%s requires two arguments", opname);
220 	return 1;
221     }
222 
223     wa = strtowc(argv[0]);
224     wb = strtowc(argv[1]);
225     p = utf8_wc_strchr_ci(wa, wb[0]);
226     if (!p)
227 	return 2;
228     printf("%td\n", p - wa);
229     return 0;
230 }
231 
232 static int
op_wc_strstr(int argc,char ** argv)233 op_wc_strstr(int argc, char **argv)
234 {
235     unsigned *wa, *wb;
236     const unsigned *p;
237     char *opname = *argv++;
238     argc--;
239     if (argc != 2) {
240 	dico_log(L_ERR, 0, "%s requires two arguments", opname);
241 	return 1;
242     }
243 
244     wa = strtowc(argv[0]);
245     wb = strtowc(argv[1]);
246     p = utf8_wc_strstr(wa, wb);
247     if (!p) {
248 	if (errno) {
249 	    dico_log(L_ERR, errno, "can't match");
250 	    return 3;
251 	}
252 	return 2;
253     }
254     printf("%td\n", p - wa);
255     return 0;
256 }
257 
258 struct optab optab[] = {
259     { "help", help },
260     { "strlen", op_strlen },
261     { "strcasecmp", op_strcasecmp },
262     { "strncasecmp", op_strncasecmp },
263     { "wc_strcmp", op_wc_strcmp },
264     { "wc_strncmp", op_wc_strncmp },
265     { "wc_strcasecmp", op_wc_strcasecmp },
266     { "wc_strncasecmp", op_wc_strncasecmp },
267     { "toupper", op_toupper },
268     { "tolower", op_tolower },
269     { "wc_strchr", op_wc_strchr },
270     { "wc_strchr_ci", op_wc_strchr_ci },
271     { "wc_strstr", op_wc_strstr },
272     { NULL }
273 };
274 
275 void
usage(FILE * fp)276 usage(FILE *fp)
277 {
278     fprintf(fp, "usage: %s [op] [args]\n", dico_program_name);
279 }
280 
281 int
main(int argc,char ** argv)282 main(int argc, char **argv)
283 {
284     struct optab *op;
285 
286     dico_set_program_name(argv[0]);
287     argc--;
288     argv++;
289     if (!argc) {
290 	usage(stderr);
291 	return 1;
292     }
293     for (op = optab; op->name; op++)
294 	if (strcmp(*argv, op->name) == 0)
295 	    return op->fun(argc, argv);
296     dico_log(L_ERR, 0, "unknown operation");
297     return 1;
298 }
299