├── README.md ├── bin_x64 ├── tl └── tl.exe ├── makefile ├── src ├── main.c └── uclib │ ├── Makefile │ ├── README.md │ ├── bin │ ├── resolveIP.o │ └── showMem.o │ ├── inc │ ├── net.h │ └── tools.h │ ├── net │ └── resolveIP.c │ ├── t │ ├── test │ ├── resolveIP.c │ ├── showMem.c │ └── test.c │ ├── tools │ └── showMem.c │ └── uclib.a └── tea.yaml /README.md: -------------------------------------------------------------------------------- 1 | Translator 2 | === 3 | 4 | 由于网络原因,API无法直接访问,请使用可设置 HTTP 代理的 [Node.js 版本](https://github.com/develon2015/Translator/tree/node) 5 | 6 | 安装 7 | --- 8 | 直接下载 9 | ``` 10 | wget https://github.com/develon2015/Translator/raw/master/bin_x64/tl 11 | chmod +x tl 12 | ./tl hello 13 | ``` 14 | 编译安装,请先安装gcc、make 15 | ``` 16 | git clone https://github.com/develon2015/Translator 17 | make clean 18 | make 19 | make install 20 | ``` 21 | 22 | 运行效果 23 | --- 24 | ``` 25 | $ tl -h 26 | 翻译程序 27 | tl [sl] [tl] 28 | 交互式Shell中可以切换语种, 使用":sl tl"命令即可 29 | 例如":en_US zh_CN" 30 | 31 | Sep 22 2019 - 09:33:24 32 | 33 | $ tl わたし、プログラミングが好きなの 34 | 我喜欢编程 35 | 36 | $ tl ja_JP zh_TW わたし、プログラミングが好きなの 37 | 我喜歡編程 38 | 39 | $ tl en_US わたし、プログラミングが好きなの 40 | I like programming 41 | 42 | $ tl 43 | Are you OK? 44 | 你还好吗? 45 | 46 | :ja 47 | [INFO]语种切换: auto -> ja. 48 | 49 | Are you OK? 50 | 大丈夫ですか? 51 | 52 | :auto zh_HK 53 | [INFO]语种切换: auto -> zh_HK. 54 | 55 | 大丈夫ですか? 56 | 你還好嗎? 57 | 58 | ^D 59 | ``` 60 | 61 | 项目结构 62 | --- 63 | 64 | ```Bash 65 | . 66 | ├── bin_x64 67 | │   └── tl 68 | ├── makefile 69 | ├── README.md 70 | ├── src 71 | │   ├── main.c 72 | │   └── uclib 73 | │   ├── inc 74 | │   │   └── net.h 75 | │   ├── Makefile 76 | │   ├── net 77 | │   │   └── resolveIP.c 78 | │   ├── README.md 79 | │   └── uclib.a 80 | └── translate.exe 81 | ``` 82 | -------------------------------------------------------------------------------- /bin_x64/tl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/develon2015/Translator/74458e713ee446b93204a716e75d8d4221df1e04/bin_x64/tl -------------------------------------------------------------------------------- /bin_x64/tl.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/develon2015/Translator/74458e713ee446b93204a716e75d8d4221df1e04/bin_x64/tl.exe -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | DIR := bin_x64 2 | BIN := $(DIR)/tl 3 | 4 | $(BIN): src/main.c src/uclib/uclib.a | $(DIR) 5 | gcc -W -Wall $^ -o $(BIN) -Isrc 6 | 7 | src/uclib/uclib.a: 8 | make -C src/uclib 9 | 10 | $(DIR): 11 | mkdir $@ 12 | 13 | .PHONY: deploy install 14 | install deploy: 15 | sudo cp $(BIN) /usr/bin 16 | 17 | .PHONY: clean 18 | clean: 19 | make -C src/uclib clean 20 | rm -rf $(DIR) 21 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | #define HOST "translate.my-api.workers.dev" 17 | #define PORT htons(80) 18 | #define HEADER \ 19 | "GET /translate_a/single?client=gtx&dt=t&dj=1&ie=UTF-8&sl=%s&tl=%s&q=%s HTTP/1.1\r\n"\ 20 | "Host: " HOST "\r\n"\ 21 | "User-Agent: Chrome/12.8\r\n"\ 22 | "Accept: application/json\r\n"\ 23 | "Connection: close\r\n"\ 24 | "\r\n" 25 | 26 | #define DEBUG 0 27 | 28 | #if !DEBUG 29 | #define log(args, ...) {} 30 | #else 31 | #define log(args, ...) printf(args"\n", ##__VA_ARGS__) 32 | #endif 33 | 34 | int 35 | translate(const char *target); 36 | void 37 | handle(const char *response); 38 | const char * 39 | getBody(const char *response); 40 | char * 41 | URIEncode(const char *uri); 42 | char * 43 | getJSONValue(const char *json, const char *key); 44 | 45 | char *sl = "auto"; 46 | char *tl = "zh_CN"; 47 | char *target = NULL; 48 | 49 | struct sockaddr_in remoteAddr = { 0 }; 50 | 51 | int 52 | main(int argc, char *argv[]) { 53 | int isShell = 0; 54 | switch (argc) { 55 | case 1: // 交互式 OR 管道式 56 | isShell = 1; 57 | break; 58 | case 2: 59 | if (strcmp("-h", argv[argc - 1]) == 0) 60 | goto DEFAULT; 61 | break; 62 | case 3: // 指定了目标语言 63 | tl = argv[1]; 64 | break; 65 | case 4: // 指定了源和目标语言 66 | sl = argv[1]; 67 | tl = argv[2]; 68 | break; 69 | DEFAULT: 70 | default: 71 | printf("翻译程序\n\t%s [sl] [tl] \n\t交互式Shell中可以切换语种, "\ 72 | "使用\":sl tl\"命令即可\n\t例如\":en_US zh_CN\"\n\n"\ 73 | "\t%s\n\n", argv[0], __DATE__ " - " __TIME__); 74 | return 1; 75 | } 76 | 77 | // 解析 IP 地址 78 | struct in_addr addr = { 0 }; 79 | if (resolveIP(HOST, AF_INET, &addr) != 0) { 80 | puts("解析服务器地址失败"); 81 | return 2; 82 | } 83 | char buf[128] = { 0 }; 84 | inet_ntop(AF_INET, &addr, buf, sizeof buf); 85 | log("服务器地址: %s", buf); 86 | 87 | // 设置远程主机地址和端口 88 | remoteAddr.sin_family = AF_INET; 89 | remoteAddr.sin_port = PORT; 90 | remoteAddr.sin_addr.s_addr = addr.s_addr; 91 | 92 | // 新特性 93 | if (strcmp("--", argv[argc - 1]) == 0) 94 | isShell = 1; 95 | 96 | if (isShell) 97 | GETLINE: 98 | while (1) { 99 | char buf[10240] = { 0 }; 100 | if (fgets(buf, 10240, stdin) == NULL) 101 | return 0; 102 | if (buf[0] == ':') { 103 | // 切换源和目标语言 104 | char *bufSL = (char *)malloc(128); 105 | char *bufTL = (char *)malloc(128); 106 | int n = sscanf(buf, ":%s %s", bufSL, bufTL); 107 | if (n > 0) { 108 | if (n == 1) 109 | tl = bufSL; 110 | else { 111 | sl = bufSL; 112 | tl = bufTL; 113 | } 114 | printf("[INFO]语种切换: %s -> %s.\n", sl, tl); 115 | goto GETLINE; 116 | } 117 | } 118 | buf[strlen(buf) - 1] = '\0'; 119 | if (strcmp("", buf) == 0 || strcmp(" ", buf) == 0) 120 | continue; 121 | log("翻译%s", buf); 122 | translate(buf); 123 | } 124 | else { 125 | translate(argv[argc - 1]); 126 | } 127 | } 128 | 129 | 130 | int 131 | translate(const char *target) { 132 | // HTTP GET 请求 133 | int sock = socket(AF_INET, SOCK_STREAM, 0); 134 | if (sock < 1) { 135 | perror("socket"); 136 | return 3; 137 | } 138 | 139 | log("连接服务器中..."); 140 | int n = connect(sock, (void *)&remoteAddr, sizeof remoteAddr); 141 | if (n != 0) { 142 | printf("disconnect: %s\n", hstrerror(h_errno)); 143 | return 4; 144 | } 145 | log("已连接服务器."); 146 | 147 | // 发送请求之前处理URI编码 148 | target = URIEncode(target); 149 | 150 | // 单线程发送, 接收数据 151 | char buf[10240] = { 0 }; 152 | memset(buf, 0, sizeof buf); 153 | sprintf(buf, HEADER, sl, tl, target); 154 | log("HEADER:\n%ssize: %ld", buf, strlen(buf)); 155 | n = send(sock, buf, strlen(buf), 0); // flag 156 | if (n < 0) { 157 | perror("发送失败"); 158 | close(sock); 159 | return 0; 160 | } 161 | 162 | log("写入%d字节", n); 163 | 164 | memset(buf, 0, sizeof buf); 165 | while (1) { 166 | char bufSegm[10240] = { 0 }; 167 | n = read(sock, bufSegm, sizeof bufSegm); 168 | if (n < 1) { 169 | log("连接被关闭"); 170 | break; 171 | } 172 | log("读取%d字节", n); 173 | strcat(buf, bufSegm); 174 | } 175 | log("RESPONSE:\n%s", buf); 176 | 177 | // 处理response 178 | handle(buf); 179 | close(sock); 180 | 181 | return 0; 182 | } 183 | 184 | void 185 | handle(const char *response) { 186 | int statu = 0; 187 | if (sscanf(response, "%*s %d", &statu) != 1) { 188 | printf("无法识别状态码:\n%s\n", response); 189 | return; 190 | } 191 | if (statu != 200) { 192 | printf("错误的状态码: %d\n%s\n", statu, response); 193 | return; 194 | } 195 | const char *body = getBody(response); 196 | log("关注body:\n%s", body); 197 | char *result = (char *)malloc(strlen(body)); 198 | result = getJSONValue(body, "trans"); 199 | if (result == NULL) { 200 | printf("翻译失败: %s\n", body); 201 | return; 202 | } 203 | //result[strlen(result) - 1] = '\0'; 204 | printf("%s\n", result); 205 | } 206 | 207 | // 获取 Response body 部分, 删除了头部的空行 208 | const char * 209 | getBody(const char *text) { 210 | int n = strlen(text); 211 | for (int i = 0; i < n; i ++ ) { 212 | if (text[i] == '\n' && ((text[i+1] == '\r' && text[i+2] == '\n') || text[i+1] == '\n')) { 213 | //return text[i + 2] == '\n' ? &text[i + 3] : &text[i + 2]; 214 | for (i = i+2; i < n; i ++ ) { 215 | if (text[i] != '\n' && text[i] != '\r') 216 | return &text[i]; 217 | } 218 | } 219 | } 220 | return NULL; 221 | } 222 | 223 | // "只有字母和数字[0-9a-zA-Z]、一些特殊符号"$-_.+!*'(),"[不包括双引号]、以及某些保留字,才可以不经过编码直接用于URL。" 224 | static int 225 | isURIChar(const char ch) { 226 | if (isalnum(ch)) 227 | return 1; 228 | if (ch == ' ') 229 | return 0; 230 | switch (ch) { 231 | case '$': 232 | case '-': 233 | case '_': 234 | case '.': 235 | case '+': 236 | case '!': 237 | case '*': 238 | case '\'': 239 | case '(': 240 | case ')': 241 | return 1; 242 | default: 243 | return 0; 244 | } 245 | } 246 | 247 | char * 248 | URIEncode(const char *uri) { 249 | int n = strlen(uri); 250 | char *cp = (char *)malloc(n * 3); 251 | memset(cp, 0, n * 3); 252 | int pn = 0; 253 | // scan uri 254 | for (int i = 0; i < n; i ++ ) { 255 | if (isURIChar(uri[i])) { 256 | cp[pn++] = uri[i]; 257 | continue; 258 | } 259 | if (uri[i] == ' ') { 260 | cp[pn++] = '+'; 261 | continue; 262 | } 263 | //log("uri[%d] 需要 编码", i); 264 | // UTF8 265 | char it[4] = { 0 }; 266 | sprintf(it, "%%%X", (unsigned char)uri[i]); 267 | //log("it -> %s", it); 268 | strcat(cp, it); 269 | pn += 3; 270 | } 271 | log("%s. -> %s.\n", uri, cp); 272 | return cp; 273 | } 274 | 275 | char * 276 | getJSONValue(const char *json, const char *key) { 277 | log("查找key:%s", key); 278 | int n = strlen(json); 279 | int nk = strlen(key); 280 | char *result = (char *)malloc(n); 281 | memset(result, 0, n); 282 | int isSucceed = 0; 283 | for (int i = 0; i < n; i ++ ) { 284 | if (json[i] == '"' && json[i+1] == *key) { // "k... 285 | log("有点儿意思:%s", &json[i]); 286 | int isTarget = 1; 287 | for (int j = 0; j < nk; j ++ ) { 288 | if (json[i + j + 1] == key[j]) 289 | continue; 290 | isTarget = 0; 291 | } 292 | // "key? 293 | if (isTarget && json[i + nk + 1] == '"') { // "key"... 294 | char *buf = (char *)malloc(n); 295 | memset(buf, 0, n); 296 | int offs = strcspn(&json[i], ":"); // "key"(:.*) 297 | int offe = n - 1; 298 | for (int k = offs; k < n; k ++ ) { 299 | if (json[i + k] == ',' && json[i + k + 1] == '"') { 300 | offe = k; 301 | break; 302 | } 303 | } 304 | log("s&e %d %d", offs, offe); 305 | strncpy(buf, &json[i + offs], offe - offs); 306 | //return buf; 307 | // cat buf to result 308 | buf[strlen(buf) - 1] = '\0'; 309 | log("找到:%s", &buf[2]); 310 | strcat(result, &buf[2]); 311 | isSucceed ++ ; 312 | } 313 | } 314 | } 315 | if (isSucceed) 316 | return result; 317 | return NULL; 318 | } 319 | 320 | -------------------------------------------------------------------------------- /src/uclib/Makefile: -------------------------------------------------------------------------------- 1 | # makefile 2 | VPATH=test:net 3 | 4 | .PHONY: MultiTarget 5 | MultiTarget: uclib.a t 6 | @echo OK 7 | 8 | src_t = $(wildcard test/*.c) 9 | 10 | t: $(src_t) uclib.a 11 | $(CC) -o t $^ -Iinc -ldl -rdynamic 12 | 13 | src_uclib = $(wildcard net/*.c) $(wildcard tools/*.c) 14 | 15 | uclib.a: $(src_uclib) 16 | $(CC) -c $^ -Iinc 17 | @-mkdir bin > /dev/null 2>&1 18 | mv *.o bin 19 | ar rcs $@ bin/*.o 20 | 21 | .PHONY:clean 22 | clean: 23 | rm -rf *.o 24 | rm -rf bin 25 | rm -rf t uclib.a 26 | -------------------------------------------------------------------------------- /src/uclib/README.md: -------------------------------------------------------------------------------- 1 | ## uclib 2 | > ublic 是基于 glibc 的 C 程序库.
3 | 4 | > 下载
5 | > git clone https://github.com/develon2015/uclib.git
6 | 7 | > 更新
8 | > cd uclib && git pull
9 | 10 | > 使用头文件:
11 | > #include
12 | 13 | > 添加头文件搜索路径.和静态库uclib.a以编译:
14 | > gcc \*.c `-I. uclib/uclib.a`
15 | 16 | ### 测试 17 | ``` 18 | develon@desktop:~/git/uclib$ t resolveIP 19 | 测试 tresolveIP 函数... 20 | javac.ga -> 104.18.44.94 21 | javac.ga -> 2606:4700:30::6812:2d5e 22 | ``` 23 | 24 | -------------------------------------------------------------------------------- /src/uclib/bin/resolveIP.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/develon2015/Translator/74458e713ee446b93204a716e75d8d4221df1e04/src/uclib/bin/resolveIP.o -------------------------------------------------------------------------------- /src/uclib/bin/showMem.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/develon2015/Translator/74458e713ee446b93204a716e75d8d4221df1e04/src/uclib/bin/showMem.o -------------------------------------------------------------------------------- /src/uclib/inc/net.h: -------------------------------------------------------------------------------- 1 | /** 2 | * net.h 3 | * 网络工具包 4 | */ 5 | 6 | // 解析IP地址 7 | int 8 | resolveIP(const char *domain, int type, void *addr_t); 9 | 10 | // IPv6判断 11 | int 12 | isIPv6Supported(); 13 | 14 | -------------------------------------------------------------------------------- /src/uclib/inc/tools.h: -------------------------------------------------------------------------------- 1 | /** 2 | * tools.h 3 | * 提供工具方法 4 | * 5 | */ 6 | 7 | // 显示内存p 8 | void 9 | showMem(const void *p, size_t le); 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/uclib/net/resolveIP.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int 8 | resolveIP(const char *domain, int type, void *ip) { 9 | if (domain == NULL || ip == NULL) 10 | return -1; 11 | if (type != AF_INET && type != AF_INET6) 12 | return -1; 13 | struct hostent *ent = gethostbyname2(domain, type); 14 | if (ent == NULL) 15 | return -1; 16 | if (type == AF_INET) 17 | *(struct in_addr *)ip = *(struct in_addr*)ent->h_addr; 18 | else 19 | *(struct in6_addr *)ip = *(struct in6_addr*)ent->h_addr; 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /src/uclib/t: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/develon2015/Translator/74458e713ee446b93204a716e75d8d4221df1e04/src/uclib/t -------------------------------------------------------------------------------- /src/uclib/test/resolveIP.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void 9 | tresolveIP(const char *p) { 10 | const char *domain = p; 11 | printf("%s %s\n", __func__, domain); 12 | struct in6_addr addr; 13 | char buf[1024]; 14 | if (resolveIP(domain, AF_INET, &addr) == 0) 15 | printf("%s -> %s\n", domain, inet_ntop(AF_INET, &addr, buf, sizeof addr)); 16 | else 17 | printf("%s\n", hstrerror(h_errno)); 18 | if (resolveIP(domain, AF_INET6, &addr) == 0) 19 | printf("%s -> %s\n", domain, inet_ntop(AF_INET6, &addr, buf, sizeof buf)); 20 | else 21 | printf("%s\n", hstrerror(h_errno)); 22 | } 23 | -------------------------------------------------------------------------------- /src/uclib/test/showMem.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void 6 | tshowMem(const char *p) { 7 | showMem(p, strlen(p) + 2); 8 | } 9 | -------------------------------------------------------------------------------- /src/uclib/test/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int 8 | main(int argc, char *argv[]) { 9 | if (argc == 1) { 10 | printf("测试程序t\n\tt <函数> [参数]\n"); 11 | return 0; 12 | } 13 | char fn[1024] = { 0 }; 14 | sprintf(fn, "t%s", argv[1]); 15 | void (*fp)(const char *) = dlsym(NULL, fn); 16 | if (fp == NULL) { 17 | printf("%s\n", dlerror()); 18 | return 1; 19 | } 20 | fp(argv[2]); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /src/uclib/tools/showMem.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | void 5 | showMem(const void *p, size_t le) { 6 | #define RL 16 // 换行数 7 | printf("显示内存 %p :\n", p); 8 | printf("=======================================================\n"); 9 | const unsigned char *cp = p; 10 | for (int i = 0; i < le; i++) { 11 | int c = cp[i]; 12 | printf("%c%X ", c < 0x10 ? '0' : 0, c); 13 | if ((i + 1) % RL == 0 || i == le - 1) 14 | puts(""); 15 | } 16 | printf("=======================================================\n"); 17 | } 18 | -------------------------------------------------------------------------------- /src/uclib/uclib.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/develon2015/Translator/74458e713ee446b93204a716e75d8d4221df1e04/src/uclib/uclib.a -------------------------------------------------------------------------------- /tea.yaml: -------------------------------------------------------------------------------- 1 | # https://tea.xyz/what-is-this-file 2 | # 3 | # DO NOT REMOVE OR EDIT THIS WARNING: 4 | # 5 | # This file is auto-generated by the TEA app. It is intended to validate ownership of your repository. 6 | # DO NOT commit this file or accept any PR if you don't know what this is. 7 | # We are aware that spammers will try to use this file to try to profit off others' work. 8 | # We take this very seriously and will take action against any malicious actors. 9 | # 10 | # If you are not the owner of this repository, and someone maliciously opens a commit with this file 11 | # please report it to us at support@tea.xyz. 12 | # 13 | # A constitution without this header is invalid. 14 | --- 15 | version: 2.0.0 16 | codeOwners: 17 | - '0xd326F1f50fc62A449b05cF66041E5D5052E2b446' 18 | quorum: 1 19 | --------------------------------------------------------------------------------