/* * Copyright (C) 2004, 2005 Jean-Yves Lefort * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Jean-Yves Lefort nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include "translate.h" static void translate_cli_fatal (const char *format, ...) G_GNUC_NORETURN G_GNUC_PRINTF(1, 2); static void translate_cli_print_help (void); static void translate_cli_print_version (void); static void translate_cli_list_services (void); static void translate_cli_list_pairs (TranslateSession *session, const char *from, const char *to); static void translate_cli_translate (TranslateSession *session, const char *from, const char *to, const char *arg); static void translate_cli_translate_text (TranslateSession *session, const char *from, const char *to, const char *filename, gboolean tty); static void translate_cli_translate_web_page (TranslateSession *session, const char *from, const char *to, const char *url, gboolean tty); static gboolean translate_cli_progress_cb (double progress, gpointer user_data); int main (int argc, char **argv) { int c; char mode = 0; /* translate */ char *services = NULL; char *from = NULL; char *to = NULL; gboolean set_max_threads = FALSE; unsigned int max_threads; gboolean set_max_retries = FALSE; int max_retries; #define OPT_HELP '?' #define OPT_HELP_S "?" #define OPT_VERSION 'v' #define OPT_VERSION_S "v" #define OPT_LIST_SERVICES '1' #define OPT_SERVICES 's' #define OPT_SERVICES_S "s" #define OPT_FROM 'f' #define OPT_FROM_S "f" #define OPT_TO 't' #define OPT_TO_S "t" #define OPT_LIST_PAIRS 'l' #define OPT_LIST_PAIRS_S "l" #define OPT_MAX_THREADS '2' #define OPT_MAX_RETRIES '3' const struct option options[] = { { "help", no_argument, NULL, OPT_HELP }, { "version", no_argument, NULL, OPT_VERSION }, { "list-services", no_argument, NULL, OPT_LIST_SERVICES }, { "services", required_argument, NULL, OPT_SERVICES }, { "from", required_argument, NULL, OPT_FROM }, { "to", required_argument, NULL, OPT_TO }, { "list-pairs", no_argument, NULL, OPT_LIST_PAIRS }, { "max-threads", required_argument, NULL, OPT_MAX_THREADS }, { "max-retries", required_argument, NULL, OPT_MAX_RETRIES }, { NULL, 0, NULL, 0 } }; g_set_prgname(argc > 0 ? argv[0] : "translate"); setlocale(LC_ALL, ""); /* use user's locale */ #ifdef ENABLE_NLS bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR); bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); textdomain(GETTEXT_PACKAGE); #endif while ((c = getopt_long(argc, argv, OPT_HELP_S OPT_VERSION_S OPT_SERVICES_S ":" OPT_FROM_S ":" OPT_TO_S ":" OPT_LIST_PAIRS_S, options, NULL)) != -1) switch (c) { case OPT_HELP: case OPT_VERSION: case OPT_LIST_SERVICES: case OPT_LIST_PAIRS: mode = c; break; case OPT_SERVICES: g_free(services); services = g_strdup(optarg); break; case OPT_FROM: g_free(from); from = g_strdup(optarg); break; case OPT_TO: g_free(to); to = g_strdup(optarg); break; case OPT_MAX_THREADS: set_max_threads = TRUE; max_threads = atoi(optarg); break; case OPT_MAX_RETRIES: set_max_retries = TRUE; max_retries = atoi(optarg); break; default: g_assert_not_reached(); } argc -= optind; argv += optind; if (argc > (mode ? 0: 1)) translate_cli_fatal(_("too many arguments")); if (mode == OPT_HELP) translate_cli_print_help(); else if (mode == OPT_VERSION) translate_cli_print_version(); else { GError *err = NULL; const char *http_proxy; if (! translate_init(&err)) translate_cli_fatal(_("unable to initialize libtranslate: %s"), err->message); http_proxy = g_getenv("HTTP_PROXY"); if (! http_proxy) http_proxy = g_getenv("http_proxy"); translate_set_proxy(http_proxy); if (mode == OPT_LIST_SERVICES) translate_cli_list_services(); else { GSList *list = NULL; TranslateSession *session; if (services) { char **vector; int i; vector = g_strsplit(services, ",", 0); for (i = 0; vector[i]; i++) { TranslateService *service; service = translate_get_service(vector[i]); if (! service) translate_cli_fatal(_("unknown service \"%s\""), vector[i]); list = g_slist_append(list, service); } g_strfreev(vector); } else list = translate_get_services(); session = translate_session_new(list); g_slist_foreach(list, (GFunc) g_object_unref, NULL); g_slist_free(list); if (set_max_threads) translate_session_set_max_threads(session, max_threads); if (set_max_retries) translate_session_set_max_retries(session, max_retries); if (mode == OPT_LIST_PAIRS) translate_cli_list_pairs(session, from, to); else translate_cli_translate(session, from, to, argc == 1 ? argv[0] : NULL); g_object_unref(session); } } /* on some systems, the return value of main() is ignored */ exit(0); return 0; } static void translate_cli_fatal (const char *format, ...) { va_list args; char *message; g_assert(format != NULL); va_start(args, format); message = g_strdup_vprintf(format, args); va_end(args); g_printerr("%s: %s\n", g_get_prgname(), message); g_free(message); exit(1); } static void translate_cli_print_help (void) { g_print("%s\n", _("Synopsis:")); g_print(" %s {-? | -v | --list-services}\n", g_get_prgname()); g_print(" %s [-s SERVICES] [-f LANG] [-t LANG] -l\n", g_get_prgname()); g_print(" %s [-s SERVICES] [-f LANG] [-t LANG] {HTTP_URL | HTTPS_URL}\n", g_get_prgname()); g_print(" %s [-s SERVICES] [-f LANG] [-t LANG] [--max-threads=N] [--max-retries=N] [FILE]\n", g_get_prgname()); g_print("\n"); g_print("%s\n", _("Options:")); g_print(" -?, --help %s\n", _("Show this help")); g_print(" -v, --version %s\n", _("Show version information")); g_print(" --list-services %s\n", _("List the available services")); g_print(" -s, --services=SERVICES %s\n", _("Specify the list of services to use")); g_print(" -f, --from=LANG %s\n", _("Specify the source language")); g_print(" -t, --to=LANG %s\n", _("Specify the destination language")); g_print(" -l, --list-pairs %s\n", _("List the available language pairs")); g_print(" --max-threads=N %s\n", _("Specify the maximum number of threads to use")); g_print(" --max-retries=N %s\n", _("Specify the maximum number of retries per chunk")); } static void translate_cli_print_version (void) { g_print(_("%s version %s\n"), "translate", VERSION); g_print("Copyright (C) 2004, 2005 Jean-Yves Lefort\n"); } static void translate_cli_list_services (void) { GSList *l; GSList *services; services = translate_get_services(); for (l = services; l != NULL; l = l->next) g_print("%s (%s)\n", translate_service_get_name(l->data), translate_service_get_nick(l->data)); g_slist_foreach(services, (GFunc) g_object_unref, NULL); g_slist_free(services); } static void translate_cli_list_pairs (TranslateSession *session, const char *from, const char *to) { GSList *pairs; GSList *l; g_return_if_fail(TRANSLATE_IS_SESSION(session)); pairs = translate_session_get_pairs(session); pairs = translate_pairs_sort_by_name(pairs); for (l = pairs; l != NULL; l = l->next) { TranslatePair *pair = l->data; const char *pair_from = translate_pair_get_from(pair); const char *pair_to = translate_pair_get_to(pair); if ((! from || ! g_ascii_strcasecmp(from, pair_from)) && (! to || ! g_ascii_strcasecmp(to, pair_to))) { TranslatePairFlags flags = translate_pair_get_flags(pair); g_print("%s (%s) -> %s (%s): %s\n", pair_from, translate_get_language_name(pair_from), pair_to, translate_get_language_name(pair_to), (flags & TRANSLATE_PAIR_TEXT && flags & TRANSLATE_PAIR_WEB_PAGE) ? _("text, web page") : ((flags & TRANSLATE_PAIR_TEXT) ? _("text") : ((flags & TRANSLATE_PAIR_WEB_PAGE) ? _("web page") : ""))); } } g_slist_foreach(pairs, (GFunc) g_object_unref, NULL); g_slist_free(pairs); } static void translate_cli_translate (TranslateSession *session, const char *from, const char *to, const char *arg) { const char *var; char *default_from; char *default_to; gboolean tty; var = g_getenv("TRANSLATE_DEFAULT_FROM"); default_from = g_strdup(var ? var : "en"); var = g_getenv("TRANSLATE_DEFAULT_TO"); default_to = g_strdup(var ? var : "fr"); if (! from) from = ! to || g_ascii_strcasecmp(to, default_from) ? default_from : default_to; if (! to) to = ! from || g_ascii_strcasecmp(from, default_to) ? default_to : default_from; tty = isatty(fileno(stderr)); if (arg && (g_str_has_prefix(arg, "http://") || g_str_has_prefix(arg, "https://"))) translate_cli_translate_web_page(session, from, to, arg, tty); else translate_cli_translate_text(session, from, to, arg, tty); g_free(default_from); g_free(default_to); } static void translate_cli_translate_text (TranslateSession *session, const char *from, const char *to, const char *filename, gboolean tty) { FILE *file; char buf[4096]; GString *string; size_t len; char *converted; char *translated; GError *err = NULL; g_return_if_fail(TRANSLATE_IS_SESSION(session)); g_return_if_fail(from != NULL); g_return_if_fail(to != NULL); if (filename && strcmp(filename, "-")) { file = fopen(filename, "r"); if (! file) translate_cli_fatal(_("unable to open \"%s\": %s"), filename, g_strerror(errno)); } else file = stdin; string = g_string_new(NULL); while ((len = fread(buf, 1, sizeof(buf), file))) g_string_append_len(string, buf, len); if (ferror(file)) { if (file == stdin) translate_cli_fatal(_("unable to read from standard input: %s"), g_strerror(errno)); else translate_cli_fatal(_("unable to read from \"%s\": %s"), filename, g_strerror(errno)); } if (file != stdin) fclose(file); if (g_utf8_validate(string->str, -1, NULL)) converted = g_string_free(string, FALSE); else { converted = g_locale_to_utf8(string->str, -1, NULL, NULL, &err); g_string_free(string, TRUE); if (! converted) translate_cli_fatal(_("unable to convert input text to UTF-8: %s"), err->message); } if (tty) g_printerr("[%77c]", ' '); translated = translate_session_translate_text(session, converted, from, to, tty ? translate_cli_progress_cb : NULL, NULL, &err); g_free(converted); if (tty) g_printerr("\r%79c\r", ' '); if (translated) { g_print("%s", translated); g_free(translated); } else translate_cli_fatal(_("unable to translate: %s"), err->message); } static void translate_cli_translate_web_page (TranslateSession *session, const char *from, const char *to, const char *url, gboolean tty) { char *translated_url; GError *err = NULL; g_return_if_fail(TRANSLATE_IS_SESSION(session)); g_return_if_fail(from != NULL); g_return_if_fail(to != NULL); g_return_if_fail(url != NULL); if (tty) g_printerr("[%77c]", ' '); translated_url = translate_session_translate_web_page(session, url, from, to, tty ? translate_cli_progress_cb : NULL, NULL, &err); if (tty) g_printerr("\r%79c\r", ' '); if (translated_url) { g_print("%s\n", translated_url); g_free(translated_url); } else translate_cli_fatal(_("unable to get URL of translated web page: %s"), err->message); } static gboolean translate_cli_progress_cb (double progress, gpointer user_data) { int i; g_printerr("\r["); if (progress < 0) { static int pre_spaces = 0; static int direction = 1; int post_spaces; switch (direction) { case 1: if (pre_spaces + 1 > 74) direction = -1; break; case -1: if (pre_spaces - 1 < 0) direction = 1; break; } switch (direction) { case 1: pre_spaces++; break; case -1: pre_spaces--; break; } post_spaces = 74 - pre_spaces; for (i = 0; i < pre_spaces; i++) g_printerr(" "); g_printerr("###"); for (i = 0; i < post_spaces; i++) g_printerr(" "); } else { int n_dashes; int n_spaces; n_dashes = progress * 77; n_spaces = 77 - n_dashes; for (i = 0; i < n_dashes; i++) g_printerr("#"); for (i = 0; i < n_spaces; i++) g_printerr(" "); } g_printerr("]"); return TRUE; /* continue */ }