diff options
Diffstat (limited to 'third_party/liblouis')
18 files changed, 7477 insertions, 1 deletions
diff --git a/third_party/liblouis/README.chromium b/third_party/liblouis/README.chromium index 866732a..3178a46 100644 --- a/third_party/liblouis/README.chromium +++ b/third_party/liblouis/README.chromium @@ -15,4 +15,13 @@ libloius is used in a native client binary in ChromeVox and not linked into Chrome itself. Local Modifications: -... + +* Add manually created liblouis.h. +* On Android: log to logcat. +* Fix backtranslation to not output unicode braille patterns + (svn r838) +* Fix 3 letters in Danish 8 dot braille table, reverting part of svn r238. +* Fix out-of-bounds array access (code removed by upstream). +* Fix compiler warnings (part of svn r856). +* Add tables.json a list of tables with metadata. +* Add a wrapper to expose the library in native client. diff --git a/third_party/liblouis/liblouis_list_tables.py b/third_party/liblouis/liblouis_list_tables.py new file mode 100644 index 0000000..79b0c10 --- /dev/null +++ b/third_party/liblouis/liblouis_list_tables.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python +# Copyright 2013 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import re +import sys + +import json +import optparse + +# Matches the include statement in the braille table files. +INCLUDE_RE = re.compile(r"^\s*include\s+([^#\s]+)") + + +def Error(msg): + print >> sys.stderr, 'liblouis_list_tables: %s' % msg + sys.exit(1) + + +def ToNativePath(pathname): + return os.path.sep.join(pathname.split('/')) + + +def LoadTablesFile(filename): + with open(ToNativePath(filename), 'r') as fh: + return json.load(fh) + + +def FindFile(filename, directories): + for d in directories: + fullname = '/'.join([d, filename]) + if os.path.isfile(ToNativePath(fullname)): + return fullname + Error('File not found: %s' % filename) + + +def GetIncludeFiles(filename): + result = [] + with open(ToNativePath(filename), 'r') as fh: + for line in fh.xreadlines(): + match = INCLUDE_RE.match(line) + if match: + result.append(match.group(1)) + return result + + +def ProcessFile(output_set, filename, directories): + fullname = FindFile(filename, directories) + if fullname in output_set: + return + output_set.add(fullname) + for include_file in GetIncludeFiles(fullname): + ProcessFile(output_set, include_file, directories) + + +def DoMain(argv): + "Entry point for gyp's pymod_do_main command." + parser = optparse.OptionParser() + # Give a clearer error message when this is used as a module. + parser.prog = 'liblouis_list_tables' + parser.set_usage('usage: %prog [options] listfile') + parser.add_option('-D', '--directory', dest='directories', + action='append', help='Where to search for table files') + (options, args) = parser.parse_args(argv) + + if len(args) != 1: + parser.error('Expecting exactly one argument') + if not options.directories: + parser.error('At least one --directory option must be specified') + + tables = LoadTablesFile(args[0]) + output_set = set() + for table in tables: + ProcessFile(output_set, table['fileName'], options.directories) + return '\n'.join(output_set) + + +def main(argv): + print DoMain(argv[1:]) + + +if __name__ == '__main__': + try: + sys.exit(main(sys.argv)) + except KeyboardInterrupt: + Error('interrupted') diff --git a/third_party/liblouis/liblouis_untrusted.gyp b/third_party/liblouis/liblouis_untrusted.gyp new file mode 100644 index 0000000..530425f --- /dev/null +++ b/third_party/liblouis/liblouis_untrusted.gyp @@ -0,0 +1,183 @@ +# Copyright 2013 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +{ + 'variables': { + 'braille_test_data_dir': '<(PRODUCT_DIR)/chromevox_test_data/braille', + 'braille_chromevox_dir': '<(PRODUCT_DIR)/resources/chromeos/chromevox/chromevox/background/braille', + 'table_files': [ + '>!@pymod_do_main(liblouis_list_tables -D overrides/tables -D src/tables tables.json)', + ], + }, + # x86 targets build both 32 and 64 bit binaries by default. We only need + # the one that matches our target architecture. + 'target_defaults': { + 'conditions': [ + ['target_arch=="ia32"', { + 'variables': { + 'enable_x86_64': 0, + }, + }], + ['target_arch=="x64"', { + 'variables': { + 'enable_x86_32': 0, + }, + }], + ], + }, + 'includes': [ + '../../build/common_untrusted.gypi', + ], + 'conditions': [ + ['disable_nacl==0 and disable_nacl_untrusted==0', { + 'targets': [ + { + 'target_name': 'liblouis_untrusted', + 'type': 'none', + 'variables': { + 'nacl_untrusted_build': 1, + 'nlib_target': 'liblouis_untrusted.a', + 'build_newlib': 1, + }, + 'include_dirs': [ + 'overrides/liblouis', + 'src/liblouis', + '.', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + 'overrides', + ], + }, + 'sources': [ + 'overrides/liblouis/config.h', + 'overrides/liblouis/liblouis.h', + 'overrides/liblouis/compileTranslationTable.c', + 'src/liblouis/lou_backTranslateString.c', + 'src/liblouis/lou_translateString.c', + 'src/liblouis/transcommon.ci', + 'src/liblouis/wrappers.c', + ], + 'dependencies': [ + '../../native_client/tools.gyp:prep_toolchain', + ], + }, + + { + 'target_name': 'liblouis_nacl_wrapper_untrusted', + 'type': 'none', + 'variables': { + 'nacl_untrusted_build': 1, + 'nexe_target': 'liblouis_nacl', + 'out_newlib64': '<(braille_test_data_dir)/>(nexe_target)_x86_64.nexe', + 'out_newlib32': '<(braille_test_data_dir)/>(nexe_target)_x86_32.nexe', + 'out_newlib_arm': '<(braille_test_data_dir)/>(nexe_target)_arm.nexe', + 'build_newlib': 1, + 'extra_args': [ + '--strip-debug', + ], + 'nmf': '<(braille_test_data_dir)/>(nexe_target).nmf', + 'target_conditions': [ + ['enable_x86_64==1', { + 'nexe_files': ['>(out_newlib64)'], + }], + ['enable_x86_32==1', { + 'nexe_files': ['>(out_newlib32)'], + }], + ['enable_arm==1', { + 'nexe_files': ['>(out_newlib_arm)'], + }], + ], + }, + 'sources': [ + 'nacl_wrapper/liblouis_instance.h', + 'nacl_wrapper/liblouis_instance.cc', + 'nacl_wrapper/liblouis_module.h', + 'nacl_wrapper/liblouis_module.cc', + 'nacl_wrapper/liblouis_wrapper.h', + 'nacl_wrapper/liblouis_wrapper.cc', + 'nacl_wrapper/translation_params.h', + 'nacl_wrapper/translation_result.h', + ], + 'link_flags': [ + '-lppapi', + '-lppapi_cpp', + '-llouis_untrusted', + '-ljsoncpp_untrusted', + '-lpthread', + '-lnacl_io', + ], + 'dependencies': [ + '../../native_client/src/untrusted/nacl/nacl.gyp:nacl_lib', + '../../native_client/tools.gyp:prep_toolchain', + '../../native_client_sdk/native_client_sdk_untrusted.gyp:nacl_io_untrusted', + '../../ppapi/native_client/native_client.gyp:ppapi_lib', + '../../ppapi/ppapi_untrusted.gyp:ppapi_cpp_lib', + '../jsoncpp/jsoncpp_untrusted.gyp:jsoncpp_untrusted', + 'liblouis_untrusted', + ], + 'actions': [ + { + 'action_name': 'Generate NEWLIB NMF', + 'inputs': [ + '>@(nexe_files)', + ], + 'outputs': ['>(nmf)'], + 'action': [ + 'python', + '<(DEPTH)/native_client_sdk/src/tools/create_nmf.py', + '>@(_inputs)', + '--output=>(nmf)', + ], + }, + ], + # Copy specific files into the product directory to avoid + # copying over the unstripped binary file. + 'copies': [ + { + 'destination': '<(braille_chromevox_dir)', + 'files': [ + '<(nmf)', + '>@(nexe_files)', + 'tables.json', + ], + }, + { + 'destination': '<(braille_chromevox_dir)/tables', + 'files': [ + '<@(table_files)', + ], + }, + ], + }, + { + 'target_name': 'liblouis_test_data', + 'type': 'none', + 'variables': { + 'test_extension_dir': '<(DEPTH)/chrome/test/data/chromeos/liblouis_nacl', + }, + 'dependencies': [ + 'liblouis_nacl_wrapper_untrusted', + ], + 'copies': [ + { + 'destination': '<(braille_test_data_dir)', + 'files': [ + 'tables.json', + '<(test_extension_dir)/manifest.json', + '<(test_extension_dir)/test.js', + ], + }, + { + 'destination': '<(braille_test_data_dir)/tables', + 'files': [ + '<@(table_files)', + ], + }, + ], + }, + ], + }], + ], +} diff --git a/third_party/liblouis/nacl_wrapper/liblouis_instance.cc b/third_party/liblouis/nacl_wrapper/liblouis_instance.cc new file mode 100644 index 0000000..e92b9a0 --- /dev/null +++ b/third_party/liblouis/nacl_wrapper/liblouis_instance.cc @@ -0,0 +1,323 @@ +// Copyright 2013 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#include "liblouis_instance.h" + +#include <cstdio> +#include <cstring> +#include <sys/mount.h> +#include <vector> + +#include "nacl_io/nacl_io.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/cpp/module.h" + +#include "translation_result.h" + +namespace { + +static const char kHexadecimalChars[] = "0123456789abcdef"; + +// Converts a vector of bytes into a (lowercase) hexadecimal string. +static void BytesToHexString(const std::vector<unsigned char>& bytes, + std::string* out) { + std::string hex; + hex.reserve(bytes.size() * 2); + for (size_t i = 0; i < bytes.size(); ++i) { + unsigned char byte = bytes[i]; + hex.push_back(kHexadecimalChars[byte >> 4]); + hex.push_back(kHexadecimalChars[byte & 0x0f]); + } + out->swap(hex); +} + +// Converts a hexadecimal string to a vector of bytes. +// Returns false on failure. +static bool HexStringToBytes(const std::string& hex, + std::vector<unsigned char>* out) { + if (hex.size() % 2 != 0) { + return false; + } + + std::vector<unsigned char> bytes; + bytes.reserve(hex.size() / 2); + for (size_t i = 0; i < hex.size(); i += 2) { + unsigned char byte; + char ch = hex[i]; + if ('0' <= ch && ch <= '9') { + byte = (ch - '0') << 4; + } else if ('a' <= ch && ch <= 'f') { + byte = (ch - 'a' + 10) << 4; + } else if ('A' <= ch && ch <= 'F') { + byte = (ch - 'A' + 10) << 4; + } else { + return false; + } + ch = hex[i+1]; + if ('0' <= ch && ch <= '9') { + byte |= ch - '0'; + } else if ('a' <= ch && ch <= 'f') { + byte |= ch - 'a' + 10; + } else if ('A' <= ch && ch <= 'F') { + byte |= ch - 'A' + 10; + } else { + return false; + } + bytes.push_back(byte); + } + out->swap(bytes); + return true; +} + +template <typename T> +static void CopyVectorToJson(const std::vector<T>& vec, Json::Value* out) { + Json::Value result(Json::arrayValue); + result.resize(vec.size()); + for (size_t i = 0; i < vec.size(); ++i) { + result[i] = vec[i]; + } + out->swap(result); +} + +} // namespace + + +namespace liblouis_nacl { + +// Well-known strings used for configuration. +static const char kTablesDirKey[] = "tablesdir"; +static const char kTablesDirDefault[] = "tables"; + +// Well-known strings used in JSON messages. +static const char kCommandKey[] = "command"; +static const char kMessageIdKey[] = "message_id"; +static const char kInReplyToKey[] = "in_reply_to"; +static const char kErrorKey[] = "error"; +static const char kTableNameKey[] = "table_name"; +static const char kSuccessKey[] = "success"; +static const char kTextKey[] = "text"; +static const char kCellsKey[] = "cells"; +static const char kCursorPositionKey[] = "cursor_position"; +static const char kTextToBrailleKey[] = "text_to_braille"; +static const char kBrailleToTextKey[] = "braille_to_text"; +static const char kCheckTableCommand[] = "CheckTable"; +static const char kTranslateCommand[] = "Translate"; +static const char kBackTranslateCommand[] = "BackTranslate"; + +LibLouisInstance::LibLouisInstance(PP_Instance instance) + : pp::Instance(instance), liblouis_thread_(this), cc_factory_(this) {} + +LibLouisInstance::~LibLouisInstance() {} + +bool LibLouisInstance::Init(uint32_t argc, const char* argn[], + const char* argv[]) { + const char* tables_dir = kTablesDirDefault; + for (size_t i = 0; i < argc; ++i) { + if (strcmp(argn[i], kTablesDirKey) == 0) { + tables_dir = argv[i]; + } + } + + nacl_io_init_ppapi(pp_instance(), + pp::Module::Get()->get_browser_interface()); + if (mount(tables_dir, liblouis_.tables_dir(), "httpfs", 0, "") != 0) { + // TODO(jbroman): report this error. + return false; + } + + return liblouis_thread_.Start(); +} + +void LibLouisInstance::HandleMessage(const pp::Var& var_message) { + if (!var_message.is_string()) { + PostError("expected message to be a JSON string"); + return; + } + + Json::Value message; + Json::Reader reader; + bool parsed = reader.parse(var_message.AsString(), + message, false /* collectComments */); + if (!parsed) { + PostError("expected message to be a JSON string"); + return; + } + + Json::Value message_id = message[kMessageIdKey]; + if (!message_id.isString()) { + PostError("expected message_id string"); + return; + } + std::string message_id_str = message_id.asString(); + + Json::Value command = message[kCommandKey]; + if (!command.isString()) { + PostError("expected command string", message_id_str); + return; + } + + std::string command_str = command.asString(); + if (command_str == kCheckTableCommand) { + HandleCheckTable(message, message_id_str); + } else if (command_str == kTranslateCommand) { + HandleTranslate(message, message_id_str); + } else if (command_str == kBackTranslateCommand) { + HandleBackTranslate(message, message_id_str); + } else { + PostError("unknown command", message_id_str); + } +} + +void LibLouisInstance::PostReply(Json::Value reply, + const std::string& in_reply_to) { + Json::FastWriter writer; + reply[kInReplyToKey] = in_reply_to; + pp::Var var_reply(writer.write(reply)); + PostMessage(var_reply); +} + +void LibLouisInstance::PostError(const std::string& error_message) { + Json::FastWriter writer; + Json::Value reply(Json::objectValue); + reply[kErrorKey] = error_message; + pp::Var var_reply(writer.write(reply)); + PostMessage(var_reply); +} + +void LibLouisInstance::PostError(const std::string& error_message, + const std::string& in_reply_to) { + Json::FastWriter writer; + Json::Value reply(Json::objectValue); + reply[kErrorKey] = error_message; + reply[kInReplyToKey] = in_reply_to; + reply[kSuccessKey] = false; + pp::Var var_reply(writer.write(reply)); + PostMessage(var_reply); +} + +void LibLouisInstance::HandleCheckTable(const Json::Value& message, + const std::string& message_id) { + Json::Value table_name = message[kTableNameKey]; + if (!table_name.isString()) { + PostError("expected table_name to be a string", message_id); + return; + } + PostWorkToBackground(cc_factory_.NewCallback( + &LibLouisInstance::CheckTableInBackground, + table_name.asString(), message_id)); +} + +void LibLouisInstance::CheckTableInBackground(int32_t result, + const std::string& table_name, const std::string& message_id) { + if (result != PP_OK) { + PostError("failed to transfer call to background thread", message_id); + return; + } + bool success = liblouis_.CheckTable(table_name); + Json::Value reply(Json::objectValue); + reply[kSuccessKey] = success; + PostReply(reply, message_id); +} + +void LibLouisInstance::HandleTranslate(const Json::Value& message, + const std::string& message_id) { + Json::Value table_name = message[kTableNameKey]; + Json::Value text = message[kTextKey]; + Json::Value cursor_position = message[kCursorPositionKey]; + if (!table_name.isString()) { + PostError("expected table_name to be a string", message_id); + return; + } else if (!text.isString()) { + PostError("expected text to be a string", message_id); + return; + } else if (!cursor_position.isNull() && !cursor_position.isIntegral()) { + PostError("expected cursor_position to be null or integral", message_id); + return; + } + TranslationParams params; + params.table_name = table_name.asString(); + params.text = text.asString(); + params.cursor_position = cursor_position.isIntegral() ? + cursor_position.asInt() : -1; + PostWorkToBackground(cc_factory_.NewCallback( + &LibLouisInstance::TranslateInBackground, + params, message_id)); +} + +void LibLouisInstance::TranslateInBackground(int32_t result, + const TranslationParams& params, const std::string& message_id) { + if (result != PP_OK) { + PostError("failed to transfer call to background thread", message_id); + return; + } + TranslationResult translation_result; + bool success = liblouis_.Translate(params, &translation_result); + Json::Value reply(Json::objectValue); + reply[kSuccessKey] = success; + if (success) { + std::string hex_cells; + Json::Value text_to_braille; + Json::Value braille_to_text; + BytesToHexString(translation_result.cells, &hex_cells); + CopyVectorToJson(translation_result.text_to_braille, &text_to_braille); + CopyVectorToJson(translation_result.braille_to_text, &braille_to_text); + reply[kCellsKey] = hex_cells; + reply[kTextToBrailleKey] = text_to_braille; + reply[kBrailleToTextKey] = braille_to_text; + if (translation_result.cursor_position >= 0) { + reply[kCursorPositionKey] = translation_result.cursor_position; + } + } + PostReply(reply, message_id); +} + +void LibLouisInstance::HandleBackTranslate(const Json::Value& message, + const std::string& message_id) { + Json::Value table_name = message[kTableNameKey]; + Json::Value cells = message[kCellsKey]; + if (!table_name.isString()) { + PostError("expected table_name to be a string", message_id); + return; + } else if (!cells.isString()) { + PostError("expected cells to be a string", message_id); + return; + } + std::vector<unsigned char> cells_vector; + if (!HexStringToBytes(cells.asString(), &cells_vector)) { + PostError("expected cells to be a valid hexadecimal string", message_id); + return; + } + PostWorkToBackground(cc_factory_.NewCallback( + &LibLouisInstance::BackTranslateInBackground, + table_name.asString(), cells_vector, message_id)); +} + +void LibLouisInstance::BackTranslateInBackground(int32_t result, + const std::string& table_name, const std::vector<unsigned char>& cells, + const std::string& message_id) { + if (result != PP_OK) { + PostError("failed to transfer call to background thread", message_id); + return; + } + std::string text; + bool success = liblouis_.BackTranslate(table_name, cells, &text); + Json::Value reply(Json::objectValue); + reply[kSuccessKey] = success; + if (success) { + reply[kTextKey] = text; + } + PostReply(reply, message_id); +} + +} // namespace liblouis_nacl diff --git a/third_party/liblouis/nacl_wrapper/liblouis_instance.h b/third_party/liblouis/nacl_wrapper/liblouis_instance.h new file mode 100644 index 0000000..d202a76 --- /dev/null +++ b/third_party/liblouis/nacl_wrapper/liblouis_instance.h @@ -0,0 +1,92 @@ +// Copyright 2013 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#ifndef LIBLOUIS_NACL_LIBLOUIS_INSTANCE_H_ +#define LIBLOUIS_NACL_LIBLOUIS_INSTANCE_H_ + +#include <string> + +#include "base/basictypes.h" +#include "json/json.h" +#include "liblouis_wrapper.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/cpp/completion_callback.h" +#include "ppapi/cpp/instance.h" +#include "ppapi/cpp/message_loop.h" +#include "ppapi/cpp/var.h" +#include "ppapi/utility/completion_callback_factory.h" +#include "ppapi/utility/threading/simple_thread.h" +#include "translation_params.h" + +namespace liblouis_nacl { + +class LibLouisInstance : public pp::Instance { + public: + explicit LibLouisInstance(PP_Instance instance); + virtual ~LibLouisInstance(); + + virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]); + virtual void HandleMessage(const pp::Var& var_message); + + private: + // Post work to the background (liblouis) thread. + int32_t PostWorkToBackground(const pp::CompletionCallback& callback) { + return liblouis_thread_.message_loop().PostWork(callback); + } + + // Encodes a message as JSON and sends it over to JavaScript. + void PostReply(Json::Value reply, const std::string& in_reply_to); + + // Posts an error response to JavaScript. + void PostError(const std::string& error); + + // Posts an error response to JavaScript, with the message ID of the call + // which caused it. + void PostError(const std::string& error, const std::string& in_reply_to); + + // Parses and executes a table check command. + void HandleCheckTable(const Json::Value& message, + const std::string& message_id); + + // Called to check a table on a background thread. + void CheckTableInBackground(int32_t result, const std::string& table_name, + const std::string& message_id); + + // Parses and executes a translation command. + void HandleTranslate(const Json::Value& message, + const std::string& message_id); + + // Called to translate text on a background thread. + void TranslateInBackground(int32_t result, const TranslationParams& params, + const std::string& message_id); + + // Parses and executes a back translation command. + void HandleBackTranslate(const Json::Value& message, + const std::string& message_id); + + // Called to back-translate text on a background thread. + void BackTranslateInBackground(int32_t result, + const std::string& table_name, const std::vector<unsigned char>& cells, + const std::string& message_id); + + LibLouisWrapper liblouis_; + pp::SimpleThread liblouis_thread_; + pp::CompletionCallbackFactory<LibLouisInstance> cc_factory_; + + DISALLOW_COPY_AND_ASSIGN(LibLouisInstance); +}; + +} // namespace liblouis_nacl + +#endif // LIBLOUIS_NACL_LIBLOUIS_INSTANCE_H_ diff --git a/third_party/liblouis/nacl_wrapper/liblouis_module.cc b/third_party/liblouis/nacl_wrapper/liblouis_module.cc new file mode 100644 index 0000000..1c0170d2 --- /dev/null +++ b/third_party/liblouis/nacl_wrapper/liblouis_module.cc @@ -0,0 +1,49 @@ +// Copyright 2013 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#include "liblouis_module.h" + +#include <cstddef> + +#include "liblouis_instance.h" + +namespace liblouis_nacl { + +LibLouisModule::LibLouisModule() : pp::Module() {} + +LibLouisModule::~LibLouisModule() {} + +pp::Instance* LibLouisModule::CreateInstance(PP_Instance instance) { + static bool created = false; + if (!created) { + created = true; + return new LibLouisInstance(instance); + } + return NULL; +} + +} // namespace liblouis_nacl + +namespace pp { + +Module* CreateModule() { + static bool created = false; + if (!created) { + created = true; + return new liblouis_nacl::LibLouisModule(); + } + return NULL; +} + +} // namespace pp diff --git a/third_party/liblouis/nacl_wrapper/liblouis_module.h b/third_party/liblouis/nacl_wrapper/liblouis_module.h new file mode 100644 index 0000000..09d2493 --- /dev/null +++ b/third_party/liblouis/nacl_wrapper/liblouis_module.h @@ -0,0 +1,39 @@ +// Copyright 2013 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#ifndef LIBLOUIS_NACL_LIBLOUIS_MODULE_H_ +#define LIBLOUIS_NACL_LIBLOUIS_MODULE_H_ + +#include "base/basictypes.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/cpp/instance.h" +#include "ppapi/cpp/module.h" + +namespace liblouis_nacl { + +// Native Client module which contains liblouis. +class LibLouisModule : public pp::Module { + public: + LibLouisModule(); + virtual ~LibLouisModule(); + + virtual pp::Instance* CreateInstance(PP_Instance instance); + + private: + DISALLOW_COPY_AND_ASSIGN(LibLouisModule); +}; + +} // namespace liblouis_nacl + +#endif // LIBLOUIS_NACL_LIBLOUIS_MODULE_H_ diff --git a/third_party/liblouis/nacl_wrapper/liblouis_wrapper.cc b/third_party/liblouis/nacl_wrapper/liblouis_wrapper.cc new file mode 100644 index 0000000..390e192 --- /dev/null +++ b/third_party/liblouis/nacl_wrapper/liblouis_wrapper.cc @@ -0,0 +1,204 @@ +// Copyright 2013 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#include "liblouis_wrapper.h" + +#include <cstddef> + +#include "liblouis/liblouis.h" + +namespace { + +// Decodes UTF-8 into 16-bit wide characters. +// This implementation is very permissive and may miss encoding errors. +// It ignores charaters which are not in the Unicode Basic Multilingual Plane. +// TODO(jbroman): Handle more than BMP if liblouis changes to accept UTF-16. +static bool DecodeUtf8(const std::string& in, std::vector<widechar>* out) { + int len = in.length(); + std::vector<widechar> result; + result.reserve(len); + int i = 0; + while (i < len) { + int ch = static_cast<unsigned char>(in[i++]); + widechar cp; + if ((ch & 0x80) == 0x00) { // U+0000 - U+007F + cp = ch; + } else if ((ch & 0xe0) == 0xc0 && i < len) { // U+0080 - U+07FF + cp = (ch & 0x1f) << 6; + ch = static_cast<unsigned char>(in[i++]); + cp |= (ch & 0x3f); + } else if ((ch & 0xf0) == 0xe0 && i+1 < len) { // U+0800 - U+FFFF + cp = (ch & 0x0f) << 12; + ch = static_cast<unsigned char>(in[i++]); + cp |= (ch & 0x3f) << 6; + ch = static_cast<unsigned char>(in[i++]); + cp |= (ch & 0x3f); + } else if ((ch & 0xf8) == 0xf0 && i+2 < len) { // U+10000 - U+1FFFFF + i += 3; + continue; + } else if ((ch & 0xfc) == 0xf8 && i+3 < len) { // U+200000 - U+3FFFFFF + i += 4; + continue; + } else if ((ch & 0xfe) == 0xfc && i+4 < len) { // U+4000000 - U+7FFFFFFF + i += 5; + continue; + } else { + // Invalid first code point. + return false; + } + result.push_back(cp); + } + out->swap(result); + return true; +} + +// Encodes 16-bit wide characters into UTF-8. +// This implementation is very permissive and may miss invalid code points in +// its input. +// TODO(jbroman): Handle more than BMP if widechar ever becomes larger. +static bool EncodeUtf8(const std::vector<widechar>& in, std::string* out) { + std::string result; + result.reserve(in.size() * 2); + for (std::vector<widechar>::const_iterator it = in.begin(); it != in.end(); + ++it) { + unsigned int cp = *it; + if (cp <= 0x007f) { // U+0000 - U+007F + result.push_back(static_cast<char>(cp)); + } else if (cp <= 0x07ff) { // U+0080 - U+07FF + result.push_back(static_cast<char>(0xc0 | ((cp >> 6) & 0x1f))); + result.push_back(static_cast<char>(0x80 | (cp & 0x3f))); + } else if (cp <= 0xffff) { // U+0800 - U+FFFF + result.push_back(static_cast<char>(0xe0 | ((cp >> 12) & 0x0f))); + result.push_back(static_cast<char>(0x80 | ((cp >> 6) & 0x3f))); + result.push_back(static_cast<char>(0x80 | (cp & 0x3f))); + } else { + // This can't happen if widechar is 16 bits wide. + // TODO(jbroman): assert this + } + } + out->swap(result); + return true; +} + +} // namespace + + +namespace liblouis_nacl { + +LibLouisWrapper::LibLouisWrapper() { + char data_path[] = "/"; // Needed because lou_setDataPath takes a char*. + lou_setDataPath(data_path); +} + +LibLouisWrapper::~LibLouisWrapper() { + lou_free(); +} + +const char* LibLouisWrapper::tables_dir() const { + return "/liblouis/tables"; +} + +bool LibLouisWrapper::CheckTable(const std::string& table_name) { + return lou_getTable(table_name.c_str()) != NULL; +} + +bool LibLouisWrapper::Translate(const TranslationParams& params, + TranslationResult* out) { + // Convert the character set of the input text. + std::vector<widechar> inbuf; + if (!DecodeUtf8(params.text, &inbuf)) { + // TODO(jbroman): log this + return false; + } + + int inlen = inbuf.size(); + int outlen = inlen * 2; // TODO(jbroman): choose this size more accurately. + std::vector<widechar> outbuf(outlen); + std::vector<int> text_to_braille(inlen); + std::vector<int> braille_to_text(outlen); + + // Compute the cursor position pointer to pass to liblouis. + int out_cursor_position; + int* out_cursor_position_ptr; + if (params.cursor_position < 0) { + out_cursor_position = -1; + out_cursor_position_ptr = NULL; + } else { + out_cursor_position = params.cursor_position; + out_cursor_position_ptr = &out_cursor_position; + } + + // Invoke liblouis. + int result = lou_translate(params.table_name.c_str(), + &inbuf[0], &inlen, &outbuf[0], &outlen, + NULL /* typeform */, NULL /* spacing */, + &text_to_braille[0], &braille_to_text[0], + out_cursor_position_ptr, dotsIO /* mode */); + if (result == 0) { + // TODO(jbroman): log this + return false; + } + + // Massage the result. + std::vector<unsigned char> cells; + cells.reserve(outlen); + for (int i = 0; i < outlen; i++) { + cells.push_back(outbuf[i]); + } + braille_to_text.resize(outlen); + + // Return the translation result. + out->cells.swap(cells); + out->text_to_braille.swap(text_to_braille); + out->braille_to_text.swap(braille_to_text); + out->cursor_position = out_cursor_position; + return true; +} + +bool LibLouisWrapper::BackTranslate(const std::string& table_name, + const std::vector<unsigned char>& cells, std::string* out) { + std::vector<widechar> inbuf; + inbuf.reserve(cells.size()); + for (std::vector<unsigned char>::const_iterator it = cells.begin(); + it != cells.end(); ++it) { + // Set the high-order bit to prevent liblouis from dropping empty cells. + inbuf.push_back(*it | 0x8000); + } + int inlen = inbuf.size(); + int outlen = inlen * 2; // TODO(jbroman): choose this size more accurately. + std::vector<widechar> outbuf(outlen); + + // Invoke liblouis. + int result = lou_backTranslateString(table_name.c_str(), + &inbuf[0], &inlen, &outbuf[0], &outlen, + NULL /* typeform */, NULL /* spacing */, dotsIO /* mode */); + if (result == 0) { + // TODO(njbroman): log this + return false; + } + + // Massage the result. + outbuf.resize(outlen); + std::string text; + if (!EncodeUtf8(outbuf, &text)) { + // TODO(jbroman): log this + return false; + } + + // Return the back translation result. + out->swap(text); + return true; +} + +} // namespace liblouis_nacl diff --git a/third_party/liblouis/nacl_wrapper/liblouis_wrapper.h b/third_party/liblouis/nacl_wrapper/liblouis_wrapper.h new file mode 100644 index 0000000..dac2b4a --- /dev/null +++ b/third_party/liblouis/nacl_wrapper/liblouis_wrapper.h @@ -0,0 +1,58 @@ +// Copyright 2013 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#ifndef LIBLOUIS_NACL_LIBLOUIS_WRAPPER_H_ +#define LIBLOUIS_NACL_LIBLOUIS_WRAPPER_H_ + +#include <string> + +#include "base/basictypes.h" +#include "translation_params.h" +#include "translation_result.h" + +namespace liblouis_nacl { + +// Encapsulates logic for interacting (synchronously) with liblouis. +// +// This class is *not* thread-safe; it should be used only from one thread. +// Since the underlying library is not reentrant, only one instance should be +// in use at a time. +// +// All input strings should be represented in UTF-8. +class LibLouisWrapper { + public: + LibLouisWrapper(); + ~LibLouisWrapper(); + + // Returns one of the paths where tables may be searched for. + const char* tables_dir() const; + + // Loads, checks, and compiles the requested table. + // Returns true on success. + bool CheckTable(const std::string& table_name); + + // Translates the given text and cursor position into braille. + bool Translate(const TranslationParams& params, TranslationResult* out); + + // Translates the given braille cells into text. + bool BackTranslate(const std::string& table_name, + const std::vector<unsigned char>& cells, std::string* out); + + private: + DISALLOW_COPY_AND_ASSIGN(LibLouisWrapper); +}; + +} // namespace liblouis_nacl + +#endif // LIBLOUIS_NACL_LIBLOUIS_WRAPPER_H_ diff --git a/third_party/liblouis/nacl_wrapper/liblouis_wrapper_browsertest.cc b/third_party/liblouis/nacl_wrapper/liblouis_wrapper_browsertest.cc new file mode 100644 index 0000000..bc2fda2 --- /dev/null +++ b/third_party/liblouis/nacl_wrapper/liblouis_wrapper_browsertest.cc @@ -0,0 +1,18 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/base_paths.h" +#include "base/files/file_path.h" +#include "base/path_service.h" +#include "chrome/browser/extensions/extension_apitest.h" + +class LibLouisWrapperTest : public ExtensionApiTest { +}; + +IN_PROC_BROWSER_TEST_F(LibLouisWrapperTest, LibLouisLoad) { + ASSERT_TRUE(PathService::Get(base::DIR_EXE, &test_data_dir_)); + test_data_dir_ = test_data_dir_.AppendASCII("chromevox_test_data"); + LOG(ERROR) << "Test data dir: " << test_data_dir_.MaybeAsASCII(); + ASSERT_TRUE(RunExtensionTest("braille")) << message_; +} diff --git a/third_party/liblouis/nacl_wrapper/translation_params.h b/third_party/liblouis/nacl_wrapper/translation_params.h new file mode 100644 index 0000000..3505520 --- /dev/null +++ b/third_party/liblouis/nacl_wrapper/translation_params.h @@ -0,0 +1,32 @@ +// Copyright 2013 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#ifndef LIBLOUIS_NACL_TRANSLATION_PARAMS_H_ +#define LIBLOUIS_NACL_TRANSLATION_PARAMS_H_ + +#include <string> + +namespace liblouis_nacl { + +// Struct containing the parameters of translation. +struct TranslationParams { + public: + std::string table_name; + std::string text; + int cursor_position; +}; + +} + +#endif // LIBLOUIS_NACL_TRANSLATION_PARAMS_H_ diff --git a/third_party/liblouis/nacl_wrapper/translation_result.h b/third_party/liblouis/nacl_wrapper/translation_result.h new file mode 100644 index 0000000..34a7beb --- /dev/null +++ b/third_party/liblouis/nacl_wrapper/translation_result.h @@ -0,0 +1,33 @@ +// Copyright 2013 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#ifndef LIBLOUIS_NACL_TRANSLATION_RESULT_H_ +#define LIBLOUIS_NACL_TRANSLATION_RESULT_H_ + +#include <vector> + +namespace liblouis_nacl { + +// Struct containing the result of translation. +struct TranslationResult { + public: + std::vector<unsigned char> cells; + std::vector<int> text_to_braille; + std::vector<int> braille_to_text; + int cursor_position; +}; + +} + +#endif // LIBLOUIS_NACL_TRANSLATION_RESULT_H_ diff --git a/third_party/liblouis/overrides/liblouis/compileTranslationTable.c b/third_party/liblouis/overrides/liblouis/compileTranslationTable.c new file mode 100644 index 0000000..8af65f2 --- /dev/null +++ b/third_party/liblouis/overrides/liblouis/compileTranslationTable.c @@ -0,0 +1,5219 @@ +/* liblouis Braille Translation and Back-Translation +Library + + Based on the Linux screenreader BRLTTY, copyright (C) 1999-2006 by + The BRLTTY Team + + Copyright (C) 2004, 2005, 2006 + ViewPlus Technologies, Inc. www.viewplus.com + and + JJB Software, Inc. www.jjb-software.com + All rights reserved + + This file is free software; you can redistribute it and/or modify it + under the terms of the Lesser or Library GNU General Public License + as published by the + Free Software Foundation; either version 3, or (at your option) any + later version. + + This file 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 + Library GNU General Public License for more details. + + You should have received a copy of the Library GNU General Public + License along with this program; see the file COPYING. If not, write to + the Free Software Foundation, 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + Maintained by John J. Boyer john.boyer@jjb-software.com + */ + +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <ctype.h> +//#include <unistd.h> + +#include "louis.h" +#include "config.h" + +#define QUOTESUB 28 /*Stand-in for double quotes in strings */ + + +/* Contributed by Michel Such <michel.such@free.fr */ +#ifdef _WIN32 + +/* Adapted from BRLTTY code (see sys_progs_wihdows.h) */ + +#include <shlobj.h> + +static void +noMemory (void) +{ + printf ("Insufficient memory: %s", strerror (errno), "\n"); + exit (3); +} + +static void * +reallocWrapper (void *address, size_t size) +{ + if (!(address = realloc (address, size)) && size) + noMemory (); + return address; +} + +static char * +strdupWrapper (const char *string) +{ + char *address = strdup (string); + if (!address) + noMemory (); + return address; +} + +char *EXPORT_CALL +lou_getProgramPath (void) +{ + char *path = NULL; + HMODULE handle; + + if ((handle = GetModuleHandle (NULL))) + { + size_t size = 0X80; + char *buffer = NULL; + + while (1) + { + buffer = reallocWrapper (buffer, size <<= 1); + + { + DWORD length = GetModuleFileName (handle, buffer, size); + + if (!length) + { + printf ("GetModuleFileName\n"); + exit (3); + 3; + } + + if (length < size) + { + buffer[length] = 0; + path = strdupWrapper (buffer); + + while (length > 0) + if (path[--length] == '\\') + break; + + strncpy (path, path, length + 1); + path[length + 1] = '\0'; + break; + } + } + } + + free (buffer); + } + else + { + printf ("GetModuleHandle\n"); + exit (3); + } + + return path; +} + +#define PATH_SEP ';' +#define DIR_SEP '\\' +#else +#define PATH_SEP ':' +#define DIR_SEP '/' +#endif +/* End of MS contribution */ + +#ifdef ANDROID +#include "android/log.h" +#endif + +/* The folowing variables and functions make it possible to specify the +* path on which all tables for liblouis and all files for liblouisutdml, +* in their proper directories, will be found. +*/ + +static char dataPath[MAXSTRING]; +static char *dataPathPtr; + +char *EXPORT_CALL +lou_setDataPath (char *path) +{ + dataPathPtr = NULL; + if (path == NULL) + return NULL; + strcpy (dataPath, path); + dataPathPtr = dataPath; + return dataPathPtr; +} + +char *EXPORT_CALL +lou_getDataPath () +{ + return dataPathPtr; +} + +/* End of dataPath code.*/ + +static char tablePath[MAXSTRING]; +static FILE *logFile = NULL; +static char initialLogFileName[256]; + +void EXPORT_CALL +lou_logFile (const char *fileName) +{ + if (fileName == NULL || fileName[0] == 0) + return; + if (initialLogFileName[0] == 0) + strcpy (initialLogFileName, fileName); + logFile = fopen (fileName, "wb"); + if (logFile == NULL && initialLogFileName[0] != 0) + logFile = fopen (initialLogFileName, "wb"); + if (logFile == NULL) + { + fprintf (stderr, "Cannot open log file %s\n", fileName); + logFile = stderr; + } +} + +void EXPORT_CALL +lou_logPrint (char *format, ...) +{ +#ifndef __SYMBIAN32__ + va_list argp; + if (format == NULL) + return; + if (logFile == NULL && initialLogFileName[0] != 0) + logFile = fopen (initialLogFileName, "wb"); + if (logFile == NULL) + logFile = stderr; + va_start (argp, format); +#ifndef ANDROID + vfprintf (logFile, format, argp); + fprintf (logFile, "\n"); +#else + __android_log_vprint(ANDROID_LOG_DEBUG, "liblouis", format, argp); +#endif + va_end (argp); +#endif +} + +void EXPORT_CALL +lou_logEnd (void) +{ + if (logFile != NULL) + fclose (logFile); + logFile = NULL; +} + +static int +eqasc2uni (const unsigned char *a, const widechar * b, const int len) +{ + int k; + for (k = 0; k < len; k++) + if ((widechar) a[k] != b[k]) + return 0; + return 1; +} + +typedef struct +{ + widechar length; + widechar chars[MAXSTRING]; +} +CharsString; + +static int errorCount; +static int warningCount; +static TranslationTableHeader *table; +static TranslationTableOffset tableSize; +static TranslationTableOffset tableUsed; + +static const char *characterClassNames[] = { + "space", + "letter", + "digit", + "punctuation", + "uppercase", + "lowercase", + "math", + "sign", + "litdigit", + NULL +}; + +struct CharacterClass +{ + struct CharacterClass *next; + TranslationTableCharacterAttributes attribute; + widechar length; + widechar name[1]; +}; +static struct CharacterClass *characterClasses; +static TranslationTableCharacterAttributes characterClassAttribute; + +static const char *opcodeNames[CTO_None] = { + "include", + "locale", + "undefined", + "capsign", + "begcaps", + "lenbegcaps", + "endcaps", + "firstwordcaps", + "lastwordbeforecaps", + "lastwordaftercaps", + "lencapsphrase", + "letsign", + "noletsignbefore", + "noletsign", + "noletsignafter", + "numsign", + "firstwordital", + "italsign", + "lastworditalbefore", + "lastworditalafter", + "begital", + "firstletterital", + "endital", + "lastletterital", + "singleletterital", + "italword", + "lenitalphrase", + "firstwordbold", + "boldsign", + "lastwordboldbefore", + "lastwordboldafter", + "begbold", + "firstletterbold", + "endbold", + "lastletterbold", + "singleletterbold", + "boldword", + "lenboldphrase", + "firstwordunder", + "undersign", + "lastwordunderbefore", + "lastwordunderafter", + "begunder", + "firstletterunder", + "endunder", + "lastletterunder", + "singleletterunder", + "underword", + "lenunderphrase", + "begcomp", + "compbegemph1", + "compendemph1", + "compbegemph2", + "compendemph2", + "compbegemph3", + "compendemph3", + "compcapsign", + "compbegcaps", + "compendcaps", + "endcomp", + "multind", + "compdots", + "comp6", + "class", + "after", + "before", + "noback", + "nofor", + "swapcc", + "swapcd", + "swapdd", + "space", + "digit", + "punctuation", + "math", + "sign", + "letter", + "uppercase", + "lowercase", + "grouping", + "uplow", + "litdigit", + "display", + "replace", + "context", + "correct", + "pass2", + "pass3", + "pass4", + "repeated", + "repword", + "capsnocont", + "always", + "exactdots", + "nocross", + "syllable", + "nocont", + "compbrl", + "literal", + "largesign", + "word", + "partword", + "joinnum", + "joinword", + "lowword", + "contraction", + "sufword", + "prfword", + "begword", + "begmidword", + "midword", + "midendword", + "endword", + "prepunc", + "postpunc", + "begnum", + "midnum", + "endnum", + "decpoint", + "hyphen", + "nobreak" +}; +static short opcodeLengths[CTO_None] = { 0 }; + +typedef enum +{ noEncoding, bigEndian, littleEndian, ascii8 } EncodingType; + + +typedef struct +{ + const char *fileName; + FILE *in; + int lineNumber; + EncodingType encoding; + int status; + int linelen; + int linepos; + int checkencoding[2]; + widechar line[MAXSTRING]; +} +FileInfo; + +static char scratchBuf[MAXSTRING]; + +char * +showString (widechar const *chars, int length) +{ +/*Translate a string of characters to the encoding used in character +* operands */ + int charPos; + int bufPos = 0; + scratchBuf[bufPos++] = '\''; + for (charPos = 0; charPos < length; charPos++) + { + if (chars[charPos] >= 32 && chars[charPos] < 127) + scratchBuf[bufPos++] = (char) chars[charPos]; + else + { + char hexbuf[20]; + int hexLength; + char escapeLetter; + + int leadingZeros; + int hexPos; + hexLength = sprintf (hexbuf, "%x", chars[charPos]); + switch (hexLength) + { + case 1: + case 2: + case 3: + case 4: + escapeLetter = 'x'; + leadingZeros = 4 - hexLength; + break; + case 5: + escapeLetter = 'y'; + leadingZeros = 0; + break; + case 6: + case 7: + case 8: + escapeLetter = 'z'; + leadingZeros = 8 - hexLength; + break; + default: + escapeLetter = '?'; + leadingZeros = 0; + break; + } + if ((bufPos + leadingZeros + hexLength + 4) >= sizeof (scratchBuf)) + break; + scratchBuf[bufPos++] = '\\'; + scratchBuf[bufPos++] = escapeLetter; + for (hexPos = 0; hexPos < leadingZeros; hexPos++) + scratchBuf[bufPos++] = '0'; + for (hexPos = 0; hexPos < hexLength; hexPos++) + scratchBuf[bufPos++] = hexbuf[hexPos]; + } + } + scratchBuf[bufPos++] = '\''; + scratchBuf[bufPos] = 0; + return scratchBuf; +} + +char * +showDots (widechar const *dots, int length) +{ +/* Translate a sequence of dots to the encoding used in dots operands. +*/ + int bufPos = 0; + int dotsPos; + for (dotsPos = 0; bufPos < sizeof (scratchBuf) && dotsPos < length; + dotsPos++) + { + if ((dots[dotsPos] & B1)) + scratchBuf[bufPos++] = '1'; + if ((dots[dotsPos] & B2)) + scratchBuf[bufPos++] = '2'; + if ((dots[dotsPos] & B3)) + scratchBuf[bufPos++] = '3'; + if ((dots[dotsPos] & B4)) + scratchBuf[bufPos++] = '4'; + if ((dots[dotsPos] & B5)) + scratchBuf[bufPos++] = '5'; + if ((dots[dotsPos] & B6)) + scratchBuf[bufPos++] = '6'; + if ((dots[dotsPos] & B7)) + scratchBuf[bufPos++] = '7'; + if ((dots[dotsPos] & B8)) + scratchBuf[bufPos++] = '8'; + if ((dots[dotsPos] & B9)) + scratchBuf[bufPos++] = '9'; + if ((dots[dotsPos] & B10)) + scratchBuf[bufPos++] = 'A'; + if ((dots[dotsPos] & B11)) + scratchBuf[bufPos++] = 'B'; + if ((dots[dotsPos] & B12)) + scratchBuf[bufPos++] = 'C'; + if ((dots[dotsPos] & B13)) + scratchBuf[bufPos++] = 'D'; + if ((dots[dotsPos] & B14)) + scratchBuf[bufPos++] = 'E'; + if ((dots[dotsPos] & B15)) + scratchBuf[bufPos++] = 'F'; + if ((dots[dotsPos] == B16)) + scratchBuf[bufPos++] = '0'; + if (dotsPos != length - 1) + scratchBuf[bufPos++] = '-'; + } + scratchBuf[bufPos] = 0; + return &scratchBuf[0]; +} + +char * +showAttributes (TranslationTableCharacterAttributes a) +{ +/* Show attributes using the letters used after the $ in multipass +* opcodes. */ + int bufPos = 0; + if ((a & CTC_Space)) + scratchBuf[bufPos++] = 's'; + if ((a & CTC_Letter)) + scratchBuf[bufPos++] = 'l'; + if ((a & CTC_Digit)) + scratchBuf[bufPos++] = 'd'; + if ((a & CTC_Punctuation)) + scratchBuf[bufPos++] = 'p'; + if ((a & CTC_UpperCase)) + scratchBuf[bufPos++] = 'U'; + if ((a & CTC_LowerCase)) + scratchBuf[bufPos++] = 'u'; + if ((a & CTC_Math)) + scratchBuf[bufPos++] = 'm'; + if ((a & CTC_Sign)) + scratchBuf[bufPos++] = 'S'; + if ((a & CTC_LitDigit)) + scratchBuf[bufPos++] = 'D'; + if ((a & CTC_Class1)) + scratchBuf[bufPos++] = 'w'; + if ((a & CTC_Class2)) + scratchBuf[bufPos++] = 'x'; + if ((a & CTC_Class3)) + scratchBuf[bufPos++] = 'y'; + if ((a & CTC_Class4)) + scratchBuf[bufPos++] = 'z'; + scratchBuf[bufPos] = 0; + return scratchBuf; +} + +static void compileError (FileInfo * nested, char *format, ...); + +static int +getAChar (FileInfo * nested) +{ +/*Read a big endian, little *ndian or ASCII 8 file and convert it to +* 16- or 32-bit unsigned integers */ + int ch1 = 0, ch2 = 0; + widechar character; + if (nested->encoding == ascii8) + if (nested->status == 2) + { + nested->status++; + return nested->checkencoding[1]; + } + while ((ch1 = fgetc (nested->in)) != EOF) + { + if (nested->status < 2) + nested->checkencoding[nested->status] = ch1; + nested->status++; + if (nested->status == 2) + { + if (nested->checkencoding[0] == 0xfe + && nested->checkencoding[1] == 0xff) + nested->encoding = bigEndian; + else if (nested->checkencoding[0] == 0xff + && nested->checkencoding[1] == 0xfe) + nested->encoding = littleEndian; + else if (nested->checkencoding[0] < 128 + && nested->checkencoding[1] < 128) + { + nested->encoding = ascii8; + return nested->checkencoding[0]; + } + else + { + compileError (nested, + "encoding is neither big-endian, little-endian nor ASCII 8."); + ch1 = EOF; + break;; + } + continue; + } + switch (nested->encoding) + { + case noEncoding: + break; + case ascii8: + return ch1; + break; + case bigEndian: + ch2 = fgetc (nested->in); + if (ch2 == EOF) + break; + character = (ch1 << 8) | ch2; + return (int) character; + break; + case littleEndian: + ch2 = fgetc (nested->in); + if (ch2 == EOF) + break; + character = (ch2 << 8) | ch1; + return (int) character; + break; + } + if (ch1 == EOF || ch2 == EOF) + break; + } + return EOF; +} + +static int +getALine (FileInfo * nested) +{ +/*Read a line of widechar's from an input file */ + int ch; + int pch = 0; + nested->linelen = 0; + while ((ch = getAChar (nested)) != EOF) + { + if (ch == 13) + continue; + if (pch == '\\' && ch == 10) + { + nested->linelen--; + continue; + } + if (ch == 10 || nested->linelen >= MAXSTRING) + break; + nested->line[nested->linelen++] = (widechar) ch; + pch = ch; + } + nested->line[nested->linelen] = 0; + nested->linepos = 0; + if (ch == EOF) + return 0; + nested->lineNumber++; + return 1; +} + +static int lastToken; +static int +getToken (FileInfo * nested, CharsString * result, const char *description) +{ +/*Find the next string of contiguous non-whitespace characters. If this + * is the last token on the line, return 2 instead of 1. */ + while (nested->line[nested->linepos] && nested->line[nested->linepos] <= 32) + nested->linepos++; + result->length = 0; + while (nested->line[nested->linepos] && nested->line[nested->linepos] > 32) + result->chars[result->length++] = nested->line[nested->linepos++]; + if (!result->length) + { + /* Not enough tokens */ + if (description) + compileError (nested, "%s not specified.", description); + return 0; + } + result->chars[result->length] = 0; + while (nested->line[nested->linepos] && nested->line[nested->linepos] <= 32) + nested->linepos++; + if (nested->line[nested->linepos] == 0) + { + lastToken = 1; + return 2; + } + else + { + lastToken = 0; + return 1; + } +} + +static void +compileError (FileInfo * nested, char *format, ...) +{ +#ifndef __SYMBIAN32__ + char buffer[MAXSTRING]; + va_list arguments; + va_start (arguments, format); +#ifdef _WIN32 + (void) _vsnprintf (buffer, sizeof (buffer), format, arguments); +#else + (void) vsnprintf (buffer, sizeof (buffer), format, arguments); +#endif + va_end (arguments); + if (nested) + lou_logPrint ("%s:%d: error: %s", nested->fileName, + nested->lineNumber, buffer); + else + lou_logPrint ("error: %s", buffer); + errorCount++; +#endif +} + +static void +compileWarning (FileInfo * nested, char *format, ...) +{ +#ifndef __SYMBIAN32__ + char buffer[MAXSTRING]; + va_list arguments; + va_start (arguments, format); +#ifdef _WIN32 + (void) _vsnprintf (buffer, sizeof (buffer), format, arguments); +#else + (void) vsnprintf (buffer, sizeof (buffer), format, arguments); +#endif + va_end (arguments); + if (nested) + lou_logPrint ("%s:%d: warning: %s", nested->fileName, + nested->lineNumber, buffer); + else + lou_logPrint ("warning: %s", buffer); + warningCount++; +#endif +} + +static int +allocateSpaceInTable (FileInfo * nested, TranslationTableOffset * offset, + int count) +{ +/* allocate memory for translation table and expand previously allocated +* memory if necessary */ + int spaceNeeded = ((count + OFFSETSIZE - 1) / OFFSETSIZE) * OFFSETSIZE; + TranslationTableOffset size = tableUsed + spaceNeeded; + if (size > tableSize) + { + void *newTable; + size += (size / OFFSETSIZE); + newTable = realloc (table, size); + if (!newTable) + { + compileError (nested, "Not enough memory for translation table."); + return 0; + } + memset (((unsigned char *) newTable) + tableSize, 0, size - tableSize); + table = (TranslationTableHeader *) newTable; + tableSize = size; + } + if (offset != NULL) + { + *offset = (tableUsed - sizeof (*table)) / OFFSETSIZE; + tableUsed += spaceNeeded; + } + return 1; +} + +static int +reserveSpaceInTable (FileInfo * nested, int count) +{ + return (allocateSpaceInTable (nested, NULL, count)); +} + +static int +allocateHeader (FileInfo * nested) +{ +/*Allocate memory for the table header and a guess on the number of +* rules */ + const TranslationTableOffset startSize = 2 * sizeof (*table); + if (table) + return 1; + tableUsed = sizeof (*table) + OFFSETSIZE; /*So no offset is ever zero */ + if (!(table = malloc (startSize))) + { + compileError (nested, "Not enough memory"); + if (table != NULL) + free (table); + table = NULL; + return 0; + } + memset (table, 0, startSize); + tableSize = startSize; + return 1; +} + +int +stringHash (const widechar * c) +{ +/*hash function for strings */ + unsigned long int makeHash = (((unsigned long int) c[0] << 8) + + (unsigned long int) c[1]) % HASHNUM; + return (int) makeHash; +} + +int +charHash (widechar c) +{ + unsigned long int makeHash = (unsigned long int) c % HASHNUM; + return (int) makeHash; +} + +static TranslationTableCharacter * +compile_findCharOrDots (widechar c, int m) +{ +/*Look up a character or dot pattern. If m is 0 look up a character, +* otherwise look up a dot pattern. Although the algorithms are almost +* identical, different tables are needed for characters and dots because +* of the possibility of conflicts.*/ + TranslationTableCharacter *character; + TranslationTableOffset bucket; + unsigned long int makeHash = (unsigned long int) c % HASHNUM; + if (m == 0) + bucket = table->characters[makeHash]; + else + bucket = table->dots[makeHash]; + while (bucket) + { + character = (TranslationTableCharacter *) & table->ruleArea[bucket]; + if (character->realchar == c) + return character; + bucket = character->next; + } + return NULL; +} + +static TranslationTableCharacter noChar = { 0, 0, 0, CTC_Space, 32, 32, 32 }; +static TranslationTableCharacter noDots = + { 0, 0, 0, CTC_Space, B16, B16, B16 }; +static char *unknownDots (widechar dots); + +static TranslationTableCharacter * +definedCharOrDots (FileInfo * nested, widechar c, int m) +{ + TranslationTableCharacter *notFound; + TranslationTableCharacter *charOrDots = compile_findCharOrDots (c, m); + if (charOrDots) + return charOrDots; + if (m == 0) + { + notFound = &noChar; + compileError (nested, + "character %s should be defined at this point but is not", + showString (&c, 1)); + } + else + { + notFound = &noDots; + compileError (nested, + "cell %s should be defined at this point but is not", + unknownDots (c)); + } + return notFound; +} + +static TranslationTableCharacter * +addCharOrDots (FileInfo * nested, widechar c, int m) +{ +/*See if a character or dot pattern is in the appropriate table. If not, +* insert it. In either +* case, return a pointer to it. */ + TranslationTableOffset bucket; + TranslationTableCharacter *character; + TranslationTableCharacter *oldchar; + TranslationTableOffset offset; + unsigned long int makeHash; + if ((character = compile_findCharOrDots (c, m))) + return character; + if (!allocateSpaceInTable (nested, &offset, sizeof (*character))) + return NULL; + character = (TranslationTableCharacter *) & table->ruleArea[offset]; + memset (character, 0, sizeof (*character)); + character->realchar = c; + makeHash = (unsigned long int) c % HASHNUM; + if (m == 0) + bucket = table->characters[makeHash]; + else + bucket = table->dots[makeHash]; + if (!bucket) + { + if (m == 0) + table->characters[makeHash] = offset; + else + table->dots[makeHash] = offset; + } + else + { + oldchar = (TranslationTableCharacter *) & table->ruleArea[bucket]; + while (oldchar->next) + oldchar = + (TranslationTableCharacter *) & table->ruleArea[oldchar->next]; + oldchar->next = offset; + } + return character; +} + +static CharOrDots * +getCharOrDots (widechar c, int m) +{ + CharOrDots *cdPtr; + TranslationTableOffset bucket; + unsigned long int makeHash = (unsigned long int) c % HASHNUM; + if (m == 0) + bucket = table->charToDots[makeHash]; + else + bucket = table->dotsToChar[makeHash]; + while (bucket) + { + cdPtr = (CharOrDots *) & table->ruleArea[bucket]; + if (cdPtr->lookFor == c) + return cdPtr; + bucket = cdPtr->next; + } + return NULL; +} + +widechar +getDotsForChar (widechar c) +{ + CharOrDots *cdPtr = getCharOrDots (c, 0); + if (cdPtr) + return cdPtr->found; + return B16; +} + +widechar +getCharFromDots (widechar d) +{ + CharOrDots *cdPtr = getCharOrDots (d, 1); + if (cdPtr) + return cdPtr->found; + return ' '; +} + +static int +putCharAndDots (FileInfo * nested, widechar c, widechar d) +{ + TranslationTableOffset bucket; + CharOrDots *cdPtr; + CharOrDots *oldcdPtr = NULL; + TranslationTableOffset offset; + unsigned long int makeHash; + if (!(cdPtr = getCharOrDots (c, 0))) + { + if (!allocateSpaceInTable (nested, &offset, sizeof (*cdPtr))) + return 0; + cdPtr = (CharOrDots *) & table->ruleArea[offset]; + cdPtr->next = 0; + cdPtr->lookFor = c; + cdPtr->found = d; + makeHash = (unsigned long int) c % HASHNUM; + bucket = table->charToDots[makeHash]; + if (!bucket) + table->charToDots[makeHash] = offset; + else + { + oldcdPtr = (CharOrDots *) & table->ruleArea[bucket]; + while (oldcdPtr->next) + oldcdPtr = (CharOrDots *) & table->ruleArea[oldcdPtr->next]; + oldcdPtr->next = offset; + } + } + if (!(cdPtr = getCharOrDots (d, 1))) + { + if (!allocateSpaceInTable (nested, &offset, sizeof (*cdPtr))) + return 0; + cdPtr = (CharOrDots *) & table->ruleArea[offset]; + cdPtr->next = 0; + cdPtr->lookFor = d; + cdPtr->found = c; + makeHash = (unsigned long int) d % HASHNUM; + bucket = table->dotsToChar[makeHash]; + if (!bucket) + table->dotsToChar[makeHash] = offset; + else + { + oldcdPtr = (CharOrDots *) & table->ruleArea[bucket]; + while (oldcdPtr->next) + oldcdPtr = (CharOrDots *) & table->ruleArea[oldcdPtr->next]; + oldcdPtr->next = offset; + } + } + return 1; +} + +static char * +unknownDots (widechar dots) +{ +/*Print out dot numbers */ + static char buffer[20]; + int k = 1; + buffer[0] = '\\'; + if ((dots & B1)) + buffer[k++] = '1'; + if ((dots & B2)) + buffer[k++] = '2'; + if ((dots & B3)) + buffer[k++] = '3'; + if ((dots & B4)) + buffer[k++] = '4'; + if ((dots & B5)) + buffer[k++] = '5'; + if ((dots & B6)) + buffer[k++] = '6'; + if ((dots & B7)) + buffer[k++] = '7'; + if ((dots & B8)) + buffer[k++] = '8'; + if ((dots & B9)) + buffer[k++] = '9'; + if ((dots & B10)) + buffer[k++] = 'A'; + if ((dots & B11)) + buffer[k++] = 'B'; + if ((dots & B12)) + buffer[k++] = 'C'; + if ((dots & B13)) + buffer[k++] = 'D'; + if ((dots & B14)) + buffer[k++] = 'E'; + if ((dots & B15)) + buffer[k++] = 'F'; + buffer[k++] = '/'; + buffer[k] = 0; + return buffer; +} + +static TranslationTableOffset newRuleOffset = 0; +static TranslationTableRule *newRule = NULL; + +static int +charactersDefined (FileInfo * nested) +{ +/*Check that all characters are defined by character-definition +* opcodes*/ + int noErrors = 1; + int k; + if ((newRule->opcode >= CTO_Space && newRule->opcode <= CTO_LitDigit) + || newRule->opcode == CTO_SwapDd + || + newRule->opcode == CTO_Replace || newRule->opcode == CTO_MultInd + || newRule->opcode == CTO_Repeated || + ((newRule->opcode >= CTO_Context && newRule->opcode <= + CTO_Pass4) && newRule->opcode != CTO_Correct)) + return 1; + for (k = 0; k < newRule->charslen; k++) + if (!compile_findCharOrDots (newRule->charsdots[k], 0)) + { + compileError (nested, "Character %s is not defined", showString + (&newRule->charsdots[k], 1)); + noErrors = 0; + } + if (!(newRule->opcode == CTO_Correct || newRule->opcode == + CTO_NoBreak || newRule->opcode == CTO_SwapCc || newRule->opcode == + CTO_SwapCd)) + { + for (k = newRule->charslen; k < newRule->charslen + newRule->dotslen; + k++) + if (!compile_findCharOrDots (newRule->charsdots[k], 1)) + { + compileError (nested, "Dot pattern %s is not defined.", + unknownDots (newRule->charsdots[k])); + noErrors = 0; + } + } + return noErrors; +} + +static int noback = 0; +static int nofor = 0; + +/*The following functions are +called by addRule to handle various +* cases.*/ + +static void +add_0_single (FileInfo * nested) +{ +/*direction = 0, newRule->charslen = 1*/ + TranslationTableRule *currentRule; + TranslationTableOffset *currentOffsetPtr; + TranslationTableCharacter *character; + int m = 0; + if (newRule->opcode == CTO_CompDots || newRule->opcode == CTO_Comp6) + return; + if (newRule->opcode >= CTO_Pass2 && newRule->opcode <= CTO_Pass4) + m = 1; + character = definedCharOrDots (nested, newRule->charsdots[0], m); + if (m != 1 && character->attributes & CTC_Letter && (newRule->opcode + == + CTO_WholeWord + || newRule->opcode == + CTO_LargeSign)) + { + if (table->noLetsignCount < LETSIGNSIZE) + table->noLetsign[table->noLetsignCount++] = newRule->charsdots[0]; + } + if (newRule->opcode >= CTO_Space && newRule->opcode < CTO_UpLow) + character->definitionRule = newRuleOffset; + currentOffsetPtr = &character->otherRules; + while (*currentOffsetPtr) + { + currentRule = (TranslationTableRule *) + & table->ruleArea[*currentOffsetPtr]; + if (currentRule->charslen == 0) + break; + if (currentRule->opcode >= CTO_Space && currentRule->opcode < CTO_UpLow) + if (!(newRule->opcode >= CTO_Space && newRule->opcode < CTO_UpLow)) + break; + currentOffsetPtr = ¤tRule->charsnext; + } + newRule->charsnext = *currentOffsetPtr; + *currentOffsetPtr = newRuleOffset; +} + +static void +add_0_multiple (void) +{ +/*direction = 0 newRule->charslen > 1*/ + TranslationTableRule *currentRule = NULL; + TranslationTableOffset *currentOffsetPtr = + &table->forRules[stringHash (&newRule->charsdots[0])]; + while (*currentOffsetPtr) + { + currentRule = (TranslationTableRule *) + & table->ruleArea[*currentOffsetPtr]; + if (newRule->charslen > currentRule->charslen) + break; + if (newRule->charslen == currentRule->charslen) + if ((currentRule->opcode == CTO_Always) + && (newRule->opcode != CTO_Always)) + break; + currentOffsetPtr = ¤tRule->charsnext; + } + newRule->charsnext = *currentOffsetPtr; + *currentOffsetPtr = newRuleOffset; +} + +static void +add_1_single (FileInfo * nested) +{ +/*direction = 1, newRule->dotslen = 1*/ + TranslationTableRule *currentRule; + TranslationTableOffset *currentOffsetPtr; + TranslationTableCharacter *dots; + if (newRule->opcode == CTO_NoBreak || newRule->opcode == CTO_SwapCc || + (newRule->opcode >= CTO_Context + && + newRule->opcode <= CTO_Pass4) + || newRule->opcode == CTO_Repeated || (newRule->opcode == CTO_Always + && newRule->charslen == 1)) + return; /*too ambiguous */ + dots = definedCharOrDots (nested, newRule->charsdots[newRule->charslen], 1); + if (newRule->opcode >= CTO_Space && newRule->opcode < CTO_UpLow) + dots->definitionRule = newRuleOffset; + currentOffsetPtr = &dots->otherRules; + while (*currentOffsetPtr) + { + currentRule = (TranslationTableRule *) + & table->ruleArea[*currentOffsetPtr]; + if (newRule->charslen > currentRule->charslen || + currentRule->dotslen == 0) + break; + if (currentRule->opcode >= CTO_Space && currentRule->opcode < CTO_UpLow) + if (!(newRule->opcode >= CTO_Space && newRule->opcode < CTO_UpLow)) + break; + currentOffsetPtr = ¤tRule->dotsnext; + } + newRule->dotsnext = *currentOffsetPtr; + *currentOffsetPtr = newRuleOffset; +} + +static void +add_1_multiple (void) +{ +/*direction = 1, newRule->dotslen > 1*/ + TranslationTableRule *currentRule = NULL; + TranslationTableOffset *currentOffsetPtr = &table->backRules[stringHash + (&newRule-> + charsdots + [newRule-> + charslen])]; + if (newRule->opcode == CTO_NoBreak || newRule->opcode == CTO_SwapCc || + (newRule->opcode >= CTO_Context && newRule->opcode <= CTO_Pass4)) + return; + while (*currentOffsetPtr) + { + int currentLength; + int newLength; + currentRule = (TranslationTableRule *) + & table->ruleArea[*currentOffsetPtr]; + currentLength = currentRule->dotslen + currentRule->charslen; + newLength = newRule->dotslen + newRule->charslen; + if (newLength > currentLength) + break; + if (currentLength == newLength) + if ((currentRule->opcode == CTO_Always) + && (newRule->opcode != CTO_Always)) + break; + currentOffsetPtr = ¤tRule->dotsnext; + } + newRule->dotsnext = *currentOffsetPtr; + *currentOffsetPtr = newRuleOffset; +} + +static void +makeRuleChain (TranslationTableOffset * offsetPtr) +{ + TranslationTableRule *currentRule; + while (*offsetPtr) + { + currentRule = (TranslationTableRule *) & table->ruleArea[*offsetPtr]; + offsetPtr = ¤tRule->charsnext; + } + newRule->charsnext = *offsetPtr; + *offsetPtr = newRuleOffset; +} + +static int +addPassRule (FileInfo * nested) +{ + TranslationTableOffset *offsetPtr; + switch (newRule->opcode) + { + case CTO_Correct: + offsetPtr = &table->attribOrSwapRules[0]; + break; + case CTO_Context: + offsetPtr = &table->attribOrSwapRules[1]; + break; + case CTO_Pass2: + offsetPtr = &table->attribOrSwapRules[2]; + break; + case CTO_Pass3: + offsetPtr = &table->attribOrSwapRules[3]; + break; + case CTO_Pass4: + offsetPtr = &table->attribOrSwapRules[4]; + break; + default: + return 0; + } + makeRuleChain (offsetPtr); + return 1; +} + +static int + addRule + (FileInfo * nested, + TranslationTableOpcode opcode, + CharsString * ruleChars, + CharsString * ruleDots, + TranslationTableCharacterAttributes after, + TranslationTableCharacterAttributes before) +{ +/*Add a rule to the table, using the hash function to find the start of +* chains and chaining both the chars and dots strings */ + int ruleSize = sizeof (TranslationTableRule) - (DEFAULTRULESIZE * CHARSIZE); + int direction = 0; /*0 = forward translation; 1 = bacward */ + if (ruleChars) + ruleSize += CHARSIZE * ruleChars->length; + if (ruleDots) + ruleSize += CHARSIZE * ruleDots->length; + if (!allocateSpaceInTable (nested, &newRuleOffset, ruleSize)) + return 0; + newRule = (TranslationTableRule *) & table->ruleArea[newRuleOffset]; + newRule->opcode = opcode; + newRule->after = after; + newRule->before = before; + if (ruleChars) + memcpy (&newRule->charsdots[0], &ruleChars->chars[0], + CHARSIZE * (newRule->charslen = ruleChars->length)); + else + newRule->charslen = 0; + if (ruleDots) + memcpy (&newRule->charsdots[newRule->charslen], + &ruleDots->chars[0], CHARSIZE * (newRule->dotslen = + ruleDots->length)); + else + newRule->dotslen = 0; + if (!charactersDefined (nested)) + return 0; + + /*link new rule into table. */ + if (opcode == CTO_SwapCc || opcode == CTO_SwapCd || opcode == CTO_SwapDd) + return 1; + if (opcode >= CTO_Context && opcode <= CTO_Pass4 && newRule->charslen == 0) + return addPassRule (nested); + if (newRule->charslen == 0 || nofor) + direction = 1; + while (direction < 2) + { + if (direction == 0 && newRule->charslen == 1) + add_0_single (nested); + else if (direction == 0 && newRule->charslen > 1) + add_0_multiple (); + else if (direction == 1 && newRule->dotslen == 1 && !noback) + add_1_single (nested); + else if (direction == 1 && newRule->dotslen > 1 && !noback) + add_1_multiple (); + else + { + } + direction++; + if (newRule->dotslen == 0) + direction = 2; + } + return 1; +} + +static const struct CharacterClass * +findCharacterClass (const CharsString * name) +{ +/*Find a character class, whether predefined or user-defined */ + const struct CharacterClass *class = characterClasses; + while (class) + { + if ((name->length == class->length) && + (memcmp (&name->chars[0], class->name, CHARSIZE * + name->length) == 0)) + return class; + class = class->next; + } + return NULL; +} + +static struct CharacterClass * +addCharacterClass (FileInfo * nested, const widechar * name, int length) +{ +/*Define a character class, Whether predefined or user-defined */ + struct CharacterClass *class; + if (characterClassAttribute) + { + if ((class = malloc (sizeof (*class) + CHARSIZE * (length - 1)))) + { + memset (class, 0, sizeof (*class)); + memcpy (class->name, name, CHARSIZE * (class->length = length)); + class->attribute = characterClassAttribute; + characterClassAttribute <<= 1; + class->next = characterClasses; + characterClasses = class; + return class; + } + } + compileError (nested, "character class table overflow."); + return NULL; +} + +static void +deallocateCharacterClasses (void) +{ + while (characterClasses) + { + struct CharacterClass *class = characterClasses; + characterClasses = characterClasses->next; + if (class) + free (class); + } +} + +static int +allocateCharacterClasses (void) +{ +/*Allocate memory for predifined character classes */ + int k = 0; + characterClasses = NULL; + characterClassAttribute = 1; + while (characterClassNames[k]) + { + widechar wname[MAXSTRING]; + int length = strlen (characterClassNames[k]); + int kk; + for (kk = 0; kk < length; kk++) + wname[kk] = (widechar) characterClassNames[k][kk]; + if (!addCharacterClass (NULL, wname, length)) + { + deallocateCharacterClasses (); + return 0; + } + k++; + } + return 1; +} + +static TranslationTableOpcode +getOpcode (FileInfo * nested, const CharsString * token) +{ + static TranslationTableOpcode lastOpcode = 0; + TranslationTableOpcode opcode = lastOpcode; + + do + { + if (token->length == opcodeLengths[opcode]) + if (eqasc2uni ((unsigned char *) opcodeNames[opcode], + &token->chars[0], token->length)) + { + lastOpcode = opcode; + return opcode; + } + opcode++; + if (opcode >= CTO_None) + opcode = 0; + } + while (opcode != lastOpcode); + compileError (nested, "opcode %s not defined.", showString + (&token->chars[0], token->length)); + return CTO_None; +} + +TranslationTableOpcode +findOpcodeNumber (const char *toFind) +{ +/* Used by tools such as lou_debug */ + static TranslationTableOpcode lastOpcode = 0; + TranslationTableOpcode opcode = lastOpcode; + int length = strlen (toFind); + do + { + if (length == opcodeLengths[opcode] && strcasecmp (toFind, + opcodeNames[opcode]) + == 0) + { + lastOpcode = opcode; + return opcode; + } + opcode++; + if (opcode >= CTO_None) + opcode = 0; + } + while (opcode != lastOpcode); + return CTO_None; +} + +const char * +findOpcodeName (TranslationTableOpcode opcode) +{ +/* Used by tools such as lou_debug */ + if (opcode < 0 || opcode >= CTO_None) + { + sprintf (scratchBuf, "%d", opcode); + return scratchBuf; + } + return opcodeNames[opcode]; +} + +static widechar +hexValue (FileInfo * nested, const widechar * digits, int length) +{ + int k; + unsigned int binaryValue = 0; + for (k = 0; k < length; k++) + { + unsigned int hexDigit = 0; + if (digits[k] >= '0' && digits[k] <= '9') + hexDigit = digits[k] - '0'; + else if (digits[k] >= 'a' && digits[k] <= 'f') + hexDigit = digits[k] - 'a' + 10; + else if (digits[k] >= 'A' && digits[k] <= 'F') + hexDigit = digits[k] - 'A' + 10; + else + { + compileError (nested, "invalid %d-digit hexadecimal number", + length); + return (widechar) 0xffffffff; + } + binaryValue |= hexDigit << (4 * (length - 1 - k)); + } + return (widechar) binaryValue; +} + +#define MAXBYTES 7 +static int first0Bit[MAXBYTES] = { 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0XFE }; + +static int +parseChars (FileInfo * nested, CharsString * result, CharsString * token) +{ + int in = 0; + int out = 0; + int lastOutSize = 0; + int lastIn; + unsigned int ch = 0; + int numBytes = 0; + unsigned int utf32 = 0; + int k; + while (in < token->length) + { + ch = token->chars[in++] & 0xff; + if (ch < 128) + { + if (ch == '\\') + { /* escape sequence */ + switch (ch = token->chars[in]) + { + case '\\': + break; + case 'e': + ch = 0x1b; + break; + case 'f': + ch = 12; + break; + case 'n': + ch = 10; + break; + case 'r': + ch = 13; + break; + case 's': + ch = ' '; + break; + case 't': + ch = 9; + break; + case 'v': + ch = 22; + break; + case 'w': + ch = ENDSEGMENT; + break; + case 34: + ch = QUOTESUB; + break; + case 'X': + case 'x': + if (token->length - in > 4) + { + ch = hexValue (nested, &token->chars[in + 1], 4); + in += 4; + } + break; + case 'y': + case 'Y': + if (CHARSIZE == 2) + { + not32: + compileError (nested, + "liblouis has not been compiled for 32-bit Unicode"); + break; + } + if (token->length - in > 5) + { + ch = hexValue (nested, &token->chars[in + 1], 5); + in += 5; + } + break; + case 'z': + case 'Z': + if (CHARSIZE == 2) + goto not32; + if (token->length - in > 8) + { + ch = hexValue (nested, &token->chars[in + 1], 8); + in += 8; + } + break; + default: + compileError (nested, "invalid escape sequence '\\%c'", ch); + break; + } + in++; + } + result->chars[out++] = (widechar) ch; + if (out >= MAXSTRING) + { + result->length = out; + return 1; + } + continue; + } + lastOutSize = out; + lastIn = in; + for (numBytes = MAXBYTES - 1; numBytes >= 0; numBytes--) + if (ch >= first0Bit[numBytes]) + break; + utf32 = ch & (0XFF - first0Bit[numBytes]); + for (k = 0; k < numBytes; k++) + { + if (in >= MAXSTRING) + break; + if (token->chars[in] < 128 || (token->chars[in] & 0x0040)) + { + compileWarning (nested, "invalid UTF-8. Assuming Latin-1."); + result->chars[out++] = token->chars[lastIn]; + in = lastIn + 1; + continue; + } + utf32 = (utf32 << 6) + (token->chars[in++] & 0x3f); + } + if (CHARSIZE == 2 && utf32 > 0xffff) + utf32 = 0xffff; + result->chars[out++] = (widechar) utf32; + if (out >= MAXSTRING) + { + result->length = lastOutSize; + return 1; + } + } + result->length = out; + return 1; +} + +int +extParseChars (const char *inString, widechar * outString) +{ +/* Parse external character strings */ + CharsString wideIn; + CharsString result; + int k; + for (k = 0; inString[k] && k < MAXSTRING; k++) + wideIn.chars[k] = inString[k]; + wideIn.chars[k] = 0; + wideIn.length = k; + parseChars (NULL, &result, &wideIn); + if (errorCount) + { + errorCount = 0; + return 0; + } + for (k = 0; k < result.length; k++) + outString[k] = result.chars[k]; + outString[k] = 0; + return result.length; +} + +static int +parseDots (FileInfo * nested, CharsString * cells, const CharsString * token) +{ +/*get dot patterns */ + widechar cell = 0; /*assembly place for dots */ + int cellCount = 0; + int index; + int start = 0; + + for (index = 0; index < token->length; index++) + { + int started = index != start; + widechar character = token->chars[index]; + switch (character) + { /*or dots to make up Braille cell */ + { + int dot; + case '1': + dot = B1; + goto haveDot; + case '2': + dot = B2; + goto haveDot; + case '3': + dot = B3; + goto haveDot; + case '4': + dot = B4; + goto haveDot; + case '5': + dot = B5; + goto haveDot; + case '6': + dot = B6; + goto haveDot; + case '7': + dot = B7; + goto haveDot; + case '8': + dot = B8; + goto haveDot; + case '9': + dot = B9; + goto haveDot; + case 'a': + case 'A': + dot = B10; + goto haveDot; + case 'b': + case 'B': + dot = B11; + goto haveDot; + case 'c': + case 'C': + dot = B12; + goto haveDot; + case 'd': + case 'D': + dot = B13; + goto haveDot; + case 'e': + case 'E': + dot = B14; + goto haveDot; + case 'f': + case 'F': + dot = B15; + haveDot: + if (started && !cell) + goto invalid; + if (cell & dot) + { + compileError (nested, "dot specified more than once."); + return 0; + } + cell |= dot; + break; + } + case '0': /*blank */ + if (started) + goto invalid; + break; + case '-': /*got all dots for this cell */ + if (!started) + { + compileError (nested, "missing cell specification."); + return 0; + } + cells->chars[cellCount++] = cell | B16; + cell = 0; + start = index + 1; + break; + default: + invalid: + compileError (nested, "invalid dot number %s.", showString + (&character, 1)); + return 0; + } + } + if (index == start) + { + compileError (nested, "missing cell specification."); + return 0; + } + cells->chars[cellCount++] = cell | B16; /*last cell */ + cells->length = cellCount; + return 1; +} + +int +extParseDots (const char *inString, widechar * outString) +{ +/* Parse external dot patterns */ + CharsString wideIn; + CharsString result; + int k; + for (k = 0; inString[k] && k < MAXSTRING; k++) + wideIn.chars[k] = inString[k]; + wideIn.chars[k] = 0; + wideIn.length = k; + parseDots (NULL, &result, &wideIn); + if (errorCount) + { + errorCount = 0; + return 0; + } + for (k = 0; k < result.length; k++) + outString[k] = result.chars[k]; + outString[k] = 0; + return result.length; +} + +static int +getCharacters (FileInfo * nested, CharsString * characters) +{ +/*Get ruleChars string */ + CharsString token; + if (getToken (nested, &token, "characters")) + if (parseChars (nested, characters, &token)) + return 1; + return 0; +} + +static int +getRuleCharsText (FileInfo * nested, CharsString * ruleChars) +{ + CharsString token; + if (getToken (nested, &token, "Characters operand")) + if (parseChars (nested, ruleChars, &token)) + return 1; + return 0; +} + +static int +getRuleDotsText (FileInfo * nested, CharsString * ruleDots) +{ + CharsString token; + if (getToken (nested, &token, "characters")) + if (parseChars (nested, ruleDots, &token)) + return 1; + return 0; +} + +static int +getRuleDotsPattern (FileInfo * nested, CharsString * ruleDots) +{ +/*Interpret the dets operand */ + CharsString token; + if (getToken (nested, &token, "Dots operand")) + { + if (token.length == 1 && token.chars[0] == '=') + { + ruleDots->length = 0; + return 1; + } + if (parseDots (nested, ruleDots, &token)) + return 1; + } + return 0; +} + +static int +getCharacterClass (FileInfo * nested, const struct CharacterClass **class) +{ + CharsString token; + if (getToken (nested, &token, "character class name")) + { + if ((*class = findCharacterClass (&token))) + return 1; + compileError (nested, "character class not defined."); + } + return 0; +} + +static int compileFile (const char *fileName); + +static int +includeFile (FileInfo * nested, CharsString * includedFile) +{ +/*Implement include opcode*/ + int k; + char includeThis[MAXSTRING]; + for (k = 0; k < includedFile->length; k++) + includeThis[k] = (char) includedFile->chars[k]; + includeThis[k] = 0; + return compileFile (includeThis); +} + +struct RuleName +{ + struct RuleName *next; + TranslationTableOffset ruleOffset; + widechar length; + widechar name[1]; +}; +static struct RuleName *ruleNames = NULL; +static TranslationTableOffset +findRuleName (const CharsString * name) +{ + const struct RuleName *nameRule = ruleNames; + while (nameRule) + { + if ((name->length == nameRule->length) && + (memcmp (&name->chars[0], nameRule->name, CHARSIZE * + name->length) == 0)) + return nameRule->ruleOffset; + nameRule = nameRule->next; + } + return 0; +} + +static int +addRuleName (FileInfo * nested, CharsString * name) +{ + int k; + struct RuleName *nameRule; + if (!(nameRule = malloc (sizeof (*nameRule) + CHARSIZE * + (name->length - 1)))) + { + compileError (nested, "not enough memory"); + return 0; + } + memset (nameRule, 0, sizeof (*nameRule)); + for (k = 0; k < name->length; k++) + { + TranslationTableCharacter *ch = definedCharOrDots + (nested, name->chars[k], + 0); + if (!(ch->attributes & CTC_Letter)) + { + compileError (nested, "a name may contain only letters"); + return 0; + } + nameRule->name[k] = name->chars[k]; + } + nameRule->length = name->length; + nameRule->ruleOffset = newRuleOffset; + nameRule->next = ruleNames; + ruleNames = nameRule; + return 1; +} + +static void +deallocateRuleNames (void) +{ + while (ruleNames) + { + struct RuleName *nameRule = ruleNames; + ruleNames = ruleNames->next; + if (nameRule) + free (nameRule); + } +} + +static int +compileSwapDots (FileInfo * nested, CharsString * source, CharsString * dest) +{ + int k = 0; + int kk = 0; + CharsString dotsSource; + CharsString dotsDest; + dest->length = 0; + dotsSource.length = 0; + while (k <= source->length) + { + if (source->chars[k] != ',' && k != source->length) + dotsSource.chars[dotsSource.length++] = source->chars[k]; + else + { + if (!parseDots (nested, &dotsDest, &dotsSource)) + return 0; + dest->chars[dest->length++] = dotsDest.length + 1; + for (kk = 0; kk < dotsDest.length; kk++) + dest->chars[dest->length++] = dotsDest.chars[kk]; + dotsSource.length = 0; + } + k++; + } + return 1; +} + +static int +compileSwap (FileInfo * nested, TranslationTableOpcode opcode) +{ + CharsString ruleChars; + CharsString ruleDots; + CharsString name; + CharsString matches; + CharsString replacements; + if (!getToken (nested, &name, "name operand")) + return 0; + if (!getToken (nested, &matches, "matches operand")) + return 0; + if (!getToken (nested, &replacements, "replacements operand")) + return 0; + if (opcode == CTO_SwapCc || opcode == CTO_SwapCd) + { + if (!parseChars (nested, &ruleChars, &matches)) + return 0; + } + else + { + if (!compileSwapDots (nested, &matches, &ruleChars)) + return 0; + } + if (opcode == CTO_SwapCc) + { + if (!parseChars (nested, &ruleDots, &replacements)) + return 0; + } + else + { + if (!compileSwapDots (nested, &replacements, &ruleDots)) + return 0; + } + if (!addRule (nested, opcode, &ruleChars, &ruleDots, 0, 0)) + return 0; + if (!addRuleName (nested, &name)) + return 0; + return 1; +} + + +static int +getNumber (widechar * source, widechar * dest) +{ +/*Convert a string of wide character digits to an integer*/ + int k = 0; + *dest = 0; + while (source[k] >= '0' && source[k] <= '9') + *dest = 10 * *dest + (source[k++] - '0'); + return k; +} + +/* Start of multipass compiler*/ +static CharsString passRuleChars; +static CharsString passRuleDots; +static CharsString passHoldString; +static CharsString passLine; +static int passLinepos; +static int passPrevLinepos; +static widechar passHoldNumber; +static widechar passEmphasis; +static TranslationTableCharacterAttributes passAttributes; +static FileInfo *passNested; +static TranslationTableOpcode passOpcode; +static widechar *passInstructions; +static int passIC; + +static int +passGetAttributes () +{ + int more = 1; + passAttributes = 0; + while (more) + { + switch (passLine.chars[passLinepos]) + { + case pass_any: + passAttributes = 0xffffffff; + break; + case pass_digit: + passAttributes |= CTC_Digit; + break; + case pass_litDigit: + passAttributes |= CTC_LitDigit; + break; + case pass_letter: + passAttributes |= CTC_Letter; + break; + case pass_math: + passAttributes |= CTC_Math; + break; + case pass_punctuation: + passAttributes |= CTC_Punctuation; + break; + case pass_sign: + passAttributes |= CTC_Sign; + break; + case pass_space: + passAttributes |= CTC_Space; + break; + case pass_uppercase: + passAttributes |= CTC_UpperCase; + break; + case pass_lowercase: + passAttributes |= CTC_LowerCase; + break; + case pass_class1: + passAttributes |= CTC_Class1; + break; + case pass_class2: + passAttributes |= CTC_Class2; + break; + case pass_class3: + passAttributes |= CTC_Class3; + break; + case pass_class4: + passAttributes |= CTC_Class4; + break; + default: + more = 0; + break; + } + if (more) + passLinepos++; + } + if (!passAttributes) + { + compileError (passNested, "Missing attribute"); + passLinepos--; + return 0; + } + return 1; +} + +static int +passGetEmphasis () +{ + int more = 1; + passLinepos++; + passEmphasis = 0; + while (more) + { + switch (passLine.chars[passLinepos]) + { + case 'i': + passEmphasis |= italic; + break; + case 'b': + passEmphasis |= bold; + break; + case 'u': + passEmphasis |= underline; + break; + case 'c': + passEmphasis |= computer_braille; + break; + default: + more = 0; + break; + } + if (more) + passLinepos++; + } + if (!passEmphasis) + { + compileError (passNested, "emphasis indicators expected"); + passLinepos--; + return 0; + } + return 1; +} + +static int +passGetDots () +{ + CharsString collectDots; + collectDots.length = 0; + while (passLinepos < passLine.length && (passLine.chars[passLinepos] + == '-' + || (passLine.chars[passLinepos] >= + '0' + && passLine. + chars[passLinepos] <= '9') + || + ((passLine. + chars[passLinepos] | 32) >= 'a' + && (passLine. + chars[passLinepos] | 32) <= + 'f'))) + collectDots.chars[collectDots.length++] = passLine.chars[passLinepos++]; + if (!parseDots (passNested, &passHoldString, &collectDots)) + return 0; + return 1; +} + +static int +passGetString () +{ + passHoldString.length = 0; + while (1) + { + if (!passLine.chars[passLinepos]) + { + compileError (passNested, "unterminated string"); + return 0; + } + if (passLine.chars[passLinepos] == 34) + break; + if (passLine.chars[passLinepos] == QUOTESUB) + passHoldString.chars[passHoldString.length++] = 34; + else + passHoldString.chars[passHoldString.length++] = + passLine.chars[passLinepos]; + passLinepos++; + } + passHoldString.chars[passHoldString.length] = 0; + passLinepos++; + return 1; +} + +static int +passGetNumber () +{ + /*Convert a string of wide character digits to an integer */ + passHoldNumber = 0; + while (passLine.chars[passLinepos] >= '0' + && passLine.chars[passLinepos] <= '9') + passHoldNumber = + 10 * passHoldNumber + (passLine.chars[passLinepos++] - '0'); + return 1; +} + +static int +passGetName () +{ + TranslationTableCharacterAttributes attr; + passHoldString.length = 0; + do + { + attr = definedCharOrDots (passNested, passLine.chars[passLinepos], + 0)->attributes; + if (passHoldString.length == 0) + { + if (!(attr & CTC_Letter)) + { + passLinepos++; + continue; + } + } + if (!(attr & CTC_Letter)) + break; + passHoldString.chars[passHoldString.length++] = + passLine.chars[passLinepos]; + passLinepos++; + } + while (passLinepos < passLine.length); + return 1; +} + +static int +passIsKeyword (const char *token) +{ + int k; + int length = strlen (token); + int ch = passLine.chars[passLinepos + length + 1]; + if (((ch | 32) >= 'a' && (ch | 32) <= 'z') || (ch >= '0' && ch <= '9')) + return 0; + for (k = 0; k < length && passLine.chars[passLinepos + k + 1] + == (widechar) token[k]; k++); + if (k == length) + { + passLinepos += length + 1; + return 1; + } + return 0; +} + +struct PassName +{ + struct PassName *next; + int varnum; + widechar length; + widechar name[1]; +}; +static struct PassName *passNames = NULL; + +static int +passFindName (const CharsString * name) +{ + const struct PassName *curname = passNames; + CharsString augmentedName; + for (augmentedName.length = 0; augmentedName.length < name->length; + augmentedName.length++) + augmentedName.chars[augmentedName.length] = + name->chars[augmentedName.length]; + augmentedName.chars[augmentedName.length++] = passOpcode; + while (curname) + { + if ((augmentedName.length == curname->length) && + (memcmp + (&augmentedName.chars[0], curname->name, + CHARSIZE * name->length) == 0)) + return curname->varnum; + curname = curname->next; + } + compileError (passNested, "name not found"); + return 0; +} + +static int +passAddName (CharsString * name, int var) +{ + int k; + struct PassName *curname; + CharsString augmentedName; + for (augmentedName.length = 0; + augmentedName.length < name->length; augmentedName.length++) + augmentedName. + chars[augmentedName.length] = name->chars[augmentedName.length]; + augmentedName.chars[augmentedName.length++] = passOpcode; + if (! + (curname = + malloc (sizeof (*curname) + CHARSIZE * (augmentedName.length - 1)))) + { + compileError (passNested, "not enough memory"); + return 0; + } + memset (curname, 0, sizeof (*curname)); + for (k = 0; k < augmentedName.length; k++) + { + curname->name[k] = augmentedName.chars[k]; + } + curname->length = augmentedName.length; + curname->varnum = var; + curname->next = passNames; + passNames = curname; + return 1; +} + +static pass_Codes +passGetScriptToken () +{ + while (passLinepos < passLine.length) + { + passPrevLinepos = passLinepos; + switch (passLine.chars[passLinepos]) + { + case '\"': + passLinepos++; + if (passGetString ()) + return pass_string; + return pass_invalidToken; + case '@': + passLinepos++; + if (passGetDots ()) + return pass_dots; + return pass_invalidToken; + case '#': /*comment */ + passLinepos = passLine.length + 1; + return pass_noMoreTokens; + case '!': + if (passLine.chars[passLinepos + 1] == '=') + { + passLinepos += 2; + return pass_noteq; + } + passLinepos++; + return pass_not; + case '-': + passLinepos++; + return pass_hyphen; + case '=': + passLinepos++; + return pass_eq; + case '<': + passLinepos++; + if (passLine.chars[passLinepos] == '=') + { + passLinepos++; + return pass_lteq; + } + return pass_lt; + case '>': + passLinepos++; + if (passLine.chars[passLinepos] == '=') + { + passLinepos++; + return pass_gteq; + } + return pass_gt; + case '+': + passLinepos++; + return pass_plus; + case '(': + passLinepos++; + return pass_leftParen; + case ')': + passLinepos++; + return pass_rightParen; + case ',': + passLinepos++; + return pass_comma; + case '&': + if (passLine.chars[passLinepos = 1] == '&') + { + passLinepos += 2; + return pass_and; + } + return pass_invalidToken; + case '|': + if (passLine.chars[passLinepos + 1] == '|') + { + passLinepos += 2; + return pass_or; + } + return pass_invalidToken; + case 'a': + if (passIsKeyword ("ttr")) + return pass_attributes; + passGetName (); + return pass_nameFound; + case 'b': + if (passIsKeyword ("ack")) + return pass_lookback; + if (passIsKeyword ("ool")) + return pass_boolean; + passGetName (); + return pass_nameFound; + case 'c': + if (passIsKeyword ("lass")) + return pass_class; + passGetName (); + return pass_nameFound; + case 'd': + if (passIsKeyword ("ef")) + return pass_define; + passGetName (); + return pass_nameFound; + case 'e': + if (passIsKeyword ("mph")) + return pass_emphasis; + passGetName (); + return pass_nameFound; + case 'f': + if (passIsKeyword ("ind")) + return pass_search; + if (passIsKeyword ("irst")) + return pass_first; + passGetName (); + return pass_nameFound; + case 'g': + if (passIsKeyword ("roup")) + return pass_group; + passGetName (); + return pass_nameFound; + case 'i': + if (passIsKeyword ("f")) + return pass_if; + passGetName (); + return pass_nameFound; + case 'l': + if (passIsKeyword ("ast")) + return pass_last; + passGetName (); + return pass_nameFound; + case 'm': + if (passIsKeyword ("ark")) + return pass_mark; + passGetName (); + return pass_nameFound; + case 'r': + if (passIsKeyword ("epgroup")) + return pass_repGroup; + if (passIsKeyword ("epcopy")) + return pass_copy; + if (passIsKeyword ("epomit")) + return pass_omit; + if (passIsKeyword ("ep")) + return pass_replace; + passGetName (); + return pass_nameFound; + case 's': + if (passIsKeyword ("cript")) + return pass_script; + if (passIsKeyword ("wap")) + return pass_swap; + passGetName (); + return pass_nameFound; + case 't': + if (passIsKeyword ("hen")) + return pass_then; + passGetName (); + return pass_nameFound; + default: + if (passLine.chars[passLinepos] <= 32) + { + passLinepos++; + break; + } + if (passLine.chars[passLinepos] >= '0' + && passLine.chars[passLinepos] <= '9') + { + passGetNumber (); + return pass_numberFound; + } + else + { + if (!passGetName ()) + return pass_invalidToken; + else + return pass_nameFound; + } + } + } + return pass_noMoreTokens; +} + +static int +passIsLeftParen () +{ + pass_Codes passCode = passGetScriptToken (); + if (passCode != pass_leftParen) + { + compileError (passNested, "'(' expected"); + return 0; + } + return 1; +} + +static int +passIsName () +{ + pass_Codes passCode = passGetScriptToken (); + if (passCode != pass_nameFound) + { + compileError (passNested, "a name expected"); + return 0; + } + return 1; +} + +static int +passIsComma () +{ + pass_Codes passCode = passGetScriptToken (); + if (passCode != pass_comma) + { + compileError (passNested, "',' expected"); + return 0; + } + return 1; +} + +static int +passIsNumber () +{ + pass_Codes passCode = passGetScriptToken (); + if (passCode != pass_numberFound) + { + compileError (passNested, "a number expected"); + return 0; + } + return 1; +} + +static int +passIsRightParen () +{ + pass_Codes passCode = passGetScriptToken (); + if (passCode != pass_rightParen) + { + compileError (passNested, "')' expected"); + return 0; + } + return 1; +} + +static int +passGetRange () +{ + pass_Codes passCode = passGetScriptToken (); + if (!(passCode == pass_comma || passCode == pass_rightParen)) + { + compileError (passNested, "invalid range"); + return 0; + } + if (passCode == pass_rightParen) + { + passInstructions[passIC++] = 1; + passInstructions[passIC++] = 1; + return 1; + } + if (!passIsNumber ()) + return 0; + passInstructions[passIC++] = passHoldNumber; + passCode = passGetScriptToken (); + if (!(passCode == pass_comma || passCode == pass_rightParen)) + { + compileError (passNested, "invalid range"); + return 0; + } + if (passCode == pass_rightParen) + { + passInstructions[passIC++] = passHoldNumber; + return 1; + } + if (!passIsNumber ()) + return 0; + passInstructions[passIC++] = passHoldNumber; + if (!passIsRightParen ()) + return 0; + return 1; +} + +static int +passInsertAttributes () +{ + passInstructions[passIC++] = pass_attributes; + passInstructions[passIC++] = passAttributes >> 16; + passInstructions[passIC++] = passAttributes & 0xffff; + if (!passGetRange ()) + return 0; + return 1; +} + +static int +compilePassOpcode (FileInfo * nested, TranslationTableOpcode opcode) +{ +/*Compile the operands of a pass opcode */ + TranslationTableCharacterAttributes after = 0; + TranslationTableCharacterAttributes before = 0; + widechar passSubOp; + const struct CharacterClass *class; + TranslationTableOffset ruleOffset = 0; + TranslationTableRule *rule = NULL; + int k; + int kk = 0; + pass_Codes passCode; + int endTest = 0; + int isScript = 1; + passInstructions = passRuleDots.chars; + passIC = 0; /*Instruction counter */ + passRuleChars.length = 0; + passNested = nested; + passOpcode = opcode; +/* passHoldString and passLine are static variables declared + * previously.*/ + passLinepos = 0; + passHoldString.length = 0; + for (k = nested->linepos; k < nested->linelen; k++) + passHoldString.chars[passHoldString.length++] = nested->line[k]; + if (!eqasc2uni ((unsigned char *) "script", passHoldString.chars, 6)) + { + isScript = 0; +#define SEPCHAR 0x0001 + for (k = 0; k < passHoldString.length && passHoldString.chars[k] > 32; + k++); + if (k < passHoldString.length) + passHoldString.chars[k] = SEPCHAR; + else + { + compileError (passNested, "Invalid multipass operands"); + return 0; + } + } + parseChars (passNested, &passLine, &passHoldString); + if (isScript) + { + int more = 1; + passCode = passGetScriptToken (); + if (passCode != pass_script) + { + compileError (passNested, "Invalid multipass statement"); + return 0; + } + /* Declaratives */ + while (more) + { + passCode = passGetScriptToken (); + switch (passCode) + { + case pass_define: + if (!passIsLeftParen ()) + return 0; + if (!passIsName ()) + return 0; + if (!passIsComma ()) + return 0; + if (!passIsNumber ()) + return 0; + if (!passIsRightParen ()) + return 0; + passAddName (&passHoldString, passHoldNumber); + break; + case pass_if: + more = 0; + break; + default: + compileError (passNested, + "invalid definition in declarative part"); + return 0; + } + } + /* if part */ + more = 1; + while (more) + { + passCode = passGetScriptToken (); + passSubOp = passCode; + switch (passCode) + { + case pass_not: + passInstructions[passIC++] = pass_not; + break; + case pass_first: + passInstructions[passIC++] = pass_first; + break; + case pass_last: + passInstructions[passIC++] = pass_last; + break; + case pass_search: + passInstructions[passIC++] = pass_search; + break; + case pass_string: + if (opcode != CTO_Context && opcode != CTO_Correct) + { + compileError (passNested, + "Character strings can only be used with the context and correct opcodes."); + return 0; + } + passInstructions[passIC++] = pass_string; + goto ifDoCharsDots; + case pass_dots: + if (passOpcode == CTO_Correct || passOpcode == CTO_Context) + { + compileError (passNested, + "dot patterns cannot be specified in the if part\ + of the correct or context opcodes"); + return 0; + } + passInstructions[passIC++] = pass_dots; + ifDoCharsDots: + passInstructions[passIC++] = passHoldString.length; + for (kk = 0; kk < passHoldString.length; kk++) + passInstructions[passIC++] = passHoldString.chars[kk]; + break; + case pass_attributes: + if (!passIsLeftParen ()) + return 0; + if (!passGetAttributes ()) + return 0; + if (!passInsertAttributes ()) + return 0; + break; + case pass_emphasis: + if (!passIsLeftParen ()) + return 0; + if (!passGetEmphasis ()) + return 0; + /*Right parenthis handled by subfunctiion */ + break; + case pass_lookback: + passInstructions[passIC++] = pass_lookback; + passCode = passGetScriptToken (); + if (passCode != pass_leftParen) + { + passInstructions[passIC++] = 1; + passLinepos = passPrevLinepos; + break; + } + if (!passIsNumber ()) + return 0; + if (!passIsRightParen ()) + return 0; + passInstructions[passIC] = passHoldNumber; + break; + case pass_group: + if (!passIsLeftParen ()) + return 0; + break; + case pass_mark: + passInstructions[passIC++] = pass_startReplace; + passInstructions[passIC++] = pass_endReplace; + break; + case pass_replace: + passInstructions[passIC++] = pass_startReplace; + if (!passIsLeftParen ()) + return 0; + break; + case pass_rightParen: + passInstructions[passIC++] = pass_endReplace; + break; + case pass_groupstart: + case pass_groupend: + if (!passIsLeftParen ()) + return 0; + if (!passGetName ()) + return 0; + if (!passIsRightParen ()) + return 0; + ruleOffset = findRuleName (&passHoldString); + if (ruleOffset) + rule = (TranslationTableRule *) & table->ruleArea[ruleOffset]; + if (rule && rule->opcode == CTO_Grouping) + { + passInstructions[passIC++] = passSubOp; + passInstructions[passIC++] = ruleOffset >> 16; + passInstructions[passIC++] = ruleOffset & 0xffff; + break; + } + else + { + compileError (passNested, "%s is not a grouping name", + showString (&passHoldString.chars[0], + passHoldString.length)); + return 0; + } + break; + case pass_class: + if (!passIsLeftParen ()) + return 0; + if (!passGetName ()) + return 0; + if (!passIsRightParen ()) + return 0; + if (!(class = findCharacterClass (&passHoldString))) + return 0; + passAttributes = class->attribute; + passInsertAttributes (); + break; + case pass_swap: + ruleOffset = findRuleName (&passHoldString); + if (!passIsLeftParen ()) + return 0; + if (!passGetName ()) + return 0; + if (!passIsRightParen ()) + return 0; + ruleOffset = findRuleName (&passHoldString); + if (ruleOffset) + rule = (TranslationTableRule *) & table->ruleArea[ruleOffset]; + if (rule + && (rule->opcode == CTO_SwapCc || rule->opcode == CTO_SwapCd + || rule->opcode == CTO_SwapDd)) + { + passInstructions[passIC++] = pass_swap; + passInstructions[passIC++] = ruleOffset >> 16; + passInstructions[passIC++] = ruleOffset & 0xffff; + if (!passGetRange ()) + return 0; + break; + } + compileError (passNested, + "%s is not a swap name.", + showString (&passHoldString.chars[0], + passHoldString.length)); + return 0; + case pass_nameFound: + passHoldNumber = passFindName (&passHoldString); + passCode = passGetScriptToken (); + if (!(passCode == pass_eq || passCode == pass_lt || passCode + == pass_gt || passCode == pass_noteq || passCode == + pass_lteq || passCode == pass_gteq)) + { + compileError (nested, + "invalid comparison operator in if part"); + return 0; + } + passInstructions[passIC++] = passCode; + passInstructions[passIC++] = passHoldNumber; + if (!passIsNumber ()) + return 0; + passInstructions[passIC++] = passHoldNumber; + break; + case pass_then: + passInstructions[passIC++] = pass_endTest; + more = 0; + break; + default: + compileError (passNested, "invalid choice in if part"); + return 0; + } + } + + /* then part */ + more = 1; + while (more) + { + passCode = passGetScriptToken (); + passSubOp = passCode; + switch (passCode) + { + case pass_string: + if (opcode != CTO_Correct) + { + compileError (passNested, + "Character strings can only be used in the then part with the correct opcode."); + return 0; + } + passInstructions[passIC++] = pass_string; + goto thenDoCharsDots; + case pass_dots: + if (opcode == CTO_Correct) + { + compileError (passNested, + "Dot patterns cannot be used with the correct opcode."); + return 0; + } + passInstructions[passIC++] = pass_dots; + thenDoCharsDots: + passInstructions[passIC++] = passHoldString.length; + for (kk = 0; kk < passHoldString.length; kk++) + passInstructions[passIC++] = passHoldString.chars[kk]; + break; + case pass_nameFound: + passHoldNumber = passFindName (&passHoldString); + passCode = passGetScriptToken (); + if (!(passCode == pass_plus || passCode == pass_hyphen + || passCode == pass_eq)) + { + compileError (nested, + "Invalid variable operator in then part"); + return 0; + } + passInstructions[passIC++] = passCode; + passInstructions[passIC++] = passHoldNumber; + if (!passIsNumber ()) + return 0; + passInstructions[passIC++] = passHoldNumber; + break; + case pass_copy: + passInstructions[passIC++] = pass_copy; + break; + case pass_omit: + passInstructions[passIC++] = pass_omit; + break; + case pass_swap: + ruleOffset = findRuleName (&passHoldString); + if (!passIsLeftParen ()) + return 0; + if (!passGetName ()) + return 0; + if (!passIsRightParen ()) + return 0; + ruleOffset = findRuleName (&passHoldString); + if (ruleOffset) + rule = (TranslationTableRule *) & table->ruleArea[ruleOffset]; + if (rule + && (rule->opcode == CTO_SwapCc || rule->opcode == CTO_SwapCd + || rule->opcode == CTO_SwapDd)) + { + passInstructions[passIC++] = pass_swap; + passInstructions[passIC++] = ruleOffset >> 16; + passInstructions[passIC++] = ruleOffset & 0xffff; + if (!passGetRange ()) + return 0; + break; + } + compileError (passNested, + "%s is not a swap name.", + showString (&passHoldString.chars[0], + passHoldString.length)); + return 0; + case pass_noMoreTokens: + more = 0; + break; + default: + compileError (passNested, "invalid action in then part"); + return 0; + } + } + } + else + { + /* Older machine-language-like "assembler". */ + + /*Compile test part */ + for (k = 0; k < passLine.length && passLine.chars[k] != SEPCHAR; k++); + endTest = k; + passLine.chars[endTest] = pass_endTest; + passLinepos = 0; + while (passLinepos <= endTest) + { + switch ((passSubOp = passLine.chars[passLinepos])) + { + case pass_lookback: + passInstructions[passIC++] = pass_lookback; + passLinepos++; + passGetNumber (); + if (passHoldNumber == 0) + passHoldNumber = 1; + passInstructions[passIC++] = passHoldNumber; + break; + case pass_not: + passInstructions[passIC++] = pass_not; + passLinepos++; + break; + case pass_first: + passInstructions[passIC++] = pass_first; + passLinepos++; + break; + case pass_last: + passInstructions[passIC++] = pass_last; + passLinepos++; + break; + case pass_search: + passInstructions[passIC++] = pass_search; + passLinepos++; + break; + case pass_string: + if (opcode != CTO_Context && opcode != CTO_Correct) + { + compileError (passNested, + "Character strings can only be used with the context and correct opcodes."); + return 0; + } + passLinepos++; + passInstructions[passIC++] = pass_string; + passGetString (); + goto testDoCharsDots; + case pass_dots: + passLinepos++; + passInstructions[passIC++] = pass_dots; + passGetDots (); + testDoCharsDots: + if (passHoldString.length == 0) + return 0; + passInstructions[passIC++] = passHoldString.length; + for (kk = 0; kk < passHoldString.length; kk++) + passInstructions[passIC++] = passHoldString.chars[kk]; + break; + case pass_startReplace: + passInstructions[passIC++] = pass_startReplace; + passLinepos++; + break; + case pass_endReplace: + passInstructions[passIC++] = pass_endReplace; + passLinepos++; + break; + case pass_variable: + passLinepos++; + passGetNumber (); + switch (passLine.chars[passLinepos]) + { + case pass_eq: + passInstructions[passIC++] = pass_eq; + goto doComp; + case pass_lt: + if (passLine.chars[passLinepos + 1] == pass_eq) + { + passLinepos++; + passInstructions[passIC++] = pass_lteq; + } + else + passInstructions[passIC++] = pass_lt; + goto doComp; + case pass_gt: + if (passLine.chars[passLinepos + 1] == pass_eq) + { + passLinepos++; + passInstructions[passIC++] = pass_gteq; + } + else + passInstructions[passIC++] = pass_gt; + doComp: + passInstructions[passIC++] = passHoldNumber; + passLinepos++; + passGetNumber (); + passInstructions[passIC++] = passHoldNumber; + break; + default: + compileError (passNested, "incorrect comparison operator"); + return 0; + } + break; + case pass_attributes: + passLinepos++; + passGetAttributes (); + insertAttributes: + passInstructions[passIC++] = pass_attributes; + passInstructions[passIC++] = passAttributes >> 16; + passInstructions[passIC++] = passAttributes & 0xffff; + getRange: + if (passLine.chars[passLinepos] == pass_until) + { + passLinepos++; + passInstructions[passIC++] = 1; + passInstructions[passIC++] = 0xffff; + break; + } + passGetNumber (); + if (passHoldNumber == 0) + { + passHoldNumber = passInstructions[passIC++] = 1; + passInstructions[passIC++] = 1; /*This is not an error */ + break; + } + passInstructions[passIC++] = passHoldNumber; + if (passLine.chars[passLinepos] != pass_hyphen) + { + passInstructions[passIC++] = passHoldNumber; + break; + } + passLinepos++; + passGetNumber (); + if (passHoldNumber == 0) + { + compileError (passNested, "invalid range"); + return 0; + } + passInstructions[passIC++] = passHoldNumber; + break; + case pass_groupstart: + case pass_groupend: + passLinepos++; + passGetName (); + ruleOffset = findRuleName (&passHoldString); + if (ruleOffset) + rule = (TranslationTableRule *) & table->ruleArea[ruleOffset]; + if (rule && rule->opcode == CTO_Grouping) + { + passInstructions[passIC++] = passSubOp; + passInstructions[passIC++] = ruleOffset >> 16; + passInstructions[passIC++] = ruleOffset & 0xffff; + break; + } + else + { + compileError (passNested, "%s is not a grouping name", + showString (&passHoldString.chars[0], + passHoldString.length)); + return 0; + } + break; + case pass_swap: + passGetName (); + if ((class = findCharacterClass (&passHoldString))) + { + passAttributes = class->attribute; + goto insertAttributes; + } + ruleOffset = findRuleName (&passHoldString); + if (ruleOffset) + rule = (TranslationTableRule *) & table->ruleArea[ruleOffset]; + if (rule + && (rule->opcode == CTO_SwapCc || rule->opcode == CTO_SwapCd + || rule->opcode == CTO_SwapDd)) + { + passInstructions[passIC++] = pass_swap; + passInstructions[passIC++] = ruleOffset >> 16; + passInstructions[passIC++] = ruleOffset & 0xffff; + goto getRange; + } + compileError (passNested, + "%s is neither a class name nor a swap name.", + showString (&passHoldString.chars[0], + passHoldString.length)); + return 0; + case pass_endTest: + passInstructions[passIC++] = pass_endTest; + passLinepos++; + break; + default: + compileError (passNested, + "incorrect operator '%c ' in test part", + passLine.chars[passLinepos]); + return 0; + } + + } /*Compile action part */ + + /* Compile action part */ + while (passLinepos < passLine.length && + passLine.chars[passLinepos] <= 32) + passLinepos++; + while (passLinepos < passLine.length && + passLine.chars[passLinepos] > 32) + { + switch ((passSubOp = passLine.chars[passLinepos])) + { + case pass_string: + if (opcode != CTO_Correct) + { + compileError (passNested, + "Character strings can only be used with the ccorrect opcode."); + return 0; + } + passLinepos++; + passInstructions[passIC++] = pass_string; + passGetString (); + goto actionDoCharsDots; + case pass_dots: + if (opcode == CTO_Correct) + { + compileError (passNested, + "Dot patterns cannot be used with the correct opcode."); + return 0; + } + passLinepos++; + passGetDots (); + passInstructions[passIC++] = pass_dots; + actionDoCharsDots: + if (passHoldString.length == 0) + return 0; + passInstructions[passIC++] = passHoldString.length; + for (kk = 0; kk < passHoldString.length; kk++) + passInstructions[passIC++] = passHoldString.chars[kk]; + break; + case pass_variable: + passLinepos++; + passGetNumber (); + switch (passLine.chars[passLinepos]) + { + case pass_eq: + passInstructions[passIC++] = pass_eq; + passInstructions[passIC++] = passHoldNumber; + passLinepos++; + passGetNumber (); + passInstructions[passIC++] = passHoldNumber; + break; + case pass_plus: + case pass_hyphen: + passInstructions[passIC++] = passLine.chars[passLinepos]; + passInstructions[passIC++] = passHoldNumber; + break; + default: + compileError (passNested, + "incorrect variable operator in action part"); + return 0; + } + break; + case pass_copy: + passInstructions[passIC++] = pass_copy; + passLinepos++; + break; + case pass_omit: + passInstructions[passIC++] = pass_omit; + passLinepos++; + break; + case pass_groupreplace: + case pass_groupstart: + case pass_groupend: + passLinepos++; + passGetName (); + ruleOffset = findRuleName (&passHoldString); + if (ruleOffset) + rule = (TranslationTableRule *) & table->ruleArea[ruleOffset]; + if (rule && rule->opcode == CTO_Grouping) + { + passInstructions[passIC++] = passSubOp; + passInstructions[passIC++] = ruleOffset >> 16; + passInstructions[passIC++] = ruleOffset & 0xffff; + break; + } + compileError (passNested, "%s is not a grouping name", + showString (&passHoldString.chars[0], + passHoldString.length)); + return 0; + case pass_swap: + passLinepos++; + passGetName (); + ruleOffset = findRuleName (&passHoldString); + if (ruleOffset) + rule = (TranslationTableRule *) & table->ruleArea[ruleOffset]; + if (rule + && (rule->opcode == CTO_SwapCc || rule->opcode == CTO_SwapCd + || rule->opcode == CTO_SwapDd)) + { + passInstructions[passIC++] = pass_swap; + passInstructions[passIC++] = ruleOffset >> 16; + passInstructions[passIC++] = ruleOffset & 0xffff; + break; + } + compileError (passNested, "%s is not a swap name.", + showString (&passHoldString.chars[0], + passHoldString.length)); + return 0; + break; + default: + compileError (passNested, "incorrect operator in action part"); + return 0; + } + } + } + + /*Analyze and add rule */ + passRuleDots.length = passIC; + passIC = 0; + while (passIC < passRuleDots.length) + { + int start = 0; + switch (passInstructions[passIC]) + { + case pass_string: + case pass_dots: + case pass_attributes: + case pass_swap: + start = 1; + break; + case pass_groupstart: + case pass_groupend: + start = 1; + break; + case pass_eq: + case pass_lt: + case pass_gt: + case pass_lteq: + case pass_gteq: + passIC += 3; + break; + case pass_lookback: + passIC += 2; + break; + case pass_not: + case pass_startReplace: + case pass_endReplace: + case pass_first: + passIC++; + break; + default: + compileError (passNested, + "Test/if part must contain characters, dots, attributes or class \ +swap."); + return 0; + } + if (start) + break; + } + + switch (passInstructions[passIC]) + { + case pass_string: + case pass_dots: + for (k = 0; k < passInstructions[passIC + 1]; k++) + passRuleChars.chars[k] = passInstructions[passIC + 2 + k]; + passRuleChars.length = k; + after = before = 0; + break; + case pass_attributes: + case pass_groupstart: + case pass_groupend: + case pass_swap: + after = passRuleDots.length; + before = 0; + break; + default: + break; + } + if (!addRule (passNested, opcode, &passRuleChars, &passRuleDots, + after, before)) + return 0; + return 1; +} + +/* End of multipass compiler */ + +static int +compileBrailleIndicator (FileInfo * nested, char *ermsg, + TranslationTableOpcode opcode, + TranslationTableOffset * rule) +{ + CharsString token; + CharsString cells; + if (getToken (nested, &token, ermsg)) + if (parseDots (nested, &cells, &token)) + if (!addRule (nested, opcode, NULL, &cells, 0, 0)) + return 0; + *rule = newRuleOffset; + return 1; +} + +static int +compileNumber (FileInfo * nested) +{ + CharsString token; + widechar dest; + if (!getToken (nested, &token, "number")) + return 0; + getNumber (&token.chars[0], &dest); + if (!(dest > 0)) + { + compileError (nested, "a nonzero positive number is required"); + return 0; + } + return dest; +} + +static int +compileGrouping (FileInfo * nested) +{ + int k; + CharsString name; + CharsString groupChars; + CharsString groupDots; + CharsString dotsParsed; + TranslationTableCharacter *charsDotsPtr; + widechar endChar; + widechar endDots; + if (!getToken (nested, &name, "name operand")) + return 0; + if (!getRuleCharsText (nested, &groupChars)) + return 0; + if (!getToken (nested, &groupDots, "dots operand")) + return 0; + for (k = 0; k < groupDots.length && groupDots.chars[k] != ','; k++); + if (k == groupDots.length) + { + compileError (nested, + "Dots operand must consist of two cells separated by a comma"); + return 0; + } + groupDots.chars[k] = '-'; + if (!parseDots (nested, &dotsParsed, &groupDots)) + return 0; + if (groupChars.length != 2 || dotsParsed.length != 2) + { + compileError (nested, + "two Unicode characters and two cells separated by a comma are needed."); + return 0; + } + charsDotsPtr = addCharOrDots (nested, groupChars.chars[0], 0); + charsDotsPtr->attributes |= CTC_Math; + charsDotsPtr->uppercase = charsDotsPtr->realchar; + charsDotsPtr->lowercase = charsDotsPtr->realchar; + charsDotsPtr = addCharOrDots (nested, groupChars.chars[1], 0); + charsDotsPtr->attributes |= CTC_Math; + charsDotsPtr->uppercase = charsDotsPtr->realchar; + charsDotsPtr->lowercase = charsDotsPtr->realchar; + charsDotsPtr = addCharOrDots (nested, dotsParsed.chars[0], 1); + charsDotsPtr->attributes |= CTC_Math; + charsDotsPtr->uppercase = charsDotsPtr->realchar; + charsDotsPtr->lowercase = charsDotsPtr->realchar; + charsDotsPtr = addCharOrDots (nested, dotsParsed.chars[1], 1); + charsDotsPtr->attributes |= CTC_Math; + charsDotsPtr->uppercase = charsDotsPtr->realchar; + charsDotsPtr->lowercase = charsDotsPtr->realchar; + if (!addRule (nested, CTO_Grouping, &groupChars, &dotsParsed, 0, 0)) + return 0; + if (!addRuleName (nested, &name)) + return 0; + putCharAndDots (nested, groupChars.chars[0], dotsParsed.chars[0]); + putCharAndDots (nested, groupChars.chars[1], dotsParsed.chars[1]); + endChar = groupChars.chars[1]; + endDots = dotsParsed.chars[1]; + groupChars.length = dotsParsed.length = 1; + if (!addRule (nested, CTO_Math, &groupChars, &dotsParsed, 0, 0)) + return 0; + groupChars.chars[0] = endChar; + dotsParsed.chars[0] = endDots; + if (!addRule (nested, CTO_Math, &groupChars, &dotsParsed, 0, 0)) + return 0; + return 1; +} + +static int +compileUplow (FileInfo * nested) +{ + int k; + TranslationTableCharacter *upperChar; + TranslationTableCharacter *lowerChar; + TranslationTableCharacter *upperCell = NULL; + TranslationTableCharacter *lowerCell = NULL; + CharsString ruleChars; + CharsString ruleDots; + CharsString upperDots; + CharsString lowerDots; + int haveLowerDots = 0; + TranslationTableCharacterAttributes attr; + if (!getRuleCharsText (nested, &ruleChars)) + return 0; + if (!getToken (nested, &ruleDots, "dots operand")) + return 0; + for (k = 0; k < ruleDots.length && ruleDots.chars[k] != ','; k++); + if (k == ruleDots.length) + { + if (!parseDots (nested, &upperDots, &ruleDots)) + return 0; + lowerDots.length = upperDots.length; + for (k = 0; k < upperDots.length; k++) + lowerDots.chars[k] = upperDots.chars[k]; + lowerDots.chars[k] = 0; + } + else + { + haveLowerDots = ruleDots.length; + ruleDots.length = k; + if (!parseDots (nested, &upperDots, &ruleDots)) + return 0; + ruleDots.length = 0; + k++; + for (; k < haveLowerDots; k++) + ruleDots.chars[ruleDots.length++] = ruleDots.chars[k]; + if (!parseDots (nested, &lowerDots, &ruleDots)) + return 0; + } + if (ruleChars.length != 2 || upperDots.length < 1) + { + compileError (nested, + "Exactly two Unicode characters and at least one cell are required."); + return 0; + } + if (haveLowerDots && lowerDots.length < 1) + { + compileError (nested, "at least one cell is required after the comma."); + return 0; + } + upperChar = addCharOrDots (nested, ruleChars.chars[0], 0); + upperChar->attributes |= CTC_Letter | CTC_UpperCase; + upperChar->uppercase = ruleChars.chars[0]; + upperChar->lowercase = ruleChars.chars[1]; + lowerChar = addCharOrDots (nested, ruleChars.chars[1], 0); + lowerChar->attributes |= CTC_Letter | CTC_LowerCase; + lowerChar->uppercase = ruleChars.chars[0]; + lowerChar->lowercase = ruleChars.chars[1]; + for (k = 0; k < upperDots.length; k++) + if (!compile_findCharOrDots (upperDots.chars[k], 1)) + { + attr = CTC_Letter | CTC_UpperCase; + upperCell = addCharOrDots (nested, upperDots.chars[k], 1); + if (upperDots.length != 1) + attr = CTC_Space; + upperCell->attributes |= attr; + upperCell->uppercase = upperCell->realchar; + } + if (haveLowerDots) + { + for (k = 0; k < lowerDots.length; k++) + if (!compile_findCharOrDots (lowerDots.chars[k], 1)) + { + attr = CTC_Letter | CTC_LowerCase; + lowerCell = addCharOrDots (nested, lowerDots.chars[k], 1); + if (lowerDots.length != 1) + attr = CTC_Space; + lowerCell->attributes |= attr; + lowerCell->lowercase = lowerCell->realchar; + } + } + else if (upperCell != NULL && upperDots.length == 1) + upperCell->attributes |= CTC_LowerCase; + if (lowerDots.length == 1) + putCharAndDots (nested, ruleChars.chars[1], lowerDots.chars[0]); + if (upperCell != NULL) + upperCell->lowercase = lowerDots.chars[0]; + if (lowerCell != NULL) + lowerCell->uppercase = upperDots.chars[0]; + if (upperDots.length == 1) + putCharAndDots (nested, ruleChars.chars[0], upperDots.chars[0]); + ruleChars.length = 1; + ruleChars.chars[2] = ruleChars.chars[0]; + ruleChars.chars[0] = ruleChars.chars[1]; + if (!addRule (nested, CTO_LowerCase, &ruleChars, &lowerDots, 0, 0)) + return 0; + ruleChars.chars[0] = ruleChars.chars[2]; + if (!addRule (nested, CTO_UpperCase, &ruleChars, &upperDots, 0, 0)) + return 0; + return 1; +} + +/*Functions for compiling hyphenation tables*/ + +typedef struct /*hyphenation dictionary: finite state machine */ +{ + int numStates; + HyphenationState *states; +} HyphenDict; + +#define DEFAULTSTATE 0xffff +#define HYPHENHASHSIZE 8191 + +typedef struct +{ + void *next; + CharsString *key; + int val; +} HyphenHashEntry; + +typedef struct +{ + HyphenHashEntry *entries[HYPHENHASHSIZE]; +} HyphenHashTab; + +/* a hash function from ASU - adapted from Gtk+ */ +static unsigned int +hyphenStringHash (const CharsString * s) +{ + int k; + unsigned int h = 0, g; + for (k = 0; k < s->length; k++) + { + h = (h << 4) + s->chars[k]; + if ((g = h & 0xf0000000)) + { + h = h ^ (g >> 24); + h = h ^ g; + } + } + return h; +} + +static HyphenHashTab * +hyphenHashNew (void) +{ + HyphenHashTab *hashTab; + hashTab = malloc (sizeof (HyphenHashTab)); + memset (hashTab, 0, sizeof (HyphenHashTab)); + return hashTab; +} + +static void +hyphenHashFree (HyphenHashTab * hashTab) +{ + int i; + HyphenHashEntry *e, *next; + for (i = 0; i < HYPHENHASHSIZE; i++) + for (e = hashTab->entries[i]; e; e = next) + { + next = e->next; + free (e->key); + free (e); + } + free (hashTab); +} + +/* assumes that key is not already present! */ +static void +hyphenHashInsert (HyphenHashTab * hashTab, const CharsString * key, int val) +{ + int i, j; + HyphenHashEntry *e; + i = hyphenStringHash (key) % HYPHENHASHSIZE; + e = malloc (sizeof (HyphenHashEntry)); + e->next = hashTab->entries[i]; + e->key = malloc ((key->length + 1) * CHARSIZE); + e->key->length = key->length; + for (j = 0; j < key->length; j++) + e->key->chars[j] = key->chars[j]; + e->val = val; + hashTab->entries[i] = e; +} + +/* return val if found, otherwise DEFAULTSTATE */ +static int +hyphenHashLookup (HyphenHashTab * hashTab, const CharsString * key) +{ + int i, j; + HyphenHashEntry *e; + if (key->length == 0) + return 0; + i = hyphenStringHash (key) % HYPHENHASHSIZE; + for (e = hashTab->entries[i]; e; e = e->next) + { + if (key->length != e->key->length) + continue; + for (j = 0; j < key->length; j++) + if (key->chars[j] != e->key->chars[j]) + break; + if (j == key->length) + return e->val; + } + return DEFAULTSTATE; +} + +static int +hyphenGetNewState (HyphenDict * dict, HyphenHashTab * hashTab, const + CharsString * string) +{ + hyphenHashInsert (hashTab, string, dict->numStates); + /* predicate is true if dict->numStates is a power of two */ + if (!(dict->numStates & (dict->numStates - 1))) + dict->states = realloc (dict->states, + (dict->numStates << 1) * + sizeof (HyphenationState)); + dict->states[dict->numStates].hyphenPattern = 0; + dict->states[dict->numStates].fallbackState = DEFAULTSTATE; + dict->states[dict->numStates].numTrans = 0; + dict->states[dict->numStates].trans.pointer = NULL; + return dict->numStates++; +} + +/* add a transition from state1 to state2 through ch - assumes that the + transition does not already exist */ +static void +hyphenAddTrans (HyphenDict * dict, int state1, int state2, widechar ch) +{ + int numTrans; + numTrans = dict->states[state1].numTrans; + if (numTrans == 0) + dict->states[state1].trans.pointer = malloc (sizeof (HyphenationTrans)); + else if (!(numTrans & (numTrans - 1))) + dict->states[state1].trans.pointer = realloc + (dict->states[state1].trans.pointer, + (numTrans << 1) * sizeof (HyphenationTrans)); + dict->states[state1].trans.pointer[numTrans].ch = ch; + dict->states[state1].trans.pointer[numTrans].newState = state2; + dict->states[state1].numTrans++; +} + +static int +compileHyphenation (FileInfo * nested, CharsString * encoding) +{ + CharsString hyph; + HyphenationTrans *holdPointer; + HyphenHashTab *hashTab; + CharsString word; + char pattern[MAXSTRING]; + unsigned int stateNum = 0, lastState = 0; + int i, j, k = encoding->length; + widechar ch; + int found; + HyphenHashEntry *e; + HyphenDict dict; + TranslationTableOffset holdOffset; + /*Set aside enough space for hyphenation states and transitions in + * translation table. Must be done before anything else*/ + reserveSpaceInTable (nested, 250000); + hashTab = hyphenHashNew (); + dict.numStates = 1; + dict.states = malloc (sizeof (HyphenationState)); + dict.states[0].hyphenPattern = 0; + dict.states[0].fallbackState = DEFAULTSTATE; + dict.states[0].numTrans = 0; + dict.states[0].trans.pointer = NULL; + do + { + if (encoding->chars[0] == 'I') + { + if (!getToken (nested, &hyph, NULL)) + continue; + } + else + { + /*UTF-8 */ + if (!getToken (nested, &word, NULL)) + continue; + parseChars (nested, &hyph, &word); + } + if (hyph.length == 0 || hyph.chars[0] == '#' || hyph.chars[0] == + '%' || hyph.chars[0] == '<') + continue; /*comment */ + for (i = 0; i < hyph.length; i++) + definedCharOrDots (nested, hyph.chars[i], 0); + j = 0; + pattern[j] = '0'; + for (i = 0; i < hyph.length; i++) + { + if (hyph.chars[i] >= '0' && hyph.chars[i] <= '9') + pattern[j] = (char) hyph.chars[i]; + else + { + word.chars[j] = hyph.chars[i]; + pattern[++j] = '0'; + } + } + word.chars[j] = 0; + word.length = j; + pattern[j + 1] = 0; + for (i = 0; pattern[i] == '0'; i++); + found = hyphenHashLookup (hashTab, &word); + if (found != DEFAULTSTATE) + stateNum = found; + else + stateNum = hyphenGetNewState (&dict, hashTab, &word); + k = j + 2 - i; + if (k > 0) + { + allocateSpaceInTable (nested, + &dict.states[stateNum].hyphenPattern, k); + memcpy (&table->ruleArea[dict.states[stateNum].hyphenPattern], + &pattern[i], k); + } + /* now, put in the prefix transitions */ + while (found == DEFAULTSTATE) + { + lastState = stateNum; + ch = word.chars[word.length-- - 1]; + found = hyphenHashLookup (hashTab, &word); + if (found != DEFAULTSTATE) + stateNum = found; + else + stateNum = hyphenGetNewState (&dict, hashTab, &word); + hyphenAddTrans (&dict, stateNum, lastState, ch); + } + } + while (getALine (nested)); + /* put in the fallback states */ + for (i = 0; i < HYPHENHASHSIZE; i++) + { + for (e = hashTab->entries[i]; e; e = e->next) + { + for (j = 1; j <= e->key->length; j++) + { + word.length = 0; + for (k = j; k < e->key->length; k++) + word.chars[word.length++] = e->key->chars[k]; + stateNum = hyphenHashLookup (hashTab, &word); + if (stateNum != DEFAULTSTATE) + break; + } + if (e->val) + dict.states[e->val].fallbackState = stateNum; + } + } + hyphenHashFree (hashTab); +/*Transfer hyphenation information to table*/ + for (i = 0; i < dict.numStates; i++) + { + if (dict.states[i].numTrans == 0) + dict.states[i].trans.offset = 0; + else + { + holdPointer = dict.states[i].trans.pointer; + allocateSpaceInTable (nested, + &dict.states[i].trans.offset, + dict.states[i].numTrans * + sizeof (HyphenationTrans)); + memcpy (&table->ruleArea[dict.states[i].trans.offset], + holdPointer, + dict.states[i].numTrans * sizeof (HyphenationTrans)); + free (holdPointer); + } + } + allocateSpaceInTable (nested, + &holdOffset, dict.numStates * + sizeof (HyphenationState)); + table->hyphenStatesArray = holdOffset; + /* Prevents segmentajion fault if table is reallocated */ + memcpy (&table->ruleArea[table->hyphenStatesArray], &dict.states[0], + dict.numStates * sizeof (HyphenationState)); + free (dict.states); + return 1; +} + +static int +compileNoBreak (FileInfo * nested) +{ + int k; + CharsString ruleDots; + CharsString otherDots; + CharsString dotsBefore; + CharsString dotsAfter; + int haveDotsAfter = 0; + if (!getToken (nested, &ruleDots, "dots operand")) + return 0; + for (k = 0; k < ruleDots.length && ruleDots.chars[k] != ','; k++); + if (k == ruleDots.length) + { + if (!parseDots (nested, &dotsBefore, &ruleDots)) + return 0; + dotsAfter.length = dotsBefore.length; + for (k = 0; k < dotsBefore.length; k++) + dotsAfter.chars[k] = dotsBefore.chars[k]; + dotsAfter.chars[k] = 0; + } + else + { + haveDotsAfter = ruleDots.length; + ruleDots.length = k; + if (!parseDots (nested, &dotsBefore, &ruleDots)) + return 0; + otherDots.length = 0; + k++; + for (; k < haveDotsAfter; k++) + otherDots.chars[otherDots.length++] = ruleDots.chars[k]; + if (!parseDots (nested, &dotsAfter, &otherDots)) + return 0; + } + for (k = 0; k < dotsBefore.length; k++) + dotsBefore.chars[k] = getCharFromDots (dotsBefore.chars[k]); + for (k = 0; k < dotsAfter.length; k++) + dotsAfter.chars[k] = getCharFromDots (dotsAfter.chars[k]); + if (!addRule (nested, CTO_NoBreak, &dotsBefore, &dotsAfter, 0, 0)) + return 0; + table->noBreak = newRuleOffset; + return 1; +} + +static int +compileCharDef (FileInfo * nested, + TranslationTableOpcode opcode, + TranslationTableCharacterAttributes attributes) +{ + CharsString ruleChars; + CharsString ruleDots; + TranslationTableCharacter *character; + TranslationTableCharacter *cell; + TranslationTableCharacter *otherCell; + TranslationTableCharacterAttributes attr; + int k; + if (!getRuleCharsText (nested, &ruleChars)) + return 0; + if (attributes & (CTC_UpperCase | CTC_LowerCase)) + attributes |= CTC_Letter; + if (!getRuleDotsPattern (nested, &ruleDots)) + return 0; + if (ruleChars.length != 1 || ruleDots.length < 1) + { + compileError (nested, + "Exactly one Unicode character and at least one cell are required."); + return 0; + } + character = addCharOrDots (nested, ruleChars.chars[0], 0); + character->attributes |= attributes; + character->uppercase = character->lowercase = character->realchar; + cell = compile_findCharOrDots (ruleDots.chars[0], 1); + if (ruleDots.length == 1 && cell) + cell->attributes |= attributes; + else + { + for (k = 0; k < ruleDots.length; k++) + { + if (!compile_findCharOrDots (ruleDots.chars[k], 1)) + { + attr = attributes; + otherCell = addCharOrDots (nested, ruleDots.chars[k], 1); + if (ruleDots.length != 1) + attr = CTC_Space; + otherCell->attributes |= attr; + otherCell->uppercase = otherCell->lowercase = + otherCell->realchar; + } + } + } + if (!addRule (nested, opcode, &ruleChars, &ruleDots, 0, 0)) + return 0; + if (ruleDots.length == 1) + putCharAndDots (nested, ruleChars.chars[0], ruleDots.chars[0]); + return 1; +} + +static int +compileRule (FileInfo * nested) +{ + int ok = 1; + CharsString token; + TranslationTableOpcode opcode; + CharsString ruleChars; + CharsString ruleDots; + CharsString cells; + CharsString scratchPad; + TranslationTableCharacterAttributes after = 0; + TranslationTableCharacterAttributes before = 0; + int k; + + noback = nofor = 0; +doOpcode: + if (!getToken (nested, &token, NULL)) + return 1; /*blank line */ + if (token.chars[0] == '#' || token.chars[0] == '<') + return 1; /*comment */ + if (nested->lineNumber == 1 && (eqasc2uni ((unsigned char *) "ISO", + token.chars, 3) || + eqasc2uni ((unsigned char *) "UTF-8", + token.chars, 5))) + { + compileHyphenation (nested, &token); + return 1; + } + opcode = getOpcode (nested, &token); + switch (opcode) + { /*Carry out operations */ + case CTO_None: + break; + case CTO_IncludeFile: + { + CharsString includedFile; + if (getToken (nested, &token, "include file name")) + if (parseChars (nested, &includedFile, &token)) + if (!includeFile (nested, &includedFile)) + ok = 0; + break; + } + case CTO_Locale: + break; + case CTO_Undefined: + ok = + compileBrailleIndicator (nested, "undefined character opcode", + CTO_Undefined, &table->undefined); + break; + case CTO_CapitalSign: + ok = + compileBrailleIndicator (nested, "capital sign", CTO_CapitalRule, + &table->capitalSign); + break; + case CTO_BeginCapitalSign: + ok = + compileBrailleIndicator (nested, "begin capital sign", + CTO_BeginCapitalRule, + &table->beginCapitalSign); + break; + case CTO_LenBegcaps: + ok = table->lenBeginCaps = compileNumber (nested); + break; + case CTO_EndCapitalSign: + ok = + compileBrailleIndicator (nested, "end capitals sign", + CTO_EndCapitalRule, &table->endCapitalSign); + break; + case CTO_FirstWordCaps: + ok = + compileBrailleIndicator (nested, "first word capital sign", + CTO_FirstWordCapsRule, + &table->firstWordCaps); + break; + case CTO_LastWordCapsBefore: + ok = + compileBrailleIndicator (nested, "capital sign before last word", + CTO_LastWordCapsBeforeRule, + &table->lastWordCapsBefore); + break; + case CTO_LastWordCapsAfter: + ok = + compileBrailleIndicator (nested, "capital sign after last word", + CTO_LastWordCapsAfterRule, + &table->lastWordCapsAfter); + break; + case CTO_LenCapsPhrase: + ok = table->lenCapsPhrase = compileNumber (nested); + break; + case CTO_LetterSign: + ok = + compileBrailleIndicator (nested, "letter sign", CTO_LetterRule, + &table->letterSign); + break; + case CTO_NoLetsignBefore: + if (getRuleCharsText (nested, &ruleChars)) + { + if ((table->noLetsignBeforeCount + ruleChars.length) > LETSIGNSIZE) + { + compileError (nested, "More than %d characters", LETSIGNSIZE); + ok = 0; + break; + } + for (k = 0; k < ruleChars.length; k++) + table->noLetsignBefore[table->noLetsignBeforeCount++] = + ruleChars.chars[k]; + } + break; + case CTO_NoLetsign: + if (getRuleCharsText (nested, &ruleChars)) + { + if ((table->noLetsignCount + ruleChars.length) > LETSIGNSIZE) + { + compileError (nested, "More than %d characters", LETSIGNSIZE); + ok = 0; + break; + } + for (k = 0; k < ruleChars.length; k++) + table->noLetsign[table->noLetsignCount++] = ruleChars.chars[k]; + } + break; + case CTO_NoLetsignAfter: + if (getRuleCharsText (nested, &ruleChars)) + { + if ((table->noLetsignAfterCount + ruleChars.length) > LETSIGNSIZE) + { + compileError (nested, "More than %d characters", LETSIGNSIZE); + ok = 0; + break; + } + for (k = 0; k < ruleChars.length; k++) + table->noLetsignAfter[table->noLetsignAfterCount++] = + ruleChars.chars[k]; + } + break; + case CTO_NumberSign: + ok = + compileBrailleIndicator (nested, "number sign", CTO_NumberRule, + &table->numberSign); + break; + case CTO_FirstWordItal: + ok = + compileBrailleIndicator (nested, "first word italic", + CTO_FirstWordItalRule, + &table->firstWordItal); + break; + case CTO_ItalSign: + case CTO_LastWordItalBefore: + ok = + compileBrailleIndicator (nested, "first word italic before", + CTO_LastWordItalBeforeRule, + &table->lastWordItalBefore); + break; + case CTO_LastWordItalAfter: + ok = + compileBrailleIndicator (nested, "last word italic after", + CTO_LastWordItalAfterRule, + &table->lastWordItalAfter); + break; + case CTO_BegItal: + case CTO_FirstLetterItal: + ok = + compileBrailleIndicator (nested, "first letter italic", + CTO_FirstLetterItalRule, + &table->firstLetterItal); + break; + case CTO_EndItal: + case CTO_LastLetterItal: + ok = + compileBrailleIndicator (nested, "last letter italic", + CTO_LastLetterItalRule, + &table->lastLetterItal); + break; + case CTO_SingleLetterItal: + ok = + compileBrailleIndicator (nested, "single letter italic", + CTO_SingleLetterItalRule, + &table->singleLetterItal); + break; + case CTO_ItalWord: + ok = + compileBrailleIndicator (nested, "italic word", CTO_ItalWordRule, + &table->italWord); + break; + case CTO_LenItalPhrase: + ok = table->lenItalPhrase = compileNumber (nested); + break; + case CTO_FirstWordBold: + ok = + compileBrailleIndicator (nested, "first word bold", + CTO_FirstWordBoldRule, + &table->firstWordBold); + break; + case CTO_BoldSign: + case CTO_LastWordBoldBefore: + ok = + compileBrailleIndicator (nested, "last word bold before", + CTO_LastWordBoldBeforeRule, + &table->lastWordBoldBefore); + break; + case CTO_LastWordBoldAfter: + ok = + compileBrailleIndicator (nested, "last word bold after", + CTO_LastWordBoldAfterRule, + &table->lastWordBoldAfter); + break; + case CTO_BegBold: + case CTO_FirstLetterBold: + ok = + compileBrailleIndicator (nested, "first letter bold", + CTO_FirstLetterBoldRule, + &table->firstLetterBold); + break; + case CTO_EndBold: + case CTO_LastLetterBold: + ok = + compileBrailleIndicator (nested, "last letter bold", + CTO_LastLetterBoldRule, + &table->lastLetterBold); + break; + case CTO_SingleLetterBold: + ok = + compileBrailleIndicator (nested, "single letter bold", + CTO_SingleLetterBoldRule, + &table->singleLetterBold); + break; + case CTO_BoldWord: + ok = + compileBrailleIndicator (nested, "bold word", CTO_BoldWordRule, + &table->boldWord); + break; + case CTO_LenBoldPhrase: + ok = table->lenBoldPhrase = compileNumber (nested); + break; + case CTO_FirstWordUnder: + ok = + compileBrailleIndicator (nested, "first word underline", + CTO_FirstWordUnderRule, + &table->firstWordUnder); + break; + case CTO_UnderSign: + case CTO_LastWordUnderBefore: + ok = + compileBrailleIndicator (nested, "last word underline before", + CTO_LastWordUnderBeforeRule, + &table->lastWordUnderBefore); + break; + case CTO_LastWordUnderAfter: + ok = + compileBrailleIndicator (nested, "last word underline after", + CTO_LastWordUnderAfterRule, + &table->lastWordUnderAfter); + break; + case CTO_BegUnder: + case CTO_FirstLetterUnder: + ok = + compileBrailleIndicator (nested, "first letter underline", + CTO_FirstLetterUnderRule, + &table->firstLetterUnder); + break; + case CTO_EndUnder: + case CTO_LastLetterUnder: + ok = + compileBrailleIndicator (nested, "last letter underline", + CTO_LastLetterUnderRule, + &table->lastLetterUnder); + break; + case CTO_SingleLetterUnder: + ok = + compileBrailleIndicator (nested, "single letter underline", + CTO_SingleLetterUnderRule, + &table->singleLetterUnder); + break; + case CTO_UnderWord: + ok = + compileBrailleIndicator (nested, "underlined word", CTO_UnderWordRule, + &table->underWord); + break; + case CTO_LenUnderPhrase: + ok = table->lenUnderPhrase = compileNumber (nested); + break; + case CTO_BegComp: + ok = + compileBrailleIndicator (nested, "begin computer braille", + CTO_BegCompRule, &table->begComp); + break; + case CTO_EndComp: + ok = + compileBrailleIndicator (nested, "end computer braslle", + CTO_EndCompRule, &table->endComp); + break; + case CTO_Syllable: + table->syllables = 1; + case CTO_Always: + case CTO_NoCross: + case CTO_LargeSign: + case CTO_WholeWord: + case CTO_PartWord: + case CTO_JoinNum: + case CTO_JoinableWord: + case CTO_LowWord: + case CTO_SuffixableWord: + case CTO_PrefixableWord: + case CTO_BegWord: + case CTO_BegMidWord: + case CTO_MidWord: + case CTO_MidEndWord: + case CTO_EndWord: + case CTO_PrePunc: + case CTO_PostPunc: + case CTO_BegNum: + case CTO_MidNum: + case CTO_EndNum: + case CTO_Repeated: + case CTO_RepWord: + if (getRuleCharsText (nested, &ruleChars)) + if (getRuleDotsPattern (nested, &ruleDots)) + if (!addRule (nested, opcode, &ruleChars, &ruleDots, after, before)) + ok = 0; + break; + case CTO_CompDots: + case CTO_Comp6: + if (!getRuleCharsText (nested, &ruleChars)) + return 0; + if (ruleChars.length != 1 || ruleChars.chars[0] > 255) + { + compileError (nested, + "first operand must be 1 character and < 256"); + return 0; + } + if (!getRuleDotsPattern (nested, &ruleDots)) + return 0; + if (!addRule (nested, opcode, &ruleChars, &ruleDots, after, before)) + ok = 0; + table->compdotsPattern[ruleChars.chars[0]] = newRuleOffset; + break; + case CTO_ExactDots: + if (!getRuleCharsText (nested, &ruleChars)) + return 0; + if (ruleChars.chars[0] != '@') + { + compileError (nested, "The operand must begin with an at sign (@)"); + return 0; + } + for (k = 1; k < ruleChars.length; k++) + scratchPad.chars[k - 1] = ruleChars.chars[k]; + scratchPad.length = ruleChars.length - 1; + if (!parseDots (nested, &ruleDots, &scratchPad)) + return 0; + if (!addRule (nested, opcode, &ruleChars, &ruleDots, before, after)) + ok = 0; + break; + case CTO_CapsNoCont: + ruleChars.length = 1; + ruleChars.chars[0] = 'a'; + if (!addRule + (nested, CTO_CapsNoContRule, &ruleChars, NULL, after, before)) + ok = 0; + table->capsNoCont = newRuleOffset; + break; + case CTO_Replace: + if (getRuleCharsText (nested, &ruleChars)) + { + if (lastToken) + ruleDots.length = ruleDots.chars[0] = 0; + else + { + getRuleDotsText (nested, &ruleDots); + if (ruleDots.chars[0] == '#') + ruleDots.length = ruleDots.chars[0] = 0; + else if (ruleDots.chars[0] == '\\' && ruleDots.chars[1] == '#') + memcpy (&ruleDots.chars[0], &ruleDots.chars[1], + ruleDots.length-- * CHARSIZE); + } + } + for (k = 0; k < ruleChars.length; k++) + addCharOrDots (nested, ruleChars.chars[k], 0); + for (k = 0; k < ruleDots.length; k++) + addCharOrDots (nested, ruleDots.chars[k], 0); + if (!addRule (nested, opcode, &ruleChars, &ruleDots, after, before)) + ok = 0; + break; + case CTO_Pass2: + if (table->numPasses < 2) + table->numPasses = 2; + goto doPass; + case CTO_Pass3: + if (table->numPasses < 3) + table->numPasses = 3; + goto doPass; + case CTO_Pass4: + if (table->numPasses < 4) + table->numPasses = 4; + doPass: + case CTO_Context: + if (!compilePassOpcode (nested, opcode)) + ok = 0; + break; + case CTO_Correct: + if (!compilePassOpcode (nested, opcode)) + ok = 0; + table->corrections = 1; + break; + case CTO_Contraction: + case CTO_NoCont: + case CTO_CompBrl: + case CTO_Literal: + if (getRuleCharsText (nested, &ruleChars)) + if (!addRule (nested, opcode, &ruleChars, NULL, after, before)) + ok = 0; + break; + case CTO_MultInd: + { + int lastToken; + ruleChars.length = 0; + if (getToken (nested, &token, "multiple braille indicators") && + parseDots (nested, &cells, &token)) + { + while ((lastToken = getToken (nested, &token, "multind opcodes"))) + { + opcode = getOpcode (nested, &token); + if (opcode >= CTO_CapitalSign && opcode < CTO_MultInd) + ruleChars.chars[ruleChars.length++] = (widechar) opcode; + else + { + compileError (nested, "Not a braille indicator opcode."); + ok = 0; + } + if (lastToken == 2) + break; + } + } + else + ok = 0; + if (!addRule (nested, CTO_MultInd, &ruleChars, &cells, after, before)) + ok = 0; + break; + } + + case CTO_Class: + { + CharsString characters; + const struct CharacterClass *class; + if (!characterClasses) + { + if (!allocateCharacterClasses ()) + ok = 0; + } + if (getToken (nested, &token, "character class name")) + { + if ((class = findCharacterClass (&token))) + { + compileError (nested, "character class already defined."); + } + else + if ((class = + addCharacterClass (nested, &token.chars[0], token.length))) + { + if (getCharacters (nested, &characters)) + { + int index; + for (index = 0; index < characters.length; ++index) + { + TranslationTableRule *defRule; + TranslationTableCharacter *character = + definedCharOrDots + (nested, characters.chars[index], 0); + character->attributes |= class->attribute; + defRule = (TranslationTableRule *) + & table->ruleArea[character->definitionRule]; + if (defRule->dotslen == 1) + { + character = definedCharOrDots + (nested, + defRule->charsdots[defRule->charslen], 1); + character->attributes |= class->attribute; + } + } + } + } + } + break; + } + + { + TranslationTableCharacterAttributes *attributes; + const struct CharacterClass *class; + case CTO_After: + attributes = &after; + goto doClass; + case CTO_Before: + attributes = &before; + doClass: + + if (!characterClasses) + { + if (!allocateCharacterClasses ()) + ok = 0; + } + if (getCharacterClass (nested, &class)) + { + *attributes |= class->attribute; + goto doOpcode; + } + break; + } + case CTO_NoBack: + noback = 1; + goto doOpcode; + case CTO_NoFor: + nofor = 1; + goto doOpcode; + case CTO_SwapCc: + case CTO_SwapCd: + case CTO_SwapDd: + if (!compileSwap (nested, opcode)) + ok = 0; + break; + case CTO_Hyphen: + case CTO_DecPoint: + if (getRuleCharsText (nested, &ruleChars)) + if (getRuleDotsPattern (nested, &ruleDots)) + { + if (ruleChars.length != 1 || ruleDots.length < 1) + { + compileError (nested, + "One Unicode character and at least one cell are required."); + ok = 0; + } + if (!addRule + (nested, opcode, &ruleChars, &ruleDots, after, before)) + ok = 0; + } + break; + case CTO_Space: + compileCharDef (nested, opcode, CTC_Space); + break; + case CTO_Digit: + compileCharDef (nested, opcode, CTC_Digit); + break; + case CTO_LitDigit: + compileCharDef (nested, opcode, CTC_LitDigit); + break; + case CTO_Punctuation: + compileCharDef (nested, opcode, CTC_Punctuation); + break; + case CTO_Math: + compileCharDef (nested, opcode, CTC_Math); + break; + case CTO_Sign: + compileCharDef (nested, opcode, CTC_Sign); + break; + case CTO_Letter: + compileCharDef (nested, opcode, CTC_Letter); + break; + case CTO_UpperCase: + compileCharDef (nested, opcode, CTC_UpperCase); + break; + case CTO_LowerCase: + compileCharDef (nested, opcode, CTC_LowerCase); + break; + case CTO_NoBreak: + ok = compileNoBreak (nested); + break; + case CTO_Grouping: + ok = compileGrouping (nested); + break; + case CTO_UpLow: + ok = compileUplow (nested); + break; + case CTO_Display: + if (getRuleCharsText (nested, &ruleChars)) + if (getRuleDotsPattern (nested, &ruleDots)) + { + if (ruleChars.length != 1 || ruleDots.length != 1) + { + compileError (nested, + "Exactly one character and one cell are required."); + ok = 0; + } + putCharAndDots (nested, ruleChars.chars[0], ruleDots.chars[0]); + } + break; + default: + compileError (nested, "unimplemented opcode."); + break; + } + return ok; +} + +int EXPORT_CALL +lou_readCharFromFile (const char *fileName, int *mode) +{ +/*Read a character from a file, whether big-endian, little-endian or +* ASCII8*/ + int ch; + static FileInfo nested; + if (fileName == NULL) + return 0; + if (*mode == 1) + { + *mode = 0; + nested.fileName = fileName; + nested.encoding = noEncoding; + nested.status = 0; + nested.lineNumber = 0; + if (!(nested.in = fopen (nested.fileName, "r"))) + { + lou_logPrint ("Cannot open file '%s'", nested.fileName); + *mode = 1; + return EOF; + } + } + if (nested.in == NULL) + { + *mode = 1; + return EOF; + } + ch = getAChar (&nested); + if (ch == EOF) + { + fclose (nested.in); + nested.in = NULL; + *mode = 1; + } + return ch; +} + +static int fileCount = 0; +static FILE * +findTable (const char *tableName) +{ +/* Search paths for tables */ + FILE *tableFile; + char *pathList; + char pathEnd[2]; + char trialPath[MAXSTRING]; + if (tableName == NULL || tableName[0] == 0) + return NULL; + strcpy (trialPath, tablePath); + strcat (trialPath, tableName); + if ((tableFile = fopen (trialPath, "rb"))) + return tableFile; + pathEnd[0] = DIR_SEP; + pathEnd[1] = 0; + /* See if table is on environment path LOUIS_TABLEPATH */ + pathList = getenv ("LOUIS_TABLEPATH"); + if (pathList) + while (1) + { + int k; + int listLength; + int currentListPos = 0; + listLength = strlen (pathList); + for (k = 0; k < listLength; k++) + if (pathList[k] == ',') + break; + if (k == listLength || k == 0) + { /* Only one file */ + strcpy (trialPath, pathList); + strcat (trialPath, pathEnd); + strcat (trialPath, tableName); + if ((tableFile = fopen (trialPath, "rb"))) + break; + } + else + { /* Compile a list of files */ + strncpy (trialPath, pathList, k); + trialPath[k] = 0; + strcat (trialPath, pathEnd); + strcat (trialPath, tableName); + currentListPos = k + 1; + if ((tableFile = fopen (trialPath, "rb"))) + break; + while (currentListPos < listLength) + { + for (k = currentListPos; k < listLength; k++) + if (pathList[k] == ',') + break; + strncpy (trialPath, + &pathList[currentListPos], k - currentListPos); + trialPath[k - currentListPos] = 0; + strcat (trialPath, pathEnd); + strcat (trialPath, tableName); + if ((tableFile = fopen (trialPath, "rb"))) + currentListPos = k + 1; + break; + } + } + break; + } + if (tableFile) + return tableFile; + /* See if table in current directory or on a path in + * the table name*/ + if ((tableFile = fopen (tableName, "rb"))) + return tableFile; +/* See if table on dataPath. */ + pathList = lou_getDataPath (); + if (pathList) + { + strcpy (trialPath, pathList); + strcat (trialPath, pathEnd); +#ifdef _WIN32 + strcat (trialPath, "liblouis\\tables\\"); +#else + strcat (trialPath, "liblouis/tables/"); +#endif + strcat (trialPath, tableName); + if ((tableFile = fopen (trialPath, "rb"))) + return tableFile; + } + /* See if table on installed or program path. */ +#ifdef _WIN32 + strcpy (trialPath, lou_getProgramPath ()); + strcat (trialPath, "\\share\\liblouss\\tables\\"); +#else + strcpy (trialPath, TABLESDIR); + strcat (trialPath, pathEnd); +#endif + strcat (trialPath, tableName); + if ((tableFile = fopen (trialPath, "rb"))) + return tableFile; + return NULL; +} + +static int +compileFile (const char *fileName) +{ +/*Compile a table file */ + FileInfo nested; + fileCount++; + nested.fileName = fileName; + nested.encoding = noEncoding; + nested.status = 0; + nested.lineNumber = 0; + if ((nested.in = findTable (fileName))) + { + while (getALine (&nested)) + compileRule (&nested); + fclose (nested.in); + } + else + { + if (fileCount > 1) + lou_logPrint ("Cannot open table '%s'", nested.fileName); + errorCount++; + return 0; + } + return 1; +} + +static int +compileString (const char *inString) +{ +/* This function can be used to make changes to tables on the fly. */ + int k; + FileInfo nested; + if (inString == NULL) + return 0; + nested.fileName = inString; + nested.encoding = noEncoding; + nested.lineNumber = 1; + nested.status = 0; + nested.linepos = 0; + for (k = 0; inString[k]; k++) + nested.line[k] = inString[k]; + nested.line[k] = 0; + return compileRule (&nested); +} + +static int +makeDoubleRule (TranslationTableOpcode opcode, TranslationTableOffset + * singleRule, TranslationTableOffset * doubleRule) +{ + CharsString dots; + TranslationTableRule *rule; + if (!*singleRule || *doubleRule) + return 1; + rule = (TranslationTableRule *) & table->ruleArea[*singleRule]; + memcpy (dots.chars, &rule->charsdots[0], rule->dotslen * CHARSIZE); + memcpy (&dots.chars[rule->dotslen], &rule->charsdots[0], + rule->dotslen * CHARSIZE); + dots.length = 2 * rule->dotslen; + if (!addRule (NULL, opcode, NULL, &dots, 0, 0)) + return 0; + *doubleRule = newRuleOffset; + return 1; +} + +static int +setDefaults (void) +{ + if (!table->lenBeginCaps) + table->lenBeginCaps = 2; + makeDoubleRule (CTO_FirstWordItal, &table->lastWordItalBefore, + &table->firstWordItal); + if (!table->lenItalPhrase) + table->lenItalPhrase = 4; + makeDoubleRule (CTO_FirstWordBold, &table->lastWordBoldBefore, + &table->firstWordBold); + if (!table->lenBoldPhrase) + table->lenBoldPhrase = 4; + makeDoubleRule (CTO_FirstWordUnder, &table->lastWordUnderBefore, + &table->firstWordUnder); + if (!table->lenUnderPhrase) + table->lenUnderPhrase = 4; + if (table->numPasses == 0) + table->numPasses = 1; + return 1; +} + +static char * +doLang2table (const char *tableList) +{ + static char newList[MAXSTRING]; + int k; + char buffer[MAXSTRING]; + FILE *l2t; + char *langCode; + int langCodeLen; + if (tableList == NULL || *tableList == 0) + return NULL; + strcpy (newList, tableList); + for (k = strlen (newList) - 1; k >= 0 && newList[k] != '='; k--); + if (k < 0) + return newList; + fileCount = 1; + errorCount = 1; + newList[k] = 0; + strcpy (buffer, newList); + langCode = &newList[k + 1]; + langCodeLen = strlen (langCode); + strcat (buffer, "lang2table"); + l2t = fopen (buffer, "r"); + if (l2t == NULL) + return NULL; + while ((fgets (buffer, sizeof (buffer) - 2, l2t))) + { + char *codeInFile; + int codeInFileLen; + char *tableInFile; + for (k = 0; buffer[k] < 32; k++); + if (buffer[k] == '#' || buffer[k] < 32) + continue; + codeInFile = &buffer[k]; + codeInFileLen = k; + while (buffer[k] > 32) + k++; + codeInFileLen = k - codeInFileLen; + codeInFile[codeInFileLen] = 0; + if (! + (codeInFileLen == langCodeLen + && strcasecmp (langCode, codeInFile) == 0)) + continue; + while (buffer[k] < 32) + k++; + tableInFile = &buffer[k]; + while (buffer[k] > 32) + k++; + buffer[k] = 0; + strcat (newList, tableInFile); + fclose (l2t); + fileCount = 0; + errorCount = 0; + return newList; + } + fclose (l2t); + return NULL; +} + +static void * +compileTranslationTable (const char *tl) +{ +/*compile source tables into a table in memory */ + const char *tableList; + int k; + char mainTable[MAXSTRING]; + char subTable[MAXSTRING]; + int listLength; + int currentListPos = 0; + errorCount = 0; + warningCount = 0; + fileCount = 0; + table = NULL; + characterClasses = NULL; + ruleNames = NULL; + tableList = doLang2table (tl); + if (tableList == NULL) + return NULL; + if (!opcodeLengths[0]) + { + TranslationTableOpcode opcode; + for (opcode = 0; opcode < CTO_None; opcode++) + opcodeLengths[opcode] = strlen (opcodeNames[opcode]); + } + allocateHeader (NULL); + /*Compile things that are necesary for the proper operation of + liblouis or liblouisxml or liblouisutdml */ + compileString ("space \\s 0"); + compileString ("noback sign \\x0000 0"); + compileString ("space \\x00a0 a unbreakable space"); + compileString ("space \\x001b 1b escape"); + compileString ("space \\xffff 123456789abcdef ENDSEGMENT"); + listLength = strlen (tableList); + for (k = currentListPos; k < listLength; k++) + if (tableList[k] == ',') + break; + if (k == listLength) + { /* Only one file */ + strcpy (tablePath, tableList); + for (k = strlen (tablePath); k >= 0; k--) + if (tablePath[k] == '\\' || tablePath[k] == '/') + break; + strcpy (mainTable, &tablePath[k + 1]); + tablePath[++k] = 0; + if (!compileFile (mainTable)) + goto cleanup; + } + else + { /* Compile a list of files */ + currentListPos = k + 1; + strncpy (tablePath, tableList, k); + tablePath[k] = 0; + for (k = strlen (tablePath); k >= 0; k--) + if (tablePath[k] == '\\' || tablePath[k] == '/') + break; + strcpy (mainTable, &tablePath[k + 1]); + tablePath[++k] = 0; + if (!compileFile (mainTable)) + goto cleanup; + while (currentListPos < listLength) + { + for (k = currentListPos; k < listLength; k++) + if (tableList[k] == ',') + break; + strncpy (subTable, &tableList[currentListPos], k - currentListPos); + subTable[k - currentListPos] = 0; + if (!compileFile (subTable)) + goto cleanup; + currentListPos = k + 1; + } + } +/*Clean up after compiling files*/ +cleanup: + if (characterClasses) + deallocateCharacterClasses (); + if (ruleNames) + deallocateRuleNames (); + if (warningCount) + lou_logPrint ("%d warnings issued", warningCount); + if (!errorCount) + { + setDefaults (); + table->tableSize = tableSize; + table->bytesUsed = tableUsed; + } + else + { + if (!(errorCount == 1 && fileCount == 1)) + lou_logPrint ("%d errors found.", errorCount); + if (table) + free (table); + table = NULL; + } + return (void *) table; +} + +typedef struct +{ + void *next; + void *table; + int tableListLength; + char tableList[1]; +} ChainEntry; +static ChainEntry *tableChain = NULL; +static ChainEntry *lastTrans = NULL; +static void * +getTable (const char *tableList) +{ +/*Keep track of which tables have already been compiled */ + int tableListLen; + ChainEntry *currentEntry = NULL; + ChainEntry *lastEntry = NULL; + void *newTable; + if (tableList == NULL || *tableList == 0) + return NULL; + errorCount = fileCount = 0; + tableListLen = strlen (tableList); + /*See if this is the last table used. */ + if (lastTrans != NULL) + if (tableListLen == lastTrans->tableListLength && (memcmp + (&lastTrans-> + tableList + [0], + tableList, + tableListLen)) == 0) + return (table = lastTrans->table); +/*See if Table has already been compiled*/ + currentEntry = tableChain; + while (currentEntry != NULL) + { + if (tableListLen == currentEntry->tableListLength && (memcmp + (¤tEntry-> + tableList + [0], + tableList, + tableListLen)) + == 0) + { + lastTrans = currentEntry; + return (table = currentEntry->table); + } + lastEntry = currentEntry; + currentEntry = currentEntry->next; + } + if ((newTable = compileTranslationTable (tableList))) + { + /*Add a new entry to the table chain. */ + int entrySize = sizeof (ChainEntry) + tableListLen; + ChainEntry *newEntry = malloc (entrySize); + if (tableChain == NULL) + tableChain = newEntry; + else + lastEntry->next = newEntry; + newEntry->next = NULL; + newEntry->table = newTable; + newEntry->tableListLength = tableListLen; + memcpy (&newEntry->tableList[0], tableList, tableListLen); + lastTrans = newEntry; + return newEntry->table; + } + return NULL; +} + +char * +getLastTableList () +{ + if (lastTrans == NULL) + return NULL; + strncpy (scratchBuf, lastTrans->tableList, lastTrans->tableListLength); + scratchBuf[lastTrans->tableListLength] = 0; + return scratchBuf; +} + +void *EXPORT_CALL +lou_getTable (const char *tableList) +{ +/* Search paths for tables and keep track of compiled tables. */ + void *table = NULL; + char *pathList; + char pathEnd[2]; + char trialPath[MAXSTRING]; + if (tableList == NULL || tableList[0] == 0) + return NULL; + errorCount = fileCount = 0; + pathEnd[0] = DIR_SEP; + pathEnd[1] = 0; + /* See if table is on environment path LOUIS_TABLEPATH */ + pathList = getenv ("LOUIS_TABLEPATH"); + if (pathList) + while (1) + { + int k; + int listLength; + int currentListPos = 0; + listLength = strlen (pathList); + for (k = 0; k < listLength; k++) + if (pathList[k] == ',') + break; + if (k == listLength || k == 0) + { /* Only one file */ + strcpy (trialPath, pathList); + strcat (trialPath, pathEnd); + strcat (trialPath, tableList); + table = getTable (trialPath); + if (table) + break; + } + else + { /* Compile a list of files */ + strncpy (trialPath, pathList, k); + trialPath[k] = 0; + strcat (trialPath, pathEnd); + strcat (trialPath, tableList); + currentListPos = k + 1; + table = getTable (trialPath); + if (table) + break; + while (currentListPos < listLength) + { + for (k = currentListPos; k < listLength; k++) + if (pathList[k] == ',') + break; + strncpy (trialPath, + &pathList[currentListPos], k - currentListPos); + trialPath[k - currentListPos] = 0; + strcat (trialPath, pathEnd); + strcat (trialPath, tableList); + table = getTable (trialPath); + currentListPos = k + 1; + if (table) + break; + } + } + break; + } + if (!table) + { + /* See if table in current directory or on a path in + * the table name*/ + if (errorCount > 0 && (!(errorCount == 1 && fileCount == 1))) + return NULL; + table = getTable (tableList); + } + if (!table) + { +/* See if table on dataPath. */ + if (errorCount > 0 && (!(errorCount == 1 && fileCount == 1))) + return NULL; + pathList = lou_getDataPath (); + if (pathList) + { + strcpy (trialPath, pathList); + strcat (trialPath, pathEnd); +#ifdef _WIN32 + strcat (trialPath, "liblouis\\tables\\"); +#else + strcat (trialPath, "liblouis/tables/"); +#endif + strcat (trialPath, tableList); + table = getTable (trialPath); + } + } + if (!table) + { + /* See if table on installed or program path. */ + if (errorCount > 0 && (!(errorCount == 1 && fileCount == 1))) + return NULL; +#ifdef _WIN32 + strcpy (trialPath, lou_getProgramPath ()); + strcat (trialPath, "\\share\\liblouss\\tables\\"); +#else + strcpy (trialPath, TABLESDIR); + strcat (trialPath, pathEnd); +#endif + strcat (trialPath, tableList); + table = getTable (trialPath); + } + if (!table) + lou_logPrint ("%s could not be found", tableList); + return table; +} + +static unsigned char *destSpacing = NULL; +static int sizeDestSpacing = 0; +static unsigned short *typebuf = NULL; +static int sizeTypebuf = 0; +static widechar *passbuf1 = NULL; +static int sizePassbuf1 = 0; +static widechar *passbuf2 = NULL; +static int sizePassbuf2 = 0; +static int *srcMapping = NULL; +static int *prevSrcMapping = NULL; +static int sizeSrcMapping = 0; +static int sizePrevSrcMapping = 0; +void * +liblouis_allocMem (AllocBuf buffer, int srcmax, int destmax) +{ + if (srcmax < 1024) + srcmax = 1024; + if (destmax < 1024) + destmax = 1024; + switch (buffer) + { + case alloc_typebuf: + if (destmax > sizeTypebuf) + { + if (typebuf != NULL) + free (typebuf); + typebuf = malloc ((destmax + 4) * sizeof (unsigned short)); + sizeTypebuf = destmax; + } + return typebuf; + case alloc_destSpacing: + if (destmax > sizeDestSpacing) + { + if (destSpacing != NULL) + free (destSpacing); + destSpacing = malloc (destmax + 4); + sizeDestSpacing = destmax; + } + return destSpacing; + case alloc_passbuf1: + if (destmax > sizePassbuf1) + { + if (passbuf1 != NULL) + free (passbuf1); + passbuf1 = malloc ((destmax + 4) * CHARSIZE); + sizePassbuf1 = destmax; + } + return passbuf1; + case alloc_passbuf2: + if (destmax > sizePassbuf2) + { + if (passbuf2 != NULL) + free (passbuf2); + passbuf2 = malloc ((destmax + 4) * CHARSIZE); + sizePassbuf2 = destmax; + } + return passbuf2; + case alloc_srcMapping: + { + int mapSize; + if (srcmax >= destmax) + mapSize = srcmax; + else + mapSize = destmax; + if (mapSize > sizeSrcMapping) + { + if (srcMapping != NULL) + free (srcMapping); + srcMapping = malloc ((mapSize + 4) * sizeof (int)); + sizeSrcMapping = mapSize; + } + } + return srcMapping; + case alloc_prevSrcMapping: + { + int mapSize; + if (srcmax >= destmax) + mapSize = srcmax; + else + mapSize = destmax; + if (mapSize > sizePrevSrcMapping) + { + if (prevSrcMapping != NULL) + free (prevSrcMapping); + prevSrcMapping = malloc ((mapSize + 4) * sizeof (int)); + sizePrevSrcMapping = mapSize; + } + } + return prevSrcMapping; + default: + return NULL; + } +} + +void EXPORT_CALL +lou_free (void) +{ + ChainEntry *currentEntry; + ChainEntry *previousEntry; + if (logFile != NULL) + fclose (logFile); + if (tableChain != NULL) + { + currentEntry = tableChain; + while (currentEntry) + { + free (currentEntry->table); + previousEntry = currentEntry; + currentEntry = currentEntry->next; + free (previousEntry); + } + tableChain = NULL; + lastTrans = NULL; + } + if (typebuf != NULL) + free (typebuf); + typebuf = NULL; + sizeTypebuf = 0; + if (destSpacing != NULL) + free (destSpacing); + destSpacing = NULL; + sizeDestSpacing = 0; + if (passbuf1 != NULL) + free (passbuf1); + passbuf1 = NULL; + sizePassbuf1 = 0; + if (passbuf2 != NULL) + free (passbuf2); + passbuf2 = NULL; + sizePassbuf2 = 0; + if (srcMapping != NULL) + free (srcMapping); + srcMapping = NULL; + sizeSrcMapping = 0; + if (prevSrcMapping != NULL) + free (prevSrcMapping); + prevSrcMapping = NULL; + sizePrevSrcMapping = 0; + opcodeLengths[0] = 0; +} + +char *EXPORT_CALL +lou_version () +{ + static char *version = PACKAGE_VERSION; + return version; +} + +int EXPORT_CALL +lou_charSize (void) +{ + return CHARSIZE; +} + +int EXPORT_CALL +lou_compileString (const char *tableList, const char *inString) +{ + if (!lou_getTable (tableList)) + return 0; + return compileString (inString); +} + +/** + * This procedure provides a target for cals that serve as breakpoints + * for gdb. + */ +/* +char *EXPORT_CALL +lou_getTablePaths () +{ + static char paths[MAXSTRING]; + char *pathList; + strcpy (paths, tablePath); + strcat (paths, ","); + pathList = getenv ("LOUIS_TABLEPATH"); + if (pathList) + { + strcat (paths, pathList); + strcat (paths, ","); + } + pathList = getcwd (scratchBuf, MAXSTRING); + if (pathList) + { + strcat (paths, pathList); + strcat (paths, ","); + } + pathList = lou_getDataPath (); + if (pathList) + { + strcat (paths, pathList); + strcat (paths, ","); + } +#ifdef _WIN32 + strcpy (paths, lou_getProgramPath ()); + strcat (paths, "\\share\\liblouss\\tables\\"); +#else + strcpy (paths, TABLESDIR); +#endif + return paths; +} +*/ + +void debugHook () +{ + char *hook = "debug hook"; + printf ("%s\n", hook); +} diff --git a/third_party/liblouis/overrides/liblouis/config.h b/third_party/liblouis/overrides/liblouis/config.h new file mode 100644 index 0000000..6ae8012 --- /dev/null +++ b/third_party/liblouis/overrides/liblouis/config.h @@ -0,0 +1,18 @@ +/* + * Copyright 2013 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +#define TABLESDIR "" +#define PACKAGE_VERSION "2.5.1-google" diff --git a/third_party/liblouis/overrides/liblouis/liblouis.h b/third_party/liblouis/overrides/liblouis/liblouis.h new file mode 100644 index 0000000..140296b --- /dev/null +++ b/third_party/liblouis/overrides/liblouis/liblouis.h @@ -0,0 +1,146 @@ +/* liblouis Braille Translation and Back-Translation Library + + Based on the Linux screenreader BRLTTY, copyright (C) 1999-2006 by + The BRLTTY Team + + Copyright (C) 2004, 2005, 2006, 2009 ViewPlus Technologies, Inc. + www.viewplus.com and JJB Software, Inc. www.jjb-software.com + + liblouis is free software: you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + liblouis 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program. If not, see + <http://www.gnu.org/licenses/>. + + Maintained by John J. Boyer john.boyer@abilitiessoft.com + */ + +#ifndef __LIBLOUIS_H_ +#define __LIBLOUIS_H_ +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#define widechar unsigned short int + +#ifdef _WIN32 +#define EXPORT_CALL __stdcall +char * EXPORT_CALL lou_getProgramPath (); +#else +#define EXPORT_CALL +#endif + + typedef enum + { + plain_text = 0, + italic = 1, + underline = 2, + bold = 4, + computer_braille = 8 + } typeforms; +#define comp_emph_1 italic +#define comp_emph_2 underline +#define comp_emph_3 bold + + typedef enum + { + noContractions = 1, + compbrlAtCursor = 2, + dotsIO = 4, + comp8Dots = 8, + pass1Only = 16, + compbrlLeftCursor = 32, + otherTrans = 64, + ucBrl = 128 + } translationModes; + +char * EXPORT_CALL lou_version (); + +int EXPORT_CALL lou_charSize (); + +/* Return the size of widechar */ + + int EXPORT_CALL lou_translateString + (const char *tableList, + const widechar *inbuf, + int *inlen, + widechar * outbuf, + int *outlen, char *typeform, char *spacing, int mode); + + int EXPORT_CALL lou_translate (const char *tableList, const widechar + *inbuf, + int *inlen, widechar * outbuf, int *outlen, + char *typeform, char *spacing, int *outputPos, int +*inputPos, int *cursorPos, int mode); +int EXPORT_CALL lou_hyphenate (const char *tableList, const widechar + *inbuf, + int inlen, char *hyphens, int mode); +int EXPORT_CALL lou_dotsToChar (const char *tableList, widechar *inbuf, + widechar *outbuf, int length, int mode); +int EXPORT_CALL lou_charToDots (const char *tableList, const widechar +*inbuf, + widechar *outbuf, int length, int mode); + int EXPORT_CALL lou_backTranslateString (const char *tableList, + const widechar *inbuf, + int *inlen, + widechar * outbuf, + int *outlen, char *typeform, char + *spacing, int mode); + + int EXPORT_CALL lou_backTranslate (const char *tableList, const widechar + *inbuf, + int *inlen, widechar * outbuf, int *outlen, +char *typeform, char *spacing, int + *outputPos, int *inputPos, int *cursorPos, int + mode); + void EXPORT_CALL lou_logPrint (char *format, ...); +/* prints error messages to a file */ + + void EXPORT_CALL lou_logFile (const char *filename); +/* Specifies the name of the file to be used by lou_logPrint. If it is +* not used, this file is stderr*/ + + int EXPORT_CALL lou_readCharFromFile (const char *fileName, int *mode); +/*Read a character from a file, whether big-encian, little-endian or +* ASCII8, and return it as an integer. EOF at end of file. Mode = 1 on +* first call, any other value thereafter*/ + + void EXPORT_CALL lou_logEnd (); + /* Closes the log file so it can be read by other functions. */ + + void * EXPORT_CALL lou_getTable (const char *tableList); +/* This function checks a table for errors. If none are found it loads +* the table into memory and returns a pointer to it. if errors are found +* it returns a null pointer. It is called by lou_translateString and +* lou_backTranslateString and also by functions in liblouisxml +*/ + +int EXPORT_CALL lou_compileString (const char *tableList, const char + *inString); + char * EXPORT_CALL lou_setDataPath (char *path); + /* Set the path used for searching for tables and liblouisutdml files. + * Overrides the installation path. */ + + char * EXPORT_CALL lou_getDataPath (); + /* Get the path set in the previous function. */ + +// char EXPORT_CALL * lou_getTablePaths (); + /* Get a list of paths actually used in seraching for tables*/ + + void EXPORT_CALL lou_free (); +/* This function should be called at the end of +* the application to free all memory allocated by liblouis. */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /*LibLOUIS_H_ */ diff --git a/third_party/liblouis/overrides/tables/braille-patterns.cti b/third_party/liblouis/overrides/tables/braille-patterns.cti new file mode 100644 index 0000000..eafd6c0 --- /dev/null +++ b/third_party/liblouis/overrides/tables/braille-patterns.cti @@ -0,0 +1,287 @@ +# +# Copyright (C) 2010, 2011 DocArch <http://www.docarch.be>. +# +# This file is part of liblouis. +# +# liblouis is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# liblouis 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with liblouis. If not, see +# <http://www.gnu.org/licenses/>. +# +# ---------------------------------------------------------------------------------------------- +# odt2braille - Braille authoring in OpenOffice.org. +# ---------------------------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------------------------- +# Unicode 2800..28FF Braille Patterns +# ---------------------------------------------------------------------------------------------- + +noback sign \x2800 0 # ⠀ BRAILLE PATTERN DOTS-0 +noback sign \x2801 1 # ⠁ BRAILLE PATTERN DOTS-1 +noback sign \x2802 2 # ⠂ BRAILLE PATTERN DOTS-2 +noback sign \x2803 12 # ⠃ BRAILLE PATTERN DOTS-12 +noback sign \x2804 3 # ⠄ BRAILLE PATTERN DOTS-3 +noback sign \x2805 13 # ⠅ BRAILLE PATTERN DOTS-13 +noback sign \x2806 23 # ⠆ BRAILLE PATTERN DOTS-23 +noback sign \x2807 123 # ⠇ BRAILLE PATTERN DOTS-123 +noback sign \x2808 4 # ⠈ BRAILLE PATTERN DOTS-4 +noback sign \x2809 14 # ⠉ BRAILLE PATTERN DOTS-14 +noback sign \x280A 24 # ⠊ BRAILLE PATTERN DOTS-24 +noback sign \x280B 124 # ⠋ BRAILLE PATTERN DOTS-124 +noback sign \x280C 34 # ⠌ BRAILLE PATTERN DOTS-34 +noback sign \x280D 134 # ⠍ BRAILLE PATTERN DOTS-134 +noback sign \x280E 234 # ⠎ BRAILLE PATTERN DOTS-234 +noback sign \x280F 1234 # ⠏ BRAILLE PATTERN DOTS-1234 +noback sign \x2810 5 # ⠐ BRAILLE PATTERN DOTS-5 +noback sign \x2811 15 # ⠑ BRAILLE PATTERN DOTS-15 +noback sign \x2812 25 # ⠒ BRAILLE PATTERN DOTS-25 +noback sign \x2813 125 # ⠓ BRAILLE PATTERN DOTS-125 +noback sign \x2814 35 # ⠔ BRAILLE PATTERN DOTS-35 +noback sign \x2815 135 # ⠕ BRAILLE PATTERN DOTS-135 +noback sign \x2816 235 # ⠖ BRAILLE PATTERN DOTS-235 +noback sign \x2817 1235 # ⠗ BRAILLE PATTERN DOTS-1235 +noback sign \x2818 45 # ⠘ BRAILLE PATTERN DOTS-45 +noback sign \x2819 145 # ⠙ BRAILLE PATTERN DOTS-145 +noback sign \x281A 245 # ⠚ BRAILLE PATTERN DOTS-245 +noback sign \x281B 1245 # ⠛ BRAILLE PATTERN DOTS-1245 +noback sign \x281C 345 # ⠜ BRAILLE PATTERN DOTS-345 +noback sign \x281D 1345 # ⠝ BRAILLE PATTERN DOTS-1345 +noback sign \x281E 2345 # ⠞ BRAILLE PATTERN DOTS-2345 +noback sign \x281F 12345 # ⠟ BRAILLE PATTERN DOTS-12345 +noback sign \x2820 6 # ⠠ BRAILLE PATTERN DOTS-6 +noback sign \x2821 16 # ⠡ BRAILLE PATTERN DOTS-16 +noback sign \x2822 26 # ⠢ BRAILLE PATTERN DOTS-26 +noback sign \x2823 126 # ⠣ BRAILLE PATTERN DOTS-126 +noback sign \x2824 36 # ⠤ BRAILLE PATTERN DOTS-36 +noback sign \x2825 136 # ⠥ BRAILLE PATTERN DOTS-136 +noback sign \x2826 236 # ⠦ BRAILLE PATTERN DOTS-236 +noback sign \x2827 1236 # ⠧ BRAILLE PATTERN DOTS-1236 +noback sign \x2828 46 # ⠨ BRAILLE PATTERN DOTS-46 +noback sign \x2829 146 # ⠩ BRAILLE PATTERN DOTS-146 +noback sign \x282A 246 # ⠪ BRAILLE PATTERN DOTS-246 +noback sign \x282B 1246 # ⠫ BRAILLE PATTERN DOTS-1246 +noback sign \x282C 346 # ⠬ BRAILLE PATTERN DOTS-346 +noback sign \x282D 1346 # ⠭ BRAILLE PATTERN DOTS-1346 +noback sign \x282E 2346 # ⠮ BRAILLE PATTERN DOTS-2346 +noback sign \x282F 12346 # ⠯ BRAILLE PATTERN DOTS-12346 +noback sign \x2830 56 # ⠰ BRAILLE PATTERN DOTS-56 +noback sign \x2831 156 # ⠱ BRAILLE PATTERN DOTS-156 +noback sign \x2832 256 # ⠲ BRAILLE PATTERN DOTS-256 +noback sign \x2833 1256 # ⠳ BRAILLE PATTERN DOTS-1256 +noback sign \x2834 356 # ⠴ BRAILLE PATTERN DOTS-356 +noback sign \x2835 1356 # ⠵ BRAILLE PATTERN DOTS-1356 +noback sign \x2836 2356 # ⠶ BRAILLE PATTERN DOTS-2356 +noback sign \x2837 12356 # ⠷ BRAILLE PATTERN DOTS-12356 +noback sign \x2838 456 # ⠸ BRAILLE PATTERN DOTS-456 +noback sign \x2839 1456 # ⠹ BRAILLE PATTERN DOTS-1456 +noback sign \x283A 2456 # ⠺ BRAILLE PATTERN DOTS-2456 +noback sign \x283B 12456 # ⠻ BRAILLE PATTERN DOTS-12456 +noback sign \x283C 3456 # ⠼ BRAILLE PATTERN DOTS-3456 +noback sign \x283D 13456 # ⠽ BRAILLE PATTERN DOTS-13456 +noback sign \x283E 23456 # ⠾ BRAILLE PATTERN DOTS-23456 +noback sign \x283F 123456 # ⠿ BRAILLE PATTERN DOTS-123456 +noback sign \x2840 7 # ⡀ BRAILLE PATTERN DOTS-7 +noback sign \x2841 17 # ⡁ BRAILLE PATTERN DOTS-17 +noback sign \x2842 27 # ⡂ BRAILLE PATTERN DOTS-27 +noback sign \x2843 127 # ⡃ BRAILLE PATTERN DOTS-127 +noback sign \x2844 37 # ⡄ BRAILLE PATTERN DOTS-37 +noback sign \x2845 137 # ⡅ BRAILLE PATTERN DOTS-137 +noback sign \x2846 237 # ⡆ BRAILLE PATTERN DOTS-237 +noback sign \x2847 1237 # ⡇ BRAILLE PATTERN DOTS-1237 +noback sign \x2848 47 # ⡈ BRAILLE PATTERN DOTS-47 +noback sign \x2849 147 # ⡉ BRAILLE PATTERN DOTS-147 +noback sign \x284A 247 # ⡊ BRAILLE PATTERN DOTS-247 +noback sign \x284B 1247 # ⡋ BRAILLE PATTERN DOTS-1247 +noback sign \x284C 347 # ⡌ BRAILLE PATTERN DOTS-347 +noback sign \x284D 1347 # ⡍ BRAILLE PATTERN DOTS-1347 +noback sign \x284E 2347 # ⡎ BRAILLE PATTERN DOTS-2347 +noback sign \x284F 12347 # ⡏ BRAILLE PATTERN DOTS-12347 +noback sign \x2850 57 # ⡐ BRAILLE PATTERN DOTS-57 +noback sign \x2851 157 # ⡑ BRAILLE PATTERN DOTS-157 +noback sign \x2852 257 # ⡒ BRAILLE PATTERN DOTS-257 +noback sign \x2853 1257 # ⡓ BRAILLE PATTERN DOTS-1257 +noback sign \x2854 357 # ⡔ BRAILLE PATTERN DOTS-357 +noback sign \x2855 1357 # ⡕ BRAILLE PATTERN DOTS-1357 +noback sign \x2856 2357 # ⡖ BRAILLE PATTERN DOTS-2357 +noback sign \x2857 12357 # ⡗ BRAILLE PATTERN DOTS-12357 +noback sign \x2858 457 # ⡘ BRAILLE PATTERN DOTS-457 +noback sign \x2859 1457 # ⡙ BRAILLE PATTERN DOTS-1457 +noback sign \x285A 2457 # ⡚ BRAILLE PATTERN DOTS-2457 +noback sign \x285B 12457 # ⡛ BRAILLE PATTERN DOTS-12457 +noback sign \x285C 3457 # ⡜ BRAILLE PATTERN DOTS-3457 +noback sign \x285D 13457 # ⡝ BRAILLE PATTERN DOTS-13457 +noback sign \x285E 23457 # ⡞ BRAILLE PATTERN DOTS-23457 +noback sign \x285F 123457 # ⡟ BRAILLE PATTERN DOTS-123457 +noback sign \x2860 67 # ⡠ BRAILLE PATTERN DOTS-67 +noback sign \x2861 167 # ⡡ BRAILLE PATTERN DOTS-167 +noback sign \x2862 267 # ⡢ BRAILLE PATTERN DOTS-267 +noback sign \x2863 1267 # ⡣ BRAILLE PATTERN DOTS-1267 +noback sign \x2864 367 # ⡤ BRAILLE PATTERN DOTS-367 +noback sign \x2865 1367 # ⡥ BRAILLE PATTERN DOTS-1367 +noback sign \x2866 2367 # ⡦ BRAILLE PATTERN DOTS-2367 +noback sign \x2867 12367 # ⡧ BRAILLE PATTERN DOTS-12367 +noback sign \x2868 467 # ⡨ BRAILLE PATTERN DOTS-467 +noback sign \x2869 1467 # ⡩ BRAILLE PATTERN DOTS-1467 +noback sign \x286A 2467 # ⡪ BRAILLE PATTERN DOTS-2467 +noback sign \x286B 12467 # ⡫ BRAILLE PATTERN DOTS-12467 +noback sign \x286C 3467 # ⡬ BRAILLE PATTERN DOTS-3467 +noback sign \x286D 13467 # ⡭ BRAILLE PATTERN DOTS-13467 +noback sign \x286E 23467 # ⡮ BRAILLE PATTERN DOTS-23467 +noback sign \x286F 123467 # ⡯ BRAILLE PATTERN DOTS-123467 +noback sign \x2870 567 # ⡰ BRAILLE PATTERN DOTS-567 +noback sign \x2871 1567 # ⡱ BRAILLE PATTERN DOTS-1567 +noback sign \x2872 2567 # ⡲ BRAILLE PATTERN DOTS-2567 +noback sign \x2873 12567 # ⡳ BRAILLE PATTERN DOTS-12567 +noback sign \x2874 3567 # ⡴ BRAILLE PATTERN DOTS-3567 +noback sign \x2875 13567 # ⡵ BRAILLE PATTERN DOTS-13567 +noback sign \x2876 23567 # ⡶ BRAILLE PATTERN DOTS-23567 +noback sign \x2877 123567 # ⡷ BRAILLE PATTERN DOTS-123567 +noback sign \x2878 4567 # ⡸ BRAILLE PATTERN DOTS-4567 +noback sign \x2879 14567 # ⡹ BRAILLE PATTERN DOTS-14567 +noback sign \x287A 24567 # ⡺ BRAILLE PATTERN DOTS-24567 +noback sign \x287B 124567 # ⡻ BRAILLE PATTERN DOTS-124567 +noback sign \x287C 34567 # ⡼ BRAILLE PATTERN DOTS-34567 +noback sign \x287D 134567 # ⡽ BRAILLE PATTERN DOTS-134567 +noback sign \x287E 234567 # ⡾ BRAILLE PATTERN DOTS-234567 +noback sign \x287F 1234567 # ⡿ BRAILLE PATTERN DOTS-1234567 +noback sign \x2880 8 # ⢀ BRAILLE PATTERN DOTS-8 +noback sign \x2881 18 # ⢁ BRAILLE PATTERN DOTS-18 +noback sign \x2882 28 # ⢂ BRAILLE PATTERN DOTS-28 +noback sign \x2883 128 # ⢃ BRAILLE PATTERN DOTS-128 +noback sign \x2884 38 # ⢄ BRAILLE PATTERN DOTS-38 +noback sign \x2885 138 # ⢅ BRAILLE PATTERN DOTS-138 +noback sign \x2886 238 # ⢆ BRAILLE PATTERN DOTS-238 +noback sign \x2887 1238 # ⢇ BRAILLE PATTERN DOTS-1238 +noback sign \x2888 48 # ⢈ BRAILLE PATTERN DOTS-48 +noback sign \x2889 148 # ⢉ BRAILLE PATTERN DOTS-148 +noback sign \x288A 248 # ⢊ BRAILLE PATTERN DOTS-248 +noback sign \x288B 1248 # ⢋ BRAILLE PATTERN DOTS-1248 +noback sign \x288C 348 # ⢌ BRAILLE PATTERN DOTS-348 +noback sign \x288D 1348 # ⢍ BRAILLE PATTERN DOTS-1348 +noback sign \x288E 2348 # ⢎ BRAILLE PATTERN DOTS-2348 +noback sign \x288F 12348 # ⢏ BRAILLE PATTERN DOTS-12348 +noback sign \x2890 58 # ⢐ BRAILLE PATTERN DOTS-58 +noback sign \x2891 158 # ⢑ BRAILLE PATTERN DOTS-158 +noback sign \x2892 258 # ⢒ BRAILLE PATTERN DOTS-258 +noback sign \x2893 1258 # ⢓ BRAILLE PATTERN DOTS-1258 +noback sign \x2894 358 # ⢔ BRAILLE PATTERN DOTS-358 +noback sign \x2895 1358 # ⢕ BRAILLE PATTERN DOTS-1358 +noback sign \x2896 2358 # ⢖ BRAILLE PATTERN DOTS-2358 +noback sign \x2897 12358 # ⢗ BRAILLE PATTERN DOTS-12358 +noback sign \x2898 458 # ⢘ BRAILLE PATTERN DOTS-458 +noback sign \x2899 1458 # ⢙ BRAILLE PATTERN DOTS-1458 +noback sign \x289A 2458 # ⢚ BRAILLE PATTERN DOTS-2458 +noback sign \x289B 12458 # ⢛ BRAILLE PATTERN DOTS-12458 +noback sign \x289C 3458 # ⢜ BRAILLE PATTERN DOTS-3458 +noback sign \x289D 13458 # ⢝ BRAILLE PATTERN DOTS-13458 +noback sign \x289E 23458 # ⢞ BRAILLE PATTERN DOTS-23458 +noback sign \x289F 123458 # ⢟ BRAILLE PATTERN DOTS-123458 +noback sign \x28A0 68 # ⢠ BRAILLE PATTERN DOTS-68 +noback sign \x28A1 168 # ⢡ BRAILLE PATTERN DOTS-168 +noback sign \x28A2 268 # ⢢ BRAILLE PATTERN DOTS-268 +noback sign \x28A3 1268 # ⢣ BRAILLE PATTERN DOTS-1268 +noback sign \x28A4 368 # ⢤ BRAILLE PATTERN DOTS-368 +noback sign \x28A5 1368 # ⢥ BRAILLE PATTERN DOTS-1368 +noback sign \x28A6 2368 # ⢦ BRAILLE PATTERN DOTS-2368 +noback sign \x28A7 12368 # ⢧ BRAILLE PATTERN DOTS-12368 +noback sign \x28A8 468 # ⢨ BRAILLE PATTERN DOTS-468 +noback sign \x28A9 1468 # ⢩ BRAILLE PATTERN DOTS-1468 +noback sign \x28AA 2468 # ⢪ BRAILLE PATTERN DOTS-2468 +noback sign \x28AB 12468 # ⢫ BRAILLE PATTERN DOTS-12468 +noback sign \x28AC 3468 # ⢬ BRAILLE PATTERN DOTS-3468 +noback sign \x28AD 13468 # ⢭ BRAILLE PATTERN DOTS-13468 +noback sign \x28AE 23468 # ⢮ BRAILLE PATTERN DOTS-23468 +noback sign \x28AF 123468 # ⢯ BRAILLE PATTERN DOTS-123468 +noback sign \x28B0 568 # ⢰ BRAILLE PATTERN DOTS-568 +noback sign \x28B1 1568 # ⢱ BRAILLE PATTERN DOTS-1568 +noback sign \x28B2 2568 # ⢲ BRAILLE PATTERN DOTS-2568 +noback sign \x28B3 12568 # ⢳ BRAILLE PATTERN DOTS-12568 +noback sign \x28B4 3568 # ⢴ BRAILLE PATTERN DOTS-3568 +noback sign \x28B5 13568 # ⢵ BRAILLE PATTERN DOTS-13568 +noback sign \x28B6 23568 # ⢶ BRAILLE PATTERN DOTS-23568 +noback sign \x28B7 123568 # ⢷ BRAILLE PATTERN DOTS-123568 +noback sign \x28B8 4568 # ⢸ BRAILLE PATTERN DOTS-4568 +noback sign \x28B9 14568 # ⢹ BRAILLE PATTERN DOTS-14568 +noback sign \x28BA 24568 # ⢺ BRAILLE PATTERN DOTS-24568 +noback sign \x28BB 124568 # ⢻ BRAILLE PATTERN DOTS-124568 +noback sign \x28BC 34568 # ⢼ BRAILLE PATTERN DOTS-34568 +noback sign \x28BD 134568 # ⢽ BRAILLE PATTERN DOTS-134568 +noback sign \x28BE 234568 # ⢾ BRAILLE PATTERN DOTS-234568 +noback sign \x28BF 1234568 # ⢿ BRAILLE PATTERN DOTS-1234568 +noback sign \x28C0 78 # ⣀ BRAILLE PATTERN DOTS-78 +noback sign \x28C1 178 # ⣁ BRAILLE PATTERN DOTS-178 +noback sign \x28C2 278 # ⣂ BRAILLE PATTERN DOTS-278 +noback sign \x28C3 1278 # ⣃ BRAILLE PATTERN DOTS-1278 +noback sign \x28C4 378 # ⣄ BRAILLE PATTERN DOTS-378 +noback sign \x28C5 1378 # ⣅ BRAILLE PATTERN DOTS-1378 +noback sign \x28C6 2378 # ⣆ BRAILLE PATTERN DOTS-2378 +noback sign \x28C7 12378 # ⣇ BRAILLE PATTERN DOTS-12378 +noback sign \x28C8 478 # ⣈ BRAILLE PATTERN DOTS-478 +noback sign \x28C9 1478 # ⣉ BRAILLE PATTERN DOTS-1478 +noback sign \x28CA 2478 # ⣊ BRAILLE PATTERN DOTS-2478 +noback sign \x28CB 12478 # ⣋ BRAILLE PATTERN DOTS-12478 +noback sign \x28CC 3478 # ⣌ BRAILLE PATTERN DOTS-3478 +noback sign \x28CD 13478 # ⣍ BRAILLE PATTERN DOTS-13478 +noback sign \x28CE 23478 # ⣎ BRAILLE PATTERN DOTS-23478 +noback sign \x28CF 123478 # ⣏ BRAILLE PATTERN DOTS-123478 +noback sign \x28D0 578 # ⣐ BRAILLE PATTERN DOTS-578 +noback sign \x28D1 1578 # ⣑ BRAILLE PATTERN DOTS-1578 +noback sign \x28D2 2578 # ⣒ BRAILLE PATTERN DOTS-2578 +noback sign \x28D3 12578 # ⣓ BRAILLE PATTERN DOTS-12578 +noback sign \x28D4 3578 # ⣔ BRAILLE PATTERN DOTS-3578 +noback sign \x28D5 13578 # ⣕ BRAILLE PATTERN DOTS-13578 +noback sign \x28D6 23578 # ⣖ BRAILLE PATTERN DOTS-23578 +noback sign \x28D7 123578 # ⣗ BRAILLE PATTERN DOTS-123578 +noback sign \x28D8 4578 # ⣘ BRAILLE PATTERN DOTS-4578 +noback sign \x28D9 14578 # ⣙ BRAILLE PATTERN DOTS-14578 +noback sign \x28DA 24578 # ⣚ BRAILLE PATTERN DOTS-24578 +noback sign \x28DB 124578 # ⣛ BRAILLE PATTERN DOTS-124578 +noback sign \x28DC 34578 # ⣜ BRAILLE PATTERN DOTS-34578 +noback sign \x28DD 134578 # ⣝ BRAILLE PATTERN DOTS-134578 +noback sign \x28DE 234578 # ⣞ BRAILLE PATTERN DOTS-234578 +noback sign \x28DF 1234578 # ⣟ BRAILLE PATTERN DOTS-1234578 +noback sign \x28E0 678 # ⣠ BRAILLE PATTERN DOTS-678 +noback sign \x28E1 1678 # ⣡ BRAILLE PATTERN DOTS-1678 +noback sign \x28E2 2678 # ⣢ BRAILLE PATTERN DOTS-2678 +noback sign \x28E3 12678 # ⣣ BRAILLE PATTERN DOTS-12678 +noback sign \x28E4 3678 # ⣤ BRAILLE PATTERN DOTS-3678 +noback sign \x28E5 13678 # ⣥ BRAILLE PATTERN DOTS-13678 +noback sign \x28E6 23678 # ⣦ BRAILLE PATTERN DOTS-23678 +noback sign \x28E7 123678 # ⣧ BRAILLE PATTERN DOTS-123678 +noback sign \x28E8 4678 # ⣨ BRAILLE PATTERN DOTS-4678 +noback sign \x28E9 14678 # ⣩ BRAILLE PATTERN DOTS-14678 +noback sign \x28EA 24678 # ⣪ BRAILLE PATTERN DOTS-24678 +noback sign \x28EB 124678 # ⣫ BRAILLE PATTERN DOTS-124678 +noback sign \x28EC 34678 # ⣬ BRAILLE PATTERN DOTS-34678 +noback sign \x28ED 134678 # ⣭ BRAILLE PATTERN DOTS-134678 +noback sign \x28EE 234678 # ⣮ BRAILLE PATTERN DOTS-234678 +noback sign \x28EF 1234678 # ⣯ BRAILLE PATTERN DOTS-1234678 +noback sign \x28F0 5678 # ⣰ BRAILLE PATTERN DOTS-5678 +noback sign \x28F1 15678 # ⣱ BRAILLE PATTERN DOTS-15678 +noback sign \x28F2 25678 # ⣲ BRAILLE PATTERN DOTS-25678 +noback sign \x28F3 125678 # ⣳ BRAILLE PATTERN DOTS-125678 +noback sign \x28F4 35678 # ⣴ BRAILLE PATTERN DOTS-35678 +noback sign \x28F5 135678 # ⣵ BRAILLE PATTERN DOTS-135678 +noback sign \x28F6 235678 # ⣶ BRAILLE PATTERN DOTS-235678 +noback sign \x28F7 1235678 # ⣷ BRAILLE PATTERN DOTS-1235678 +noback sign \x28F8 45678 # ⣸ BRAILLE PATTERN DOTS-45678 +noback sign \x28F9 145678 # ⣹ BRAILLE PATTERN DOTS-145678 +noback sign \x28FA 245678 # ⣺ BRAILLE PATTERN DOTS-245678 +noback sign \x28FB 1245678 # ⣻ BRAILLE PATTERN DOTS-1245678 +noback sign \x28FC 345678 # ⣼ BRAILLE PATTERN DOTS-345678 +noback sign \x28FD 1345678 # ⣽ BRAILLE PATTERN DOTS-1345678 +noback sign \x28FE 2345678 # ⣾ BRAILLE PATTERN DOTS-2345678 +noback sign \x28FF 12345678 # ⣿ BRAILLE PATTERN DOTS-12345678 + + +# ---------------------------------------------------------------------------------------------- + diff --git a/third_party/liblouis/overrides/tables/da.ctb b/third_party/liblouis/overrides/tables/da.ctb new file mode 100644 index 0000000..49baad3 --- /dev/null +++ b/third_party/liblouis/overrides/tables/da.ctb @@ -0,0 +1,280 @@ +############################################################################### +# BRLTTY - A background process providing access to the console screen (when in +# text mode) for a blind person using a refreshable braille display. +# +# Copyright (C) 1995-2008 by The BRLTTY Developers. +# +# BRLTTY comes with ABSOLUTELY NO WARRANTY. +# +# This is free software, placed under the terms of the +# GNU Lesser General Public License, as published by the Free Software +# Foundation; either version 2.1 of the License, or (at your option) any +# later version. Please see the file LICENSE-LGPL for details. +# +# Web Page: http://mielke.cc/brltty/ +# +# This software is maintained by Dave Mielke <dave@mielke.cc>. +############################################################################### + +# BRLTTY Text Table - Danish (iso-8859-1) + +# This is the table which comes closest to the Danish standard 1252 table. All +# control characters are mapped as their corresponding capital letters with +# dot-8 added. Most Danish braille users should use this table. + +# generated by ttbtest +letter \x0000 8 NULL +letter \x0001 178 START OF HEADING +letter \x0002 1278 START OF TEXT +letter \x0003 1478 END OF TEXT +letter \x0004 14578 END OF TRANSMISSION +letter \x0005 24568 ENQUIRY +letter \x0006 12478 ACKNOWLEDGE +letter \x0007 124578 BELL +letter \x0008 12578 BACKSPACE +space \t 2478 CHARACTER TABULATION +space \n 678 LINE FEED (LF) +space \v 1368 LINE TABULATION +space \f 12378 FORM FEED (FF) +space \r 257 CARRIAGE RETURN (CR) +letter \x000e 134578 SHIFT OUT +letter \x000f 12358 SHIFT IN +letter \x0010 123478 DATA LINK ESCAPE +letter \x0011 1234578 DEVICE CONTROL ONE +letter \x0012 13568 DEVICE CONTROL TWO +letter \x0013 4578 DEVICE CONTROL THREE +letter \x0014 268 DEVICE CONTROL FOUR +letter \x0015 13678 NEGATIVE ACKNOWLEDGE +letter \x0016 278 SYNCHRONOUS IDLE +letter \x0017 3578 END OF TRANSMISSION BLOCK +letter \x0018 78 CANCEL +letter \x0019 68 END OF MEDIUM +letter \x001a 135678 SUBSTITUTE +letter \x001b 2678 ESCAPE +letter \x001c 45678 INFORMATION SEPARATOR FOUR +letter \x001d 12368 INFORMATION SEPARATOR THREE +letter \x001e 1234678 INFORMATION SEPARATOR TWO +letter \x001f 235678 INFORMATION SEPARATOR ONE +space \s 0 SPACE +punctuation ! 235 EXCLAMATION MARK +punctuation " 2356 QUOTATION MARK +punctuation # 34568 NUMBER SIGN +punctuation $ 25678 DOLLAR SIGN +punctuation % 24578 PERCENT SIGN +punctuation & 123468 AMPERSAND +punctuation ' 4 APOSTROPHE +punctuation ( 2368 LEFT PARENTHESIS +punctuation ) 3568 RIGHT PARENTHESIS +punctuation * 35 ASTERISK +punctuation + 2358 PLUS SIGN +punctuation , 2 COMMA +punctuation - 368 HYPHEN-MINUS +punctuation . 3 FULL STOP +punctuation / 34 SOLIDUS +include digits8Dots.uti +punctuation : 25 COLON +punctuation ; 23 SEMICOLON +punctuation < 358 LESS-THAN SIGN +punctuation = 23568 EQUALS SIGN +punctuation > 267 GREATER-THAN SIGN +punctuation ? 26 QUESTION MARK +punctuation @ 478 COMMERCIAL AT +uppercase A 17 LATIN CAPITAL LETTER A +uppercase B 127 LATIN CAPITAL LETTER B +uppercase C 147 LATIN CAPITAL LETTER C +uppercase D 1457 LATIN CAPITAL LETTER D +uppercase E 157 LATIN CAPITAL LETTER E +uppercase F 1247 LATIN CAPITAL LETTER F +uppercase G 12457 LATIN CAPITAL LETTER G +uppercase H 1257 LATIN CAPITAL LETTER H +uppercase I 247 LATIN CAPITAL LETTER I +uppercase J 2457 LATIN CAPITAL LETTER J +uppercase K 137 LATIN CAPITAL LETTER K +uppercase L 1237 LATIN CAPITAL LETTER L +uppercase M 1347 LATIN CAPITAL LETTER M +uppercase N 13457 LATIN CAPITAL LETTER N +uppercase O 1357 LATIN CAPITAL LETTER O +uppercase P 12347 LATIN CAPITAL LETTER P +uppercase Q 123457 LATIN CAPITAL LETTER Q +uppercase R 12357 LATIN CAPITAL LETTER R +uppercase S 2347 LATIN CAPITAL LETTER S +uppercase T 23457 LATIN CAPITAL LETTER T +uppercase U 1367 LATIN CAPITAL LETTER U +uppercase V 12367 LATIN CAPITAL LETTER V +uppercase W 24567 LATIN CAPITAL LETTER W +uppercase X 13467 LATIN CAPITAL LETTER X +uppercase Y 134567 LATIN CAPITAL LETTER Y +uppercase Z 13567 LATIN CAPITAL LETTER Z +punctuation [ 23678 LEFT SQUARE BRACKET +punctuation \\ 347 REVERSE SOLIDUS +punctuation ] 35678 RIGHT SQUARE BRACKET +punctuation ^ 12348 CIRCUMFLEX ACCENT +punctuation _ 3678 LOW LINE +punctuation ` 5 GRAVE ACCENT +lowercase a 1 LATIN SMALL LETTER A +lowercase b 12 LATIN SMALL LETTER B +lowercase c 14 LATIN SMALL LETTER C +lowercase d 145 LATIN SMALL LETTER D +lowercase e 15 LATIN SMALL LETTER E +lowercase f 124 LATIN SMALL LETTER F +lowercase g 1245 LATIN SMALL LETTER G +lowercase h 125 LATIN SMALL LETTER H +lowercase i 24 LATIN SMALL LETTER I +lowercase j 245 LATIN SMALL LETTER J +lowercase k 13 LATIN SMALL LETTER K +lowercase l 123 LATIN SMALL LETTER L +lowercase m 134 LATIN SMALL LETTER M +lowercase n 1345 LATIN SMALL LETTER N +lowercase o 135 LATIN SMALL LETTER O +lowercase p 1234 LATIN SMALL LETTER P +lowercase q 12345 LATIN SMALL LETTER Q +lowercase r 1235 LATIN SMALL LETTER R +lowercase s 234 LATIN SMALL LETTER S +lowercase t 2345 LATIN SMALL LETTER T +lowercase u 136 LATIN SMALL LETTER U +lowercase v 1236 LATIN SMALL LETTER V +lowercase w 2456 LATIN SMALL LETTER W +lowercase x 1346 LATIN SMALL LETTER X +lowercase y 13456 LATIN SMALL LETTER Y +lowercase z 1356 LATIN SMALL LETTER Z +punctuation { 123678 LEFT CURLY BRACKET +punctuation | 4568 VERTICAL LINE +punctuation } 345678 RIGHT CURLY BRACKET +punctuation ~ 467 TILDE +letter \x007f 7 DELETE +letter \x20AC 1578 EURO SIGN +letter \x201A 457 +letter \x0192 58 +letter \x201E 2378 +letter \x2022 37 +letter \x2026 6 +letter \x0080 24568 <control-0080> +letter \x0081 45 <control-0081> +letter \x0082 457 BREAK PERMITTED HERE +letter \x0083 5 NO BREAK HERE +letter \x0084 2378 <control-0084> +letter \x0085 6 NEXT LINE (NEL) +letter \x0086 2357 START OF SELECTED AREA +letter \x0087 23578 END OF SELECTED AREA +letter \x0088 5678 CHARACTER TABULATION SET +letter \x0089 3578 CHARACTER TABULATION WITH JUSTIFICATION +letter \x008a 4578 LINE TABULATION SET +letter \x008b 456 PARTIAL LINE FORWARD +letter \x008c 12358 PARTIAL LINE BACKWARD +letter \x008d 3567 REVERSE LINE FEED +letter \x008e 3467 SINGLE SHIFT TWO +letter \x008f 27 SINGLE SHIFT THREE +letter \x0090 357 DEVICE CONTROL STRING +letter \x0091 47 PRIVATE USE ONE +letter \x0092 48 PRIVATE USE TWO +letter \x0093 237 SET TRANSMIT STATE +letter \x0094 568 CANCEL CHARACTER +letter \x0095 37 MESSAGE WAITING +letter \x0096 36 START OF GUARDED AREA +letter \x0097 367 END OF GUARDED AREA +letter \x0098 46 START OF STRING +letter \x0099 268 <control-0099> +letter \x009a 2348 SINGLE CHARACTER INTRODUCER +letter \x009b 4567 CONTROL SEQUENCE INTRODUCER +letter \x009c 1358 STRING TERMINATOR +letter \x009d 23458 OPERATING SYSTEM COMMAND +letter \x009e 346 PRIVACY MESSAGE +letter \x009f 2345678 APPLICATION PROGRAM COMMAND +punctuation \x00a0 0 NO-BREAK SPACE +punctuation \x00a1 256 INVERTED EXCLAMATION MARK +punctuation \x00a2 2578 CENT SIGN +punctuation \x00a3 1238 POUND SIGN +punctuation \x00a4 2367 CURRENCY SIGN +punctuation \x00a5 67 YEN SIGN +punctuation \x00a6 3478 BROKEN BAR +punctuation \x00a7 578 SECTION SIGN +punctuation \x00a8 56 DIAERESIS +punctuation \x00a9 78 COPYRIGHT SIGN +letter \x00aa 234678 FEMININE ORDINAL INDICATOR +punctuation \x00ab 57 LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +punctuation \x00ac 34567 NOT SIGN +punctuation \x00ad 378 SOFT HYPHEN +punctuation \x00ae 13568 REGISTERED SIGN +punctuation \x00af 23567 MACRON +punctuation \x00b0 356 DEGREE SIGN +punctuation \x00b1 123458 PLUS-MINUS SIGN +punctuation \x00b2 238 SUPERSCRIPT TWO +punctuation \x00b3 258 SUPERSCRIPT THREE +punctuation \x00b4 468 ACUTE ACCENT +lowercase \x00b5 236 MICRO SIGN +punctuation \x00b6 1234568 PILCROW SIGN +punctuation \x00b7 38 MIDDLE DOT +punctuation \x00b8 4678 CEDILLA +punctuation \x00b9 28 SUPERSCRIPT ONE +letter \x00ba 7 MASCULINE ORDINAL INDICATOR +punctuation \x00bb 567 RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +punctuation \x00bc 13458 VULGAR FRACTION ONE QUARTER +punctuation \x00bd 458 VULGAR FRACTION ONE HALF +punctuation \x00be 3456 VULGAR FRACTION THREE QUARTERS +punctuation \x00bf 348 INVERTED QUESTION MARK +uppercase \x00c0 123567 LATIN CAPITAL LETTER A WITH GRAVE +uppercase \x00c1 1235678 LATIN CAPITAL LETTER A WITH ACUTE +uppercase \x00c2 1678 LATIN CAPITAL LETTER A WITH CIRCUMFLEX +uppercase \x00c3 14678 LATIN CAPITAL LETTER A WITH TILDE +uppercase \x00c4 34578 LATIN CAPITAL LETTER A WITH DIAERESIS +uppercase \x00c5 167 LATIN CAPITAL LETTER A WITH RING ABOVE +uppercase \x00c6 3457 LATIN CAPITAL LETTER AE +uppercase \x00c7 123467 LATIN CAPITAL LETTER C WITH CEDILLA +uppercase \x00c8 23467 LATIN CAPITAL LETTER E WITH GRAVE +uppercase \x00c9 1234567 LATIN CAPITAL LETTER E WITH ACUTE +uppercase \x00ca 1267 LATIN CAPITAL LETTER E WITH CIRCUMFLEX +uppercase \x00cb 12467 LATIN CAPITAL LETTER E WITH DIAERESIS +uppercase \x00cc 15678 LATIN CAPITAL LETTER I WITH GRAVE +uppercase \x00cd 12678 LATIN CAPITAL LETTER I WITH ACUTE +uppercase \x00ce 1467 LATIN CAPITAL LETTER I WITH CIRCUMFLEX +uppercase \x00cf 124567 LATIN CAPITAL LETTER I WITH DIAERESIS +uppercase \x00d0 68 LATIN CAPITAL LETTER ETH +uppercase \x00d1 1245678 LATIN CAPITAL LETTER N WITH TILDE +uppercase \x00d2 124678 LATIN CAPITAL LETTER O WITH GRAVE +uppercase \x00d3 34678 LATIN CAPITAL LETTER O WITH ACUTE +uppercase \x00d4 14567 LATIN CAPITAL LETTER O WITH CIRCUMFLEX +uppercase \x00d5 145678 LATIN CAPITAL LETTER O WITH TILDE +uppercase \x00d6 24678 LATIN CAPITAL LETTER O WITH DIAERESIS +punctuation \x00d7 13468 MULTIPLICATION SIGN +uppercase \x00d8 2467 LATIN CAPITAL LETTER O WITH STROKE +uppercase \x00d9 234567 LATIN CAPITAL LETTER U WITH GRAVE +uppercase \x00da 125678 LATIN CAPITAL LETTER U WITH ACUTE +uppercase \x00db 1567 LATIN CAPITAL LETTER U WITH CIRCUMFLEX +uppercase \x00dc 12567 LATIN CAPITAL LETTER U WITH DIAERESIS +uppercase \x00dd 257 LATIN CAPITAL LETTER Y WITH ACUTE +uppercase \x00de 1368 LATIN CAPITAL LETTER THORN +lowercase \x00df 23468 LATIN SMALL LETTER SHARP S +lowercase \x00e0 12356 LATIN SMALL LETTER A WITH GRAVE +lowercase \x00e1 123568 LATIN SMALL LETTER A WITH ACUTE +lowercase \x00e2 168 LATIN SMALL LETTER A WITH CIRCUMFLEX +lowercase \x00e3 1468 LATIN SMALL LETTER A WITH TILDE +lowercase \x00e4 3458 LATIN SMALL LETTER A WITH DIAERESIS +lowercase \x00e5 16 LATIN SMALL LETTER A WITH RING ABOVE +lowercase \x00e6 345 LATIN SMALL LETTER AE +lowercase \x00e7 12346 LATIN SMALL LETTER C WITH CEDILLA +lowercase \x00e8 2346 LATIN SMALL LETTER E WITH GRAVE +lowercase \x00e9 123456 LATIN SMALL LETTER E WITH ACUTE +lowercase \x00ea 126 LATIN SMALL LETTER E WITH CIRCUMFLEX +lowercase \x00eb 1246 LATIN SMALL LETTER E WITH DIAERESIS +lowercase \x00ec 1568 LATIN SMALL LETTER I WITH GRAVE +lowercase \x00ed 1268 LATIN SMALL LETTER I WITH ACUTE +lowercase \x00ee 146 LATIN SMALL LETTER I WITH CIRCUMFLEX +lowercase \x00ef 12456 LATIN SMALL LETTER I WITH DIAERESIS +lowercase \x00f0 134568 LATIN SMALL LETTER ETH +lowercase \x00f1 124568 LATIN SMALL LETTER N WITH TILDE +lowercase \x00f2 12468 LATIN SMALL LETTER O WITH GRAVE +lowercase \x00f3 3468 LATIN SMALL LETTER O WITH ACUTE +lowercase \x00f4 1456 LATIN SMALL LETTER O WITH CIRCUMFLEX +lowercase \x00f5 14568 LATIN SMALL LETTER O WITH TILDE +lowercase \x00f6 2468 LATIN SMALL LETTER O WITH DIAERESIS +punctuation \x00f7 2568 DIVISION SIGN +lowercase \x00f8 246 LATIN SMALL LETTER O WITH STROKE +lowercase \x00f9 23456 LATIN SMALL LETTER U WITH GRAVE +lowercase \x00fa 12568 LATIN SMALL LETTER U WITH ACUTE +lowercase \x00fb 156 LATIN SMALL LETTER U WITH CIRCUMFLEX +lowercase \x00fc 1256 LATIN SMALL LETTER U WITH DIAERESIS +lowercase \x00fd 1348 LATIN SMALL LETTER Y WITH ACUTE +lowercase \x00fe 138 LATIN SMALL LETTER THORN +lowercase \x00ff 234568 LATIN SMALL LETTER Y WITH DIAERESIS +punctuation \x0192 58 + diff --git a/third_party/liblouis/tables.json b/third_party/liblouis/tables.json new file mode 100644 index 0000000..54e089d --- /dev/null +++ b/third_party/liblouis/tables.json @@ -0,0 +1,398 @@ +[ + { + "locale": "ar", + "dots": "6", + "id": "ar-g1", + "grade": "1", + "fileName": "ar-ar-g1.utb" + }, + { + "locale": "bg", + "dots": "8", + "id": "bg-comp8", + "fileName": "bg.ctb" + }, + { + "locale": "ca", + "dots": "6", + "id": "ca-g1", + "grade": "1", + "fileName": "ca-g1.ctb" + }, + { + "locale": "hr", + "dots": "8", + "id": "hr-comp8", + "fileName": "hr.ctb" + }, + { + "locale": "cs", + "dots": "6", + "id": "cs-g1", + "grade": "1", + "fileName": "cs-g1.ctb" + }, + { + "locale": "da", + "dots": "8", + "id": "da-comp8", + "fileName": "da.ctb" + }, + { + "locale": "nl", + "dots": "6", + "id": "nl-g1", + "grade": "1", + "fileName": "Nl-Nl-g1.utb" + }, + { + "locale": "en_CA", + "dots": "8", + "id": "en-CA-comp8", + "fileName": "en_CA.ctb" + }, + { + "locale": "en_GB", + "dots": "6", + "id": "en-GB-g1", + "grade": "1", + "fileName": "en-gb-g1.utb" + }, + { + "locale": "en_GB", + "dots": "6", + "id": "en-GB-g2", + "grade": "2", + "fileName": "en-GB-g2.ctb" + }, + { + "locale": "en_US", + "dots": "8", + "id": "en-US-comp8", + "fileName": "en-us-comp8.ctb" + }, + { + "locale": "en_US", + "dots": "6", + "id": "en-US-g1", + "grade": "1", + "fileName": "en-us-g1.ctb" + }, + { + "locale": "en_US", + "dots": "6", + "id": "en-US-g2", + "grade": "2", + "fileName": "en-us-g2.ctb" + }, + { + "locale": "et", + "dots": "8", + "id": "et-comp8", + "fileName": "et-g0.utb" + }, + { + "locale": "fr", + "dots": "8", + "id": "fr-comp8", + "fileName": "fr-2007.ctb" + }, + { + "locale": "fr_CA", + "dots": "6", + "id": "fr-CA-g1", + "grade": "1", + "fileName": "fr-ca-g1.utb" + }, + { + "locale": "fr_CA", + "dots": "6", + "id": "fr-CA-g2", + "grade": "2", + "fileName": "Fr-Ca-g2.ctb" + }, + { + "locale": "fr_FR", + "dots": "6", + "id": "fr-FR-g1", + "grade": "1", + "fileName": "fr-fr-g1.utb" + }, + { + "locale": "fr_FR", + "dots": "6", + "id": "fr-FR-g2", + "grade": "2", + "fileName": "Fr-Fr-g2.ctb" + }, + { + "locale": "fi", + "dots": "8", + "id": "fi-comp8", + "fileName": "fi-fi-8dot.ctb" + }, + { + "locale": "de", + "dots": "8", + "id": "de-comp8", + "fileName": "de-de-comp8.ctb" + }, + { + "locale": "de_CH", + "dots": "6", + "id": "de-CH-g0", + "grade": "0", + "fileName": "de-ch-g0.utb" + }, + { + "locale": "de_CH", + "dots": "6", + "id": "de-CH-g1", + "grade": "1", + "fileName": "de-ch-g1.ctb" + }, + { + "locale": "de_CH", + "dots": "6", + "id": "de-CH-g2", + "grade": "2", + "fileName": "de-ch-g2.ctb" + }, + { + "locale": "de_DE", + "dots": "6", + "id": "de-DE-g0", + "grade": "0", + "fileName": "de-de-g0.utb" + }, + { + "locale": "de_DE", + "dots": "6", + "id": "de-DE-g1", + "grade": "1", + "fileName": "de-de-g1.ctb" + }, + { + "locale": "de_DE", + "dots": "6", + "id": "de-DE-g2", + "grade": "2", + "fileName": "de-de-g2.ctb" + }, + { + "locale": "el", + "dots": "6", + "id": "el-g1", + "grade": "1", + "fileName": "gr-gr-g1.utb" + }, + { + "locale": "hi", + "dots": "8", + "id": "hi-comp8", + "fileName": "hi.ctb" + }, + { + "locale": "hi", + "dots": "6", + "id": "hi-g1", + "grade": "1", + "fileName": "hi-in-g1.utb" + }, + { + "locale": "hu", + "dots": "8", + "id": "hu-comp8", + "fileName": "hu-hu-comp8.ctb" + }, + { + "locale": "hu", + "dots": "6", + "id": "hu-g1", + "grade": "1", + "fileName": "hu-hu-g1.ctb" + }, + { + "locale": "is", + "dots": "8", + "id": "is-comp8", + "fileName": "is.ctb" + }, + { + "locale": "it", + "dots": "8", + "id": "it-comp8", + "fileName": "it-it-comp8.utb" + }, + { + "locale": "it", + "dots": "6", + "id": "it-g1", + "grade": "1", + "fileName": "it-it-comp6.utb" + }, + { + "locale": "lv", + "dots": "6", + "id": "lv-g1", + "grade": "1", + "fileName": "Lv-Lv-g1.utb" + }, + { + "locale": "lt", + "dots": "8", + "id": "lt-comp8", + "fileName": "lt.ctb" + }, + { + "locale": "nb", + "dots": "8", + "id": "nb-comp8", + "fileName": "no-no.ctb" + }, + { + "locale": "nb", + "dots": "6", + "id": "nb-g0", + "grade": "0", + "fileName": "no-no-g0.utb" + }, + { + "locale": "nb", + "dots": "6", + "id": "nb-g1", + "grade": "1", + "fileName": "no-no-g1.ctb" + }, + { + "locale": "nb", + "dots": "6", + "id": "nb-g2", + "grade": "2", + "fileName": "no-no-g2.ctb" + }, + { + "locale": "nb", + "dots": "6", + "id": "nb-g3", + "grade": "3", + "fileName": "no-no-g3.ctb" + }, + { + "locale": "pl", + "dots": "6", + "id": "pl-g1", + "grade": "1", + "fileName": "Pl-Pl-g1.utb" + }, + { + "locale": "pt", + "dots": "8", + "id": "pt-comp8", + "fileName": "pt-pt-comp8.ctb" + }, + { + "locale": "pt", + "dots": "6", + "id": "pt-g1", + "grade": "1", + "fileName": "pt-pt-g1.utb" + }, + { + "locale": "pt", + "dots": "6", + "id": "pt-g2", + "grade": "2", + "fileName": "pt-pt-g2.ctb" + }, + { + "locale": "ro", + "dots": "8", + "id": "ro-comp8", + "fileName": "ro.ctb" + }, + { + "locale": "ru", + "dots": "8", + "id": "ru-comp8", + "fileName": "ru.ctb" + }, + { + "locale": "ru", + "dots": "6", + "id": "ru-g1", + "grade": "1", + "fileName": "ru-ru-g1.utb" + }, + { + "locale": "sr", + "dots": "6", + "id": "sr-g1", + "grade": "1", + "fileName": "sr-g1.ctb" + }, + { + "locale": "sk", + "dots": "6", + "id": "sk-g1", + "grade": "1", + "fileName": "sk-sk-g1.utb" + }, + { + "locale": "sl", + "dots": "6", + "id": "sl-g1", + "grade": "1", + "fileName": "sl-si-g1.utb" + }, + { + "locale": "es", + "dots": "8", + "id": "es-comp8", + "fileName": "Es-Es-G0.utb" + }, + { + "locale": "es", + "dots": "6", + "id": "es-g1", + "grade": "1", + "fileName": "es-g1.ctb" + }, + { + "locale": "sv", + "dots": "8", + "id": "sv-comp8", + "fileName": "sv-1996.ctb" + }, + { + "locale": "sv", + "dots": "6", + "id": "sv-g1", + "grade": "1", + "fileName": "Se-Se-g1.utb" + }, + { + "locale": "tr", + "dots": "8", + "id": "tr-comp8", + "fileName": "tr.ctb" + }, + { + "locale": "vi", + "dots": "8", + "id": "vi-comp8", + "fileName": "vi.ctb" + }, + { + "locale": "zh", + "dots": "8", + "id": "zh-comp8", + "fileName": "zh-hk.ctb" + }, + { + "locale": "zh_TW", + "dots": "8", + "id": "zh-TW-comp8", + "fileName": "zh-tw.ctb" + } +] |