diff options
author | plundblad@chromium.org <plundblad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-27 23:05:46 +0000 |
---|---|---|
committer | plundblad@chromium.org <plundblad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-27 23:05:46 +0000 |
commit | 59107cf283cb9ff3b9aa1f7e1d6ef7ecff7a65c5 (patch) | |
tree | 640a1f4064ef39ea595309a5e001181bc71e4f75 /third_party | |
parent | 40fd3c0b80a3ee13c85d3baf017d10ae63b58c3d (diff) | |
download | chromium_src-59107cf283cb9ff3b9aa1f7e1d6ef7ecff7a65c5.zip chromium_src-59107cf283cb9ff3b9aa1f7e1d6ef7ecff7a65c5.tar.gz chromium_src-59107cf283cb9ff3b9aa1f7e1d6ef7ecff7a65c5.tar.bz2 |
Build liblouis_nacl using gyp.
This cl ports the nacl wrapper to the chromium build system and adds local modifications from Chromevox to liblouis. The native library and braille tables are copied to the location in the resources output directory where chromevox can pick them up.
BUG=316353
Review URL: https://codereview.chromium.org/67283007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@237638 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party')
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" + } +] |