1.[代码]safe_iconv.c
/* 在 Windows 下有许多编码是GB18030、 后缀是 cue 的文本文件,将其移到 Linux 下使用 shell 命令:
find . -type f -name "*.cue" -exec iconv -f gb18030 -t utf8 -o {} {} \;
目的是找到当前目录下所有cue文件并转码,然后替换原文件。当 iconv 转码失败时,仍然会将垃圾数据写入原文件。
而新的 safe_iconv 在转码失败时不修改原代码。safe_iconv 只适合用于小于 BUFSIZE 的文件:
find . -type f -name "*.cue" -exec safe_iconv -f gb18030 -t utf8 -o {} {} \;
*/
#include
#include
#include
#include
enum {BUFSIZE = 4096};
static iconv_t cd;
static char* fromcode;
static char* tocode;
static char* infilename;
static char* outfilename;
static char inbuf[BUFSIZE];
static char outbuf[BUFSIZE];
static FILE* fin;
static FILE* fout;
int cmdline_parsed(int argc, char*const* argv)
{
int opt;
opterr = 0;
while ( (opt=getopt(argc, argv, "f:t:o:l")) != -1 )
{
switch (opt) {
case 'f': fromcode = optarg; break;
case 't': tocode = optarg; break;
case 'o': outfilename = optarg; break;
case 'l': system("iconv -l"); return 0; //当然必须安装有 iconv。
case '?': fprintf(stderr, "error: option is \'?\'\n"); return 0;
}
}
if (! (fromcode && tocode)) {
fprintf(stderr, "error: \'fromcode\' or \'tocode\' is null.\n");
return 0;
}
infilename = argv[optind];
return 1;
}
size_t file_size(FILE* fin)
{
size_t r;
fseek(fin, 0, SEEK_END);
r = ftell(fin);
fseek(fin, 0, SEEK_SET);
return r;
}
int main(int argc, const char** argv)
{
char* pinbuf = inbuf;
char* poutbuf = outbuf;
size_t inbytesleft;
size_t outbytesleft;
size_t count;
if (! cmdline_parsed(argc, (char*const*)argv)) {
return EXIT_FAILURE;
}
cd = iconv_open(tocode, fromcode);
if (cd == (iconv_t)-1) {
fprintf(stderr, "error: f=\'%s\' t=\'%s\' i=\'%s\' o=\'%s\'\n",
fromcode, tocode, infilename, outfilename);
return EXIT_FAILURE;
}
fin = fopen(infilename, "r");
if (! fin) {
fprintf(stderr, "error: \'fopen(%s, \"r\")\'\n", infilename);
return EXIT_FAILURE;
}
inbytesleft = file_size(fin);
if (inbytesleft > BUFSIZE) {
fprintf(stderr, "error: \'%d > BUFSIZE\'\n", inbytesleft);
return EXIT_FAILURE;
}
fread(inbuf, 1, inbytesleft, fin);
outbytesleft = BUFSIZE;
count = iconv(cd, &pinbuf, &inbytesleft, &poutbuf, &outbytesleft);
if (count == (size_t)-1) {
fprintf(stderr, "error: \'iconv()\'\n");
return EXIT_FAILURE;
}
if (outfilename == NULL) {
//printf("%d %d\n", inbytesleft, outbytesleft);
printf("%s", outbuf);
}
else {
fout = fopen(outfilename, "w");
if (! fout) {
fclose(fin);
fprintf(stderr, "error: \'fopen(%s, \"w\")\'\n", outfilename);
return EXIT_FAILURE;
}
fwrite(outbuf, 1, BUFSIZE - outbytesleft, fout);
fclose(fout);
}
fclose(fin);
return EXIT_SUCCESS;
}