1 /* Copyright (c) 2013 - The libcangjie authors.
2  *
3  * This file is part of libcangjie.
4  *
5  * libcangjie is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * libcangjie is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with libcangjie.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 
20 #include <getopt.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <libgen.h>
24 
25 #include <cangjie.h>
26 
27 
28 
29 typedef enum CangjieCliMode {
30     CANGJIE_CLI_MODE_CODE      = 0,
31     CANGJIE_CLI_MODE_SHORTCODE = 1,
32     CANGJIE_CLI_MODE_RADICAL   = 2,
33 } CangjieCliMode;
34 
35 
usage(char * progname)36 void usage(char *progname) {
37     printf("Usage: %s [OPTIONS]... CODE\n", basename(progname));
38     printf("A CLI interface of libcangjie cangjie code query\n\n");
39     printf("-f, --filter=FILTER1,FILTER2...  specify the filters used in the query\n");
40     printf("                                 default: big5,hkscs\n");
41     printf("                                 acceptable values:\n");
42     printf("                                   big5, hkscs, punctuation, chinese,\n");
43     printf("                                   zhuyin, kanji, katakana, hiragana,\n");
44     printf("                                   symbols\n");
45     printf("-m, --mode=MODE                  specify the mode of query\n");
46     printf("                                 default: code\n");
47     printf("                                 acceptable values:\n");
48     printf("                                   code, shortcode, radical\n");
49     printf("-C, --cj-version=VERSION         specify the version of Cangjie used\n");
50     printf("                                 default: 3\n");
51     printf("                                 acceptable values: 3, 5\n");
52     printf("-h, --help                       print this help message and leave\n");
53     printf("\nFor complete documentation, please go to our website: \n");
54     printf("<http://cangjians.github.io/>\n");
55 }
56 
57 
print_error(char * msg)58 void print_error(char *msg) {
59     printf("libcangjie_cli: %s\n", msg);
60     printf("Try 'libcangjie_cli --help' for more information\n");
61 }
62 
63 
main(int argc,char ** argv)64 int main(int argc, char **argv) {
65     char *code;
66     Cangjie *cj;
67     int ret;
68     CangjieCharList *chars;
69     CangjieCharList *iter;
70     CangjieChar *c;
71 
72     // variables to parse options
73     int opt;
74     int option_index;
75 
76     // option flags
77     int opt_filter;
78     CangjieCliMode opt_mode;
79     int opt_cj_version;
80 
81     // helper variable(s)
82     char errmsg[255];
83     char *code_ptr;
84     char *ptr_radical;
85 
86     // available options
87     static struct option long_options[] = {
88         {"filter", required_argument, 0, 'f'},
89         {"mode", required_argument, 0, 'm'},
90         {"cj-version", required_argument, 0, 'C'},
91         {"help", no_argument, 0, 'h'},
92         {0, 0, 0, 0},
93     };
94 
95     // default options
96     opt_filter = CANGJIE_FILTER_BIG5 | CANGJIE_FILTER_HKSCS;
97     opt_mode = CANGJIE_CLI_MODE_CODE;
98     opt_cj_version = CANGJIE_VERSION_3;
99 
100     // read options
101     while (1) {
102         option_index = 0;
103         opt = getopt_long(argc, argv, "f:m:C:h", long_options, &option_index);
104 
105         if (opt == -1) {
106             break;
107         }
108 
109         switch (opt) {
110             case 'f':
111                 opt_filter = 0;
112                 if (strstr(optarg, "big5") != NULL) {
113                     opt_filter = opt_filter | CANGJIE_FILTER_BIG5;
114                 }
115                 if (strstr(optarg, "hkscs") != NULL) {
116                     opt_filter = opt_filter | CANGJIE_FILTER_HKSCS;
117                 }
118                 if (strstr(optarg, "punctuation") != NULL) {
119                     opt_filter = opt_filter | CANGJIE_FILTER_PUNCTUATION;
120                 }
121                 if (strstr(optarg, "chinese") != NULL) {
122                     opt_filter = opt_filter | CANGJIE_FILTER_CHINESE;
123                 }
124                 if (strstr(optarg, "zhuyin") != NULL) {
125                     opt_filter = opt_filter | CANGJIE_FILTER_ZHUYIN;
126                 }
127                 if (strstr(optarg, "kanji") != NULL) {
128                     opt_filter = opt_filter | CANGJIE_FILTER_KANJI;
129                 }
130                 if (strstr(optarg, "katakana") != NULL) {
131                     opt_filter = opt_filter | CANGJIE_FILTER_KATAKANA;
132                 }
133                 if (strstr(optarg, "hiragana") != NULL) {
134                     opt_filter = opt_filter | CANGJIE_FILTER_HIRAGANA;
135                 }
136                 if (strstr(optarg, "symbols") != NULL) {
137                     opt_filter = opt_filter | CANGJIE_FILTER_SYMBOLS;
138                 }
139                 if (opt_filter == 0) {
140                     sprintf(errmsg, "Invalid filter option '%s'", optarg);
141                     print_error(errmsg);
142                     return -1;
143                 }
144                 break;
145             case 'm':
146                 if (strcmp(optarg, "code") == 0) {
147                     opt_mode = CANGJIE_CLI_MODE_CODE;
148                 } else if (strcmp(optarg, "shortcode") == 0) {
149                     opt_mode = CANGJIE_CLI_MODE_SHORTCODE;
150                 } else if (strcmp(optarg, "radical") == 0) {
151                     opt_mode = CANGJIE_CLI_MODE_RADICAL;
152                 } else {
153                     sprintf(errmsg, "Invalid query mode '%s'", optarg);
154                     print_error(errmsg);
155                     return -1;
156                 }
157                 break;
158             case 'C':
159                 if (*optarg == '3') {
160                     opt_cj_version = CANGJIE_VERSION_3;
161                 } else if (*optarg == '5') {
162                     opt_cj_version = CANGJIE_VERSION_5;
163                 } else {
164                     sprintf(errmsg, "Invalid Cangjie version '%s'", optarg);
165                     print_error(errmsg);
166                     return -1;
167                 }
168                 break;
169             case '?':
170                 printf("Try 'libcangjie_cli --help' for more information\n");
171                 return -1;
172                 break;
173             case 'h':
174             default:
175                 usage(argv[0]);
176                 return (opt == 'h') ? 0 : -1;
177         }
178     }
179 
180     // check if query provided
181     if (optind == argc) {
182         print_error("missing query code");
183         return -1;
184     }
185 
186     code = argv[optind];
187 
188     ret = cangjie_new(&cj, opt_cj_version, opt_filter);
189 
190     if (ret == CANGJIE_DBOPEN) {
191         printf("Could not open the Cangjie database\n");
192         return ret;
193     } else if (ret != CANGJIE_OK) {
194         printf("Unhandled error while creating the Cangjie object: %d\n", ret);
195         return ret;
196     }
197 
198 
199     if (opt_mode == CANGJIE_CLI_MODE_RADICAL) {
200         code_ptr = code;
201         for (; *code_ptr != '\0'; code_ptr++) {
202             ret = cangjie_get_radical(cj, *code_ptr, &ptr_radical);
203             if (ret == CANGJIE_OK) {
204                 printf("code: '%c', radical: '%s'\n", *code_ptr, ptr_radical);
205             } else {
206                 printf("Query error (%d)\n", ret);
207                 return ret;
208             }
209         }
210         return ret;
211     } else {
212         if (opt_mode == CANGJIE_CLI_MODE_CODE) {
213             ret = cangjie_get_characters(cj, code, &chars);
214         } else if (opt_mode == CANGJIE_CLI_MODE_SHORTCODE) {
215             ret = cangjie_get_characters_by_shortcode(cj, code, &chars);
216         }
217 
218         if (ret == CANGJIE_NOCHARS) {
219             printf("No chars with code '%s'\n", code);
220 
221             cangjie_free(cj);
222             return CANGJIE_NOCHARS;
223         } else if (ret == CANGJIE_INVALID) {
224             printf("Invalid code '%s'\n", code);
225 
226             cangjie_free(cj);
227             return CANGJIE_INVALID;
228         } else if (ret != CANGJIE_OK) {
229             printf("Other error %d with code '%s'\n", ret, code);
230 
231             cangjie_free(cj);
232             return ret;
233         }
234 
235         iter = chars;
236 
237         while (1) {
238             if (iter == NULL) {
239                 break;
240             }
241 
242             c = iter->c;
243             printf("Char: %s, code: '%s', classic frequency: %d\n",
244                    c->chchar, c->code, c->frequency);
245 
246             iter = iter->next;
247         }
248 
249         cangjie_char_list_free(chars);
250     }
251 
252     cangjie_free(cj);
253 
254     return CANGJIE_OK;
255 }
256