/* liblouis Braille Translation and Back-Translation Library Copyright (C) 2012 Swiss Library for the Blind, Visually Impaired and Print Disabled This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include "internal.h" #include #include "progname.h" #include "unistr.h" #include "version-etc.h" const char version_etc_copyright[] = "Copyright %s %d Swiss Library for the Blind, Visually Impaired and Print " "Disabled."; #define AUTHORS "Bert Frees" static void print_help(void) { printf("\ Usage: %s [OPTIONS] TABLE[,TABLE,...]\n", program_name); fputs("\ Examine and debug Braille translation tables. This program allows you\n\ to inspect liblouis translation tables by printing out the list of\n\ applied translation rules for a given input.\n\n", stdout); fputs("\ -h, --help display this help and exit\n\ -v, --version display version information and exit\n\ -f, --forward forward translation using the given table\n\ -b, --backward backward translation using the given table\n\ --noContractions Use no contractions\n\ --dotsIO Display dot patterns\n\ --ucBrl Use Unicode Braille patterns\n\ --noUndefined Disable output of undefined dot numbers during back-translation\n\ --partialTrans Use partial back-translation\n\ If neither -f nor -b are specified forward translation\n\ is assumed\n", stdout); printf("Report bugs to %s.\n", PACKAGE_BUGREPORT); #ifdef PACKAGE_PACKAGER_BUG_REPORTS printf("Report %s bugs to: %s\n", PACKAGE_PACKAGER, PACKAGE_PACKAGER_BUG_REPORTS); #endif #ifdef PACKAGE_URL printf("%s home page: <%s>\n", PACKAGE_NAME, PACKAGE_URL); #endif } #define BUFSIZE 512 #define RULESSIZE 512 static char * get_input(void) { static char input_buffer[BUFSIZE]; size_t input_length; input_buffer[0] = 0; if (!fgets(input_buffer, sizeof(input_buffer), stdin)) exit(EXIT_FAILURE); input_length = strlen(input_buffer) - 1; if (input_length < 0) exit(0); input_buffer[input_length] = 0; return input_buffer; } static int get_wide_input(widechar *buffer) { return _lou_extParseChars(get_input(), buffer); } static char * print_chars(const widechar *buffer, int length) { static uint8_t result_buf[BUFSIZE]; size_t result_len = BUFSIZE - 1; #ifdef WIDECHARS_ARE_UCS4 u32_to_u8(buffer, length, result_buf, &result_len); #else u16_to_u8(buffer, length, result_buf, &result_len); #endif result_buf[result_len] = 0; return result_buf; } static char * print_dots(const widechar *buffer, int length) { static char dots[BUFSIZE]; strcpy(dots, _lou_showDots(buffer, length)); return dots; } static char * print_number(widechar c) { static char number[BUFSIZE]; sprintf(number, "%d", c); return number; } static char * print_attributes(unsigned int a) { static char attr[BUFSIZE]; strcpy(attr, _lou_showAttributes(a)); return attr; } static void append_char(char *destination, int *length, char source) { destination[(*length)++] = source; } static void append_string(char *destination, int *length, char *source) { strcpy(&destination[(*length)], source); (*length) += strlen(source); } static char * print_script(const widechar *buffer, int length) { static char script[BUFSIZE]; int i = 0; int j = 0; while (i < length) { switch (buffer[i]) { case pass_first: case pass_last: case pass_not: case pass_startReplace: case pass_endReplace: case pass_search: case pass_copy: case pass_omit: append_char(script, &j, buffer[i++]); break; case pass_lookback: append_char(script, &j, buffer[i++]); if (buffer[i] > 1) append_string(script, &j, print_number(buffer[i++])); break; case pass_string: append_char(script, &j, buffer[i]); append_string(script, &j, print_chars(&buffer[i + 2], buffer[i + 1])); append_char(script, &j, buffer[i]); i += (2 + buffer[i + 1]); break; case pass_dots: append_char(script, &j, buffer[i++]); append_string(script, &j, print_dots(&buffer[i + 1], buffer[i])); i += (1 + buffer[i]); break; case pass_eq: case pass_lt: case pass_gt: case pass_lteq: case pass_gteq: append_char(script, &j, '#'); append_string(script, &j, print_number(buffer[i + 1])); append_char(script, &j, buffer[i]); append_string(script, &j, print_number(buffer[i + 2])); i += 3; break; case pass_hyphen: case pass_plus: append_char(script, &j, '#'); append_string(script, &j, print_number(buffer[i + 1])); append_char(script, &j, buffer[i]); i += 2; break; case pass_attributes: append_char(script, &j, buffer[i]); append_string( script, &j, print_attributes(buffer[i + 1] << 16 | buffer[i + 2])); i += 3; if (buffer[i] == 1 && buffer[i + 1] == 1) { } else if (buffer[i] == 1 && buffer[i + 1] == 0xffff) append_char(script, &j, pass_until); else if (buffer[i] == buffer[i + 1]) append_string(script, &j, print_number(buffer[i])); else { append_string(script, &j, print_number(buffer[i])); append_char(script, &j, '-'); append_string(script, &j, print_number(buffer[i + 1])); } i += 2; break; case pass_endTest: append_char(script, &j, '\t'); i++; break; case pass_swap: case pass_groupstart: case pass_groupend: case pass_groupreplace: /* TBD */ default: i++; break; } } script[j] = 0; return script; } static void print_rule(const TranslationTableRule *rule) { const char *opcode = _lou_findOpcodeName(rule->opcode); char *chars; char *dots; char *script; switch (rule->opcode) { case CTO_Context: case CTO_Correct: case CTO_SwapCd: case CTO_SwapDd: case CTO_Pass2: case CTO_Pass3: case CTO_Pass4: script = print_script(&rule->charsdots[rule->charslen], rule->dotslen); printf("%s\t%s\n", opcode, script); break; default: chars = print_chars(rule->charsdots, rule->charslen); dots = print_dots(&rule->charsdots[rule->charslen], rule->dotslen); printf("%s\t%s\t%s\n", opcode, chars, dots); break; } } static void main_loop(int backward_translation, char *table, int mode) { widechar inbuf[BUFSIZE]; widechar outbuf[BUFSIZE]; int inlen; int outlen; const TranslationTableRule **rules = malloc(512 * sizeof(TranslationTableRule)); int ruleslen; int i, j; while (1) { inlen = get_wide_input(inbuf); outlen = BUFSIZE; ruleslen = RULESSIZE; if (backward_translation) { if (!_lou_backTranslate(table, table, inbuf, &inlen, outbuf, &outlen, NULL, NULL, NULL, NULL, NULL, mode, rules, &ruleslen)) break; } else if (!_lou_translate(table, table, inbuf, &inlen, outbuf, &outlen, NULL, NULL, NULL, NULL, NULL, mode, rules, &ruleslen)) break; if ((mode & dotsIO) && !backward_translation) printf("Dot patterns: %s\n", _lou_showDots(outbuf, outlen)); else printf("%s\n", print_chars(outbuf, outlen)); j = 0; for (i = 0; i < ruleslen; i++) { if (rules[i]->opcode < 0 || rules[i]->opcode >= CTO_None) continue; printf("%d.\t", ++j); print_rule(rules[i]); } } } int main(int argc, char **argv) { int optc; char *table; int forward_flag = 0; int backward_flag = 0; int mode = 0; int noContractionsMode = 0; int dotsIOMode = 0; int ucBrlMode = 0; int noUndefinedMode = 0; int noUndefinedDotsMode = 0; int partialTransMode = 0; const struct option longopts[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'v' }, { "forward", no_argument, NULL, 'f' }, { "backward", no_argument, NULL, 'b' }, { "noContractions", no_argument, &noContractionsMode, noContractions }, { "dotsIO", no_argument, &dotsIOMode, dotsIO }, { "ucBrl", no_argument, &ucBrlMode, ucBrl }, { "noUndefined", no_argument, &noUndefinedMode, noUndefined }, { "noUndefinedDots", no_argument, &noUndefinedDotsMode, noUndefined }, { "partialTrans", no_argument, &partialTransMode, partialTrans }, { NULL, 0, NULL, 0 }, }; set_program_name(argv[0]); while ((optc = getopt_long(argc, argv, "hvfb", longopts, NULL)) != -1) { switch (optc) { case 'v': version_etc( stdout, program_name, PACKAGE_NAME, VERSION, AUTHORS, (char *)NULL); exit(EXIT_SUCCESS); break; case 'h': print_help(); exit(EXIT_SUCCESS); break; case 'f': forward_flag = 1; break; case 'b': backward_flag = 1; break; case 0: break; default: fprintf(stderr, "Try `%s --help' for more information.\n", program_name); exit(EXIT_FAILURE); break; } } if (noUndefinedDotsMode) { fprintf(stderr, "%s: did you mean --noUndefined?\n", program_name); fprintf(stderr, "Try `%s --help' for more information.\n", program_name); exit(EXIT_FAILURE); } mode |= noContractionsMode | dotsIOMode | ucBrlMode | noUndefinedMode | partialTransMode; if (forward_flag && backward_flag) { fprintf(stderr, "%s: specify either -f or -b but not both\n", program_name); fprintf(stderr, "Try `%s --help' for more information.\n", program_name); exit(EXIT_FAILURE); } if (optind != argc - 1) { if (optind < argc - 1) fprintf(stderr, "%s: extra operand: %s\n", program_name, argv[optind + 1]); else fprintf(stderr, "%s: no table specified\n", program_name); fprintf(stderr, "Try `%s --help' for more information.\n", program_name); exit(EXIT_FAILURE); } table = argv[optind]; if (!lou_getTable(table)) { lou_free(); exit(EXIT_FAILURE); } main_loop(backward_flag, table, mode); lou_free(); exit(EXIT_SUCCESS); }