/* Copyright 2024 Japanese TeX Development Community Distributed under the 3-Clause BSD License. */ #ifndef _WIN32 #include #endif #include #include #include #include #include #include #ifdef _WIN32 #include #ifndef CP_UTF8 #define CP_UTF8 65001 #endif #endif #include #include static char opt_input_enc[5]; static char opt_output_enc[5]; static int flg_guess_enc; static int flg_output_buffer; #define GUESS_ONLY -1 #define GUESS_AND_OUTPUT +1 #define BUFFERLEN 4096 static char buff[BUFFERLEN]; static const char *optstr = "hvgbjseuGJSEU"; static struct option long_options[] = { {"help", 0, 0, 'h'}, {"version", 0, 0, 'v'}, {"guess", 0, 0, 'g'}, {"buffer", 0, 0, 'b'}, {0, 0, 0, 0} }; #define MY_VERSION "20240211" #define BUG_ADDRESS "issue@texjp.org" static void show_version(void) { printf("ptekf ver." MY_VERSION " (%s) (%s, %s)\n", get_enc_string(), ptexenc_version_string, TL_VERSION); printf(" Copyright (C) 2024 Japanese TeX Development Community\n"); } static void show_usage(void) { printf("Usage: ptekf -[OPTION] [--] in_file1 [in_file2 ...]\n"); printf(" j/s/e/u Specify output encoding ISO-2022-JP, Shift_JIS, EUC-JP, UTF-8\n"); printf(" J/S/E/U Specify input encoding ISO-2022-JP, Shift_JIS, EUC-JP, UTF-8\n"); printf(" G Guess the input encoding and output to stdout or files\n"); printf(" --guess -g Guess the input encoding (no conversion)\n"); printf(" --buffer -b Output internal buffer without code conversion\n"); printf(" --version -v Print version number\n"); printf(" --help -h Print this help\n"); printf("Default input/output encoding depends on kpathsearch parameters PTEX_KANJI_ENC, guess_input_kanji_encoding\n"); printf("\nEmail bug reports to %s.\n", BUG_ADDRESS); } const char *infname; char *outfname; FILE *infp, *outfp; #if defined(_WIN32) #define R_MODE "rb" #define W_MODE "wb" #else #define R_MODE "r" #define W_MODE "w" #endif static char *mfgets(char *buff, int size, FILE *fp) { int c, len; if ((len = input_line2(fp, (unsigned char *)buff, NULL, 0, size, &c)) == 0 && c != '\r' && c != '\n') return NULL; if (c == '\n' || c == '\r') { if (len+1 < size) { buff[len]=(unsigned char)c; buff[len+1]='\0'; } else ungetc(c, fp); } if (c == EOF) return NULL; return buff; } int main (int argc, char **argv) { int c; int opt_ienc=0, opt_oenc=0; int (*fputs__)(const char*, FILE*); if (argc<=1) { show_version(); show_usage(); return 0; } kpse_set_program_name(argv[0], "ptekf"); #if defined(_WIN32) { int ac; char **av; file_system_codepage = CP_UTF8; is_cp932_system = 0; if (get_command_line_args_utf8("utf-8", &ac, &av)) { argv = av; argc = ac; } } #endif enable_UPTEX(true); while ((c = getopt_long(argc, argv, optstr, long_options, NULL)) != -1) { switch (c) { case 'G': /* guess and output to stdout or files */ flg_guess_enc = GUESS_AND_OUTPUT; opt_ienc++; break; case 'g': /* guess */ flg_guess_enc = GUESS_ONLY; opt_ienc++; break; case 'b': /* output internal buffer */ flg_output_buffer = 1; opt_oenc++; break; case 'h': /* help */ show_version(); show_usage(); return 0; case 'v': /* version */ show_version(); return 0; /* input encoding */ case 'J': strcpy(opt_input_enc, "jis") ; opt_ienc++; break; case 'S': strcpy(opt_input_enc, "sjis") ; opt_ienc++; break; case 'E': strcpy(opt_input_enc, "euc") ; opt_ienc++; break; case 'U': strcpy(opt_input_enc, "utf8") ; opt_ienc++; break; /* output encoding */ case 'j': strcpy(opt_output_enc, "jis") ; opt_oenc++; break; case 's': strcpy(opt_output_enc, "sjis") ; opt_oenc++; break; case 'e': strcpy(opt_output_enc, "euc") ; opt_oenc++; break; case 'u': strcpy(opt_output_enc, "utf8") ; opt_oenc++; break; } } if (opt_ienc>1) { fprintf(stderr, "Option (--guess or -g), -G, -J, -S, -E and -U are mutually exclusive\n"); exit(16); } if (opt_oenc>1) { fprintf(stderr, "Option (--buffer or -b), -j, -s, -e and -u are mutually exclusive\n"); exit(16); } fputs__ = flg_output_buffer ? fputs : fputs2; /* without/with code conversion */ while (optind < argc) { char *genc, *ret; infname = argv[optind++]; if ((infp = fopen(infname, R_MODE)) == 0) { fprintf(stderr, "ERROR: fail to open input file [%s].", infname); exit(32); } if (flg_guess_enc) { genc = ptenc_guess_enc(infp, 1, 1); printf("%s: %s\n", infname, genc); setinfileenc(infp, genc); free(genc); } if ((opt_ienc && flg_guess_enc!=GUESS_ONLY) || opt_oenc) { if (opt_oenc) { outfname = xmalloc(strlen(infname)+5); strcpy(outfname, infname); strcat(outfname, ".out"); if ((outfp = fopen(outfname, W_MODE)) == 0) { fprintf(stderr, "ERROR: fail to open output file [%s].", outfname); exit(32); } } else outfp = stdout; if (strlen(opt_input_enc)) { setinfileenc(infp, opt_input_enc); } if (strlen(opt_output_enc)) { setfileenc(opt_output_enc); } while ((ret = mfgets(buff, BUFFERLEN, infp)) != NULL) { (*fputs__)(buff, outfp); } if (ret == NULL && feof(infp)) { c = buff[strlen(buff)-1]; if (c != '\n' && c != '\r') (*fputs__)(buff, outfp); } if (fclose(infp)) { fprintf(stderr, "ERROR: fail to close input file [%s].", infname); exit(32); } if (outfp != stdout && fclose(outfp)) { fprintf(stderr, "ERROR: fail to close output file [%s].", outfname); exit(32); } if (outfname) free(outfname); } } return 0; }