diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 19:44:05 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 19:44:05 +0000 |
commit | d318611dd6f23fcfedd50e9b9e24620b102ba96a (patch) | |
tree | 8b9eef82ca40fdd5a8deeabf07572074c236095d /src/libs | |
parent | Initial commit. (diff) | |
download | groff-upstream/1.23.0.tar.xz groff-upstream/1.23.0.zip |
Adding upstream version 1.23.0.upstream/1.23.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/libs')
75 files changed, 16854 insertions, 0 deletions
diff --git a/src/libs/libbib/common.cpp b/src/libs/libbib/common.cpp new file mode 100644 index 0000000..05accd8 --- /dev/null +++ b/src/libs/libbib/common.cpp @@ -0,0 +1,37 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +unsigned hash(const char *s, int len) +{ +#if 0 + unsigned h = 0, g; + while (*s != '\0') { + h <<= 4; + h += *s++; + if ((g = h & 0xf0000000) != 0) { + h ^= g >> 24; + h ^= g; + } + } +#endif + unsigned h = 0; + while (--len >= 0) + h = *s++ + 65587*h; + return h; +} + diff --git a/src/libs/libbib/index.cpp b/src/libs/libbib/index.cpp new file mode 100644 index 0000000..aebcbbf --- /dev/null +++ b/src/libs/libbib/index.cpp @@ -0,0 +1,688 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "lib.h" + +#include <stdlib.h> +#include <errno.h> + +#include "posix.h" +#include "cset.h" +#include "cmap.h" +#include "errarg.h" +#include "error.h" + +#include "refid.h" +#include "search.h" +#include "index.h" +#include "defs.h" + +#include "nonposix.h" + +// Interface to mmap. +extern "C" { + void *mapread(int fd, int len); + int unmap(void *, int len); +} + +#if 0 +const +#endif +int minus_one = -1; + +bool do_verify = false; + +struct word_list; + +class index_search_item : public search_item { + search_item *out_of_date_files; + index_header header; + char *buffer; + void *map_addr; + int map_len; + tag *tags; + int *table; + int *lists; + char *pool; + char *key_buffer; + char *filename_buffer; + int filename_buflen; + char **common_words_table; + int common_words_table_size; + const char *ignore_fields; + time_t mtime; + + const char *get_invalidity_reason(); + const int *search1(const char **pp, const char *end); + const int *search(const char *ptr, int length, int **temp_listp); + const char *munge_filename(const char *); + void read_common_words_file(); + void add_out_of_date_file(int fd, const char *filename, int fid); +public: + index_search_item(const char *, int); + ~index_search_item(); + const char *check_header(index_header *, unsigned); + bool load(int fd); + search_item_iterator *make_search_item_iterator(const char *); + bool is_valid(); + void check_files(); + int next_filename_id() const; + friend class index_search_item_iterator; +}; + +class index_search_item_iterator : public search_item_iterator { + index_search_item *indx; + search_item_iterator *out_of_date_files_iter; + search_item *next_out_of_date_file; + const int *found_list; + int *temp_list; + char *buf; + int buflen; + linear_searcher searcher; + char *query; + int get_tag(int tagno, const linear_searcher &, const char **, int *, + reference_id *); +public: + index_search_item_iterator(index_search_item *, const char *); + ~index_search_item_iterator(); + int next(const linear_searcher &, const char **, int *, reference_id *); +}; + + +index_search_item::index_search_item(const char *filename, int fid) +: search_item(filename, fid), out_of_date_files(0), buffer(0), map_addr(0), + map_len(0), key_buffer(0), filename_buffer(0), filename_buflen(0), + common_words_table(0) +{ +} + +index_search_item::~index_search_item() +{ + if (buffer) + free(buffer); + if (map_addr) { + if (unmap(map_addr, map_len) < 0) + error("unmap: %1", strerror(errno)); + } + while (out_of_date_files) { + search_item *tem = out_of_date_files; + out_of_date_files = out_of_date_files->next; + delete tem; + } + delete[] filename_buffer; + delete[] key_buffer; + if (common_words_table) { + for (int i = 0; i < common_words_table_size; i++) + delete[] common_words_table[i]; + delete[] common_words_table; + } +} + +class file_closer { + int *fdp; +public: + file_closer(int &fd) : fdp(&fd) { } + ~file_closer() { close(*fdp); } +}; + +// Tell the compiler that a variable is intentionally unused. +inline void unused(void *) { } + +// Validate the data reported in the header so that we don't overread on +// the heap in the load() member function. Return null pointer if no +// problems are detected. +const char *index_search_item::check_header(index_header *file_header, + unsigned file_size) +{ + if (file_header->tags_size < 0) + return "tag list length negative"; + if (file_header->lists_size < 0) + return "reference list length negative"; + // The table and string pool sizes will not be zero, even in an empty + // index. + if (file_header->table_size < 1) + return "table size nonpositive"; + if (file_header->strings_size < 1) + return "string pool size nonpositive"; + size_t sz = (file_header->tags_size * sizeof(tag) + + file_header->lists_size * sizeof(int) + + file_header->table_size * sizeof(int) + + file_header->strings_size + + sizeof(file_header)); + if (sz != file_size) + return("size mismatch between header and data"); + unsigned size_remaining = file_size; + unsigned chunk_size = file_header->tags_size * sizeof(tag); + if (chunk_size > size_remaining) + return "claimed tag list length exceeds file size"; + size_remaining -= chunk_size; + chunk_size = file_header->lists_size * sizeof(int); + if (chunk_size > size_remaining) + return "claimed reference list length exceeds file size"; + size_remaining -= chunk_size; + chunk_size = file_header->table_size * sizeof(int); + if (chunk_size > size_remaining) + return "claimed table size exceeds file size"; + size_remaining -= chunk_size; + chunk_size = file_header->strings_size; + if (chunk_size > size_remaining) + return "claimed string pool size exceeds file size"; + return 0; +} + +bool index_search_item::load(int fd) +{ + file_closer fd_closer(fd); // close fd on return + unused(&fd_closer); + struct stat sb; + if (fstat(fd, &sb) < 0) { + error("can't fstat index '%1': %2", name, strerror(errno)); + return false; + } + if (!S_ISREG(sb.st_mode)) { + error("index '%1' is not a regular file", name); + return false; + } + mtime = sb.st_mtime; + unsigned size = unsigned(sb.st_size); // widening conversion + if (size == 0) { + error("index '%1' is an empty file", name); + return false; + } + char *addr; + map_addr = mapread(fd, size); + if (map_addr) { + addr = (char *)map_addr; + map_len = size; + } + else { + addr = buffer = (char *)malloc(size); + if (buffer == 0) { + error("can't allocate memory to process index '%1'", name); + return false; + } + char *ptr = buffer; + int bytes_to_read = size; + while (bytes_to_read > 0) { + int nread = read(fd, ptr, bytes_to_read); + if (nread == 0) { + error("unexpected end-of-file while reading index '%1'", name); + return false; + } + if (nread < 0) { + error("read error on index '%1': %2", name, strerror(errno)); + return false; + } + bytes_to_read -= nread; + ptr += nread; + } + } + header = *(index_header *)addr; + if (header.magic != INDEX_MAGIC) { + error("'%1' is not an index file: wrong magic number", name); + return false; + } + if (header.version != INDEX_VERSION) { + error("version number in index '%1' is wrong: was %2, should be %3", + name, header.version, INDEX_VERSION); + return false; + } + const char *problem = check_header(&header, size); + if (problem != 0) { + if (do_verify) + error("corrupt header in index file '%1': %2", name, problem); + else + error("corrupt header in index file '%1'", name); + return false; + } + tags = (tag *)(addr + sizeof(header)); + lists = (int *)(tags + header.tags_size); + table = (int *)(lists + header.lists_size); + pool = (char *)(table + header.table_size); + ignore_fields = strchr(strchr(pool, '\0') + 1, '\0') + 1; + key_buffer = new char[header.truncate]; + read_common_words_file(); + return true; +} + +const char *index_search_item::get_invalidity_reason() +{ + if (tags == 0) + return "not loaded"; + if ((header.lists_size > 0) && (lists[header.lists_size - 1] >= 0)) + return "last list element not negative"; + int i; + for (i = 0; i < header.table_size; i++) { + int li = table[i]; + if (li >= header.lists_size) + return "bad list index"; + if (li >= 0) { + for (int *ptr = lists + li; *ptr >= 0; ptr++) { + if (*ptr >= header.tags_size) + return "bad tag index"; + if (*ptr >= ptr[1] && ptr[1] >= 0) + return "list not ordered"; + } + } + } + for (i = 0; i < header.tags_size; i++) { + if (tags[i].filename_index >= header.strings_size) + return "bad index in tags"; + if (tags[i].length < 0) + return "bad length in tags"; + if (tags[i].start < 0) + return "bad start in tags"; + } + if (pool[header.strings_size - 1] != '\0') + return "last character in string pool is not null"; + return 0; +} + +bool index_search_item::is_valid() +{ + const char *reason = get_invalidity_reason(); + if (!reason) + return true; + error("'%1' is bad: %2", name, reason); + return false; +} + +int index_search_item::next_filename_id() const +{ + return filename_id + header.strings_size + 1; +} + +search_item_iterator *index_search_item::make_search_item_iterator( + const char *query) +{ + return new index_search_item_iterator(this, query); +} + +search_item *make_index_search_item(const char *filename, int fid) +{ + char *index_filename = new char[strlen(filename) + sizeof(INDEX_SUFFIX)]; + strcpy(index_filename, filename); + strcat(index_filename, INDEX_SUFFIX); + int fd = open(index_filename, O_RDONLY | O_BINARY); + if (fd < 0) + return 0; + index_search_item *item = new index_search_item(index_filename, fid); + delete[] index_filename; + if (!item->load(fd)) { + close(fd); + delete item; + return 0; + } + else if (do_verify && !item->is_valid()) { + delete item; + return 0; + } + else { + item->check_files(); + return item; + } +} + + +index_search_item_iterator::index_search_item_iterator(index_search_item *ind, + const char *q) +: indx(ind), out_of_date_files_iter(0), next_out_of_date_file(0), temp_list(0), + buf(0), buflen(0), + searcher(q, strlen(q), ind->ignore_fields, ind->header.truncate), + query(strsave(q)) +{ + found_list = indx->search(q, strlen(q), &temp_list); + if (!found_list) { + found_list = &minus_one; + warning("all keys would have been discarded in constructing index '%1'", + indx->name); + } +} + +index_search_item_iterator::~index_search_item_iterator() +{ + delete[] temp_list; + delete[] buf; + delete[] query; + delete out_of_date_files_iter; +} + +int index_search_item_iterator::next(const linear_searcher &, + const char **pp, int *lenp, + reference_id *ridp) +{ + if (found_list) { + for (;;) { + int tagno = *found_list; + if (tagno == -1) + break; + found_list++; + if (get_tag(tagno, searcher, pp, lenp, ridp)) + return 1; + } + found_list = 0; + next_out_of_date_file = indx->out_of_date_files; + } + while (next_out_of_date_file) { + if (out_of_date_files_iter == 0) + out_of_date_files_iter + = next_out_of_date_file->make_search_item_iterator(query); + if (out_of_date_files_iter->next(searcher, pp, lenp, ridp)) + return 1; + delete out_of_date_files_iter; + out_of_date_files_iter = 0; + next_out_of_date_file = next_out_of_date_file->next; + } + return 0; +} + +int index_search_item_iterator::get_tag(int tagno, + const linear_searcher &searchr, + const char **pp, int *lenp, + reference_id *ridp) +{ + if (tagno < 0 || tagno >= indx->header.tags_size) { + error("bad tag number"); + return 0; + } + tag *tp = indx->tags + tagno; + const char *filename = indx->munge_filename(indx->pool + tp->filename_index); + int fd = open(filename, O_RDONLY | O_BINARY); + if (fd < 0) { + error("can't open '%1': %2", filename, strerror(errno)); + return 0; + } + struct stat sb; + if (fstat(fd, &sb) < 0) { + error("can't fstat: %1", strerror(errno)); + close(fd); + return 0; + } + time_t mtime = sb.st_mtime; + if (mtime > indx->mtime) { + indx->add_out_of_date_file(fd, filename, + indx->filename_id + tp->filename_index); + return 0; + } + int res = 0; + FILE *fp = fdopen(fd, FOPEN_RB); + if (!fp) { + error("fdopen failed"); + close(fd); + return 0; + } + if (tp->start != 0 && fseek(fp, long(tp->start), 0) < 0) + error("can't seek on '%1': %2", filename, strerror(errno)); + else { + int length = tp->length; + int err = 0; + if (length == 0) { + if (fstat(fileno(fp), &sb) < 0) { + error("can't stat '%1': %2", filename, strerror(errno)); + err = 1; + } + else if (!S_ISREG(sb.st_mode)) { + error("'%1' is not a regular file", filename); + err = 1; + } + else + length = int(sb.st_size); + } + if (!err) { + if (length + 2 > buflen) { + delete[] buf; + buflen = length + 2; + buf = new char[buflen]; + } + if (fread(buf + 1, 1, length, fp) != (size_t)length) + error("fread on '%1' failed: %2", filename, strerror(errno)); + else { + buf[0] = '\n'; + // Remove the CR characters from CRLF pairs. + int sidx = 1, didx = 1; + for ( ; sidx < length + 1; sidx++, didx++) + { + if (buf[sidx] == '\r') + { + if (buf[++sidx] != '\n') + buf[didx++] = '\r'; + else + length--; + } + if (sidx != didx) + buf[didx] = buf[sidx]; + } + buf[length + 1] = '\n'; + res = searchr.search(buf + 1, buf + 2 + length, pp, lenp); + if (res && ridp) + *ridp = reference_id(indx->filename_id + tp->filename_index, + tp->start); + } + } + } + fclose(fp); + return res; +} + +const char *index_search_item::munge_filename(const char *filename) +{ + if (IS_ABSOLUTE(filename)) + return filename; + const char *cwd = pool; + int need_slash = (cwd[0] != 0 + && strchr(DIR_SEPS, strchr(cwd, '\0')[-1]) == 0); + int len = strlen(cwd) + strlen(filename) + need_slash + 1; + if (len > filename_buflen) { + delete[] filename_buffer; + filename_buflen = len; + filename_buffer = new char[len]; + } + strcpy(filename_buffer, cwd); + if (need_slash) + strcat(filename_buffer, "/"); + strcat(filename_buffer, filename); + return filename_buffer; +} + +const int *index_search_item::search1(const char **pp, const char *end) +{ + while (*pp < end && !csalnum(**pp)) + *pp += 1; + if (*pp >= end) + return 0; + const char *start = *pp; + while (*pp < end && csalnum(**pp)) + *pp += 1; + int len = *pp - start; + if (len < header.shortest) + return 0; + if (len > header.truncate) + len = header.truncate; + int is_number = 1; + for (int i = 0; i < len; i++) + if (csdigit(start[i])) + key_buffer[i] = start[i]; + else { + key_buffer[i] = cmlower(start[i]); + is_number = 0; + } + if (is_number && !(len == 4 && start[0] == '1' && start[1] == '9')) + return 0; + unsigned hc = hash(key_buffer, len); + if (common_words_table) { + for (int h = hc % common_words_table_size; + common_words_table[h]; + --h) { + if (strlen(common_words_table[h]) == (size_t)len + && memcmp(common_words_table[h], key_buffer, len) == 0) + return 0; + if (h == 0) + h = common_words_table_size; + } + } + int li = table[int(hc % header.table_size)]; + return li < 0 ? &minus_one : lists + li; +} + +static void merge(int *result, const int *s1, const int *s2) +{ + for (; *s1 >= 0; s1++) { + while (*s2 >= 0 && *s2 < *s1) + s2++; + if (*s2 == *s1) + *result++ = *s2; + } + *result++ = -1; +} + +const int *index_search_item::search(const char *ptr, int length, + int **temp_listp) +{ + const char *end = ptr + length; + if (*temp_listp) { + delete[] *temp_listp; + *temp_listp = 0; + } + const int *first_list = 0; + while (ptr < end && (first_list = search1(&ptr, end)) == 0) + ; + if (!first_list) + return 0; + if (*first_list < 0) + return first_list; + const int *second_list = 0; + while (ptr < end && (second_list = search1(&ptr, end)) == 0) + ; + if (!second_list) + return first_list; + if (*second_list < 0) + return second_list; + const int *p; + for (p = first_list; *p >= 0; p++) + ; + int len = p - first_list; + for (p = second_list; *p >= 0; p++) + ; + if (p - second_list < len) + len = p - second_list; + int *matches = new int[len + 1]; + merge(matches, first_list, second_list); + while (ptr < end) { + const int *list = search1(&ptr, end); + if (list != 0) { + if (*list < 0) { + delete[] matches; + return list; + } + merge(matches, matches, list); + if (*matches < 0) { + delete[] matches; + return &minus_one; + } + } + } + *temp_listp = matches; + return matches; +} + +void index_search_item::read_common_words_file() +{ + if (header.common <= 0) + return; + const char *common_words_file = munge_filename(strchr(pool, '\0') + 1); + errno = 0; + FILE *fp = fopen(common_words_file, "r"); + if (!fp) { + error("can't open '%1': %2", common_words_file, strerror(errno)); + return; + } + common_words_table_size = 2*header.common + 1; + while (!is_prime(common_words_table_size)) + common_words_table_size += 2; + common_words_table = new char *[common_words_table_size]; + for (int i = 0; i < common_words_table_size; i++) + common_words_table[i] = 0; + int count = 0; + int key_len = 0; + for (;;) { + int c = getc(fp); + while (c != EOF && !csalnum(c)) + c = getc(fp); + if (c == EOF) + break; + do { + if (key_len < header.truncate) + key_buffer[key_len++] = cmlower(c); + c = getc(fp); + } while (c != EOF && csalnum(c)); + if (key_len >= header.shortest) { + int h = hash(key_buffer, key_len) % common_words_table_size; + while (common_words_table[h]) { + if (h == 0) + h = common_words_table_size; + --h; + } + common_words_table[h] = new char[key_len + 1]; + memcpy(common_words_table[h], key_buffer, key_len); + common_words_table[h][key_len] = '\0'; + } + if (++count >= header.common) + break; + key_len = 0; + if (c == EOF) + break; + } + fclose(fp); +} + +void index_search_item::add_out_of_date_file(int fd, const char *filename, + int fid) +{ + search_item **pp; + for (pp = &out_of_date_files; *pp; pp = &(*pp)->next) + if ((*pp)->is_named(filename)) + return; + *pp = make_linear_search_item(fd, filename, fid); + warning("'%1' modified since index '%2' created", filename, name); +} + +void index_search_item::check_files() +{ + const char *pool_end = pool + header.strings_size; + for (const char *ptr = strchr(ignore_fields, '\0') + 1; + ptr < pool_end; + ptr = strchr(ptr, '\0') + 1) { + const char *path = munge_filename(ptr); + struct stat sb; + if (stat(path, &sb) < 0) + error("can't stat '%1': %2", path, strerror(errno)); + else if (sb.st_mtime > mtime) { + int fd = open(path, O_RDONLY | O_BINARY); + if (fd < 0) + error("can't open '%1': %2", path, strerror(errno)); + else + add_out_of_date_file(fd, path, filename_id + (ptr - pool)); + } + } +} + +// Local Variables: +// fill-column: 72 +// mode: C++ +// End: +// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: diff --git a/src/libs/libbib/libbib.am b/src/libs/libbib/libbib.am new file mode 100644 index 0000000..00e1d3b --- /dev/null +++ b/src/libs/libbib/libbib.am @@ -0,0 +1,35 @@ +# Automake rules for 'libbib' +# +# Copyright (C) 2014-2020 Free Software Foundation, Inc. +# +# 'groff' is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# 'groff' is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see +# <http://www.gnu.org/licenses/gpl-2.0.html>. +# +######################################################################## + +noinst_LIBRARIES += libbib.a +libbib_a_SOURCES = \ + src/libs/libbib/common.cpp \ + src/libs/libbib/index.cpp \ + src/libs/libbib/linear.cpp \ + src/libs/libbib/search.cpp \ + src/libs/libbib/map.c +src/libs/libbib/index.$(OBJEXT): defs.h + + +# Local Variables: +# mode: makefile-automake +# fill-column: 72 +# End: +# vim: set autoindent filetype=automake textwidth=72: diff --git a/src/libs/libbib/linear.cpp b/src/libs/libbib/linear.cpp new file mode 100644 index 0000000..22e11d8 --- /dev/null +++ b/src/libs/libbib/linear.cpp @@ -0,0 +1,506 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "lib.h" + +#include <assert.h> +#include <stdlib.h> +#include <errno.h> + +#include "posix.h" +#include "errarg.h" +#include "error.h" +#include "cset.h" +#include "cmap.h" +#include "nonposix.h" + +#include "refid.h" +#include "search.h" + +class file_buffer { + char *buffer; + char *bufend; +public: + file_buffer(); + ~file_buffer(); + int load(int fd, const char *filename); + const char *get_start() const; + const char *get_end() const; +}; + +typedef unsigned char uchar; + +static uchar map[256]; +static uchar inv_map[256][3]; + +struct map_init { + map_init(); +}; + +static map_init the_map_init; + +map_init::map_init() +{ + int i; + for (i = 0; i < 256; i++) + map[i] = csalnum(i) ? cmlower(i) : '\0'; + for (i = 0; i < 256; i++) { + if (cslower(i)) { + inv_map[i][0] = i; + inv_map[i][1] = cmupper(i); + inv_map[i][2] = '\0'; + } + else if (csdigit(i)) { + inv_map[i][0] = i; + inv_map[i][1] = 0; + } + else + inv_map[i][0] = '\0'; + } +} + + +class bmpattern { + char *pat; + int len; + int delta[256]; +public: + bmpattern(const char *pattern, int pattern_length); + ~bmpattern(); + const char *search(const char *p, const char *end) const; + int length() const; +}; + +bmpattern::bmpattern(const char *pattern, int pattern_length) +: len(pattern_length) +{ + pat = new char[len]; + int i; + for (i = 0; i < len; i++) + pat[i] = map[uchar(pattern[i])]; + for (i = 0; i < 256; i++) + delta[i] = len; + for (i = 0; i < len; i++) + for (const unsigned char *inv = inv_map[uchar(pat[i])]; *inv; inv++) + delta[*inv] = len - i - 1; +} + +const char *bmpattern::search(const char *buf, const char *end) const +{ + int buflen = end - buf; + if (len > buflen) + return 0; + const char *strend; + if (buflen > len*4) + strend = end - len*4; + else + strend = buf; + const char *k = buf + len - 1; + const int *del = delta; + const char *pattern = pat; + for (;;) { + while (k < strend) { + int t = del[uchar(*k)]; + if (!t) + break; + k += t; + k += del[uchar(*k)]; + k += del[uchar(*k)]; + } + while (k < end && del[uchar(*k)] != 0) + k++; + if (k == end) + break; + int j = len - 1; + const char *s = k; + for (;;) { + if (j == 0) + return s; + if (map[uchar(*--s)] != uchar(pattern[--j])) + break; + } + k++; + } + return 0; +} + +bmpattern::~bmpattern() +{ + delete[] pat; +} + +inline int bmpattern::length() const +{ + return len; +} + + +static const char *find_end(const char *bufend, const char *p); + +const char *linear_searcher::search_and_check(const bmpattern *key, + const char *buf, const char *bufend, const char **start) const +{ + assert(buf[-1] == '\n'); + assert(bufend[-1] == '\n'); + const char *ptr = buf; + for (;;) { + const char *found = key->search(ptr, bufend); + if (!found) + break; + if (check_match(buf, bufend, found, key->length(), &ptr, start)) + return found; + } + return 0; +} + +static const char *skip_field(const char *end, const char *p) +{ + for (;;) + if (*p++ == '\n') { + if (p == end || *p == '%') + break; + const char *q; + for (q = p; *q == ' ' || *q == '\t'; q++) + ; + if (*q == '\n') + break; + p = q + 1; + } + return p; +} + +static const char *find_end(const char *bufend, const char *p) +{ + for (;;) + if (*p++ == '\n') { + if (p == bufend) + break; + const char *q; + for (q = p; *q == ' ' || *q == '\t'; q++) + ; + if (*q == '\n') + break; + p = q + 1; + } + return p; +} + + +int linear_searcher::check_match(const char *buf, const char *bufend, + const char *match, int matchlen, + const char **cont, const char **start) const +{ + *cont = match + 1; + // The user is required to supply only the first truncate_len characters + // of the key. If truncate_len <= 0, he must supply all the key. + if ((truncate_len <= 0 || matchlen < truncate_len) + && map[uchar(match[matchlen])] != '\0') + return 0; + + // The character before the match must not be an alphanumeric + // character (unless the alphanumeric character follows one or two + // percent characters at the beginning of the line), nor must it be + // a percent character at the beginning of a line, nor a percent + // character following a percent character at the beginning of a + // line. + + switch (match - buf) { + case 0: + break; + case 1: + if (match[-1] == '%' || map[uchar(match[-1])] != '\0') + return 0; + break; + case 2: + if (map[uchar(match[-1])] != '\0' && match[-2] != '%') + return 0; + if (match[-1] == '%' + && (match[-2] == '\n' || match[-2] == '%')) + return 0; + break; + default: + if (map[uchar(match[-1])] != '\0' + && !(match[-2] == '%' + && (match[-3] == '\n' + || (match[-3] == '%' && match[-4] == '\n')))) + return 0; + if (match[-1] == '%' + && (match[-2] == '\n' + || (match[-2] == '%' && match[-3] == '\n'))) + return 0; + } + + const char *p = match; + int had_percent = 0; + for (;;) { + if (*p == '\n') { + if (!had_percent && p[1] == '%') { + if (p[2] != '\0' && strchr(ignore_fields, p[2]) != 0) { + *cont = skip_field(bufend, match + matchlen); + return 0; + } + if (!start) + break; + had_percent = 1; + } + if (p <= buf) { + if (start) + *start = p + 1; + return 1; + } + const char *q; + for (q = p - 1; *q == ' ' || *q == '\t'; q--) + ; + if (*q == '\n') { + if (start) + *start = p + 1; + break; + } + p = q; + } + p--; + } + return 1; +} + +file_buffer::file_buffer() +: buffer(0), bufend(0) +{ +} + +file_buffer::~file_buffer() +{ + delete[] buffer; +} + +const char *file_buffer::get_start() const +{ + return buffer ? buffer + 4 : 0; +} + +const char *file_buffer::get_end() const +{ + return bufend; +} + +int file_buffer::load(int fd, const char *filename) +{ + struct stat sb; + if (fstat(fd, &sb) < 0) + error("can't fstat '%1': %2", filename, strerror(errno)); + else if (!S_ISREG(sb.st_mode)) + error("'%1' is not a regular file", filename); + else { + // We need one character extra at the beginning for an additional newline + // used as a sentinel. We get 4 instead so that the read buffer will be + // word-aligned. This seems to make the read slightly faster. We also + // need one character at the end also for an additional newline used as a + // sentinel. + int size = int(sb.st_size); + buffer = new char[size + 4 + 1]; + int nread = read(fd, buffer + 4, size); + if (nread < 0) + error("error reading '%1': %2", filename, strerror(errno)); + else if (nread != size) + error("size of '%1' decreased", filename); + else { + char c; + nread = read(fd, &c, 1); + if (nread != 0) + error("size of '%1' increased", filename); + else if (memchr(buffer + 4, '\0', size < 1024 ? size : 1024) != 0) + error("database '%1' is a binary file", filename); + else { + close(fd); + buffer[3] = '\n'; + int sidx = 4, didx = 4; + for ( ; sidx < size + 4; sidx++, didx++) + { + if (buffer[sidx] == '\r') + { + if (buffer[++sidx] != '\n') + buffer[didx++] = '\r'; + else + size--; + } + if (sidx != didx) + buffer[didx] = buffer[sidx]; + } + bufend = buffer + 4 + size; + if (bufend[-1] != '\n') + *bufend++ = '\n'; + return 1; + } + } + delete[] buffer; + buffer = 0; + } + close(fd); + return 0; +} + +linear_searcher::linear_searcher(const char *query, int query_len, + const char *ign, int trunc) +: ignore_fields(ign), truncate_len(trunc), keys(0), nkeys(0) +{ + const char *query_end = query + query_len; + int nk = 0; + const char *p; + for (p = query; p < query_end; p++) + if (map[uchar(*p)] != '\0' + && (p[1] == '\0' || map[uchar(p[1])] == '\0')) + nk++; + if (nk == 0) + return; + keys = new bmpattern*[nk]; + p = query; + for (;;) { + while (p < query_end && map[uchar(*p)] == '\0') + p++; + if (p == query_end) + break; + const char *start = p; + while (p < query_end && map[uchar(*p)] != '\0') + p++; + keys[nkeys++] = new bmpattern(start, p - start); + } + assert(nkeys <= nk); + if (nkeys == 0) { + delete[] keys; + keys = 0; + } +} + +linear_searcher::~linear_searcher() +{ + for (int i = 0; i < nkeys; i++) + delete keys[i]; + delete[] keys; +} + +int linear_searcher::search(const char *buffer, const char *bufend, + const char **startp, int *lengthp) const +{ + assert(bufend - buffer > 0); + assert(buffer[-1] == '\n'); + assert(bufend[-1] == '\n'); + if (nkeys == 0) + return 0; + for (;;) { + const char *refstart; + const char *found = search_and_check(keys[0], buffer, bufend, &refstart); + if (!found) + break; + const char *refend = find_end(bufend, found + keys[0]->length()); + int i; + for (i = 1; i < nkeys; i++) + if (!search_and_check(keys[i], refstart, refend)) + break; + if (i >= nkeys) { + *startp = refstart; + *lengthp = refend - refstart; + return 1; + } + buffer = refend; + } + return 0; +} + +class linear_search_item : public search_item { + file_buffer fbuf; +public: + linear_search_item(const char *filename, int fid); + ~linear_search_item(); + int load(int fd); + search_item_iterator *make_search_item_iterator(const char *); + friend class linear_search_item_iterator; +}; + +class linear_search_item_iterator : public search_item_iterator { + linear_search_item *lsi; + int pos; +public: + linear_search_item_iterator(linear_search_item *, const char *query); + ~linear_search_item_iterator(); + int next(const linear_searcher &, const char **ptr, int *lenp, + reference_id *ridp); +}; + +search_item *make_linear_search_item(int fd, const char *filename, int fid) +{ + linear_search_item *item = new linear_search_item(filename, fid); + if (!item->load(fd)) { + delete item; + return 0; + } + else + return item; +} + +linear_search_item::linear_search_item(const char *filename, int fid) +: search_item(filename, fid) +{ +} + +linear_search_item::~linear_search_item() +{ +} + +int linear_search_item::load(int fd) +{ + return fbuf.load(fd, name); +} + +search_item_iterator *linear_search_item::make_search_item_iterator( + const char *query) +{ + return new linear_search_item_iterator(this, query); +} + +linear_search_item_iterator::linear_search_item_iterator( + linear_search_item *p, const char *) +: lsi(p), pos(0) +{ +} + +linear_search_item_iterator::~linear_search_item_iterator() +{ +} + +int linear_search_item_iterator::next(const linear_searcher &searcher, + const char **startp, int *lengthp, + reference_id *ridp) +{ + const char *bufstart = lsi->fbuf.get_start(); + const char *bufend = lsi->fbuf.get_end(); + const char *ptr = bufstart + pos; + if (ptr < bufend && searcher.search(ptr, bufend, startp, lengthp)) { + pos = *startp + *lengthp - bufstart; + if (ridp) + *ridp = reference_id(lsi->filename_id, *startp - bufstart); + return 1; + } + else + return 0; +} + +// Local Variables: +// fill-column: 72 +// mode: C++ +// End: +// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: diff --git a/src/libs/libbib/map.c b/src/libs/libbib/map.c new file mode 100644 index 0000000..9eae72b --- /dev/null +++ b/src/libs/libbib/map.c @@ -0,0 +1,86 @@ +/* Copyright (C) 1989- 2014 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include <stdlib.h> + +#ifdef HAVE_MMAP + +#include <sys/types.h> +#include <sys/mman.h> + +/* The Net-2 man pages says that a MAP_FILE flag is required. */ +#ifndef MAP_FILE +#define MAP_FILE 0 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Prototypes */ +char *mapread(int, int); +int unmap(char *, int); + +char *mapread(int fd, int nbytes) +{ + char *p = (char *)mmap((void *)0, (size_t)nbytes, PROT_READ, + MAP_FILE|MAP_PRIVATE, fd, (off_t)0); + if (p == MAP_FAILED) + return 0; + /* mmap() shouldn't return 0 since MAP_FIXED wasn't specified. */ + if (p == 0) + abort(); + return p; +} + +int unmap(char *p, int len) +{ + return munmap((void *)p, len); +} + +#ifdef __cplusplus +} +#endif + +#else /* not HAVE_MMAP */ + +#include <errno.h> + +#ifdef __cplusplus +extern "C" { +#endif + +char *mapread(int fd, int nbytes) +{ + errno = ENODEV; + return 0; +} + +int unmap(char *p, int len) +{ + errno = EINVAL; + return -1; +} + +#ifdef __cplusplus +} +#endif + +#endif /* not HAVE_MMAP */ diff --git a/src/libs/libbib/search.cpp b/src/libs/libbib/search.cpp new file mode 100644 index 0000000..10867b6 --- /dev/null +++ b/src/libs/libbib/search.cpp @@ -0,0 +1,136 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "lib.h" + +#include <assert.h> +#include <stdlib.h> +#include <errno.h> + +#include "posix.h" +#include "errarg.h" +#include "error.h" +#include "nonposix.h" + +#include "refid.h" +#include "search.h" + +int linear_truncate_len = 6; +const char *linear_ignore_fields = "XYZ"; + +search_list::search_list() +: list(0), niterators(0), next_fid(1) +{ +} + +search_list::~search_list() +{ + assert(niterators == 0); + while (list) { + search_item *tem = list->next; + delete list; + list = tem; + } +} + +void search_list::add_file(const char *filename, int silent) +{ + search_item *p = make_index_search_item(filename, next_fid); + if (!p) { + int fd = open(filename, O_RDONLY | O_BINARY); + if (fd < 0) { + if (!silent) + error("can't open '%1': %2", filename, strerror(errno)); + } + else + p = make_linear_search_item(fd, filename, next_fid); + } + if (p) { + search_item **pp; + for (pp = &list; *pp; pp = &(*pp)->next) + ; + *pp = p; + next_fid = p->next_filename_id(); + } +} + +int search_list::nfiles() const +{ + int n = 0; + for (search_item *ptr = list; ptr; ptr = ptr->next) + n++; + return n; +} + +search_list_iterator::search_list_iterator(search_list *p, const char *q) +: list(p), ptr(p->list), iter(0), query(strsave(q)), + searcher(q, strlen(q), linear_ignore_fields, linear_truncate_len) +{ + list->niterators += 1; +} + +search_list_iterator::~search_list_iterator() +{ + list->niterators -= 1; + delete[] query; + delete iter; +} + +int search_list_iterator::next(const char **pp, int *lenp, reference_id *ridp) +{ + while (ptr) { + if (iter == 0) + iter = ptr->make_search_item_iterator(query); + if (iter->next(searcher, pp, lenp, ridp)) + return 1; + delete iter; + iter = 0; + ptr = ptr->next; + } + return 0; +} + +search_item::search_item(const char *nm, int fid) +: name(strsave(nm)), filename_id(fid), next(0) +{ +} + +search_item::~search_item() +{ + delete[] name; +} + +int search_item::is_named(const char *nm) const +{ + return strcmp(name, nm) == 0; +} + +int search_item::next_filename_id() const +{ + return filename_id + 1; +} + +search_item_iterator::~search_item_iterator() +{ +} + +// Local Variables: +// fill-column: 72 +// mode: C++ +// End: +// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: diff --git a/src/libs/libdriver/input.cpp b/src/libs/libdriver/input.cpp new file mode 100644 index 0000000..821b526 --- /dev/null +++ b/src/libs/libdriver/input.cpp @@ -0,0 +1,1841 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + + Written by James Clark (jjc@jclark.com) + Major rewrite 2001 by Bernd Warken <groff-bernd.warken-72@web.de> + + This file is part of groff, the GNU roff text processing system. + + groff is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + groff is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* Description + + This file implements the parser for the intermediate groff output, + see groff_out(5), and does the printout for the given device. + + All parsed information is processed within the function do_file(). + A device postprocessor just needs to fill in the methods for the class + 'printer' (or rather a derived class) without having to worry about + the syntax of the intermediate output format. Consequently, the + programming of groff postprocessors is similar to the development of + device drivers. + + The prototyping for this file is done in driver.h (and error.h). +*/ + +/* Changes of the 2001 rewrite of this file. + + The interface to the outside and the handling of the global + variables was not changed, but internally many necessary changes + were performed. + + The main aim for this rewrite is to provide a first step towards + making groff fully compatible with classical troff without pain. + + Bugs fixed + - Unknown subcommands of 'D' and 'x' are now ignored like in the + classical case, but a warning is issued. This was also + implemented for the other commands. + - A warning is emitted if 'x stop' is missing. + - 'DC' and 'DE' commands didn't position to the right end after + drawing (now they do), see discussion below. + - So far, 'x stop' was ignored. Now it terminates the processing + of the current intermediate output file like the classical troff. + - The command 'c' didn't check correctly on white-space. + - The environment stack wasn't suitable for the color extensions + (replaced by a class). + - The old groff parser could only handle a prologue with the first + 3 lines having a fixed structure, while classical troff specified + the sequence of the first 3 commands without further + restrictions. Now the parser is smart about additional + white space, comments, and empty lines in the prologue. + - The old parser allowed space characters only as syntactical + separators, while classical troff had tab characters as well. + Now any sequence of tabs and/or spaces is a syntactical + separator between commands and/or arguments. + - Range checks for numbers implemented. + + New and improved features + - The color commands 'm' and 'DF' are added. + - The old color command 'Df' is now converted and delegated to 'DFg'. + - The command 'F' is implemented as 'use intended file name'. It + checks whether its argument agrees with the file name used so far, + otherwise a warning is issued. Then the new name is remembered + and used for the following error messages. + - For the positioning after drawing commands, an alternative, easier + scheme is provided, but not yet activated; it can be chosen by + undefining the preprocessor macro STUPID_DRAWING_POSITIONING. + It extends the rule of the classical troff output language in a + logical way instead of the rather strange actual positioning. + For details, see the discussion below. + - For the 'D' commands that only set the environment, the calling of + pr->send_draw() was removed because this doesn't make sense for + the 'DF' commands; the (changed) environment is sent with the + next command anyway. + - Error handling was clearly separated into warnings and fatal. + - The error behavior on additional arguments for 'D' and 'x' + commands with a fixed number of arguments was changed from being + ignored (former groff) to issue a warning and ignore (now), see + skip_line_x(). No fatal was chosen because both string and + integer arguments can occur. + - The gtroff program issues a trailing dummy integer argument for + some drawing commands with an odd number of arguments to make the + number of arguments even, e.g. the DC and Dt commands; this is + honored now. + - All D commands with a variable number of args expect an even + number of trailing integer arguments, so fatal on error was + implemented. + - Disable environment stack and the commands '{' and '}' by making + them conditional on macro USE_ENV_STACK; actually, this is + undefined by default. There isn't any known application for these + features. + + Cosmetics + - Nested 'switch' commands are avoided by using more functions. + Dangerous 'fall-through's avoided. + - Commands and functions are sorted alphabetically (where possible). + - Dynamic arrays/buffers are now implemented as container classes. + - Some functions had an ugly return structure; this has been + streamlined by using classes. + - Use standard C math functions for number handling, so getting rid + of differences to '0'. + - The macro 'IntArg' has been created for an easier transition + to guaranteed 32 bits integers ('int' is enough for GNU, while + ANSI only guarantees 'long int' to have a length of 32 bits). + - The many usages of type 'int' are differentiated by using 'Char', + 'bool', and 'IntArg' where appropriate. + - To ease the calls of the local utility functions, the parser + variables 'current_file', 'npages', and 'current_env' + (formerly env) were made global to the file (formerly they were + local to the do_file() function) + - Various comments were added. + + TODO + - Get rid of the stupid drawing positioning. + - Can the 'Dt' command be completely handled by setting environment + within do_file() instead of sending to pr? + - Integer arguments must be >= 32 bits, use conditional #define. + - Add scaling facility for classical device independence and + non-groff devices. Classical troff output had a quasi device + independence by scaling the intermediate output to the resolution + of the postprocessor device if different from the one specified + with 'x T', groff have not. So implement full quasi device + independence, including the mapping of the strange classical + devices to the postprocessor device (seems to be reasonably + easy). + - The external, global pointer variables are not optimally handled. + - The global variables 'current_filename', + 'current_source_filename', and 'current_lineno' are only used for + error reporting. So implement a static class 'Error' + ('::' calls). + - The global 'device' is the name used during the formatting + process; there should be a new variable for the device name used + during the postprocessing. + - Implement the B-spline drawing 'D~' for all graphical devices. + - Make 'environment' a class with an overflow check for its members + and a delete method to get rid of delete_current_env(). + - Implement the 'EnvStack' to use 'new' instead of 'malloc'. + - The class definitions of this document could go into a new file. + - The comments in this section should go to a 'Changelog' or some + 'README' file in this directory. +*/ + +/* + Discussion of the positioning by drawing commands + + There was some confusion about the positioning of the graphical + pointer at the printout after having executed a 'D' command. + The classical troff manual of Ossanna & Kernighan specified, + + 'The position after a graphical object has been drawn is + at its end; for circles and ellipses, the "end" is at the + right side.' + + From this, it follows that + - all open figures (args, splines, and lines) should position at their + final point. + - all circles and ellipses should position at their right-most point + (as if 2 halves had been drawn). + - all closed figures apart from circles and ellipses shouldn't change + the position because they return to their origin. + - all setting commands should not change position because they do not + draw any graphical object. + + In the case of the open figures, this means that the horizontal + displacement is the sum of all odd arguments and the vertical offset + the sum of all even arguments, called the alternate arguments sum + displacement in the following. + + Unfortunately, groff did not implement this simple rule. The former + documentation in groff_out(5) differed from the source code, and + neither of them is compatible with the classical rule. + + The former groff_out(5) specified to use the alternative arguments + sum displacement for calculating the drawing positioning of + non-classical commands, including the 'Dt' command (setting-only) + and closed polygons. Applying this to the new groff color commands + will lead to disaster. For their arguments can take large values (> + 65000). On low resolution devices, the displacement of such large + values will corrupt the display or kill the printer. So the + nonsense specification has come to a natural end anyway. + + The groff source code, however, had no positioning for the + setting-only commands (esp. 'Dt'), the right-end positioning for + outlined circles and ellipses, and the alternative argument sum + displacement for all other commands (including filled circles and + ellipses). + + The reason why no one seems to have suffered from this mayhem so + far is that the graphical objects are usually generated by + preprocessors like pic that do not depend on the automatic + positioning. When using the low level '\D' escape sequences or 'D' + output commands, the strange positionings can be circumvented by + absolute positionings or by tricks like '\Z'. + + So doing an exorcism on the strange, incompatible displacements might + not harm any existing documents, but will make the usage of the + graphical escape sequences and commands natural. + + That's why the rewrite of this file returned to the reasonable, + classical specification with its clear end-of-drawing rule that is + suitable for all cases. But a macro STUPID_DRAWING_POSITIONING is + provided for testing the funny former behavior. + + The new rule implies the following behavior. + - Setting commands ('Dt', 'Df', 'DF') and polygons ('Dp' and 'DP') + do not change position now. + - Filled circles and ellipses ('DC' and 'DE') position at their + most right point (outlined ones 'Dc' and 'De' did this anyway). + - As before, all open graphical objects position to their final + drawing point (alternate sum of the command arguments). + +*/ + +#ifndef STUPID_DRAWING_POSITIONING +// uncomment next line if all non-classical D commands shall position +// to the strange alternate sum of args displacement +#define STUPID_DRAWING_POSITIONING +#endif + +// Decide whether the commands '{' and '}' for different environments +// should be used. +#undef USE_ENV_STACK + +#include "driver.h" +#include "device.h" + +#include <stdlib.h> +#include <errno.h> +#include <ctype.h> +#include <math.h> + + +/********************************************************************** + local types + **********************************************************************/ + +// integer type used in the fields of struct environment (see printer.h) +typedef int EnvInt; + +// integer arguments of groff_out commands, must be >= 32 bits +typedef int IntArg; + +// color components of groff_out color commands, must be >= 32 bits +typedef unsigned int ColorArg; + +// Array for IntArg values. +class IntArray { + size_t num_allocated; + size_t num_stored; + IntArg *data; +public: + IntArray(void); + IntArray(const size_t); + ~IntArray(void); + IntArg operator[](const size_t i) const + { + if (i >= num_stored) + fatal("index out of range"); + return (IntArg) data[i]; + } + void append(IntArg); + IntArg *get_data(void) const { return (IntArg *)data; } + size_t len(void) const { return num_stored; } +}; + +// Characters read from the input queue. +class Char { + int data; +public: + Char(void) : data('\0') {} + Char(const int c) : data(c) {} + bool operator==(char c) const { return (data == c) ? true : false; } + bool operator==(int c) const { return (data == c) ? true : false; } + bool operator==(const Char c) const + { return (data == c.data) ? true : false; } + bool operator!=(char c) const { return !(*this == c); } + bool operator!=(int c) const { return !(*this == c); } + bool operator!=(const Char c) const { return !(*this == c); } + operator int() const { return (int) data; } + operator unsigned char() const { return (unsigned char) data; } + operator char() const { return (char) data; } +}; + +// Buffer for string arguments (Char, not char). +class StringBuf { + size_t num_allocated; + size_t num_stored; + Char *data; // not terminated by '\0' +public: + StringBuf(void); // allocate without storing + ~StringBuf(void); + void append(const Char); // append character to 'data' + char *make_string(void); // return new copy of 'data' with '\0' + bool is_empty(void) { // true if none stored + return (num_stored > 0) ? false : true; + } + void reset(void); // set 'num_stored' to 0 +}; + +#ifdef USE_ENV_STACK +class EnvStack { + environment **data; + size_t num_allocated; + size_t num_stored; +public: + EnvStack(void); + ~EnvStack(void); + environment *pop(void); + void push(environment *e); +}; +#endif // USE_ENV_STACK + + +/********************************************************************** + external variables + **********************************************************************/ + +// exported as extern by error.h (called from driver.h) +// needed for error messages (see ../libgroff/error.cpp) +const char *current_filename = 0; // printable name of the current file + // printable name of current source file +const char *current_source_filename = 0; +int current_lineno = 0; // current line number of printout + +// exported as extern by device.h; +const char *device = 0; // cancel former init with literal + +printer *pr; + +// Note: +// +// We rely on an implementation of the 'new' operator which aborts +// gracefully if it can't allocate memory (e.g. from libgroff/new.cpp). + + +/********************************************************************** + static local variables + **********************************************************************/ + +FILE *current_file = 0; // current input stream for parser + +// npages: number of pages processed so far (including current page), +// _not_ the page number in the printout (can be set with 'p'). +int npages = 0; + +const ColorArg +COLORARG_MAX = (ColorArg) 65536U; // == 0xFFFF + 1 == 0x10000 + +const IntArg +INTARG_MAX = (IntArg) 0x7FFFFFFF; // maximal signed 32 bits number + +// parser environment, created and deleted by each run of do_file() +environment *current_env = 0; + +#ifdef USE_ENV_STACK +const size_t +envp_size = sizeof(environment *); +#endif // USE_ENV_STACK + + +/********************************************************************** + function declarations + **********************************************************************/ + +// utility functions +ColorArg color_from_Df_command(IntArg); + // transform old color into new +void delete_current_env(void); // delete global var current_env +void fatal_command(char); // abort for invalid command +inline Char get_char(void); // read next character from input stream +ColorArg get_color_arg(void); // read in argument for new color cmds +IntArray *get_D_fixed_args(const size_t); + // read in fixed number of integer + // arguments +IntArray *get_D_fixed_args_odd_dummy(const size_t); + // read in a fixed number of integer + // arguments plus optional dummy +IntArray *get_D_variable_args(void); + // variable, even number of int args +char *get_extended_arg(void); // argument for 'x X' (several lines) +IntArg get_integer_arg(void); // read in next integer argument +IntArray *get_possibly_integer_args(); + // 0 or more integer arguments +char *get_string_arg(void); // read in next string arg, ended by WS +inline bool is_space_or_tab(const Char); + // test on space/tab char +Char next_arg_begin(void); // skip white space on current line +Char next_command(void); // go to next command, evt. diff. line +inline bool odd(const int); // test if integer is odd +void position_to_end_of_args(const IntArray * const); + // positioning after drawing +void remember_filename(const char *); + // set global current_filename +void remember_source_filename(const char *); + // set global current_source_filename +void send_draw(const Char, const IntArray * const); + // call pr->draw +void skip_line(void); // unconditionally skip to next line +bool skip_line_checked(void); // skip line, false if args are left +void skip_line_fatal(void); // skip line, fatal if args are left +void skip_line_warn(void); // skip line, warn if args are left +void skip_line_D(void); // skip line in D commands +void skip_line_x(void); // skip line in x commands +void skip_to_end_of_line(void); // skip to the end of the current line +inline void unget_char(const Char); + // restore character onto input + +// parser subcommands +void parse_color_command(color *); + // color sub(sub)commands m and DF +void parse_D_command(void); // graphical subcommands +bool parse_x_command(void); // device controller subcommands + + +/********************************************************************** + class methods + **********************************************************************/ + +#ifdef USE_ENV_STACK +EnvStack::EnvStack(void) +{ + num_allocated = 4; + // allocate pointer to array of num_allocated pointers to environment + data = (environment **)malloc(envp_size * num_allocated); + if (data == 0) + fatal("could not allocate environment data"); + num_stored = 0; +} + +EnvStack::~EnvStack(void) +{ + for (size_t i = 0; i < num_stored; i++) + delete data[i]; + free(data); +} + +// return top element from stack and decrease stack pointer +// +// the calling function must take care of properly deleting the result +environment * +EnvStack::pop(void) +{ + num_stored--; + environment *result = data[num_stored]; + data[num_stored] = 0; + return result; +} + +// copy argument and push this onto the stack +void +EnvStack::push(environment *e) +{ + environment *e_copy = new environment; + if (num_stored >= num_allocated) { + environment **old_data = data; + num_allocated *= 2; + data = (environment **)malloc(envp_size * num_allocated); + if (data == 0) + fatal("could not allocate data"); + for (size_t i = 0; i < num_stored; i++) + data[i] = old_data[i]; + free(old_data); + } + e_copy->col = new color; + e_copy->fill = new color; + *e_copy->col = *e->col; + *e_copy->fill = *e->fill; + e_copy->fontno = e->fontno; + e_copy->height = e->height; + e_copy->hpos = e->hpos; + e_copy->size = e->size; + e_copy->slant = e->slant; + e_copy->vpos = e->vpos; + data[num_stored] = e_copy; + num_stored++; +} +#endif // USE_ENV_STACK + +IntArray::IntArray(void) +{ + num_allocated = 4; + data = new IntArg[num_allocated]; + num_stored = 0; +} + +IntArray::IntArray(const size_t n) +{ + if (n <= 0) + fatal("number of integers to be allocated must be > 0"); + num_allocated = n; + data = new IntArg[num_allocated]; + num_stored = 0; +} + +IntArray::~IntArray(void) +{ + delete[] data; +} + +void +IntArray::append(IntArg x) +{ + if (num_stored >= num_allocated) { + IntArg *old_data = data; + num_allocated *= 2; + data = new IntArg[num_allocated]; + for (size_t i = 0; i < num_stored; i++) + data[i] = old_data[i]; + delete[] old_data; + } + data[num_stored] = x; + num_stored++; +} + +StringBuf::StringBuf(void) +{ + num_stored = 0; + num_allocated = 128; + data = new Char[num_allocated]; +} + +StringBuf::~StringBuf(void) +{ + delete[] data; +} + +void +StringBuf::append(const Char c) +{ + if (num_stored >= num_allocated) { + Char *old_data = data; + num_allocated *= 2; + data = new Char[num_allocated]; + for (size_t i = 0; i < num_stored; i++) + data[i] = old_data[i]; + delete[] old_data; + } + data[num_stored] = c; + num_stored++; +} + +char * +StringBuf::make_string(void) +{ + char *result = new char[num_stored + 1]; + for (size_t i = 0; i < num_stored; i++) + result[i] = (char) data[i]; + result[num_stored] = '\0'; + return result; +} + +void +StringBuf::reset(void) +{ + num_stored = 0; +} + +/********************************************************************** + utility functions + **********************************************************************/ + +////////////////////////////////////////////////////////////////////// +/* color_from_Df_command: + Process the gray shade setting command Df. + + Transform Df style color into DF style color. + Df color: 0-1000, 0 is white + DF color: 0-65536, 0 is black + + The Df command is obsoleted by command DFg, but kept for + compatibility. +*/ +ColorArg +color_from_Df_command(IntArg Df_gray) +{ + return ColorArg((1000-Df_gray) * COLORARG_MAX / 1000); // scaling +} + +////////////////////////////////////////////////////////////////////// +/* delete_current_env(): + Delete global variable current_env and its pointer members. + + This should be a class method of environment. +*/ +void delete_current_env(void) +{ + delete current_env->col; + delete current_env->fill; + delete current_env; + current_env = 0; +} + +////////////////////////////////////////////////////////////////////// +/* fatal_command(): + Emit error message about invalid command and abort. +*/ +void +fatal_command(char command) +{ + fatal("'%1' command invalid before first 'p' command", command); +} + +////////////////////////////////////////////////////////////////////// +/* get_char(): + Retrieve the next character from the input queue. + + Return: The retrieved character (incl. EOF), converted to Char. +*/ +inline Char +get_char(void) +{ + return (Char) getc(current_file); +} + +////////////////////////////////////////////////////////////////////// +/* get_color_arg(): + Retrieve an argument suitable for the color commands m and DF. + + Return: The retrieved color argument. +*/ +ColorArg +get_color_arg(void) +{ + IntArg x = get_integer_arg(); + if (x < 0 || x > (IntArg)COLORARG_MAX) { + error("color component argument out of range"); + x = 0; + } + return (ColorArg) x; +} + +////////////////////////////////////////////////////////////////////// +/* get_D_fixed_args(): + Get a fixed number of integer arguments for D commands. + + Fatal if wrong number of arguments. + Too many arguments on the line raise a warning. + A line skip is done. + + number: In-parameter, the number of arguments to be retrieved. + ignore: In-parameter, ignore next argument -- GNU troff always emits + pairs of parameters for 'D' extensions added by groff. + Default is 'false'. + + Return: New IntArray containing the arguments. +*/ +IntArray * +get_D_fixed_args(const size_t number) +{ + if (number <= 0) + fatal("requested number of arguments must be > 0"); + IntArray *args = new IntArray(number); + for (size_t i = 0; i < number; i++) + args->append(get_integer_arg()); + skip_line_D(); + return args; +} + +////////////////////////////////////////////////////////////////////// +/* get_D_fixed_args_odd_dummy(): + Get a fixed number of integer arguments for D commands and optionally + ignore a dummy integer argument if the requested number is odd. + + The gtroff program adds a dummy argument to some commands to get + an even number of arguments. + Error if the number of arguments differs from the scheme above. + A line skip is done. + + number: In-parameter, the number of arguments to be retrieved. + + Return: New IntArray containing the arguments. +*/ +IntArray * +get_D_fixed_args_odd_dummy(const size_t number) +{ + if (number <= 0) + fatal("requested number of arguments must be > 0"); + IntArray *args = new IntArray(number); + for (size_t i = 0; i < number; i++) + args->append(get_integer_arg()); + if (odd(number)) { + IntArray *a = get_possibly_integer_args(); + if (a->len() > 1) + error("too many arguments"); + delete a; + } + skip_line_D(); + return args; +} + +////////////////////////////////////////////////////////////////////// +/* get_D_variable_args(): + Get a variable even number of integer arguments for D commands. + + Get as many integer arguments as possible from the rest of the + current line. + - The arguments are separated by an arbitrary sequence of space or + tab characters. + - A comment, a newline, or EOF indicates the end of processing. + - Error on non-digit characters different from these. + - A final line skip is performed (except for EOF). + + Return: New IntArray of the retrieved arguments. +*/ +IntArray * +get_D_variable_args() +{ + IntArray *args = get_possibly_integer_args(); + size_t n = args->len(); + if (n <= 0) + error("no arguments found"); + if (odd(n)) + error("even number of arguments expected"); + skip_line_D(); + return args; +} + +////////////////////////////////////////////////////////////////////// +/* get_extended_arg(): + Retrieve extended arg for 'x X' command. + + - Skip leading spaces and tabs, error on EOL or newline. + - Return everything before the next NL or EOF ('#' is not a comment); + as long as the following line starts with '+' this is returned + as well, with the '+' replaced by a newline. + - Final line skip is always performed. + + Return: Allocated (new) string of retrieved text argument. +*/ +char * +get_extended_arg(void) +{ + StringBuf buf = StringBuf(); + Char c = next_arg_begin(); + while ((int) c != EOF) { + if ((int) c == '\n') { + current_lineno++; + c = get_char(); + if ((int) c == '+') + buf.append((Char) '\n'); + else { + unget_char(c); // first character of next line + break; + } + } + else + buf.append(c); + c = get_char(); + } + return buf.make_string(); +} + +////////////////////////////////////////////////////////////////////// +/* get_integer_arg(): Retrieve integer argument. + + Skip leading spaces and tabs, collect an optional '-' and all + following decimal digits (at least one) up to the next non-digit, + which is restored onto the input queue. + + Fatal error on all other situations. + + Return: Retrieved integer. +*/ +IntArg +get_integer_arg(void) +{ + StringBuf buf = StringBuf(); + Char c = next_arg_begin(); + if ((int) c == '-') { + buf.append(c); + c = get_char(); + } + if (!isdigit((int) c)) + fatal("integer argument expected"); + while (isdigit((int) c)) { + buf.append(c); + c = get_char(); + } + // c is not a digit + unget_char(c); + char *s = buf.make_string(); + errno = 0; + long int number = strtol(s, 0, 10); + if (errno != 0 + || number > INTARG_MAX || number < -INTARG_MAX) { + error("integer argument too large"); + number = 0; + } + delete[] s; + return (IntArg) number; +} + +////////////////////////////////////////////////////////////////////// +/* get_possibly_integer_args(): + Parse the rest of the input line as a list of integer arguments. + + Get as many integer arguments as possible from the rest of the + current line, even none. + - The arguments are separated by an arbitrary sequence of space or + tab characters. + - A comment, a newline, or EOF indicates the end of processing. + - Error on non-digit characters different from these. + - No line skip is performed. + + Return: New IntArray of the retrieved arguments. +*/ +IntArray * +get_possibly_integer_args() +{ + bool done = false; + StringBuf buf = StringBuf(); + Char c = get_char(); + IntArray *args = new IntArray(); + while (!done) { + buf.reset(); + while (is_space_or_tab(c)) + c = get_char(); + if (c == '-') { + Char c1 = get_char(); + if (isdigit((int) c1)) { + buf.append(c); + c = c1; + } + else + unget_char(c1); + } + while (isdigit((int) c)) { + buf.append(c); + c = get_char(); + } + if (!buf.is_empty()) { + char *s = buf.make_string(); + errno = 0; + long int x = strtol(s, 0, 10); + if (errno + || x > INTARG_MAX || x < -INTARG_MAX) { + error("invalid integer argument, set to 0"); + x = 0; + } + args->append((IntArg) x); + delete[] s; + } + // Here, c is not a digit. + // Terminate on comment, end of line, or end of file, while + // space or tab indicate continuation; otherwise error. + switch((int) c) { + case '#': + skip_to_end_of_line(); + done = true; + break; + case '\n': + done = true; + unget_char(c); + break; + case EOF: + done = true; + break; + case ' ': + case '\t': + break; + default: + error("integer argument expected"); + done = true; + break; + } + } + return args; +} + +////////////////////////////////////////////////////////////////////// +/* get_string_arg(): + Retrieve string arg. + + - Skip leading spaces and tabs; error on EOL or newline. + - Return all following characters before the next space, tab, + newline, or EOF character (in-word '#' is not a comment character). + - The terminating space, tab, newline, or EOF character is restored + onto the input queue, so no line skip. + + Return: Retrieved string as char *, allocated by 'new'. +*/ +char * +get_string_arg(void) +{ + StringBuf buf = StringBuf(); + Char c = next_arg_begin(); + while (!is_space_or_tab(c) + && c != Char('\n') && c != Char(EOF)) { + buf.append(c); + c = get_char(); + } + unget_char(c); // restore white space + return buf.make_string(); +} + +////////////////////////////////////////////////////////////////////// +/* is_space_or_tab(): + Test a character if it is a space or tab. + + c: In-parameter, character to be tested. + + Return: True, if c is a space or tab character, false otherwise. +*/ +inline bool +is_space_or_tab(const Char c) +{ + return (c == Char(' ') || c == Char('\t')) ? true : false; +} + +////////////////////////////////////////////////////////////////////// +/* next_arg_begin(): + Return first character of next argument. + + Skip space and tab characters; error on newline or EOF. + + Return: The first character different from these (including '#'). +*/ +Char +next_arg_begin(void) +{ + Char c; + while (1) { + c = get_char(); + switch ((int) c) { + case ' ': + case '\t': + break; + case '\n': + case EOF: + error("missing argument"); + return c; + default: // first essential character + return c; + } + } +} + +////////////////////////////////////////////////////////////////////// +/* next_command(): + Find the first character of the next command. + + Skip spaces, tabs, comments (introduced by #), and newlines. + + Return: The first character different from these (including EOF). +*/ +Char +next_command(void) +{ + Char c; + while (1) { + c = get_char(); + switch ((int) c) { + case ' ': + case '\t': + break; + case '\n': + current_lineno++; + break; + case '#': // comment + skip_line(); + break; + default: // EOF or first essential character + return c; + } + } +} + +////////////////////////////////////////////////////////////////////// +/* odd(): + Test whether argument is an odd number. + + n: In-parameter, the integer to be tested. + + Return: True if odd, false otherwise. +*/ +inline bool +odd(const int n) +{ + return ((n & 1) == 1) ? true : false; +} + +////////////////////////////////////////////////////////////////////// +/* position_to_end_of_args(): + Move graphical pointer to end of drawn figure. + + This is used by the D commands that draw open geometrical figures. + The algorithm simply sums up all horizontal displacements (arguments + with even number) for the horizontal component. Similarly, the + vertical component is the sum of the odd arguments. + + args: In-parameter, the arguments of a former drawing command. +*/ +void +position_to_end_of_args(const IntArray * const args) +{ + size_t i; + const size_t n = args->len(); + for (i = 0; i < n; i += 2) + current_env->hpos += (*args)[i]; + for (i = 1; i < n; i += 2) + current_env->vpos += (*args)[i]; +} + +////////////////////////////////////////////////////////////////////// +/* remember_filename(): + Set global variable current_filename. + + The actual filename is stored in current_filename. This is used by + the postprocessors, expecting the name "<standard input>" for stdin. + + filename: In-out-parameter; is changed to the new value also. +*/ +void +remember_filename(const char *filename) +{ + char *fname; + if (strcmp(filename, "-") == 0) + fname = (char *)"<standard input>"; + else + fname = (char *)filename; + size_t len = strlen(fname) + 1; + if (current_filename != 0) + free((char *)current_filename); + current_filename = (const char *)malloc(len); + if (current_filename == 0) + fatal("can't malloc space for filename"); + strncpy((char *)current_filename, (char *)fname, len); +} + +////////////////////////////////////////////////////////////////////// +/* remember_source_filename(): + Set global variable current_source_filename. + + The actual filename is stored in current_filename. This is used by + the postprocessors, expecting the name "<standard input>" for stdin. + + filename: In-out-parameter; is changed to the new value also. +*/ +void +remember_source_filename(const char *filename) +{ + char *fname; + if (strcmp(filename, "-") == 0) + fname = (char *)"<standard input>"; + else + fname = (char *)filename; + size_t len = strlen(fname) + 1; + if (current_source_filename != 0) + free((char *)current_source_filename); + current_source_filename = (const char *)malloc(len); + if (current_source_filename == 0) + fatal("can't malloc space for filename"); + strncpy((char *)current_source_filename, (char *)fname, len); +} + +////////////////////////////////////////////////////////////////////// +/* send_draw(): + Call draw method of printer class. + + subcmd: Letter of actual D subcommand. + args: Array of integer arguments of actual D subcommand. +*/ +void +send_draw(const Char subcmd, const IntArray * const args) +{ + EnvInt n = (EnvInt) args->len(); + pr->draw((int) subcmd, (IntArg *)args->get_data(), n, current_env); +} + +////////////////////////////////////////////////////////////////////// +/* skip_line(): + Go to next line within the input queue. + + Skip the rest of the current line, including the newline character. + The global variable current_lineno is adjusted. + No errors are raised. +*/ +void +skip_line(void) +{ + Char c = get_char(); + while (1) { + if (c == '\n') { + current_lineno++; + break; + } + if (c == EOF) + break; + c = get_char(); + } +} + +////////////////////////////////////////////////////////////////////// +/* skip_line_checked (): + Check that there aren't any arguments left on the rest of the line, + then skip line. + + Spaces, tabs, and a comment are allowed before newline or EOF. + All other characters raise an error. +*/ +bool +skip_line_checked(void) +{ + bool ok = true; + Char c = get_char(); + while (is_space_or_tab(c)) + c = get_char(); + switch((int) c) { + case '#': // comment + skip_line(); + break; + case '\n': + current_lineno++; + break; + case EOF: + break; + default: + ok = false; + skip_line(); + break; + } + return ok; +} + +////////////////////////////////////////////////////////////////////// +/* skip_line_fatal (): + Fatal error if arguments left, otherwise skip line. + + Spaces, tabs, and a comment are allowed before newline or EOF. + All other characters trigger the error. +*/ +void +skip_line_fatal(void) +{ + bool ok = skip_line_checked(); + if (!ok) { + current_lineno--; + error("too many arguments"); + current_lineno++; + } +} + +////////////////////////////////////////////////////////////////////// +/* skip_line_warn (): + Skip line, but warn if arguments are left on actual line. + + Spaces, tabs, and a comment are allowed before newline or EOF. + All other characters raise a warning +*/ +void +skip_line_warn(void) +{ + bool ok = skip_line_checked(); + if (!ok) { + current_lineno--; + warning("too many arguments on current line"); + current_lineno++; + } +} + +////////////////////////////////////////////////////////////////////// +/* skip_line_D (): + Skip line in 'D' commands. + + Decide whether in case of an additional argument a fatal error is + raised (the documented classical behavior), only a warning is + issued, or the line is just skipped (former groff behavior). + Actually decided for the warning. +*/ +void +skip_line_D(void) +{ + skip_line_warn(); + // or: skip_line_fatal(); + // or: skip_line(); +} + +////////////////////////////////////////////////////////////////////// +/* skip_line_x (): + Skip line in 'x' commands. + + Decide whether in case of an additional argument a fatal error is + raised (the documented classical behavior), only a warning is + issued, or the line is just skipped (former groff behavior). + Actually decided for the warning. +*/ +void +skip_line_x(void) +{ + skip_line_warn(); + // or: skip_line_fatal(); + // or: skip_line(); +} + +////////////////////////////////////////////////////////////////////// +/* skip_to_end_of_line(): + Go to the end of the current line. + + Skip the rest of the current line, excluding the newline character. + The global variable current_lineno is not changed. + No errors are raised. +*/ +void +skip_to_end_of_line(void) +{ + Char c = get_char(); + while (1) { + if (c == '\n') { + unget_char(c); + return; + } + if (c == EOF) + return; + c = get_char(); + } +} + +////////////////////////////////////////////////////////////////////// +/* unget_char(c): + Restore character c onto input queue. + + Write a character back onto the input stream. + EOF is gracefully handled. + + c: In-parameter; character to be pushed onto the input queue. +*/ +inline void +unget_char(const Char c) +{ + if (c != EOF) { + int ch = (int) c; + if (ungetc(ch, current_file) == EOF) + fatal("could not unget character"); + } +} + + +/********************************************************************** + parser subcommands + **********************************************************************/ + +////////////////////////////////////////////////////////////////////// +/* parse_color_command: + Process the commands m and DF, but not Df. + + col: In-out-parameter; the color object to be set, must have + been initialized before. +*/ +void +parse_color_command(color *col) +{ + ColorArg gray = 0; + ColorArg red = 0, green = 0, blue = 0; + ColorArg cyan = 0, magenta = 0, yellow = 0, black = 0; + Char subcmd = next_arg_begin(); + switch((int) subcmd) { + case 'c': // DFc or mc: CMY + cyan = get_color_arg(); + magenta = get_color_arg(); + yellow = get_color_arg(); + col->set_cmy(cyan, magenta, yellow); + break; + case 'd': // DFd or md: set default color + col->set_default(); + break; + case 'g': // DFg or mg: gray + gray = get_color_arg(); + col->set_gray(gray); + break; + case 'k': // DFk or mk: CMYK + cyan = get_color_arg(); + magenta = get_color_arg(); + yellow = get_color_arg(); + black = get_color_arg(); + col->set_cmyk(cyan, magenta, yellow, black); + break; + case 'r': // DFr or mr: RGB + red = get_color_arg(); + green = get_color_arg(); + blue = get_color_arg(); + col->set_rgb(red, green, blue); + break; + default: + error("invalid color scheme '%1'", (int) subcmd); + break; + } // end of color subcommands +} + +////////////////////////////////////////////////////////////////////// +/* parse_D_command(): + Parse the subcommands of graphical command D. + + This is the part of the do_file() parser that scans the graphical + subcommands. + - Error on lacking or wrong arguments. + - Warning on too many arguments. + - Line is always skipped. +*/ +void +parse_D_command() +{ + Char subcmd = next_arg_begin(); + switch((int) subcmd) { + case '~': // D~: draw B-spline + // actually, this isn't available for some postprocessors + // fall through + default: // unknown options are passed to device + { + IntArray *args = get_D_variable_args(); + send_draw(subcmd, args); + position_to_end_of_args(args); + delete args; + break; + } + case 'a': // Da: draw arc + { + IntArray *args = get_D_fixed_args(4); + send_draw(subcmd, args); + position_to_end_of_args(args); + delete args; + break; + } + case 'c': // Dc: draw circle line + { + IntArray *args = get_D_fixed_args(1); + send_draw(subcmd, args); + // move to right end + current_env->hpos += (*args)[0]; + delete args; + break; + } + case 'C': // DC: draw solid circle + { + IntArray *args = get_D_fixed_args_odd_dummy(1); + send_draw(subcmd, args); + // move to right end + current_env->hpos += (*args)[0]; + delete args; + break; + } + case 'e': // De: draw ellipse line + case 'E': // DE: draw solid ellipse + { + IntArray *args = get_D_fixed_args(2); + send_draw(subcmd, args); + // move to right end + current_env->hpos += (*args)[0]; + delete args; + break; + } + case 'f': // Df: set fill gray; obsoleted by DFg + { + IntArg arg = get_integer_arg(); + if ((arg >= 0) && (arg <= 1000)) { + // convert arg and treat it like DFg + ColorArg gray = color_from_Df_command(arg); + current_env->fill->set_gray(gray); + } + else { + // set fill color to the same value as the current outline color + delete current_env->fill; + current_env->fill = new color(current_env->col); + } + pr->change_fill_color(current_env); + // skip unused 'vertical' component (\D'...' always emits pairs) + (void) get_integer_arg(); +# ifdef STUPID_DRAWING_POSITIONING + current_env->hpos += arg; +# endif + skip_line_x(); + break; + } + case 'F': // DF: set fill color, several formats + parse_color_command(current_env->fill); + pr->change_fill_color(current_env); + // no positioning (setting-only command) + skip_line_x(); + break; + case 'l': // Dl: draw line + { + IntArray *args = get_D_fixed_args(2); + send_draw(subcmd, args); + position_to_end_of_args(args); + delete args; + break; + } + case 'p': // Dp: draw closed polygon line + case 'P': // DP: draw solid closed polygon + { + IntArray *args = get_D_variable_args(); + send_draw(subcmd, args); +# ifdef STUPID_DRAWING_POSITIONING + // final args positioning + position_to_end_of_args(args); +# endif + delete args; + break; + } + case 't': // Dt: set line thickness + { + IntArray *args = get_D_fixed_args_odd_dummy(1); + send_draw(subcmd, args); +# ifdef STUPID_DRAWING_POSITIONING + // final args positioning + position_to_end_of_args(args); +# endif + delete args; + break; + } + } // end of D subcommands +} + +////////////////////////////////////////////////////////////////////// +/* parse_x_command(): + Parse subcommands of the device control command x. + + This is the part of the do_file() parser that scans the device + controlling commands. + - Error on duplicate prologue commands. + - Error on wrong or lacking arguments. + - Warning on too many arguments. + - Line is always skipped. + + Globals: + - current_env: is set by many subcommands. + - npages: page counting variable + + Return: boolean in the meaning of 'stopped' + - true if parsing should be stopped ('x stop'). + - false if parsing should continue. +*/ +bool +parse_x_command(void) +{ + bool stopped = false; + char *subcmd_str = get_string_arg(); + char subcmd = subcmd_str[0]; + switch (subcmd) { + case 'f': // x font: mount font + { + IntArg n = get_integer_arg(); + char *name = get_string_arg(); + pr->load_font(n, name); + delete[] name; + skip_line_x(); + break; + } + case 'F': // x Filename: set filename for errors + { + char *str_arg = get_extended_arg(); + if (str_arg == 0) + warning("empty argument for 'x F' command"); + else { + remember_source_filename(str_arg); + delete[] str_arg; + } + break; + } + case 'H': // x Height: set character height + current_env->height = get_integer_arg(); + if (current_env->height == current_env->size) + current_env->height = 0; + skip_line_x(); + break; + case 'i': // x init: initialize device + error("duplicate 'x init' command"); + skip_line_x(); + break; + case 'p': // x pause: pause device + skip_line_x(); + break; + case 'r': // x res: set resolution + error("duplicate 'x res' command"); + skip_line_x(); + break; + case 's': // x stop: stop device + stopped = true; + skip_line_x(); + break; + case 'S': // x Slant: set slant + current_env->slant = get_integer_arg(); + skip_line_x(); + break; + case 't': // x trailer: generate trailer info + skip_line_x(); + break; + case 'T': // x Typesetter: set typesetter + error("duplicate 'x T' command"); + skip_line(); + break; + case 'u': // x underline: from .cu + { + char *str_arg = get_string_arg(); + pr->special(str_arg, current_env, 'u'); + delete[] str_arg; + skip_line_x(); + break; + } + case 'X': // x X: send uninterpretedly to device + { + char *str_arg = get_extended_arg(); // includes line skip + if (npages <= 0) + error("'x X' command invalid before first 'p' command"); + else if (str_arg && (strncmp(str_arg, "devtag:", + strlen("devtag:")) == 0)) + pr->devtag(str_arg, current_env); + else + pr->special(str_arg, current_env); + delete[] str_arg; + break; + } + default: // ignore unknown x commands, but warn + warning("unknown command 'x %1'", subcmd); + skip_line(); + } + delete[] subcmd_str; + return stopped; +} + + +/********************************************************************** + exported part (by driver.h) + **********************************************************************/ + +//////////////////////////////////////////////////////////////////////// +/* do_file(): + Parse and postprocess groff intermediate output. + + filename: "-" for standard input, normal file name otherwise +*/ +void +do_file(const char *filename) +{ + Char command; + bool stopped = false; // terminating condition + +#ifdef USE_ENV_STACK + EnvStack env_stack = EnvStack(); +#endif // USE_ENV_STACK + + // setup of global variables + npages = 0; + current_lineno = 1; + // 'pr' is initialized after the prologue. + // 'device' is set by the 1st prologue command. + + if (filename[0] == '-' && filename[1] == '\0') + current_file = stdin; + else { + errno = 0; + current_file = fopen(filename, "r"); + if (errno != 0 || current_file == 0) { + error("can't open file '%1'", filename); + return; + } + } + remember_filename(filename); + + if (current_env != 0) + delete_current_env(); + current_env = new environment; + current_env->col = new color; + current_env->fill = new color; + current_env->fontno = -1; + current_env->height = 0; + current_env->hpos = -1; + current_env->slant = 0; + current_env->size = 0; + current_env->vpos = -1; + + // parsing of prologue (first 3 commands) + { + char *str_arg; + IntArg int_arg; + + // 1st command 'x T' + command = next_command(); + if ((int) command == EOF) + return; + if ((int) command != 'x') + fatal("the first command must be 'x T'"); + str_arg = get_string_arg(); + if (str_arg[0] != 'T') + fatal("the first command must be 'x T'"); + delete[] str_arg; + char *tmp_dev = get_string_arg(); + if (pr == 0) { // note: 'pr' initialized after prologue + device = tmp_dev; + if (0 /* nullptr */ == font::load_desc()) + fatal("cannot load description of '%1' device", tmp_dev); + } + else { + if (device == 0 || strcmp(device, tmp_dev) != 0) + fatal("all files must use the same device"); + delete[] tmp_dev; + } + skip_line_x(); // ignore further arguments + current_env->size = 10 * font::sizescale; + + // 2nd command 'x res' + command = next_command(); + if ((int) command != 'x') + fatal("the second command must be 'x res'"); + str_arg = get_string_arg(); + if (str_arg[0] != 'r') + fatal("the second command must be 'x res'"); + delete[] str_arg; + int_arg = get_integer_arg(); + EnvInt font_res = font::res; + if (int_arg != font_res) + fatal("resolution does not match"); + int_arg = get_integer_arg(); + if (int_arg != font::hor) + fatal("minimum horizontal motion does not match"); + int_arg = get_integer_arg(); + if (int_arg != font::vert) + fatal("minimum vertical motion does not match"); + skip_line_x(); // ignore further arguments + + // 3rd command 'x init' + command = next_command(); + if (command != 'x') + fatal("the third command must be 'x init'"); + str_arg = get_string_arg(); + if (str_arg[0] != 'i') + fatal("the third command must be 'x init'"); + delete[] str_arg; + skip_line_x(); + } + + // parsing of body + if (pr == 0) + pr = make_printer(); + while (!stopped) { + command = next_command(); + if (command == EOF) + break; + // spaces, tabs, comments, and newlines are skipped here + switch ((int) command) { + case '#': // #: comment, ignore up to end of line + skip_line(); + break; +#ifdef USE_ENV_STACK + case '{': // {: start a new environment (a copy) + env_stack.push(current_env); + break; + case '}': // }: pop previous env from stack + delete_current_env(); + current_env = env_stack.pop(); + break; +#endif // USE_ENV_STACK + case '0': // ddc: obsolete jump and print command + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { // expect 2 digits and a character + char s[3]; + Char c = next_arg_begin(); + if (npages <= 0) + fatal_command(command); + if (!isdigit((int) c)) { + error("digit expected"); + c = 0; + } + s[0] = (char) command; + s[1] = (char) c; + s[2] = '\0'; + errno = 0; + long int x = strtol(s, 0, 10); + if (errno != 0) + error("couldn't convert 2 digits"); + EnvInt hor_pos = (EnvInt) x; + current_env->hpos += hor_pos; + c = next_arg_begin(); + if ((int) c == '\n' || (int) c == EOF) + error("character argument expected"); + else + pr->set_ascii_char((unsigned char) c, current_env); + break; + } + case 'c': // c: print ascii char without moving + { + if (npages <= 0) + fatal_command(command); + Char c = next_arg_begin(); + if (c == '\n' || c == EOF) + error("missing argument to 'c' command"); + else + pr->set_ascii_char((unsigned char) c, current_env); + break; + } + case 'C': // C: print named special character + { + if (npages <= 0) + fatal_command(command); + char *str_arg = get_string_arg(); + pr->set_special_char(str_arg, current_env); + delete[] str_arg; + break; + } + case 'D': // drawing commands + if (npages <= 0) + fatal_command(command); + parse_D_command(); + break; + case 'f': // f: set font to number + current_env->fontno = get_integer_arg(); + break; + case 'F': // F: obsolete, replaced by 'x F' + { + char *str_arg = get_extended_arg(); + remember_source_filename(str_arg); + delete[] str_arg; + break; + } + case 'h': // h: relative horizontal move + if (npages <= 0) + fatal_command(command); + current_env->hpos += (EnvInt) get_integer_arg(); + break; + case 'H': // H: absolute horizontal positioning + if (npages <= 0) + fatal_command(command); + current_env->hpos = (EnvInt) get_integer_arg(); + break; + case 'm': // m: glyph color + parse_color_command(current_env->col); + pr->change_color(current_env); + break; + case 'n': // n: print end of line + // ignore two arguments (historically) + if (npages <= 0) + fatal_command(command); + pr->end_of_line(); + (void) get_integer_arg(); + (void) get_integer_arg(); + break; + case 'N': // N: print char with given int code + if (npages <= 0) + fatal_command(command); + pr->set_numbered_char(get_integer_arg(), current_env); + break; + case 'p': // p: start new page with given number + if (npages > 0) + pr->end_page(current_env->vpos); + npages++; // increment # of processed pages + pr->begin_page(get_integer_arg()); + current_env->vpos = 0; + break; + case 's': // s: set point size + current_env->size = get_integer_arg(); + if (current_env->height == current_env->size) + current_env->height = 0; + break; + case 't': // t: print a text word + { + char c; + if (npages <= 0) + fatal_command(command); + char *str_arg = get_string_arg(); + size_t i = 0; + while ((c = str_arg[i++]) != '\0') { + EnvInt w; + pr->set_ascii_char((unsigned char) c, current_env, &w); + current_env->hpos += w; + } + delete[] str_arg; + break; + } + case 'u': // u: print spaced word + { + char c; + if (npages <= 0) + fatal_command(command); + EnvInt kern = (EnvInt) get_integer_arg(); + char *str_arg = get_string_arg(); + size_t i = 0; + while ((c = str_arg[i++]) != '\0') { + EnvInt w; + pr->set_ascii_char((unsigned char) c, current_env, &w); + current_env->hpos += w + kern; + } + delete[] str_arg; + break; + } + case 'v': // v: relative vertical move + if (npages <= 0) + fatal_command(command); + current_env->vpos += (EnvInt) get_integer_arg(); + break; + case 'V': // V: absolute vertical positioning + if (npages <= 0) + fatal_command(command); + current_env->vpos = (EnvInt) get_integer_arg(); + break; + case 'w': // w: inform about paddable space + break; + case 'x': // device controlling commands + stopped = parse_x_command(); + break; + default: + warning("unrecognized command '%1'", (unsigned char) command); + skip_line(); + break; + } // end of switch + } // end of while + + // end of file reached + if (npages > 0) + pr->end_page(current_env->vpos); + delete pr; + pr = 0; + fclose(current_file); + // If 'stopped' is not 'true' here then there wasn't any 'x stop'. + if (!stopped) + warning("no final 'x stop' command"); + delete_current_env(); +} + +// Local Variables: +// fill-column: 72 +// mode: C++ +// End: +// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: diff --git a/src/libs/libdriver/libdriver.am b/src/libs/libdriver/libdriver.am new file mode 100644 index 0000000..51475d8 --- /dev/null +++ b/src/libs/libdriver/libdriver.am @@ -0,0 +1,31 @@ +# Automake rules for 'libdriver' +# +# Copyright (C) 2014-2020 Free Software Foundation, Inc. +# +# 'groff' is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# 'groff' is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see +# <http://www.gnu.org/licenses/gpl-2.0.html>. +# +######################################################################## + +noinst_LIBRARIES += libdriver.a +libdriver_a_SOURCES = \ + src/libs/libdriver/input.cpp \ + src/libs/libdriver/printer.cpp + + +# Local Variables: +# mode: makefile-automake +# fill-column: 72 +# End: +# vim: set autoindent filetype=automake textwidth=72: diff --git a/src/libs/libdriver/printer.cpp b/src/libs/libdriver/printer.cpp new file mode 100644 index 0000000..f89b2e9 --- /dev/null +++ b/src/libs/libdriver/printer.cpp @@ -0,0 +1,268 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + + This file is part of groff. + + groff is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + groff is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <assert.h> + +#include "driver.h" + +/* If we are sending output to an onscreen pager (as is the normal case + when reading man pages), then we may get an error state on the output + stream, if the user does not read all the way to the end. + + We normally expect to catch this, and clean up the error context, + when the pager exits, because we should get, and handle, a SIGPIPE. + + However ... +*/ + +#if (defined(_MSC_VER) || defined(_WIN32)) \ + && !defined(__CYGWIN__) && !defined(_UWIN) + + /* Native MS-Windows doesn't know about SIGPIPE, so we cannot detect + the early exit from the pager, and therefore, cannot clean up the + error context; thus we use the following static function to + identify this particular error context, and so suppress unwanted + diagnostics. + */ + + static int + check_for_output_error (FILE* stream) + { + /* First, clean up any prior error context on the output stream */ + if (ferror (stream)) + clearerr (stream); + /* Clear errno, in case clearerr() and fflush() don't */ + errno = 0; + /* Flush the output stream, so we can capture any error context, + other than the specific case we wish to suppress. + + Microsoft doesn't document it, but the error code for the + specific context we are trying to suppress seems to be EINVAL -- + a strange choice, since it is not normally associated with + fflush(); of course, it *should* be EPIPE, but this *definitely* + is not used, and *is* so documented. + */ + return ((fflush(stream) < 0) && (errno != EINVAL)); + } + +#else + + /* For other systems, we simply assume that *any* output error context + is to be reported. + */ +# define check_for_output_error(stream) ferror(stream) || fflush(stream) < 0 + +#endif + + +font_pointer_list::font_pointer_list(font *f, font_pointer_list *fp) +: p(f), next(fp) +{ +} + +printer::printer() +: font_list(0), font_table(0), nfonts(0) +{ +} + +printer::~printer() +{ + delete[] font_table; + while (font_list) { + font_pointer_list *tem = font_list; + font_list = font_list->next; + delete tem->p; + delete tem; + } + if (check_for_output_error(stdout)) + fatal("output error"); +} + +void printer::load_font(int n, const char *nm) +{ + assert(n >= 0); + if (n >= nfonts) { + if (nfonts == 0) { + nfonts = 10; + if (nfonts <= n) + nfonts = n + 1; + font_table = new font *[nfonts]; + for (int i = 0; i < nfonts; i++) + font_table[i] = 0; + } + else { + font **old_font_table = font_table; + int old_nfonts = nfonts; + nfonts *= 2; + if (n >= nfonts) + nfonts = n + 1; + font_table = new font *[nfonts]; + int i; + for (i = 0; i < old_nfonts; i++) + font_table[i] = old_font_table[i]; + for (i = old_nfonts; i < nfonts; i++) + font_table[i] = 0; + delete[] old_font_table; + } + } + font *f = find_font(nm); + font_table[n] = f; +} + +font *printer::find_font(const char *nm) +{ + for (font_pointer_list *p = font_list; p; p = p->next) + if (strcmp(p->p->get_name(), nm) == 0) + return p->p; + font *f = make_font(nm); + if (0 /* nullptr */ == f) + fatal("cannot find font '%1'", nm); + font_list = new font_pointer_list(f, font_list); + return f; +} + +font *printer::make_font(const char *nm) +{ + return font::load_font(nm); +} + +void printer::end_of_line() +{ +} + +void printer::special(char *, const environment *, char) +{ +} + +void printer::devtag(char *, const environment *, char) +{ +} + +void printer::draw(int, int *, int, const environment *) +{ +} + +void printer::change_color(const environment * const) +{ +} + +void printer::change_fill_color(const environment * const) +{ +} + +void printer::set_ascii_char(unsigned char c, const environment *env, + int *widthp) +{ + char buf[2]; + int w; + font *f; + + buf[0] = c; + buf[1] = '\0'; + + glyph *g = set_char_and_width(buf, env, &w, &f); + + if (g != UNDEFINED_GLYPH) { + set_char(g, f, env, w, 0); + if (widthp) + *widthp = w; + } +} + +void printer::set_special_char(const char *nm, const environment *env, + int *widthp) +{ + font *f; + int w; + glyph *g = set_char_and_width(nm, env, &w, &f); + if (g != UNDEFINED_GLYPH) { + set_char(g, f, env, w, nm); + if (widthp) + *widthp = w; + } +} + +glyph *printer::set_char_and_width(const char *nm, + const environment *env, int *widthp, + font **f) +{ + glyph *g = name_to_glyph(nm); + int fn = env->fontno; + if (fn < 0 || fn >= nfonts) { + error("invalid font position '%1'", fn); + return UNDEFINED_GLYPH; + } + *f = font_table[fn]; + if (*f == 0) { + error("no font mounted at position %1", fn); + return UNDEFINED_GLYPH; + } + if (!(*f)->contains(g)) { + if (nm[0] != '\0' && nm[1] == '\0') + error("font '%1' does not contain ordinary character '%2'", + (*f)->get_name(), nm[0]); + else + error("font '%1' does not contain special character '%2'", + (*f)->get_name(), nm); + return UNDEFINED_GLYPH; + } + int w = (*f)->get_width(g, env->size); + if (widthp) + *widthp = w; + return g; +} + +void printer::set_numbered_char(int num, const environment *env, int + *widthp) +{ + glyph *g = number_to_glyph(num); + int fn = env->fontno; + if (fn < 0 || fn >= nfonts) { + error("invalid font position '%1'", fn); + return; + } + font *f = font_table[fn]; + if (f == 0) { + error("no font mounted at position %1", fn); + return; + } + if (!f->contains(g)) { + error("font '%1' does not contain numbered character %2", + f->get_name(), num); + return; + } + int w = f->get_width(g, env->size); + if (widthp) + *widthp = w; + set_char(g, f, env, w, 0); +} + +font *printer::get_font_from_index(int fontno) +{ + if ((fontno >= 0) && (fontno < nfonts)) + return font_table[fontno]; + else + return 0; +} + +// Local Variables: +// fill-column: 72 +// mode: C++ +// End: +// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: diff --git a/src/libs/libgroff/assert.cpp b/src/libs/libgroff/assert.cpp new file mode 100644 index 0000000..9da3d46 --- /dev/null +++ b/src/libs/libgroff/assert.cpp @@ -0,0 +1,38 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> + +extern "C" const char *program_name; + +void assertion_failed(int lineno, const char *filename, + const char *function, const char *msg) +{ + if (program_name != 0) + fprintf(stderr, "%s: ", program_name); + fprintf(stderr, "%s:%d: %s(): assertion failed: '%s'\n", filename, + lineno, function, msg); + fflush(stderr); + abort(); +} diff --git a/src/libs/libgroff/change_lf.cpp b/src/libs/libgroff/change_lf.cpp new file mode 100644 index 0000000..eb98766 --- /dev/null +++ b/src/libs/libgroff/change_lf.cpp @@ -0,0 +1,37 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> +#include <string.h> + +extern char *strsave(const char *); + +extern const char *current_filename; +extern int current_lineno; + +void change_filename(const char *f) +{ + if (current_filename != 0 && strcmp(current_filename, f) == 0) + return; + current_filename = strsave(f); +} + +void change_lineno(int ln) +{ + current_lineno = ln; +} diff --git a/src/libs/libgroff/cmap.cpp b/src/libs/libgroff/cmap.cpp new file mode 100644 index 0000000..3f2c0c3 --- /dev/null +++ b/src/libs/libgroff/cmap.cpp @@ -0,0 +1,56 @@ +// -*- C++ -*- +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> +#include <ctype.h> +#include "cmap.h" + +cmap cmlower(CMAP_BUILTIN); +cmap cmupper(CMAP_BUILTIN); + +#ifdef isascii +#define ISASCII(c) isascii(c) +#else +#define ISASCII(c) (1) +#endif + +cmap::cmap() +{ + unsigned char *p = v; + for (int i = 0; i <= UCHAR_MAX; i++) + p[i] = i; +} + +cmap::cmap(cmap_builtin) +{ + // these are initialised by cmap_init::cmap_init() +} + +int cmap_init::initialised = 0; + +cmap_init::cmap_init() +{ + if (initialised) + return; + initialised = 1; + for (int i = 0; i <= UCHAR_MAX; i++) { + cmupper.v[i] = ISASCII(i) && islower(i) ? toupper(i) : i; + cmlower.v[i] = ISASCII(i) && isupper(i) ? tolower(i) : i; + } +} diff --git a/src/libs/libgroff/color.cpp b/src/libs/libgroff/color.cpp new file mode 100644 index 0000000..388c2ee --- /dev/null +++ b/src/libs/libgroff/color.cpp @@ -0,0 +1,404 @@ +/* Copyright (C) 2001-2020 Free Software Foundation, Inc. + Written by Gaius Mulley <gaius@glam.ac.uk> + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "lib.h" +#include "color.h" +#include "cset.h" + +#include <assert.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include "errarg.h" +#include "error.h" + +static inline unsigned int +min(const unsigned int a, const unsigned int b) +{ + if (a < b) + return a; + else + return b; +} + + +color::color(const color * const c) +{ + nm = c->nm; + scheme = c->scheme; + components[0] = c->components[0]; + components[1] = c->components[1]; + components[2] = c->components[2]; + components[3] = c->components[3]; +} + +color::~color() +{ +} + +int color::operator==(const color & c) const +{ + if (scheme != c.scheme) + return 0; + switch (scheme) { + case DEFAULT: + break; + case RGB: + if (Red != c.Red || Green != c.Green || Blue != c.Blue) + return 0; + break; + case CMYK: + if (Cyan != c.Cyan || Magenta != c.Magenta + || Yellow != c.Yellow || Black != c.Black) + return 0; + break; + case GRAY: + if (Gray != c.Gray) + return 0; + break; + case CMY: + if (Cyan != c.Cyan || Magenta != c.Magenta || Yellow != c.Yellow) + return 0; + break; + } + return 1; +} + +int color::operator!=(const color & c) const +{ + return !(*this == c); +} + +color_scheme color::get_components(unsigned int *c) const +{ +#if 0 + if (sizeof (c) < sizeof (unsigned int) * 4) + fatal("argument is not big enough to store 4 color components"); +#endif + c[0] = components[0]; + c[1] = components[1]; + c[2] = components[2]; + c[3] = components[3]; + return scheme; +} + +void color::set_default() +{ + scheme = DEFAULT; +} + +// (0, 0, 0) is black + +void color::set_rgb(const unsigned int r, const unsigned int g, + const unsigned int b) +{ + scheme = RGB; + Red = min(MAX_COLOR_VAL, r); + Green = min(MAX_COLOR_VAL, g); + Blue = min(MAX_COLOR_VAL, b); +} + +// (0, 0, 0) is white + +void color::set_cmy(const unsigned int c, const unsigned int m, + const unsigned int y) +{ + scheme = CMY; + Cyan = min(MAX_COLOR_VAL, c); + Magenta = min(MAX_COLOR_VAL, m); + Yellow = min(MAX_COLOR_VAL, y); +} + +// (0, 0, 0, 0) is white + +void color::set_cmyk(const unsigned int c, const unsigned int m, + const unsigned int y, const unsigned int k) +{ + scheme = CMYK; + Cyan = min(MAX_COLOR_VAL, c); + Magenta = min(MAX_COLOR_VAL, m); + Yellow = min(MAX_COLOR_VAL, y); + Black = min(MAX_COLOR_VAL, k); +} + +// (0) is black + +void color::set_gray(const unsigned int g) +{ + scheme = GRAY; + Gray = min(MAX_COLOR_VAL, g); +} + +/* + * atoh - computes the decimal value of a hexadecimal number string. + * 'length' characters of 's' are read. Returns 1 if successful. + */ + +static int atoh(unsigned int *result, + const char * const s, const size_t length) +{ + size_t i = 0; + unsigned int val = 0; + while ((i < length) && csxdigit(s[i])) { + if (csdigit(s[i])) + val = val*0x10 + (s[i]-'0'); + else if (csupper(s[i])) + val = val*0x10 + (s[i]-'A') + 10; + else + val = val*0x10 + (s[i]-'a') + 10; + i++; + } + if (i != length) + return 0; + *result = val; + return 1; +} + +/* + * read_encoding - set color from a hexadecimal color string. + * + * Use color scheme 'cs' to parse 'n' color components from string 's'. + * Returns 1 if successful. + */ + +int color::read_encoding(const color_scheme cs, const char * const s, + const size_t n) +{ + size_t hex_length = 2; + scheme = cs; + char *p = (char *) s; + p++; + if (*p == '#') { + hex_length = 4; + p++; + } + for (size_t i = 0; i < n; i++) { + if (!atoh(&(components[i]), p, hex_length)) + return 0; + if (hex_length == 2) + components[i] *= 0x101; // scale up -- 0xff should become 0xffff + p += hex_length; + } + return 1; +} + +int color::read_rgb(const char * const s) +{ + return read_encoding(RGB, s, 3); +} + +int color::read_cmy(const char * const s) +{ + return read_encoding(CMY, s, 3); +} + +int color::read_cmyk(const char * const s) +{ + return read_encoding(CMYK, s, 4); +} + +int color::read_gray(const char * const s) +{ + return read_encoding(GRAY, s, 1); +} + +void +color::get_rgb(unsigned int *r, unsigned int *g, unsigned int *b) const +{ + switch (scheme) { + case RGB: + *r = Red; + *g = Green; + *b = Blue; + break; + case CMY: + *r = MAX_COLOR_VAL - Cyan; + *g = MAX_COLOR_VAL - Magenta; + *b = MAX_COLOR_VAL - Yellow; + break; + case CMYK: + *r = MAX_COLOR_VAL + - min(MAX_COLOR_VAL, + Cyan * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black); + *g = MAX_COLOR_VAL + - min(MAX_COLOR_VAL, + Magenta * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black); + *b = MAX_COLOR_VAL + - min(MAX_COLOR_VAL, + Yellow * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black); + break; + case GRAY: + *r = *g = *b = Gray; + break; + default: + assert(0); + break; + } +} + +void +color::get_cmy(unsigned int *c, unsigned int *m, unsigned int *y) const +{ + switch (scheme) { + case RGB: + *c = MAX_COLOR_VAL - Red; + *m = MAX_COLOR_VAL - Green; + *y = MAX_COLOR_VAL - Blue; + break; + case CMY: + *c = Cyan; + *m = Magenta; + *y = Yellow; + break; + case CMYK: + *c = min(MAX_COLOR_VAL, + Cyan * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black); + *m = min(MAX_COLOR_VAL, + Magenta * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black); + *y = min(MAX_COLOR_VAL, + Yellow * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black); + break; + case GRAY: + *c = *m = *y = MAX_COLOR_VAL - Gray; + break; + default: + assert(0); + break; + } +} + +void color::get_cmyk(unsigned int *c, unsigned int *m, + unsigned int *y, unsigned int *k) const +{ + switch (scheme) { + case RGB: + *k = min(MAX_COLOR_VAL - Red, + min(MAX_COLOR_VAL - Green, MAX_COLOR_VAL - Blue)); + if (MAX_COLOR_VAL == *k) { + *c = MAX_COLOR_VAL; + *m = MAX_COLOR_VAL; + *y = MAX_COLOR_VAL; + } + else { + *c = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Red - *k)) + / (MAX_COLOR_VAL - *k); + *m = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Green - *k)) + / (MAX_COLOR_VAL - *k); + *y = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Blue - *k)) + / (MAX_COLOR_VAL - *k); + } + break; + case CMY: + *k = min(Cyan, min(Magenta, Yellow)); + if (MAX_COLOR_VAL == *k) { + *c = MAX_COLOR_VAL; + *m = MAX_COLOR_VAL; + *y = MAX_COLOR_VAL; + } + else { + *c = (MAX_COLOR_VAL * (Cyan - *k)) / (MAX_COLOR_VAL - *k); + *m = (MAX_COLOR_VAL * (Magenta - *k)) / (MAX_COLOR_VAL - *k); + *y = (MAX_COLOR_VAL * (Yellow - *k)) / (MAX_COLOR_VAL - *k); + } + break; + case CMYK: + *c = Cyan; + *m = Magenta; + *y = Yellow; + *k = Black; + break; + case GRAY: + *c = *m = *y = 0; + *k = MAX_COLOR_VAL - Gray; + break; + default: + assert(0); + break; + } +} + +// we use '0.222r + 0.707g + 0.071b' (this is the ITU standard) +// as an approximation for gray + +void color::get_gray(unsigned int *g) const +{ + switch (scheme) { + case RGB: + *g = (222*Red + 707*Green + 71*Blue) / 1000; + break; + case CMY: + *g = MAX_COLOR_VAL - (222*Cyan + 707*Magenta + 71*Yellow) / 1000; + break; + case CMYK: + *g = (MAX_COLOR_VAL - (222*Cyan + 707*Magenta + 71*Yellow) / 1000) + * (MAX_COLOR_VAL - Black); + break; + case GRAY: + *g = Gray; + break; + default: + assert(0); + break; + } +} + +char *color::print_color() +{ + char *s = new char[30]; + switch (scheme) { + case DEFAULT: + sprintf(s, "default"); + break; + case RGB: + sprintf(s, "rgb %.2ff %.2ff %.2ff", + double(Red) / double(MAX_COLOR_VAL), + double(Green) / double(MAX_COLOR_VAL), + double(Blue) / double(MAX_COLOR_VAL)); + break; + case CMY: + sprintf(s, "cmy %.2ff %.2ff %.2ff", + double(Cyan) / double(MAX_COLOR_VAL), + double(Magenta) / double(MAX_COLOR_VAL), + double(Yellow) / double(MAX_COLOR_VAL)); + break; + case CMYK: + sprintf(s, "cmyk %.2ff %.2ff %.2ff %.2ff", + double(Cyan) / double(MAX_COLOR_VAL), + double(Magenta) / double(MAX_COLOR_VAL), + double(Yellow) / double(MAX_COLOR_VAL), + double(Black) / double(MAX_COLOR_VAL)); + break; + case GRAY: + sprintf(s, "gray %.2ff", + double(Gray) / double(MAX_COLOR_VAL)); + break; + } + return s; +} + +color default_color; + +// Local Variables: +// fill-column: 72 +// mode: C++ +// End: +// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: diff --git a/src/libs/libgroff/config.charset b/src/libs/libgroff/config.charset new file mode 100755 index 0000000..8fca485 --- /dev/null +++ b/src/libs/libgroff/config.charset @@ -0,0 +1,684 @@ +#! /bin/sh +# Output a system dependent table of character encoding aliases. +# +# Copyright (C) 2000-2020 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, see <http://www.gnu.org/licenses/>. +# +# The table consists of lines of the form +# ALIAS CANONICAL +# +# ALIAS is the (system dependent) result of "nl_langinfo (CODESET)". +# ALIAS is compared in a case sensitive way. +# +# CANONICAL is the GNU canonical name for this character encoding. +# It must be an encoding supported by libiconv. Support by GNU libc is +# also desirable. CANONICAL is case insensitive. Usually an upper case +# MIME charset name is preferred. +# The current list of GNU canonical charset names is as follows. +# +# name MIME? used by which systems +# (darwin = Mac OS X, woe32 = native Windows) +# +# ASCII, ANSI_X3.4-1968 glibc solaris freebsd netbsd darwin cygwin +# ISO-8859-1 Y glibc aix hpux irix osf solaris freebsd netbsd openbsd darwin cygwin +# ISO-8859-2 Y glibc aix hpux irix osf solaris freebsd netbsd openbsd darwin cygwin +# ISO-8859-3 Y glibc solaris cygwin +# ISO-8859-4 Y osf solaris freebsd netbsd openbsd darwin +# ISO-8859-5 Y glibc aix hpux irix osf solaris freebsd netbsd openbsd darwin cygwin +# ISO-8859-6 Y glibc aix hpux solaris cygwin +# ISO-8859-7 Y glibc aix hpux irix osf solaris netbsd openbsd darwin cygwin +# ISO-8859-8 Y glibc aix hpux osf solaris cygwin +# ISO-8859-9 Y glibc aix hpux irix osf solaris darwin cygwin +# ISO-8859-13 glibc netbsd openbsd darwin cygwin +# ISO-8859-14 glibc cygwin +# ISO-8859-15 glibc aix osf solaris freebsd netbsd openbsd darwin cygwin +# KOI8-R Y glibc solaris freebsd netbsd openbsd darwin +# KOI8-U Y glibc freebsd netbsd openbsd darwin cygwin +# KOI8-T glibc +# CP437 dos +# CP775 dos +# CP850 aix osf dos +# CP852 dos +# CP855 dos +# CP856 aix +# CP857 dos +# CP861 dos +# CP862 dos +# CP864 dos +# CP865 dos +# CP866 freebsd netbsd openbsd darwin dos +# CP869 dos +# CP874 woe32 dos +# CP922 aix +# CP932 aix cygwin woe32 dos +# CP943 aix +# CP949 osf darwin woe32 dos +# CP950 woe32 dos +# CP1046 aix +# CP1124 aix +# CP1125 dos +# CP1129 aix +# CP1131 darwin +# CP1250 woe32 +# CP1251 glibc solaris netbsd openbsd darwin cygwin woe32 +# CP1252 aix woe32 +# CP1253 woe32 +# CP1254 woe32 +# CP1255 glibc woe32 +# CP1256 woe32 +# CP1257 woe32 +# GB2312 Y glibc aix hpux irix solaris freebsd netbsd darwin +# EUC-JP Y glibc aix hpux irix osf solaris freebsd netbsd darwin +# EUC-KR Y glibc aix hpux irix osf solaris freebsd netbsd darwin cygwin +# EUC-TW glibc aix hpux irix osf solaris netbsd +# BIG5 Y glibc aix hpux osf solaris freebsd netbsd darwin cygwin +# BIG5-HKSCS glibc solaris darwin +# GBK glibc aix osf solaris darwin cygwin woe32 dos +# GB18030 glibc solaris netbsd darwin +# SHIFT_JIS Y hpux osf solaris freebsd netbsd darwin +# JOHAB glibc solaris woe32 +# TIS-620 glibc aix hpux osf solaris cygwin +# VISCII Y glibc +# TCVN5712-1 glibc +# ARMSCII-8 glibc darwin +# GEORGIAN-PS glibc cygwin +# PT154 glibc +# HP-ROMAN8 hpux +# HP-ARABIC8 hpux +# HP-GREEK8 hpux +# HP-HEBREW8 hpux +# HP-TURKISH8 hpux +# HP-KANA8 hpux +# DEC-KANJI osf +# DEC-HANYU osf +# UTF-8 Y glibc aix hpux osf solaris netbsd darwin cygwin +# +# Note: Names which are not marked as being a MIME name should not be used in +# Internet protocols for information interchange (mail, news, etc.). +# +# Note: ASCII and ANSI_X3.4-1968 are synonymous canonical names. Applications +# must understand both names and treat them as equivalent. +# +# The first argument passed to this file is the canonical host specification, +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM + +host="$1" +os=`echo "$host" | sed -e 's/^[^-]*-[^-]*-\(.*\)$/\1/'` +echo "# This file contains a table of character encoding aliases," +echo "# suitable for operating system '${os}'." +echo "# It was automatically generated from config.charset." +# List of references, updated during installation: +echo "# Packages using this file: " +case "$os" in + linux-gnulibc1*) + # Linux libc5 doesn't have nl_langinfo(CODESET); therefore + # localcharset.c falls back to using the full locale name + # from the environment variables. + echo "C ASCII" + echo "POSIX ASCII" + for l in af af_ZA ca ca_ES da da_DK de de_AT de_BE de_CH de_DE de_LU \ + en en_AU en_BW en_CA en_DK en_GB en_IE en_NZ en_US en_ZA \ + en_ZW es es_AR es_BO es_CL es_CO es_DO es_EC es_ES es_GT \ + es_HN es_MX es_PA es_PE es_PY es_SV es_US es_UY es_VE et \ + et_EE eu eu_ES fi fi_FI fo fo_FO fr fr_BE fr_CA fr_CH fr_FR \ + fr_LU ga ga_IE gl gl_ES id id_ID in in_ID is is_IS it it_CH \ + it_IT kl kl_GL nl nl_BE nl_NL no no_NO pt pt_BR pt_PT sv \ + sv_FI sv_SE; do + echo "$l ISO-8859-1" + echo "$l.iso-8859-1 ISO-8859-1" + echo "$l.iso-8859-15 ISO-8859-15" + echo "$l.iso-8859-15@euro ISO-8859-15" + echo "$l@euro ISO-8859-15" + echo "$l.cp-437 CP437" + echo "$l.cp-850 CP850" + echo "$l.cp-1252 CP1252" + echo "$l.cp-1252@euro CP1252" + #echo "$l.atari-st ATARI-ST" # not a commonly used encoding + echo "$l.utf-8 UTF-8" + echo "$l.utf-8@euro UTF-8" + done + for l in cs cs_CZ hr hr_HR hu hu_HU pl pl_PL ro ro_RO sk sk_SK sl \ + sl_SI sr sr_CS sr_YU; do + echo "$l ISO-8859-2" + echo "$l.iso-8859-2 ISO-8859-2" + echo "$l.cp-852 CP852" + echo "$l.cp-1250 CP1250" + echo "$l.utf-8 UTF-8" + done + for l in mk mk_MK ru ru_RU; do + echo "$l ISO-8859-5" + echo "$l.iso-8859-5 ISO-8859-5" + echo "$l.koi8-r KOI8-R" + echo "$l.cp-866 CP866" + echo "$l.cp-1251 CP1251" + echo "$l.utf-8 UTF-8" + done + for l in ar ar_SA; do + echo "$l ISO-8859-6" + echo "$l.iso-8859-6 ISO-8859-6" + echo "$l.cp-864 CP864" + #echo "$l.cp-868 CP868" # not a commonly used encoding + echo "$l.cp-1256 CP1256" + echo "$l.utf-8 UTF-8" + done + for l in el el_GR gr gr_GR; do + echo "$l ISO-8859-7" + echo "$l.iso-8859-7 ISO-8859-7" + echo "$l.cp-869 CP869" + echo "$l.cp-1253 CP1253" + echo "$l.cp-1253@euro CP1253" + echo "$l.utf-8 UTF-8" + echo "$l.utf-8@euro UTF-8" + done + for l in he he_IL iw iw_IL; do + echo "$l ISO-8859-8" + echo "$l.iso-8859-8 ISO-8859-8" + echo "$l.cp-862 CP862" + echo "$l.cp-1255 CP1255" + echo "$l.utf-8 UTF-8" + done + for l in tr tr_TR; do + echo "$l ISO-8859-9" + echo "$l.iso-8859-9 ISO-8859-9" + echo "$l.cp-857 CP857" + echo "$l.cp-1254 CP1254" + echo "$l.utf-8 UTF-8" + done + for l in lt lt_LT lv lv_LV; do + #echo "$l BALTIC" # not a commonly used encoding, wrong encoding name + echo "$l ISO-8859-13" + done + for l in ru_UA uk uk_UA; do + echo "$l KOI8-U" + done + for l in zh zh_CN; do + #echo "$l GB_2312-80" # not a commonly used encoding, wrong encoding name + echo "$l GB2312" + done + for l in ja ja_JP ja_JP.EUC; do + echo "$l EUC-JP" + done + for l in ko ko_KR; do + echo "$l EUC-KR" + done + for l in th th_TH; do + echo "$l TIS-620" + done + for l in fa fa_IR; do + #echo "$l ISIRI-3342" # a broken encoding + echo "$l.utf-8 UTF-8" + done + ;; + linux* | *-gnu*) + # With glibc-2.1 or newer, we don't need any canonicalization, + # because glibc has iconv and both glibc and libiconv support all + # GNU canonical names directly. Therefore, the Makefile does not + # need to install the alias file at all. + # The following applies only to glibc-2.0.x and older libcs. + echo "ISO_646.IRV:1983 ASCII" + ;; + aix*) + echo "ISO8859-1 ISO-8859-1" + echo "ISO8859-2 ISO-8859-2" + echo "ISO8859-5 ISO-8859-5" + echo "ISO8859-6 ISO-8859-6" + echo "ISO8859-7 ISO-8859-7" + echo "ISO8859-8 ISO-8859-8" + echo "ISO8859-9 ISO-8859-9" + echo "ISO8859-15 ISO-8859-15" + echo "IBM-850 CP850" + echo "IBM-856 CP856" + echo "IBM-921 ISO-8859-13" + echo "IBM-922 CP922" + echo "IBM-932 CP932" + echo "IBM-943 CP943" + echo "IBM-1046 CP1046" + echo "IBM-1124 CP1124" + echo "IBM-1129 CP1129" + echo "IBM-1252 CP1252" + echo "IBM-eucCN GB2312" + echo "IBM-eucJP EUC-JP" + echo "IBM-eucKR EUC-KR" + echo "IBM-eucTW EUC-TW" + echo "big5 BIG5" + echo "GBK GBK" + echo "TIS-620 TIS-620" + echo "UTF-8 UTF-8" + ;; + hpux*) + echo "iso88591 ISO-8859-1" + echo "iso88592 ISO-8859-2" + echo "iso88595 ISO-8859-5" + echo "iso88596 ISO-8859-6" + echo "iso88597 ISO-8859-7" + echo "iso88598 ISO-8859-8" + echo "iso88599 ISO-8859-9" + echo "iso885915 ISO-8859-15" + echo "roman8 HP-ROMAN8" + echo "arabic8 HP-ARABIC8" + echo "greek8 HP-GREEK8" + echo "hebrew8 HP-HEBREW8" + echo "turkish8 HP-TURKISH8" + echo "kana8 HP-KANA8" + echo "tis620 TIS-620" + echo "big5 BIG5" + echo "eucJP EUC-JP" + echo "eucKR EUC-KR" + echo "eucTW EUC-TW" + echo "hp15CN GB2312" + #echo "ccdc ?" # what is this? + echo "SJIS SHIFT_JIS" + echo "utf8 UTF-8" + ;; + irix*) + echo "ISO8859-1 ISO-8859-1" + echo "ISO8859-2 ISO-8859-2" + echo "ISO8859-5 ISO-8859-5" + echo "ISO8859-7 ISO-8859-7" + echo "ISO8859-9 ISO-8859-9" + echo "eucCN GB2312" + echo "eucJP EUC-JP" + echo "eucKR EUC-KR" + echo "eucTW EUC-TW" + ;; + osf*) + echo "ISO8859-1 ISO-8859-1" + echo "ISO8859-2 ISO-8859-2" + echo "ISO8859-4 ISO-8859-4" + echo "ISO8859-5 ISO-8859-5" + echo "ISO8859-7 ISO-8859-7" + echo "ISO8859-8 ISO-8859-8" + echo "ISO8859-9 ISO-8859-9" + echo "ISO8859-15 ISO-8859-15" + echo "cp850 CP850" + echo "big5 BIG5" + echo "dechanyu DEC-HANYU" + echo "dechanzi GB2312" + echo "deckanji DEC-KANJI" + echo "deckorean EUC-KR" + echo "eucJP EUC-JP" + echo "eucKR EUC-KR" + echo "eucTW EUC-TW" + echo "GBK GBK" + echo "KSC5601 CP949" + echo "sdeckanji EUC-JP" + echo "SJIS SHIFT_JIS" + echo "TACTIS TIS-620" + echo "UTF-8 UTF-8" + ;; + solaris*) + echo "646 ASCII" + echo "ISO8859-1 ISO-8859-1" + echo "ISO8859-2 ISO-8859-2" + echo "ISO8859-3 ISO-8859-3" + echo "ISO8859-4 ISO-8859-4" + echo "ISO8859-5 ISO-8859-5" + echo "ISO8859-6 ISO-8859-6" + echo "ISO8859-7 ISO-8859-7" + echo "ISO8859-8 ISO-8859-8" + echo "ISO8859-9 ISO-8859-9" + echo "ISO8859-15 ISO-8859-15" + echo "koi8-r KOI8-R" + echo "ansi-1251 CP1251" + echo "BIG5 BIG5" + echo "Big5-HKSCS BIG5-HKSCS" + echo "gb2312 GB2312" + echo "GBK GBK" + echo "GB18030 GB18030" + echo "cns11643 EUC-TW" + echo "5601 EUC-KR" + echo "ko_KR.johap92 JOHAB" + echo "eucJP EUC-JP" + echo "PCK SHIFT_JIS" + echo "TIS620.2533 TIS-620" + #echo "sun_eu_greek ?" # what is this? + echo "UTF-8 UTF-8" + ;; + freebsd* | os2*) + # FreeBSD 4.2 doesn't have nl_langinfo(CODESET); therefore + # localcharset.c falls back to using the full locale name + # from the environment variables. + # Likewise for OS/2. OS/2 has XFree86 just like FreeBSD. Just + # reuse FreeBSD's locale data for OS/2. + echo "C ASCII" + echo "US-ASCII ASCII" + for l in la_LN lt_LN; do + echo "$l.ASCII ASCII" + done + for l in da_DK de_AT de_CH de_DE en_AU en_CA en_GB en_US es_ES \ + fi_FI fr_BE fr_CA fr_CH fr_FR is_IS it_CH it_IT la_LN \ + lt_LN nl_BE nl_NL no_NO pt_PT sv_SE; do + echo "$l.ISO_8859-1 ISO-8859-1" + echo "$l.DIS_8859-15 ISO-8859-15" + done + for l in cs_CZ hr_HR hu_HU la_LN lt_LN pl_PL sl_SI; do + echo "$l.ISO_8859-2 ISO-8859-2" + done + for l in la_LN lt_LT; do + echo "$l.ISO_8859-4 ISO-8859-4" + done + for l in ru_RU ru_SU; do + echo "$l.KOI8-R KOI8-R" + echo "$l.ISO_8859-5 ISO-8859-5" + echo "$l.CP866 CP866" + done + echo "uk_UA.KOI8-U KOI8-U" + echo "zh_TW.BIG5 BIG5" + echo "zh_TW.Big5 BIG5" + echo "zh_CN.EUC GB2312" + echo "ja_JP.EUC EUC-JP" + echo "ja_JP.SJIS SHIFT_JIS" + echo "ja_JP.Shift_JIS SHIFT_JIS" + echo "ko_KR.EUC EUC-KR" + ;; + netbsd*) + echo "646 ASCII" + echo "ISO8859-1 ISO-8859-1" + echo "ISO8859-2 ISO-8859-2" + echo "ISO8859-4 ISO-8859-4" + echo "ISO8859-5 ISO-8859-5" + echo "ISO8859-7 ISO-8859-7" + echo "ISO8859-13 ISO-8859-13" + echo "ISO8859-15 ISO-8859-15" + echo "eucCN GB2312" + echo "eucJP EUC-JP" + echo "eucKR EUC-KR" + echo "eucTW EUC-TW" + echo "BIG5 BIG5" + echo "SJIS SHIFT_JIS" + ;; + openbsd*) + echo "646 ASCII" + echo "ISO8859-1 ISO-8859-1" + echo "ISO8859-2 ISO-8859-2" + echo "ISO8859-4 ISO-8859-4" + echo "ISO8859-5 ISO-8859-5" + echo "ISO8859-7 ISO-8859-7" + echo "ISO8859-13 ISO-8859-13" + echo "ISO8859-15 ISO-8859-15" + ;; + darwin[56]*) + # Darwin 6.8 doesn't have nl_langinfo(CODESET); therefore + # localcharset.c falls back to using the full locale name + # from the environment variables. + echo "C ASCII" + for l in en_AU en_CA en_GB en_US la_LN; do + echo "$l.US-ASCII ASCII" + done + for l in da_DK de_AT de_CH de_DE en_AU en_CA en_GB en_US es_ES \ + fi_FI fr_BE fr_CA fr_CH fr_FR is_IS it_CH it_IT nl_BE \ + nl_NL no_NO pt_PT sv_SE; do + echo "$l ISO-8859-1" + echo "$l.ISO8859-1 ISO-8859-1" + echo "$l.ISO8859-15 ISO-8859-15" + done + for l in la_LN; do + echo "$l.ISO8859-1 ISO-8859-1" + echo "$l.ISO8859-15 ISO-8859-15" + done + for l in cs_CZ hr_HR hu_HU la_LN pl_PL sl_SI; do + echo "$l.ISO8859-2 ISO-8859-2" + done + for l in la_LN lt_LT; do + echo "$l.ISO8859-4 ISO-8859-4" + done + for l in ru_RU; do + echo "$l.KOI8-R KOI8-R" + echo "$l.ISO8859-5 ISO-8859-5" + echo "$l.CP866 CP866" + done + for l in bg_BG; do + echo "$l.CP1251 CP1251" + done + echo "uk_UA.KOI8-U KOI8-U" + echo "zh_TW.BIG5 BIG5" + echo "zh_TW.Big5 BIG5" + echo "zh_CN.EUC GB2312" + echo "ja_JP.EUC EUC-JP" + echo "ja_JP.SJIS SHIFT_JIS" + echo "ko_KR.EUC EUC-KR" + ;; + darwin*) + # Darwin 7.5 has nl_langinfo(CODESET), but sometimes its value is + # useless: + # - It returns the empty string when LANG is set to a locale of the + # form ll_CC, although ll_CC/LC_CTYPE is a symlink to an UTF-8 + # LC_CTYPE file. + # - The environment variables LANG, LC_CTYPE, LC_ALL are not set by + # the system; nl_langinfo(CODESET) returns "US-ASCII" in this case. + # - The documentation says: + # "... all code that calls BSD system routines should ensure + # that the const *char parameters of these routines are in UTF-8 + # encoding. All BSD system functions expect their string + # parameters to be in UTF-8 encoding and nothing else." + # It also says + # "An additional caveat is that string parameters for files, + # paths, and other file-system entities must be in canonical + # UTF-8. In a canonical UTF-8 Unicode string, all decomposable + # characters are decomposed ..." + # but this is not true: You can pass non-decomposed UTF-8 strings + # to file system functions, and it is the OS which will convert + # them to decomposed UTF-8 before accessing the file system. + # - The Apple Terminal application displays UTF-8 by default. + # - However, other applications are free to use different encodings: + # - xterm uses ISO-8859-1 by default. + # - TextEdit uses MacRoman by default. + # We prefer UTF-8 over decomposed UTF-8-MAC because one should + # minimize the use of decomposed Unicode. Unfortunately, through the + # Darwin file system, decomposed UTF-8 strings are leaked into user + # space nevertheless. + # Then there are also the locales with encodings other than US-ASCII + # and UTF-8. These locales can be occasionally useful to users (e.g. + # when grepping through ISO-8859-1 encoded text files), when all their + # file names are in US-ASCII. + echo "ISO8859-1 ISO-8859-1" + echo "ISO8859-2 ISO-8859-2" + echo "ISO8859-4 ISO-8859-4" + echo "ISO8859-5 ISO-8859-5" + echo "ISO8859-7 ISO-8859-7" + echo "ISO8859-9 ISO-8859-9" + echo "ISO8859-13 ISO-8859-13" + echo "ISO8859-15 ISO-8859-15" + echo "KOI8-R KOI8-R" + echo "KOI8-U KOI8-U" + echo "CP866 CP866" + echo "CP949 CP949" + echo "CP1131 CP1131" + echo "CP1251 CP1251" + echo "eucCN GB2312" + echo "GB2312 GB2312" + echo "eucJP EUC-JP" + echo "eucKR EUC-KR" + echo "Big5 BIG5" + echo "Big5HKSCS BIG5-HKSCS" + echo "GBK GBK" + echo "GB18030 GB18030" + echo "SJIS SHIFT_JIS" + echo "ARMSCII-8 ARMSCII-8" + echo "PT154 PT154" + #echo "ISCII-DEV ?" + echo "* UTF-8" + ;; + beos* | haiku*) + # BeOS and Haiku have a single locale, and it has UTF-8 encoding. + echo "* UTF-8" + ;; + msdosdjgpp*) + # DJGPP 2.03 doesn't have nl_langinfo(CODESET); therefore + # localcharset.c falls back to using the full locale name + # from the environment variables. + echo "#" + echo "# The encodings given here may not all be correct." + echo "# If you find that the encoding given for your language and" + echo "# country is not the one your DOS machine actually uses, just" + echo "# correct it in this file, and send a mail to" + echo "# Juan Manuel Guerrero <juan.guerrero@gmx.de>" + echo "# and Bruno Haible <bruno@clisp.org>." + echo "#" + echo "C ASCII" + # ISO-8859-1 languages + echo "ca CP850" + echo "ca_ES CP850" + echo "da CP865" # not CP850 ?? + echo "da_DK CP865" # not CP850 ?? + echo "de CP850" + echo "de_AT CP850" + echo "de_CH CP850" + echo "de_DE CP850" + echo "en CP850" + echo "en_AU CP850" # not CP437 ?? + echo "en_CA CP850" + echo "en_GB CP850" + echo "en_NZ CP437" + echo "en_US CP437" + echo "en_ZA CP850" # not CP437 ?? + echo "es CP850" + echo "es_AR CP850" + echo "es_BO CP850" + echo "es_CL CP850" + echo "es_CO CP850" + echo "es_CR CP850" + echo "es_CU CP850" + echo "es_DO CP850" + echo "es_EC CP850" + echo "es_ES CP850" + echo "es_GT CP850" + echo "es_HN CP850" + echo "es_MX CP850" + echo "es_NI CP850" + echo "es_PA CP850" + echo "es_PY CP850" + echo "es_PE CP850" + echo "es_SV CP850" + echo "es_UY CP850" + echo "es_VE CP850" + echo "et CP850" + echo "et_EE CP850" + echo "eu CP850" + echo "eu_ES CP850" + echo "fi CP850" + echo "fi_FI CP850" + echo "fr CP850" + echo "fr_BE CP850" + echo "fr_CA CP850" + echo "fr_CH CP850" + echo "fr_FR CP850" + echo "ga CP850" + echo "ga_IE CP850" + echo "gd CP850" + echo "gd_GB CP850" + echo "gl CP850" + echo "gl_ES CP850" + echo "id CP850" # not CP437 ?? + echo "id_ID CP850" # not CP437 ?? + echo "is CP861" # not CP850 ?? + echo "is_IS CP861" # not CP850 ?? + echo "it CP850" + echo "it_CH CP850" + echo "it_IT CP850" + echo "lt CP775" + echo "lt_LT CP775" + echo "lv CP775" + echo "lv_LV CP775" + echo "nb CP865" # not CP850 ?? + echo "nb_NO CP865" # not CP850 ?? + echo "nl CP850" + echo "nl_BE CP850" + echo "nl_NL CP850" + echo "nn CP865" # not CP850 ?? + echo "nn_NO CP865" # not CP850 ?? + echo "no CP865" # not CP850 ?? + echo "no_NO CP865" # not CP850 ?? + echo "pt CP850" + echo "pt_BR CP850" + echo "pt_PT CP850" + echo "sv CP850" + echo "sv_SE CP850" + # ISO-8859-2 languages + echo "cs CP852" + echo "cs_CZ CP852" + echo "hr CP852" + echo "hr_HR CP852" + echo "hu CP852" + echo "hu_HU CP852" + echo "pl CP852" + echo "pl_PL CP852" + echo "ro CP852" + echo "ro_RO CP852" + echo "sk CP852" + echo "sk_SK CP852" + echo "sl CP852" + echo "sl_SI CP852" + echo "sq CP852" + echo "sq_AL CP852" + echo "sr CP852" # CP852 or CP866 or CP855 ?? + echo "sr_CS CP852" # CP852 or CP866 or CP855 ?? + echo "sr_YU CP852" # CP852 or CP866 or CP855 ?? + # ISO-8859-3 languages + echo "mt CP850" + echo "mt_MT CP850" + # ISO-8859-5 languages + echo "be CP866" + echo "be_BE CP866" + echo "bg CP866" # not CP855 ?? + echo "bg_BG CP866" # not CP855 ?? + echo "mk CP866" # not CP855 ?? + echo "mk_MK CP866" # not CP855 ?? + echo "ru CP866" + echo "ru_RU CP866" + echo "uk CP1125" + echo "uk_UA CP1125" + # ISO-8859-6 languages + echo "ar CP864" + echo "ar_AE CP864" + echo "ar_DZ CP864" + echo "ar_EG CP864" + echo "ar_IQ CP864" + echo "ar_IR CP864" + echo "ar_JO CP864" + echo "ar_KW CP864" + echo "ar_MA CP864" + echo "ar_OM CP864" + echo "ar_QA CP864" + echo "ar_SA CP864" + echo "ar_SY CP864" + # ISO-8859-7 languages + echo "el CP869" + echo "el_GR CP869" + # ISO-8859-8 languages + echo "he CP862" + echo "he_IL CP862" + # ISO-8859-9 languages + echo "tr CP857" + echo "tr_TR CP857" + # Japanese + echo "ja CP932" + echo "ja_JP CP932" + # Chinese + echo "zh_CN GBK" + echo "zh_TW CP950" # not CP938 ?? + # Korean + echo "kr CP949" # not CP934 ?? + echo "kr_KR CP949" # not CP934 ?? + # Thai + echo "th CP874" + echo "th_TH CP874" + # Other + echo "eo CP850" + echo "eo_EO CP850" + ;; +esac diff --git a/src/libs/libgroff/cset.cpp b/src/libs/libgroff/cset.cpp new file mode 100644 index 0000000..6702237 --- /dev/null +++ b/src/libs/libgroff/cset.cpp @@ -0,0 +1,104 @@ +// -*- C++ -*- +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> +#include <ctype.h> + +#include "lib.h" +#include "cset.h" + +cset csalpha(CSET_BUILTIN); +cset csupper(CSET_BUILTIN); +cset cslower(CSET_BUILTIN); +cset csdigit(CSET_BUILTIN); +cset csxdigit(CSET_BUILTIN); +cset csspace(CSET_BUILTIN); +cset cspunct(CSET_BUILTIN); +cset csalnum(CSET_BUILTIN); +cset csprint(CSET_BUILTIN); +cset csgraph(CSET_BUILTIN); +cset cscntrl(CSET_BUILTIN); + +#ifdef isascii +#define ISASCII(c) isascii(c) +#else +#define ISASCII(c) (1) +#endif + +void cset::clear() +{ + char *p = v; + for (int i = 0; i <= UCHAR_MAX; i++) + p[i] = 0; +} + +cset::cset() +{ + clear(); +} + +cset::cset(const char *s) +{ + clear(); + while (*s) + v[(unsigned char)*s++] = 1; +} + +cset::cset(const unsigned char *s) +{ + clear(); + while (*s) + v[*s++] = 1; +} + +cset::cset(cset_builtin) +{ + // these are initialised by cset_init::cset_init() +} + +cset &cset::operator|=(const cset &cs) +{ + for (int i = 0; i <= UCHAR_MAX; i++) + if (cs.v[i]) + v[i] = 1; + return *this; +} + + +int cset_init::initialised = 0; + +cset_init::cset_init() +{ + if (initialised) + return; + initialised = 1; + for (int i = 0; i <= UCHAR_MAX; i++) { + csalpha.v[i] = ISASCII(i) && isalpha(i); + csupper.v[i] = ISASCII(i) && isupper(i); + cslower.v[i] = ISASCII(i) && islower(i); + csdigit.v[i] = ISASCII(i) && isdigit(i); + csxdigit.v[i] = ISASCII(i) && isxdigit(i); + csspace.v[i] = ISASCII(i) && isspace(i); + cspunct.v[i] = ISASCII(i) && ispunct(i); + csalnum.v[i] = ISASCII(i) && isalnum(i); + csprint.v[i] = ISASCII(i) && isprint(i); + csgraph.v[i] = ISASCII(i) && isgraph(i); + cscntrl.v[i] = ISASCII(i) && iscntrl(i); + } +} diff --git a/src/libs/libgroff/curtime.cpp b/src/libs/libgroff/curtime.cpp new file mode 100644 index 0000000..34dbc5c --- /dev/null +++ b/src/libs/libgroff/curtime.cpp @@ -0,0 +1,55 @@ +/* Copyright (C) 2015-2020 Free Software Foundation, Inc. + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 2 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +The GNU General Public License version 2 (GPL2) is available in the +internet at <http://www.gnu.org/licenses/gpl-2.0.txt>. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "errarg.h" +#include "error.h" + +#ifdef LONG_FOR_TIME_T +long +#else +time_t +#endif +current_time() +{ + char *source_date_epoch = getenv("SOURCE_DATE_EPOCH"); + + if (source_date_epoch) { + errno = 0; + char *endptr; + long epoch = strtol(source_date_epoch, &endptr, 10); + + if ((errno == ERANGE && (epoch == LONG_MAX || epoch == LONG_MIN)) || + (errno != 0 && epoch == 0)) + fatal("$SOURCE_DATE_EPOCH: strtol: %1", strerror(errno)); + if (endptr == source_date_epoch) + fatal("$SOURCE_DATE_EPOCH: no digits found: '%1'", endptr); + if (*endptr != '\0') + fatal("$SOURCE_DATE_EPOCH: trailing garbage: '%1'", endptr); + return epoch; + } else + return time(0); +} diff --git a/src/libs/libgroff/device.cpp b/src/libs/libgroff/device.cpp new file mode 100644 index 0000000..6caeb8e --- /dev/null +++ b/src/libs/libgroff/device.cpp @@ -0,0 +1,39 @@ +// -*- C++ -*- +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include "device.h" +#include "defs.h" + +const char *device = DEVICE; + +struct device_init { + device_init(); +} _device_init; + +device_init::device_init() +{ + char *tem = getenv("GROFF_TYPESETTER"); + if (tem && tem[0]) + device = tem; +} diff --git a/src/libs/libgroff/errarg.cpp b/src/libs/libgroff/errarg.cpp new file mode 100644 index 0000000..99fc0fa --- /dev/null +++ b/src/libs/libgroff/errarg.cpp @@ -0,0 +1,136 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <assert.h> +#include <stdio.h> + +#include "errarg.h" + +errarg::errarg(const char *p) : type(STRING) +{ + s = p ? p : "(null)"; +} + +errarg::errarg() : type(EMPTY) +{ +} + +errarg::errarg(int nn) : type(INTEGER) +{ + n = nn; +} + +errarg::errarg(unsigned int uu) : type(UNSIGNED_INTEGER) +{ + u = uu; +} + +errarg::errarg(char cc) : type(CHAR) +{ + c = cc; +} + +errarg::errarg(unsigned char cc) : type(CHAR) +{ + c = cc; +} + +errarg::errarg(double dd) : type(DOUBLE) +{ + d = dd; +} + +int errarg::empty() const +{ + return type == EMPTY; +} + +extern "C" { + const char *i_to_a(int); + const char *ui_to_a(unsigned int); +} + +void errarg::print() const +{ + switch (type) { + case INTEGER: + fputs(i_to_a(n), stderr); + break; + case UNSIGNED_INTEGER: + fputs(ui_to_a(u), stderr); + break; + case CHAR: + putc(c, stderr); + break; + case STRING: + fputs(s, stderr); + break; + case DOUBLE: + fprintf(stderr, "%g", d); + break; + case EMPTY: + break; + } +} + +errarg empty_errarg; + +void errprint(const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + assert(format != 0); + char c; + while ((c = *format++) != '\0') { + if (c == '%') { + c = *format++; + switch(c) { + case '%': + fputc('%', stderr); + break; + case '1': + assert(!arg1.empty()); + arg1.print(); + break; + case '2': + assert(!arg2.empty()); + arg2.print(); + break; + case '3': + assert(!arg3.empty()); + arg3.print(); + break; + default: + assert(0 == "unsupported argument conversion (not in [%123])"); + } + } + else + putc(c, stderr); + } +} + +// Local Variables: +// fill-column: 72 +// mode: C++ +// End: +// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: diff --git a/src/libs/libgroff/error.cpp b/src/libs/libgroff/error.cpp new file mode 100644 index 0000000..b1a4e61 --- /dev/null +++ b/src/libs/libgroff/error.cpp @@ -0,0 +1,185 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "errarg.h" +#include "error.h" + +extern void fatal_error_exit(); + +enum error_type { DEBUG, WARNING, ERROR, FATAL }; + +static void do_error_with_file_and_line(const char *filename, + const char *source_filename, + int lineno, + error_type type, + const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + bool need_space = false; + if (program_name != 0 /* nullptr */) { + fputs(program_name, stderr); + fputc(':', stderr); + need_space = true; + } + if (filename != 0 /* nullptr */) { + if (strcmp(filename, "-") == 0) + filename = "<standard input>"; + fputs(filename, stderr); + if (source_filename != 0 /* nullptr */) { + fputs(":(", stderr); + fputs(source_filename, stderr); + fputc(')', stderr); + } + if (lineno > 0) { + fputc(':', stderr); + errprint("%1", lineno); + } + fputc(':', stderr); + need_space = true; + } + if (need_space) + fputc(' ', stderr); + switch (type) { + case FATAL: + fputs("fatal error", stderr); + break; + case ERROR: + fputs("error", stderr); + break; + case WARNING: + fputs("warning", stderr); + break; + case DEBUG: + fputs("debug", stderr); + break; + } + fputs(": ", stderr); + errprint(format, arg1, arg2, arg3); + fputc('\n', stderr); + fflush(stderr); + if (type == FATAL) + fatal_error_exit(); +} + +static void do_error(error_type type, + const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + do_error_with_file_and_line(current_filename, current_source_filename, + current_lineno, type, format, arg1, arg2, + arg3); +} + +void debug(const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + do_error(DEBUG, format, arg1, arg2, arg3); +} + +void error(const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + do_error(ERROR, format, arg1, arg2, arg3); +} + +void warning(const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + do_error(WARNING, format, arg1, arg2, arg3); +} + +void fatal(const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + do_error(FATAL, format, arg1, arg2, arg3); +} + +// Use the functions below when it's more costly to save and restore the +// globals current_filename, current_source_filename, and current_lineno +// than to specify additional arguments. For instance, a function that +// would need to temporarily change their values and has multiple return +// paths might prefer these to the simpler variants above. + +void debug_with_file_and_line(const char *filename, + int lineno, + const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + do_error_with_file_and_line(filename, 0 /* nullptr */, lineno, + DEBUG, format, arg1, arg2, arg3); +} + +void error_with_file_and_line(const char *filename, + int lineno, + const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + do_error_with_file_and_line(filename, 0 /* nullptr */, lineno, + ERROR, format, arg1, arg2, arg3); +} + +void warning_with_file_and_line(const char *filename, + int lineno, + const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + do_error_with_file_and_line(filename, 0 /* nullptr */, lineno, + WARNING, format, arg1, arg2, arg3); +} + +void fatal_with_file_and_line(const char *filename, + int lineno, + const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + do_error_with_file_and_line(filename, 0 /* nullptr */, lineno, + FATAL, format, arg1, arg2, arg3); +} + +// Local Variables: +// fill-column: 72 +// mode: C++ +// End: +// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: diff --git a/src/libs/libgroff/fatal.cpp b/src/libs/libgroff/fatal.cpp new file mode 100644 index 0000000..1cbf3ef --- /dev/null +++ b/src/libs/libgroff/fatal.cpp @@ -0,0 +1,30 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> + +#define FATAL_ERROR_EXIT_CODE 3 + +void fatal_error_exit() +{ + exit(FATAL_ERROR_EXIT_CODE); +} diff --git a/src/libs/libgroff/filename.cpp b/src/libs/libgroff/filename.cpp new file mode 100644 index 0000000..ded9738 --- /dev/null +++ b/src/libs/libgroff/filename.cpp @@ -0,0 +1,31 @@ +/* Copyright (C) 2014-2022 Free Software Foundation, Inc. + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +// This global stores the name of the input file being processed by +// troff, an output driver, or other program. +const char *current_filename = 0 /* nullptr */; + +// This global stores the name of the troff input file corresponding to +// the part of a device-independent troff output being processed; it is +// used only by output drivers. +const char *current_source_filename = 0 /* nullptr */; + +// Local Variables: +// fill-column: 72 +// mode: C++ +// End: +// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: diff --git a/src/libs/libgroff/fmod.c b/src/libs/libgroff/fmod.c new file mode 100644 index 0000000..45278f9 --- /dev/null +++ b/src/libs/libgroff/fmod.c @@ -0,0 +1,27 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> +#include <math.h> + +double fmod(x, y) + double x, y; +{ + double quot = x/y; + return x - (quot < 0.0 ? ceil(quot) : floor(quot)) * y; +} diff --git a/src/libs/libgroff/font.cpp b/src/libs/libgroff/font.cpp new file mode 100644 index 0000000..c1af12c --- /dev/null +++ b/src/libs/libgroff/font.cpp @@ -0,0 +1,1321 @@ +/* Copyright (C) 1989-2021 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "lib.h" + +#include <assert.h> +#include <ctype.h> +#include <math.h> +#include <stdlib.h> +#include <wchar.h> + +#include "errarg.h" +#include "error.h" +#include "cset.h" +#include "font.h" +#include "unicode.h" +#include "paper.h" + +const char *const WS = " \t\n\r"; + +struct font_char_metric { + char type; + int code; + int width; + int height; + int depth; + int pre_math_space; + int italic_correction; + int subscript_correction; + char *special_device_coding; +}; + +struct font_kern_list { + glyph *glyph1; + glyph *glyph2; + int amount; + font_kern_list *next; + + font_kern_list(glyph *, glyph *, int, font_kern_list * = 0); +}; + +struct font_widths_cache { + font_widths_cache *next; + int point_size; + int *width; + + font_widths_cache(int, int, font_widths_cache * = 0); + ~font_widths_cache(); +}; + +/* text_file */ + +struct text_file { + FILE *fp; + char *path; + int lineno; + int linebufsize; + bool recognize_comments; + bool silent; + char *buf; + text_file(FILE *fp, char *p); + ~text_file(); + bool next_line(); + void error(const char *format, + const errarg &arg1 = empty_errarg, + const errarg &arg2 = empty_errarg, + const errarg &arg3 = empty_errarg); + void fatal(const char *format, + const errarg &arg1 = empty_errarg, + const errarg &arg2 = empty_errarg, + const errarg &arg3 = empty_errarg); +}; + +text_file::text_file(FILE *p, char *s) : fp(p), path(s), lineno(0), + linebufsize(128), recognize_comments(true), silent(false), buf(0) +{ +} + +text_file::~text_file() +{ + delete[] buf; + free(path); + if (fp) + fclose(fp); +} + +bool text_file::next_line() +{ + if (fp == 0) + return false; + if (buf == 0) + buf = new char[linebufsize]; + for (;;) { + lineno++; + int length = 0; + for (;;) { + int c = getc(fp); + if (c == EOF) + break; + if (is_invalid_input_char(c)) + error("invalid input character code %1", int(c)); + else { + if (length + 1 >= linebufsize) { + char *old_buf = buf; + buf = new char[linebufsize * 2]; + memcpy(buf, old_buf, linebufsize); + delete[] old_buf; + linebufsize *= 2; + } + buf[length++] = c; + if (c == '\n') + break; + } + } + if (length == 0) + break; + buf[length] = '\0'; + char *ptr = buf; + while (csspace(*ptr)) + ptr++; + if (*ptr != 0 && (!recognize_comments || *ptr != '#')) + return true; + } + return false; +} + +void text_file::error(const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + if (!silent) + error_with_file_and_line(path, lineno, format, arg1, arg2, arg3); +} + +void text_file::fatal(const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + if (!silent) + fatal_with_file_and_line(path, lineno, format, arg1, arg2, arg3); +} + +int glyph_to_unicode(glyph *g) +{ + const char *nm = glyph_to_name(g); + if (nm != 0) { + // ASCII character? + if (nm[0] == 'c' && nm[1] == 'h' && nm[2] == 'a' && nm[3] == 'r' + && (nm[4] >= '0' && nm[4] <= '9')) { + int n = (nm[4] - '0'); + if (nm[5] == '\0') + return n; + if (n > 0 && (nm[5] >= '0' && nm[5] <= '9')) { + n = 10*n + (nm[5] - '0'); + if (nm[6] == '\0') + return n; + if (nm[6] >= '0' && nm[6] <= '9') { + n = 10*n + (nm[6] - '0'); + if (nm[7] == '\0' && n < 128) + return n; + } + } + } + // Unicode character? + if (check_unicode_name(nm)) { + char *ignore; + return (int)strtol(nm + 1, &ignore, 16); + } + // If 'nm' is a single letter 'x', the glyph name is '\x'. + char buf[] = { '\\', '\0', '\0' }; + if (nm[1] == '\0') { + buf[1] = nm[0]; + nm = buf; + } + // groff glyphs that map to Unicode? + const char *unicode = glyph_name_to_unicode(nm); + if (unicode != 0 && strchr(unicode, '_') == 0) { + char *ignore; + return (int)strtol(unicode, &ignore, 16); + } + } + return -1; +} + +/* font functions */ + +font::font(const char *s) : ligatures(0), kern_hash_table(0), + space_width(0), special(false), internalname(0), slant(0.0), zoom(0), + ch_index(0), nindices(0), ch(0), ch_used(0), ch_size(0), + widths_cache(0) +{ + name = new char[strlen(s) + 1]; + strcpy(name, s); +} + +font::~font() +{ + for (int i = 0; i < ch_used; i++) + if (ch[i].special_device_coding) + delete[] ch[i].special_device_coding; + delete[] ch; + delete[] ch_index; + if (kern_hash_table) { + for (int i = 0; i < KERN_HASH_TABLE_SIZE; i++) { + font_kern_list *kerns = kern_hash_table[i]; + while (kerns) { + font_kern_list *tem = kerns; + kerns = kerns->next; + delete tem; + } + } + delete[] kern_hash_table; + } + delete[] name; + delete[] internalname; + while (widths_cache) { + font_widths_cache *tem = widths_cache; + widths_cache = widths_cache->next; + delete tem; + } +} + +static int scale_round(int n, int x, int y) +{ + assert(x >= 0 && y > 0); + int y2 = y/2; + if (x == 0) + return 0; + if (n >= 0) { + if (n <= (INT_MAX - y2) / x) + return (n * x + y2) / y; + return int(n * double(x) / double(y) + .5); + } + else { + if (-(unsigned)n <= (-(unsigned)INT_MIN - y2) / x) + return (n * x - y2) / y; + return int(n * double(x) / double(y) - .5); + } +} + +static int scale_round(int n, int x, int y, int z) +{ + assert(x >= 0 && y > 0 && z > 0); + if (x == 0) + return 0; + if (n >= 0) + return int((n * double(x) / double(y)) * (double(z) / 1000.0) + .5); + else + return int((n * double(x) / double(y)) * (double(z) / 1000.0) - .5); +} + +inline int font::scale(int w, int sz) +{ + if (zoom) + return scale_round(w, sz, unitwidth, zoom); + else + return sz == unitwidth ? w : scale_round(w, sz, unitwidth); +} + +// Returns whether scaling by arguments was successful. Used for paper +// size conversions. +bool font::unit_scale(double *value, char unit) +{ + // Paper sizes are handled in inches. + double divisor = 0; + switch (unit) { + case 'i': + divisor = 1; + break; + case 'p': + divisor = 72; + break; + case 'P': + divisor = 6; + break; + case 'c': + divisor = 2.54; + break; + default: + assert(0 == "unit not in [cipP]"); + break; + } + if (divisor) { + *value /= divisor; + return true; + } + return false; +} + +int font::get_skew(glyph *g, int point_size, int sl) +{ + int h = get_height(g, point_size); + return int(h * tan((slant + sl) * PI / 180.0) + .5); +} + +bool font::contains(glyph *g) +{ + int idx = glyph_to_index(g); + assert(idx >= 0); + // Explicitly enumerated glyph? + if (idx < nindices && ch_index[idx] >= 0) + return true; + if (is_unicode) { + // Unicode font + // ASCII or Unicode character, or groff glyph name that maps to Unicode? + if (glyph_to_unicode(g) >= 0) + return true; + // Numbered character? + if (glyph_to_number(g) >= 0) + return true; + } + return false; +} + +bool font::is_special() +{ + return special; +} + +font_widths_cache::font_widths_cache(int ps, int ch_size, + font_widths_cache *p) +: next(p), point_size(ps) +{ + width = new int[ch_size]; + for (int i = 0; i < ch_size; i++) + width[i] = -1; +} + +font_widths_cache::~font_widths_cache() +{ + delete[] width; +} + +int font::get_width(glyph *g, int point_size) +{ + int idx = glyph_to_index(g); + assert(idx >= 0); + int real_size; + if (zoom == 0) // 0 means "don't zoom" + real_size = point_size; + else + { + if (point_size <= (INT_MAX - 500) / zoom) + real_size = (point_size * zoom + 500) / 1000; + else + real_size = int(point_size * double(zoom) / 1000.0 + .5); + } + if (idx < nindices && ch_index[idx] >= 0) { + // Explicitly enumerated glyph + int i = ch_index[idx]; + if (real_size == unitwidth || font::use_unscaled_charwidths) + return ch[i].width; + + if (!widths_cache) + widths_cache = new font_widths_cache(real_size, ch_size); + else if (widths_cache->point_size != real_size) { + font_widths_cache **p; + for (p = &widths_cache; *p; p = &(*p)->next) + if ((*p)->point_size == real_size) + break; + if (*p) { + font_widths_cache *tem = *p; + *p = (*p)->next; + tem->next = widths_cache; + widths_cache = tem; + } + else + widths_cache = new font_widths_cache(real_size, ch_size, + widths_cache); + } + int &w = widths_cache->width[i]; + if (w < 0) + w = scale(ch[i].width, point_size); + return w; + } + if (is_unicode) { + // Unicode font + int width = 24; // XXX: Add a request to override this. + int w = wcwidth(get_code(g)); + if (w > 1) + width *= w; + if (real_size == unitwidth || font::use_unscaled_charwidths) + return width; + else + return scale(width, point_size); + } + assert(0 == "glyph is not indexed and device lacks Unicode support"); + abort(); // -Wreturn-type +} + +int font::get_height(glyph *g, int point_size) +{ + int idx = glyph_to_index(g); + assert(idx >= 0); + if (idx < nindices && ch_index[idx] >= 0) { + // Explicitly enumerated glyph + return scale(ch[ch_index[idx]].height, point_size); + } + if (is_unicode) { + // Unicode font + return 0; + } + assert(0 == "glyph is not indexed and device lacks Unicode support"); + abort(); // -Wreturn-type +} + +int font::get_depth(glyph *g, int point_size) +{ + int idx = glyph_to_index(g); + assert(idx >= 0); + if (idx < nindices && ch_index[idx] >= 0) { + // Explicitly enumerated glyph + return scale(ch[ch_index[idx]].depth, point_size); + } + if (is_unicode) { + // Unicode font + return 0; + } + assert(0 == "glyph is not indexed and device lacks Unicode support"); + abort(); // -Wreturn-type +} + +int font::get_italic_correction(glyph *g, int point_size) +{ + int idx = glyph_to_index(g); + assert(idx >= 0); + if (idx < nindices && ch_index[idx] >= 0) { + // Explicitly enumerated glyph + return scale(ch[ch_index[idx]].italic_correction, point_size); + } + if (is_unicode) { + // Unicode font + return 0; + } + assert(0 == "glyph is not indexed and device lacks Unicode support"); + abort(); // -Wreturn-type +} + +int font::get_left_italic_correction(glyph *g, int point_size) +{ + int idx = glyph_to_index(g); + assert(idx >= 0); + if (idx < nindices && ch_index[idx] >= 0) { + // Explicitly enumerated glyph + return scale(ch[ch_index[idx]].pre_math_space, point_size); + } + if (is_unicode) { + // Unicode font + return 0; + } + assert(0 == "glyph is not indexed and device lacks Unicode support"); + abort(); // -Wreturn-type +} + +int font::get_subscript_correction(glyph *g, int point_size) +{ + int idx = glyph_to_index(g); + assert(idx >= 0); + if (idx < nindices && ch_index[idx] >= 0) { + // Explicitly enumerated glyph + return scale(ch[ch_index[idx]].subscript_correction, point_size); + } + if (is_unicode) { + // Unicode font + return 0; + } + assert(0 == "glyph is not indexed and device lacks Unicode support"); + abort(); // -Wreturn-type +} + +void font::set_zoom(int factor) +{ + assert(factor >= 0); + if (factor == 1000) + zoom = 0; + else + zoom = factor; +} + +int font::get_zoom() +{ + return zoom; +} + +int font::get_space_width(int point_size) +{ + return scale(space_width, point_size); +} + +font_kern_list::font_kern_list(glyph *g1, glyph *g2, int n, font_kern_list *p) +: glyph1(g1), glyph2(g2), amount(n), next(p) +{ +} + +inline int font::hash_kern(glyph *g1, glyph *g2) +{ + int n = ((glyph_to_index(g1) << 10) + glyph_to_index(g2)) + % KERN_HASH_TABLE_SIZE; + return n < 0 ? -n : n; +} + +void font::add_kern(glyph *g1, glyph *g2, int amount) +{ + if (!kern_hash_table) { + kern_hash_table = new font_kern_list *[int(KERN_HASH_TABLE_SIZE)]; + for (int i = 0; i < KERN_HASH_TABLE_SIZE; i++) + kern_hash_table[i] = 0; + } + font_kern_list **p = kern_hash_table + hash_kern(g1, g2); + *p = new font_kern_list(g1, g2, amount, *p); +} + +int font::get_kern(glyph *g1, glyph *g2, int point_size) +{ + if (kern_hash_table) { + for (font_kern_list *p = kern_hash_table[hash_kern(g1, g2)]; p; + p = p->next) + if (g1 == p->glyph1 && g2 == p->glyph2) + return scale(p->amount, point_size); + } + return 0; +} + +bool font::has_ligature(int mask) +{ + return (bool) (mask & ligatures); +} + +int font::get_character_type(glyph *g) +{ + int idx = glyph_to_index(g); + assert(idx >= 0); + if (idx < nindices && ch_index[idx] >= 0) { + // Explicitly enumerated glyph + return ch[ch_index[idx]].type; + } + if (is_unicode) { + // Unicode font + return 0; + } + assert(0 == "glyph is not indexed and device lacks Unicode support"); + abort(); // -Wreturn-type +} + +int font::get_code(glyph *g) +{ + int idx = glyph_to_index(g); + assert(idx >= 0); + if (idx < nindices && ch_index[idx] >= 0) { + // Explicitly enumerated glyph + return ch[ch_index[idx]].code; + } + if (is_unicode) { + // Unicode font + // ASCII or Unicode character, or groff glyph name that maps to Unicode? + int uni = glyph_to_unicode(g); + if (uni >= 0) + return uni; + // Numbered character? + int n = glyph_to_number(g); + if (n >= 0) + return n; + } + // The caller must check 'contains(g)' before calling get_code(g). + assert(0 == "glyph is not indexed and device lacks Unicode support"); + abort(); // -Wreturn-type +} + +const char *font::get_name() +{ + return name; +} + +const char *font::get_internal_name() +{ + return internalname; +} + +const char *font::get_special_device_encoding(glyph *g) +{ + int idx = glyph_to_index(g); + assert(idx >= 0); + if (idx < nindices && ch_index[idx] >= 0) { + // Explicitly enumerated glyph + return ch[ch_index[idx]].special_device_coding; + } + if (is_unicode) { + // Unicode font + return 0; + } + assert(0 == "glyph is not indexed and device lacks Unicode support"); + abort(); // -Wreturn-type +} + +const char *font::get_image_generator() +{ + return image_generator; +} + +void font::alloc_ch_index(int idx) +{ + if (nindices == 0) { + nindices = 128; + if (idx >= nindices) + nindices = idx + 10; + ch_index = new int[nindices]; + for (int i = 0; i < nindices; i++) + ch_index[i] = -1; + } + else { + int old_nindices = nindices; + nindices *= 2; + if (idx >= nindices) + nindices = idx + 10; + int *old_ch_index = ch_index; + ch_index = new int[nindices]; + memcpy(ch_index, old_ch_index, sizeof(int) * old_nindices); + for (int i = old_nindices; i < nindices; i++) + ch_index[i] = -1; + delete[] old_ch_index; + } +} + +void font::extend_ch() +{ + if (ch == 0) + ch = new font_char_metric[ch_size = 16]; + else { + int old_ch_size = ch_size; + ch_size *= 2; + font_char_metric *old_ch = ch; + ch = new font_char_metric[ch_size]; + memcpy(ch, old_ch, old_ch_size * sizeof(font_char_metric)); + delete[] old_ch; + } +} + +void font::compact() +{ + int i; + for (i = nindices - 1; i >= 0; i--) + if (ch_index[i] >= 0) + break; + i++; + if (i < nindices) { + int *old_ch_index = ch_index; + ch_index = new int[i]; + memcpy(ch_index, old_ch_index, i*sizeof(int)); + delete[] old_ch_index; + nindices = i; + } + if (ch_used < ch_size) { + font_char_metric *old_ch = ch; + ch = new font_char_metric[ch_used]; + memcpy(ch, old_ch, ch_used*sizeof(font_char_metric)); + delete[] old_ch; + ch_size = ch_used; + } +} + +void font::add_entry(glyph *g, const font_char_metric &metric) +{ + int idx = glyph_to_index(g); + assert(idx >= 0); + if (idx >= nindices) + alloc_ch_index(idx); + assert(idx < nindices); + if (ch_used + 1 >= ch_size) + extend_ch(); + assert(ch_used + 1 < ch_size); + ch_index[idx] = ch_used; + ch[ch_used++] = metric; +} + +void font::copy_entry(glyph *new_glyph, glyph *old_glyph) +{ + int new_index = glyph_to_index(new_glyph); + int old_index = glyph_to_index(old_glyph); + assert(new_index >= 0 && old_index >= 0 && old_index < nindices); + if (new_index >= nindices) + alloc_ch_index(new_index); + ch_index[new_index] = ch_index[old_index]; +} + +font *font::load_font(const char *s, bool load_header_only) +{ + font *f = new font(s); + if (!f->load(load_header_only)) { + delete f; + return 0; + } + return f; +} + +static char *trim_arg(char *p) +{ + if (0 == p) + return 0; + while (csspace(*p)) + p++; + char *q = strchr(p, '\0'); + while (q > p && csspace(q[-1])) + q--; + *q = '\0'; + return p; +} + +bool font::scan_papersize(const char *p, const char **size, + double *length, double *width) +{ + double l, w; + char lu[2], wu[2]; + const char *pp = p; + bool attempt_file_open = true; + char line[255]; +again: + if (csdigit(*pp)) { + if (sscanf(pp, "%lf%1[ipPc],%lf%1[ipPc]", &l, lu, &w, wu) == 4 + && l > 0 && w > 0 + && unit_scale(&l, lu[0]) && unit_scale(&w, wu[0])) { + if (length) + *length = l; + if (width) + *width = w; + if (size) + *size = "custom"; + return true; + } + } + else { + int i; + for (i = 0; i < NUM_PAPERSIZES; i++) + if (strcasecmp(papersizes[i].name, pp) == 0) { + if (length) + *length = papersizes[i].length; + if (width) + *width = papersizes[i].width; + if (size) + *size = papersizes[i].name; + return true; + } + if (attempt_file_open) { + FILE *fp = fopen(p, "r"); + if (fp != 0) { + if (fgets(line, 254, fp)) { + // Don't recurse on file names. + attempt_file_open = false; + char *linep = strchr(line, '\0'); + // skip final newline, if any + if (*(--linep) == '\n') + *linep = '\0'; + pp = line; + } + fclose(fp); + goto again; + } + } + } + return false; +} + +bool font::load(bool load_header_only) +{ + FILE *fp; + char *path; + if ((fp = open_file(name, &path)) == 0) + return false; + text_file t(fp, path); + t.silent = load_header_only; + char *p = 0; + bool saw_name_directive = false; + while (t.next_line()) { + p = strtok(t.buf, WS); + if (strcmp(p, "name") == 0) { + p = strtok(0, WS); + if (0 == p) { + t.error("'name' directive requires an argument"); + return false; + } + if (strcmp(p, name) != 0) { + t.error("font description file name '%1' does not match 'name'" + " argument '%2'", name, p); + return false; + } + saw_name_directive = true; + } + else if (strcmp(p, "spacewidth") == 0) { + p = strtok(0, WS); + int n; + if (0 == p) { + t.error("missing argument to 'spacewidth' directive"); + return false; + } + if (sscanf(p, "%d", &n) != 1) { + t.error("invalid argument '%1' to 'spacewidth' directive", p); + return false; + } + if (n <= 0) { + t.error("'spacewidth' argument '%1' out of range", n); + return false; + } + space_width = n; + } + else if (strcmp(p, "slant") == 0) { + p = strtok(0, WS); + double n; + if (0 == p) { + t.error("missing argument to 'slant' directive"); + return false; + } + if (sscanf(p, "%lf", &n) != 1) { + t.error("invalid argument '%1' to 'slant' directive", p); + return false; + } + if (n >= 90.0 || n <= -90.0) { + t.error("'slant' directive argument '%1' out of range", n); + return false; + } + slant = n; + } + else if (strcmp(p, "ligatures") == 0) { + for (;;) { + p = strtok(0, WS); + if (0 == p || strcmp(p, "0") == 0) + break; + if (strcmp(p, "ff") == 0) + ligatures |= LIG_ff; + else if (strcmp(p, "fi") == 0) + ligatures |= LIG_fi; + else if (strcmp(p, "fl") == 0) + ligatures |= LIG_fl; + else if (strcmp(p, "ffi") == 0) + ligatures |= LIG_ffi; + else if (strcmp(p, "ffl") == 0) + ligatures |= LIG_ffl; + else { + t.error("unrecognized ligature '%1'", p); + return false; + } + } + } + else if (strcmp(p, "internalname") == 0) { + p = strtok(0, WS); + if (0 == p) { + t.error("missing argument to 'internalname' directive"); + return false; + } + internalname = new char[strlen(p) + 1]; + strcpy(internalname, p); + } + else if (strcmp(p, "special") == 0) { + special = true; + } + else if (strcmp(p, "kernpairs") != 0 && strcmp(p, "charset") != 0) { + char *directive = p; + p = strtok(0, "\n"); + handle_unknown_font_command(directive, trim_arg(p), t.path, + t.lineno); + } + else + break; + } + bool saw_charset_directive = false; + char *directive = p; + t.recognize_comments = false; + while (directive) { + if (strcmp(directive, "kernpairs") == 0) { + if (load_header_only) + return true; + for (;;) { + if (!t.next_line()) { + directive = 0; + break; + } + char *c1 = strtok(t.buf, WS); + if (0 == c1) + continue; + char *c2 = strtok(0, WS); + if (0 == c2) { + directive = c1; + break; + } + p = strtok(0, WS); + if (0 == p) { + t.error("missing kern amount for kerning pair '%1 %2'", c1, + c2); + return false; + } + int n; + if (sscanf(p, "%d", &n) != 1) { + t.error("invalid kern amount '%1' for kerning pair '%2 %3'", + p, c1, c2); + return false; + } + glyph *g1 = name_to_glyph(c1); + glyph *g2 = name_to_glyph(c2); + add_kern(g1, g2, n); + } + } + else if (strcmp(directive, "charset") == 0) { + if (load_header_only) + return true; + saw_charset_directive = true; + glyph *last_glyph = 0; + for (;;) { + if (!t.next_line()) { + directive = 0; + break; + } + char *nm = strtok(t.buf, WS); + assert(nm != 0); + p = strtok(0, WS); + if (0 == p) { + directive = nm; + break; + } + if (p[0] == '"') { + if (last_glyph == 0) { + t.error("the first entry ('%1') in 'charset' subsection" + " cannot be an alias", nm); + return false; + } + if (strcmp(nm, "---") == 0) { + t.error("an unnamed character ('---') cannot be an alias"); + return false; + } + glyph *g = name_to_glyph(nm); + copy_entry(g, last_glyph); + } + else { + font_char_metric metric; + metric.height = 0; + metric.depth = 0; + metric.pre_math_space = 0; + metric.italic_correction = 0; + metric.subscript_correction = 0; + int nparms = sscanf(p, "%d,%d,%d,%d,%d,%d", + &metric.width, &metric.height, + &metric.depth, + &metric.italic_correction, + &metric.pre_math_space, + &metric.subscript_correction); + if (nparms < 1) { + t.error("missing or invalid width for glyph '%1'", nm); + return false; + } + p = strtok(0, WS); + if (0 == p) { + t.error("missing character type for '%1'", nm); + return false; + } + int type; + if (sscanf(p, "%d", &type) != 1) { + t.error("invalid character type for '%1'", nm); + return false; + } + if (type < 0 || type > 255) { + t.error("character type '%1' out of range for '%2'", type, + nm); + return false; + } + metric.type = type; + p = strtok(0, WS); + if (0 == p) { + t.error("missing code for '%1'", nm); + return false; + } + char *ptr; + metric.code = (int)strtol(p, &ptr, 0); + if (metric.code == 0 && ptr == p) { + t.error("invalid code '%1' for character '%2'", p, nm); + return false; + } + if (is_unicode) { + int w = wcwidth(metric.code); + if (w > 1) + metric.width *= w; + } + p = strtok(0, WS); + if ((0 == p) || (strcmp(p, "--") == 0)) { + metric.special_device_coding = 0; + } + else { + char *nam = new char[strlen(p) + 1]; + strcpy(nam, p); + metric.special_device_coding = nam; + } + if (strcmp(nm, "---") == 0) { + last_glyph = number_to_glyph(metric.code); + add_entry(last_glyph, metric); + } + else { + last_glyph = name_to_glyph(nm); + add_entry(last_glyph, metric); + copy_entry(number_to_glyph(metric.code), last_glyph); + } + } + } + if (0 == last_glyph) { + t.error("no glyphs defined in font description"); + return false; + } + } + else { + t.error("unrecognized font description directive '%1' (missing" + " 'kernpairs' or 'charset'?)", directive); + return false; + } + } + compact(); + t.lineno = 0; + if (!saw_name_directive) { + t.error("font description 'name' directive missing"); + return false; + } + if (!is_unicode && !saw_charset_directive) { + t.error("font description 'charset' subsection missing"); + return false; + } + if (space_width == 0) { + t.error("font description 'spacewidth' directive missing"); + // _Don't_ return false; compute a typical one for Western glyphs. + if (zoom) + space_width = scale_round(unitwidth, res, 72 * 3 * sizescale, + zoom); + else + space_width = scale_round(unitwidth, res, 72 * 3 * sizescale); + } + return true; +} + +static struct { + const char *numeric_directive; + int *ptr; +} table[] = { + { "res", &font::res }, + { "hor", &font::hor }, + { "vert", &font::vert }, + { "unitwidth", &font::unitwidth }, + { "paperwidth", &font::paperwidth }, + { "paperlength", &font::paperlength }, + { "spare1", &font::biggestfont }, + { "biggestfont", &font::biggestfont }, + { "spare2", &font::spare2 }, + { "sizescale", &font::sizescale }, + }; + +// Return file specification of DESC file for selected output device if +// it can be located and is valid, and a null pointer otherwise. +const char *font::load_desc() +{ + int nfonts = 0; + FILE *fp; + char *path; + if ((fp = open_file("DESC", &path)) == 0) + return 0 /* nullptr */; + text_file t(fp, path); + while (t.next_line()) { + char *p = strtok(t.buf, WS); + assert(p != 0); + bool numeric_directive_found = false; + unsigned int idx; + for (idx = 0; !numeric_directive_found + && idx < sizeof(table) / sizeof(table[0]); idx++) + if (strcmp(table[idx].numeric_directive, p) == 0) + numeric_directive_found = true; + if (numeric_directive_found) { + char *q = strtok(0, WS); + if (0 == q) { + t.error("missing value for directive '%1'", p); + return 0 /* nullptr */; + } + int val; + if (sscanf(q, "%d", &val) != 1) { + t.error("'%1' directive given invalid number '%2'", p, q); + return 0 /* nullptr */; + } + if ((strcmp(p, "res") == 0 + || strcmp(p, "hor") == 0 + || strcmp(p, "vert") == 0 + || strcmp(p, "unitwidth") == 0 + || strcmp(p, "paperwidth") == 0 + || strcmp(p, "paperlength") == 0 + || strcmp(p, "sizescale") == 0) + && val < 1) { + t.error("expected argument to '%1' directive to be a" + " positive number, got '%2'", p, val); + return 0 /* nullptr */; + } + *(table[idx-1].ptr) = val; + } + else if (strcmp("family", p) == 0) { + p = strtok(0, WS); + if (0 == p) { + t.error("'family' directive requires an argument"); + return 0 /* nullptr */; + } + char *tem = new char[strlen(p)+1]; + strcpy(tem, p); + family = tem; + } + else if (strcmp("fonts", p) == 0) { + p = strtok(0, WS); + if (0 == p) { + t.error("'fonts' directive requires arguments"); + return 0 /* nullptr */; + } + if (sscanf(p, "%d", &nfonts) != 1 || nfonts <= 0) { + t.error("expected first argument to 'fonts' directive to be a" + " non-negative number, got '%1'", p); + return 0 /* nullptr */; + } + font_name_table = (const char **)new char *[nfonts+1]; + for (int i = 0; i < nfonts; i++) { + p = strtok(0, WS); + while (0 == p) { + if (!t.next_line()) { + t.error("unexpected end of file while reading font list"); + return 0 /* nullptr */; + } + p = strtok(t.buf, WS); + } + char *temp = new char[strlen(p)+1]; + strcpy(temp, p); + font_name_table[i] = temp; + } + p = strtok(0, WS); + if (p != 0) { + t.error("font count does not match declared number of fonts" + " ('%1')", nfonts); + return 0 /* nullptr */; + } + font_name_table[nfonts] = 0; + } + else if (strcmp("papersize", p) == 0) { + if (0 == res) { + t.error("'res' directive must precede 'papersize' in device" + " description file"); + return 0 /* nullptr */; + } + p = strtok(0, WS); + if (0 == p) { + t.error("'papersize' directive requires an argument"); + return 0 /* nullptr */; + } + bool found_paper = false; + char *savedp = strdup(p); + if (0 == savedp) + t.fatal("memory allocation failure while processing 'papersize'" + " directive"); + while (p) { + double unscaled_paperwidth, unscaled_paperlength; + if (scan_papersize(p, &papersize, &unscaled_paperlength, + &unscaled_paperwidth)) { + paperwidth = int(unscaled_paperwidth * res + 0.5); + paperlength = int(unscaled_paperlength * res + 0.5); + found_paper = true; + break; + } + p = strtok(0, WS); + } + assert(savedp != 0); + if (!found_paper) { + t.error("unable to determine a paper format from '%1'", savedp); + free(savedp); + return 0 /* nullptr */; + } + free(savedp); + } + else if (strcmp("unscaled_charwidths", p) == 0) + use_unscaled_charwidths = true; + else if (strcmp("pass_filenames", p) == 0) + pass_filenames = true; + else if (strcmp("sizes", p) == 0) { + int n = 16; + sizes = new int[n]; + int i = 0; + for (;;) { + p = strtok(0, WS); + while (0 == p) { + if (!t.next_line()) { + t.error("list of sizes must be terminated by '0'"); + return 0 /* nullptr */; + } + p = strtok(t.buf, WS); + } + int lower, upper; + switch (sscanf(p, "%d-%d", &lower, &upper)) { + case 1: + upper = lower; + // fall through + case 2: + if (lower <= upper && lower >= 0) + break; + // fall through + default: + t.error("invalid size range '%1'", p); + return 0 /* nullptr */; + } + if (i + 2 > n) { + int *old_sizes = sizes; + sizes = new int[n*2]; + memcpy(sizes, old_sizes, n*sizeof(int)); + n *= 2; + delete[] old_sizes; + } + sizes[i++] = lower; + if (lower == 0) + break; + sizes[i++] = upper; + } + if (i == 1) { + t.error("must have some sizes"); + return 0 /* nullptr */; + } + } + else if (strcmp("styles", p) == 0) { + int style_table_size = 5; + style_table = (const char **)new char *[style_table_size]; + int j; + for (j = 0; j < style_table_size; j++) + style_table[j] = 0; + int i = 0; + for (;;) { + p = strtok(0, WS); + if (0 == p) + break; + // leave room for terminating 0 + if (i + 1 >= style_table_size) { + const char **old_style_table = style_table; + style_table_size *= 2; + style_table = (const char **)new char*[style_table_size]; + for (j = 0; j < i; j++) + style_table[j] = old_style_table[j]; + for (; j < style_table_size; j++) + style_table[j] = 0; + delete[] old_style_table; + } + char *tem = new char[strlen(p) + 1]; + strcpy(tem, p); + style_table[i++] = tem; + } + } + else if (strcmp("tcommand", p) == 0) + has_tcommand = true; + else if (strcmp("use_charnames_in_special", p) == 0) + use_charnames_in_special = true; + else if (strcmp("unicode", p) == 0) + is_unicode = true; + else if (strcmp("image_generator", p) == 0) { + p = strtok(0, WS); + if (0 == p) { + t.error("'image_generator' directive requires an argument"); + return 0 /* nullptr */; + } + image_generator = strsave(p); + } + else if (strcmp("charset", p) == 0) + break; + else if (unknown_desc_command_handler) { + char *directive = p; + p = strtok(0, "\n"); + (*unknown_desc_command_handler)(directive, trim_arg(p), t.path, + t.lineno); + } + } + t.lineno = 0; + if (res == 0) { + t.error("device description file missing 'res' directive"); + return 0 /* nullptr */; + } + if (unitwidth == 0) { + t.error("device description file missing 'unitwidth' directive"); + return 0 /* nullptr */; + } + if (font_name_table == 0) { + t.error("device description file missing 'fonts' directive"); + return 0 /* nullptr */; + } + if (sizes == 0) { + t.error("device description file missing 'sizes' directive"); + return 0 /* nullptr */; + } + return path; +} + +void font::handle_unknown_font_command(const char *, const char *, + const char *, int) +{ +} + +FONT_COMMAND_HANDLER +font::set_unknown_desc_command_handler(FONT_COMMAND_HANDLER func) +{ + FONT_COMMAND_HANDLER prev = unknown_desc_command_handler; + unknown_desc_command_handler = func; + return prev; +} + +// Local Variables: +// fill-column: 72 +// mode: C++ +// End: +// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: diff --git a/src/libs/libgroff/fontfile.cpp b/src/libs/libgroff/fontfile.cpp new file mode 100644 index 0000000..8987971 --- /dev/null +++ b/src/libs/libgroff/fontfile.cpp @@ -0,0 +1,80 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "lib.h" + +#include <stdlib.h> +#include <errno.h> +#include "font.h" +#include "searchpath.h" +#include "device.h" +#include "defs.h" + +const char *const FONT_ENV_VAR = "GROFF_FONT_PATH"; + +static search_path font_path(FONT_ENV_VAR, FONTPATH, 0, 0); + +int font::res = 0; +int font::hor = 1; +int font::vert = 1; +int font::unitwidth = 0; +int font::paperwidth = 0; +int font::paperlength = 0; +const char *font::papersize = 0; +int font::biggestfont = 0; +int font::spare2 = 0; +int font::sizescale = 1; +bool font::has_tcommand = false; +bool font::pass_filenames = false; +bool font::use_unscaled_charwidths = false; +bool font::use_charnames_in_special = false; +bool font::is_unicode = false; +const char *font::image_generator = 0; +const char **font::font_name_table = 0; +int *font::sizes = 0; +const char *font::family = 0; +const char **font::style_table = 0; +FONT_COMMAND_HANDLER font::unknown_desc_command_handler = 0; + +void font::command_line_font_dir(const char *dir) +{ + font_path.command_line_dir(dir); +} + +FILE *font::open_file(const char *nm, char **pathp) +{ + FILE *fp = 0 /* nullptr */; + // Do not traverse user-specified directories; Savannah #61424. + if (0 /* nullptr */ == strchr(nm, '/')) { + // Allocate enough for nm + device + 'dev' '/' '\0'. + int expected_size = strlen(nm) + strlen(device) + 5; + char *filename = new char[expected_size]; + const int actual_size = sprintf(filename, "dev%s/%s", device, nm); + expected_size--; // sprintf() doesn't count the null terminator. + if (actual_size == expected_size) + fp = font_path.open_file(filename, pathp); + delete[] filename; + } + return fp; +} + +// Local Variables: +// fill-column: 72 +// mode: C++ +// End: +// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: diff --git a/src/libs/libgroff/geometry.cpp b/src/libs/libgroff/geometry.cpp new file mode 100644 index 0000000..c4665c4 --- /dev/null +++ b/src/libs/libgroff/geometry.cpp @@ -0,0 +1,180 @@ +// -*- C++ -*- +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by Gaius Mulley <gaius@glam.ac.uk> + using adjust_arc_center() from printer.cpp, written by James Clark. + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <math.h> + +#undef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +#undef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + + +// This utility function adjusts the specified center of the +// arc so that it is equidistant between the specified start +// and end points. (p[0], p[1]) is a vector from the current +// point to the center; (p[2], p[3]) is a vector from the +// center to the end point. If the center can be adjusted, +// a vector from the current point to the adjusted center is +// stored in c[0], c[1] and 1 is returned. Otherwise 0 is +// returned. + +#if 1 +int adjust_arc_center(const int *p, double *c) +{ + // We move the center along a line parallel to the line between + // the specified start point and end point so that the center + // is equidistant between the start and end point. + // It can be proved (using Lagrange multipliers) that this will + // give the point nearest to the specified center that is equidistant + // between the start and end point. + + double x = p[0] + p[2]; // (x, y) is the end point + double y = p[1] + p[3]; + double n = x*x + y*y; + if (n != 0) { + c[0]= double(p[0]); + c[1] = double(p[1]); + double k = .5 - (c[0]*x + c[1]*y)/n; + c[0] += k*x; + c[1] += k*y; + return 1; + } + else + return 0; +} +#else +int printer::adjust_arc_center(const int *p, double *c) +{ + int x = p[0] + p[2]; // (x, y) is the end point + int y = p[1] + p[3]; + // Start at the current point; go in the direction of the specified + // center point until we reach a point that is equidistant between + // the specified starting point and the specified end point. Place + // the center of the arc there. + double n = p[0]*double(x) + p[1]*double(y); + if (n > 0) { + double k = (double(x)*x + double(y)*y)/(2.0*n); + // (cx, cy) is our chosen center + c[0] = k*p[0]; + c[1] = k*p[1]; + return 1; + } + else { + // We would never reach such a point. So instead start at the + // specified end point of the arc. Go towards the specified + // center point until we reach a point that is equidistant between + // the specified start point and specified end point. Place + // the center of the arc there. + n = p[2]*double(x) + p[3]*double(y); + if (n > 0) { + double k = 1 - (double(x)*x + double(y)*y)/(2.0*n); + // (c[0], c[1]) is our chosen center + c[0] = p[0] + k*p[2]; + c[1] = p[1] + k*p[3]; + return 1; + } + else + return 0; + } +} +#endif + + +/* + * check_output_arc_limits - works out the smallest box that will encompass + * an arc defined by an origin (x, y) and two + * vectors (p0, p1) and (p2, p3). + * (x1, y1) -> start of arc + * (x1, y1) + (xv1, yv1) -> center of circle + * (x1, y1) + (xv1, yv1) + (xv2, yv2) -> end of arc + * + * Works out in which quadrant the arc starts and + * stops, and from this it determines the x, y + * max/min limits. The arc is drawn clockwise. + */ + +void check_output_arc_limits(int x_1, int y_1, + int xv_1, int yv_1, + int xv_2, int yv_2, + double c_0, double c_1, + int *minx, int *maxx, + int *miny, int *maxy) +{ + int radius = (int)sqrt(c_0 * c_0 + c_1 * c_1); + // clockwise direction + int xcenter = x_1 + xv_1; + int ycenter = y_1 + yv_1; + int xend = xcenter + xv_2; + int yend = ycenter + yv_2; + // for convenience, transform to counterclockwise direction, + // centered at the origin + int xs = xend - xcenter; + int ys = yend - ycenter; + int xe = x_1 - xcenter; + int ye = y_1 - ycenter; + *minx = *maxx = xs; + *miny = *maxy = ys; + if (xe > *maxx) + *maxx = xe; + else if (xe < *minx) + *minx = xe; + if (ye > *maxy) + *maxy = ye; + else if (ye < *miny) + *miny = ye; + int qs, qe; // quadrants 0..3 + if (xs >= 0) + qs = (ys >= 0) ? 0 : 3; + else + qs = (ys >= 0) ? 1 : 2; + if (xe >= 0) + qe = (ye >= 0) ? 0 : 3; + else + qe = (ye >= 0) ? 1 : 2; + // make qs always smaller than qe + if ((qs > qe) + || ((qs == qe) && (double(xs) * ye < double(xe) * ys))) + qe += 4; + for (int i = qs; i < qe; i++) + switch (i % 4) { + case 0: + *maxy = radius; + break; + case 1: + *minx = -radius; + break; + case 2: + *miny = -radius; + break; + case 3: + *maxx = radius; + break; + } + *minx += xcenter; + *maxx += xcenter; + *miny += ycenter; + *maxy += ycenter; +} diff --git a/src/libs/libgroff/getcwd.c b/src/libs/libgroff/getcwd.c new file mode 100644 index 0000000..dd8b578 --- /dev/null +++ b/src/libs/libgroff/getcwd.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2000-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* Partial emulation of getcwd in terms of getwd. */ + +#include <config.h> +#include <sys/param.h> +#include <string.h> +#include <errno.h> + +char *getwd(); + +char *getcwd(buf, size) + char *buf; + int size; /* POSIX says this should be size_t */ +{ + if (size <= 0) { + errno = EINVAL; + return 0; + } + else { + char mybuf[MAXPATHLEN]; + int saved_errno = errno; + + errno = 0; + if (!getwd(mybuf)) { + if (errno == 0) + ; /* what to do? */ + return 0; + } + errno = saved_errno; + if (strlen(mybuf) + 1 > size) { + errno = ERANGE; + return 0; + } + strcpy(buf, mybuf); + return buf; + } +} diff --git a/src/libs/libgroff/getopt.c b/src/libs/libgroff/getopt.c new file mode 100644 index 0000000..6efa529 --- /dev/null +++ b/src/libs/libgroff/getopt.c @@ -0,0 +1,1241 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to drepper@gnu.org + before changing it! + Copyright (C) 1987-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. + Ditto for AIX 3.2 and <stdlib.h>. */ +#ifndef _NO_PROTO +# define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +# include <stdlib.h> +# include <unistd.h> +#endif /* GNU C library. */ + +#include <string.h> + +#ifdef VMS +# include <unixlib.h> +#endif + +#ifdef _LIBC +# include <libintl.h> +#else +# include "gettext.h" +# define _(msgid) gettext (msgid) +#endif + +#if defined _LIBC && defined USE_IN_LIBIO +# include <wchar.h> +#endif + +#ifndef attribute_hidden +# define attribute_hidden +#endif + +/* Unlike standard Unix 'getopt', functions like 'getopt_long' + let the user intersperse the options with the other arguments. + + As 'getopt_long' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Using 'getopt' or setting the environment variable POSIXLY_CORRECT + disables permutation. + Then the application's behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" +#include "getopt_int.h" + +/* For communication from 'getopt' to the caller. + When 'getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when 'ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to 'getopt'. + + On entry to 'getopt', zero means this is the first call; initialize. + + When 'getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, 'optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* 1003.2 says this must be 1 before any call. */ +int optind = 1; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Keep a global copy of all internal members of getopt_data. */ + +static struct _getopt_data getopt_data; + + +#ifndef __GNU_LIBRARY__ + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +#ifndef getenv +extern char *getenv (); +#endif + +#endif /* not __GNU_LIBRARY__ */ + +#ifdef _LIBC +/* Stored original parameters. + XXX This is no good solution. We should rather copy the args so + that we can compare them later. But we must not use malloc(3). */ +extern int __libc_argc; +extern char **__libc_argv; + +/* Bash 2.0 gives us an environment variable containing flags + indicating ARGV elements that should not be considered arguments. */ + +# ifdef USE_NONOPTION_FLAGS +/* Defined in getopt_init.c */ +extern char *__getopt_nonoption_flags; +# endif + +# ifdef USE_NONOPTION_FLAGS +# define SWAP_FLAGS(ch1, ch2) \ + if (d->__nonoption_flags_len > 0) \ + { \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ + } +# else +# define SWAP_FLAGS(ch1, ch2) +# endif +#else /* !_LIBC */ +# define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + 'first_nonopt' and 'last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +static void +exchange (char **argv, struct _getopt_data *d) +{ + int bottom = d->__first_nonopt; + int middle = d->__last_nonopt; + int top = d->optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + +#if defined _LIBC && defined USE_NONOPTION_FLAGS + /* First make sure the handling of the '__getopt_nonoption_flags' + string can work normally. Our top argument must be in the range + of the string. */ + if (d->__nonoption_flags_len > 0 && top >= d->__nonoption_flags_max_len) + { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char *new_str = malloc (top + 1); + if (new_str == NULL) + d->__nonoption_flags_len = d->__nonoption_flags_max_len = 0; + else + { + memset (__mempcpy (new_str, __getopt_nonoption_flags, + d->__nonoption_flags_max_len), + '\0', top + 1 - d->__nonoption_flags_max_len); + d->__nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } + } +#endif + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS (bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + d->__first_nonopt += (d->optind - d->__last_nonopt); + d->__last_nonopt = d->optind; +} + +/* Initialize the internal data when the first call is made. */ + +static const char * +_getopt_initialize (__attribute__((__unused__)) int argc, + __attribute__((__unused__)) char **argv, + const char *optstring, int posixly_correct, + struct _getopt_data *d) +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + d->__first_nonopt = d->__last_nonopt = d->optind; + + d->__nextchar = NULL; + + d->__posixly_correct = posixly_correct || !!getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + d->__ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + d->__ordering = REQUIRE_ORDER; + ++optstring; + } + else if (d->__posixly_correct) + d->__ordering = REQUIRE_ORDER; + else + d->__ordering = PERMUTE; + +#if defined _LIBC && defined USE_NONOPTION_FLAGS + if (!d->__posixly_correct + && argc == __libc_argc && argv == __libc_argv) + { + if (d->__nonoption_flags_max_len == 0) + { + if (__getopt_nonoption_flags == NULL + || __getopt_nonoption_flags[0] == '\0') + d->__nonoption_flags_max_len = -1; + else + { + const char *orig_str = __getopt_nonoption_flags; + int len = d->__nonoption_flags_max_len = strlen (orig_str); + if (d->__nonoption_flags_max_len < argc) + d->__nonoption_flags_max_len = argc; + __getopt_nonoption_flags = + (char *) malloc (d->__nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + d->__nonoption_flags_max_len = -1; + else + memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), + '\0', d->__nonoption_flags_max_len - len); + } + } + d->__nonoption_flags_len = d->__nonoption_flags_max_len; + } + else + d->__nonoption_flags_len = 0; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If 'getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If 'getopt' finds another option character, it returns that character, + updating 'optind' and 'nextchar' so that the next call to 'getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, 'getopt' returns -1. + Then 'optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set 'opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in 'optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in 'optarg', otherwise 'optarg' is set to zero. + + If OPTSTRING starts with '-' or '+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with '--' instead of '-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a '=', or else the in next ARGV-element. + When 'getopt' finds a long-named option, it returns 0 if that option's + 'flag' field is nonzero, the value of the option's 'val' field + if the 'flag' field is zero. + + LONGOPTS is a vector of 'struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. + + If POSIXLY_CORRECT is nonzero, behave as if the POSIXLY_CORRECT + environment variable were set. */ + +int +_getopt_internal_r (int argc, char **argv, const char *optstring, + const struct option *longopts, int *longind, + int long_only, int posixly_correct, struct _getopt_data *d) +{ + int print_errors = d->opterr; + if (optstring[0] == ':') + print_errors = 0; + + if (argc < 1) + return -1; + + d->optarg = NULL; + + if (d->optind == 0 || !d->__initialized) + { + if (d->optind == 0) + d->optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize (argc, argv, optstring, + posixly_correct, d); + d->__initialized = 1; + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ +#if defined _LIBC && defined USE_NONOPTION_FLAGS +# define NONOPTION_P (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0' \ + || (d->optind < d->__nonoption_flags_len \ + && __getopt_nonoption_flags[d->optind] == '1')) +#else +# define NONOPTION_P (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0') +#endif + + if (d->__nextchar == NULL || *d->__nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (d->__last_nonopt > d->optind) + d->__last_nonopt = d->optind; + if (d->__first_nonopt > d->optind) + d->__first_nonopt = d->optind; + + if (d->__ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (d->__first_nonopt != d->__last_nonopt + && d->__last_nonopt != d->optind) + exchange ((char **) argv, d); + else if (d->__last_nonopt != d->optind) + d->__first_nonopt = d->optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (d->optind < argc && NONOPTION_P) + d->optind++; + d->__last_nonopt = d->optind; + } + + /* The special ARGV-element '--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (d->optind != argc && !strcmp (argv[d->optind], "--")) + { + d->optind++; + + if (d->__first_nonopt != d->__last_nonopt + && d->__last_nonopt != d->optind) + exchange ((char **) argv, d); + else if (d->__first_nonopt == d->__last_nonopt) + d->__first_nonopt = d->optind; + d->__last_nonopt = argc; + + d->optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (d->optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (d->__first_nonopt != d->__last_nonopt) + d->optind = d->__first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (d->__ordering == REQUIRE_ORDER) + return -1; + d->optarg = argv[d->optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + d->__nextchar = (argv[d->optind] + 1 + + (longopts != NULL && argv[d->optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[d->optind][1] == '-' + || (long_only && (argv[d->optind][2] + || !strchr (optstring, argv[d->optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, d->__nextchar, nameend - d->__nextchar)) + { + if ((unsigned int) (nameend - d->__nextchar) + == (unsigned int) strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else if (long_only + || pfound->has_arg != p->has_arg + || pfound->flag != p->flag + || pfound->val != p->val) + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + if (__asprintf (&buf, _("%s: option '%s' is ambiguous\n"), + argv[0], argv[d->optind]) >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; + + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s", buf); + else + fputs (buf, stderr); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#else + fprintf (stderr, _("%s: option '%s' is ambiguous\n"), + argv[0], argv[d->optind]); +#endif + } + d->__nextchar += strlen (d->__nextchar); + d->optind++; + d->optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + d->optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + d->optarg = nameend + 1; + else + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + int n; +#endif + + if (argv[d->optind - 1][1] == '-') + { + /* --option */ +#if defined _LIBC && defined USE_IN_LIBIO + n = __asprintf (&buf, _("\ +%s: option '--%s' doesn't allow an argument\n"), + argv[0], pfound->name); +#else + fprintf (stderr, _("\ +%s: option '--%s' doesn't allow an argument\n"), + argv[0], pfound->name); +#endif + } + else + { + /* +option or -option */ +#if defined _LIBC && defined USE_IN_LIBIO + n = __asprintf (&buf, _("\ +%s: option '%c%s' doesn't allow an argument\n"), + argv[0], argv[d->optind - 1][0], + pfound->name); +#else + fprintf (stderr, _("\ +%s: option '%c%s' doesn't allow an argument\n"), + argv[0], argv[d->optind - 1][0], + pfound->name); +#endif + } + +#if defined _LIBC && defined USE_IN_LIBIO + if (n >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 + |= _IO_FLAGS2_NOTCANCEL; + + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s", buf); + else + fputs (buf, stderr); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#endif + } + + d->__nextchar += strlen (d->__nextchar); + + d->optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (d->optind < argc) + d->optarg = argv[d->optind++]; + else + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + if (__asprintf (&buf, _("\ +%s: option '%s' requires an argument\n"), + argv[0], argv[d->optind - 1]) >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 + |= _IO_FLAGS2_NOTCANCEL; + + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s", buf); + else + fputs (buf, stderr); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#else + fprintf (stderr, + _("%s: option '%s' requires an argument\n"), + argv[0], argv[d->optind - 1]); +#endif + } + d->__nextchar += strlen (d->__nextchar); + d->optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + d->__nextchar += strlen (d->__nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[d->optind][1] == '-' + || strchr (optstring, *d->__nextchar) == NULL) + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + int n; +#endif + + if (argv[d->optind][1] == '-') + { + /* --option */ +#if defined _LIBC && defined USE_IN_LIBIO + n = __asprintf (&buf, _("%s: unrecognized option '--%s'\n"), + argv[0], d->__nextchar); +#else + fprintf (stderr, _("%s: unrecognized option '--%s'\n"), + argv[0], d->__nextchar); +#endif + } + else + { + /* +option or -option */ +#if defined _LIBC && defined USE_IN_LIBIO + n = __asprintf (&buf, _("%s: unrecognized option '%c%s'\n"), + argv[0], argv[d->optind][0], d->__nextchar); +#else + fprintf (stderr, _("%s: unrecognized option '%c%s'\n"), + argv[0], argv[d->optind][0], d->__nextchar); +#endif + } + +#if defined _LIBC && defined USE_IN_LIBIO + if (n >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; + + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s", buf); + else + fputs (buf, stderr); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#endif + } + d->__nextchar = (char *) ""; + d->optind++; + d->optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *d->__nextchar++; + char *temp = strchr (optstring, c); + + /* Increment 'optind' when we start to process its last character. */ + if (*d->__nextchar == '\0') + ++d->optind; + + if (temp == NULL || c == ':') + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + int n; +#endif + + if (d->__posixly_correct) + { + /* 1003.2 specifies the format of this message. */ +#if defined _LIBC && defined USE_IN_LIBIO + n = __asprintf (&buf, _("%s: illegal option -- %c\n"), + argv[0], c); +#else + fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c); +#endif + } + else + { +#if defined _LIBC && defined USE_IN_LIBIO + n = __asprintf (&buf, _("%s: invalid option -- %c\n"), + argv[0], c); +#else + fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c); +#endif + } + +#if defined _LIBC && defined USE_IN_LIBIO + if (n >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; + + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s", buf); + else + fputs (buf, stderr); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#endif + } + d->optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*d->__nextchar != '\0') + { + d->optarg = d->__nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + d->optind++; + } + else if (d->optind == argc) + { + if (print_errors) + { + /* 1003.2 specifies the format of this message. */ +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + if (__asprintf (&buf, + _("%s: option requires an argument -- %c\n"), + argv[0], c) >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; + + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s", buf); + else + fputs (buf, stderr); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#else + fprintf (stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); +#endif + } + d->optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented 'd->optind' once; + increment it again when taking next ARGV-elt as argument. */ + d->optarg = argv[d->optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != '='; + nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, d->__nextchar, nameend - d->__nextchar)) + { + if ((unsigned int) (nameend - d->__nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + if (__asprintf (&buf, _("%s: option '-W %s' is ambiguous\n"), + argv[0], argv[d->optind]) >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; + + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s", buf); + else + fputs (buf, stderr); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#else + fprintf (stderr, _("%s: option '-W %s' is ambiguous\n"), + argv[0], argv[d->optind]); +#endif + } + d->__nextchar += strlen (d->__nextchar); + d->optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + d->optarg = nameend + 1; + else + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + if (__asprintf (&buf, _("\ +%s: option '-W %s' doesn't allow an argument\n"), + argv[0], pfound->name) >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 + |= _IO_FLAGS2_NOTCANCEL; + + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s", buf); + else + fputs (buf, stderr); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#else + fprintf (stderr, _("\ +%s: option '-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); +#endif + } + + d->__nextchar += strlen (d->__nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (d->optind < argc) + d->optarg = argv[d->optind++]; + else + { + if (print_errors) + { +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + if (__asprintf (&buf, _("\ +%s: option '%s' requires an argument\n"), + argv[0], argv[d->optind - 1]) >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 + |= _IO_FLAGS2_NOTCANCEL; + + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s", buf); + else + fputs (buf, stderr); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#else + fprintf (stderr, + _("%s: option '%s' requires an argument\n"), + argv[0], argv[d->optind - 1]); +#endif + } + d->__nextchar += strlen (d->__nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + d->__nextchar += strlen (d->__nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + d->__nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*d->__nextchar != '\0') + { + d->optarg = d->__nextchar; + d->optind++; + } + else + d->optarg = NULL; + d->__nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*d->__nextchar != '\0') + { + d->optarg = d->__nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + d->optind++; + } + else if (d->optind == argc) + { + if (print_errors) + { + /* 1003.2 specifies the format of this message. */ +#if defined _LIBC && defined USE_IN_LIBIO + char *buf; + + if (__asprintf (&buf, _("\ +%s: option requires an argument -- %c\n"), + argv[0], c) >= 0) + { + _IO_flockfile (stderr); + + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; + + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s", buf); + else + fputs (buf, stderr); + + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); + + free (buf); + } +#else + fprintf (stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); +#endif + } + d->optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented 'optind' once; + increment it again when taking next ARGV-elt as argument. */ + d->optarg = argv[d->optind++]; + d->__nextchar = NULL; + } + } + return c; + } +} + +int +_getopt_internal (int argc, char **argv, const char *optstring, + const struct option *longopts, int *longind, + int long_only, int posixly_correct) +{ + int result; + + getopt_data.optind = optind; + getopt_data.opterr = opterr; + + result = _getopt_internal_r (argc, argv, optstring, longopts, longind, + long_only, posixly_correct, &getopt_data); + + optind = getopt_data.optind; + optarg = getopt_data.optarg; + optopt = getopt_data.optopt; + + return result; +} + +/* glibc gets a LSB-compliant getopt. + Standalone applications get a POSIX-compliant getopt. */ +#if _LIBC +enum { POSIXLY_CORRECT = 0 }; +#else +enum { POSIXLY_CORRECT = 1 }; +#endif + +int +getopt (int argc, char *const *argv, const char *optstring) +{ + return _getopt_internal (argc, (char **) argv, optstring, NULL, NULL, 0, + POSIXLY_CORRECT); +} + + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of 'getopt'. */ + +int +main (int argc, char **argv) +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == -1) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value '%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/src/libs/libgroff/getopt1.c b/src/libs/libgroff/getopt1.c new file mode 100644 index 0000000..374b3ce --- /dev/null +++ b/src/libs/libgroff/getopt1.c @@ -0,0 +1,172 @@ +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef _LIBC +# include <getopt.h> +#else +# include "getopt.h" +#endif +#include "getopt_int.h" + +#include <stdio.h> + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include <stdlib.h> +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int +getopt_long (int argc, char *__getopt_argv_const *argv, const char *options, + const struct option *long_options, int *opt_index) +{ + return _getopt_internal (argc, (char **) argv, options, long_options, + opt_index, 0, 0); +} + +int +_getopt_long_r (int argc, char **argv, const char *options, + const struct option *long_options, int *opt_index, + struct _getopt_data *d) +{ + return _getopt_internal_r (argc, argv, options, long_options, opt_index, + 0, 0, d); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (int argc, char *__getopt_argv_const *argv, + const char *options, + const struct option *long_options, int *opt_index) +{ + return _getopt_internal (argc, (char **) argv, options, long_options, + opt_index, 1, 0); +} + +int +_getopt_long_only_r (int argc, char **argv, const char *options, + const struct option *long_options, int *opt_index, + struct _getopt_data *d) +{ + return _getopt_internal_r (argc, argv, options, long_options, opt_index, + 1, 0, d); +} + + +#ifdef TEST + +#include <stdio.h> + +int +main (int argc, char **argv) +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == -1) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value '%s'\n", optarg); + break; + + case 'd': + printf ("option d with value '%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/src/libs/libgroff/glyphuni.cpp b/src/libs/libgroff/glyphuni.cpp new file mode 100644 index 0000000..0d5a217 --- /dev/null +++ b/src/libs/libgroff/glyphuni.cpp @@ -0,0 +1,523 @@ +// -*- C++ -*- +/* Copyright (C) 2002-2020 Free Software Foundation, Inc. + Written by Werner Lemberg <wl@gnu.org> + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "lib.h" +#include "stringclass.h" +#include "ptable.h" + +#include "unicode.h" + +struct glyph_to_unicode { + char *value; +}; + +declare_ptable(glyph_to_unicode) +implement_ptable(glyph_to_unicode) + +PTABLE(glyph_to_unicode) glyph_to_unicode_table; + +// The entries commented out in the table below can't be used in glyph +// names. + +struct S { + const char *key; + const char *value; +} glyph_to_unicode_list[] = { + { "!", "0021" }, + { "\"", "0022" }, + { "dq", "0022" }, + { "#", "0023" }, + { "sh", "0023" }, + { "$", "0024" }, + { "Do", "0024" }, + { "%", "0025" }, + { "&", "0026" }, + { "aq", "0027" }, + { "(", "0028" }, + { ")", "0029" }, + { "*", "002A" }, + { "+", "002B" }, + { "pl", "002B" }, + { ",", "002C" }, + { ".", "002E" }, + { "/", "002F" }, + { "sl", "002F" }, + { "0", "0030" }, + { "1", "0031" }, + { "2", "0032" }, + { "3", "0033" }, + { "4", "0034" }, + { "5", "0035" }, + { "6", "0036" }, + { "7", "0037" }, + { "8", "0038" }, + { "9", "0039" }, + { ":", "003A" }, + { ";", "003B" }, + { "<", "003C" }, + { "=", "003D" }, + { "eq", "003D" }, + { ">", "003E" }, + { "?", "003F" }, + { "@", "0040" }, + { "at", "0040" }, + { "A", "0041" }, + { "B", "0042" }, + { "C", "0043" }, + { "D", "0044" }, + { "E", "0045" }, + { "F", "0046" }, + { "G", "0047" }, + { "H", "0048" }, + { "I", "0049" }, + { "J", "004A" }, + { "K", "004B" }, + { "L", "004C" }, + { "M", "004D" }, + { "N", "004E" }, + { "O", "004F" }, + { "P", "0050" }, + { "Q", "0051" }, + { "R", "0052" }, + { "S", "0053" }, + { "T", "0054" }, + { "U", "0055" }, + { "V", "0056" }, + { "W", "0057" }, + { "X", "0058" }, + { "Y", "0059" }, + { "Z", "005A" }, +//{ "[", "005B" }, + { "lB", "005B" }, +//{ "\\", "005C" }, + { "rs", "005C" }, +//{ "]", "005D" }, + { "rB", "005D" }, + { "a^", "005E" }, + { "^", "005E" }, + { "ha", "005E" }, + { "_", "005F" }, + { "ru", "005F" }, + { "ul", "005F" }, + { "ga", "0060" }, + { "a", "0061" }, + { "b", "0062" }, + { "c", "0063" }, + { "d", "0064" }, + { "e", "0065" }, + { "f", "0066" }, + { "ff", "0066_0066" }, + { "Fi", "0066_0066_0069" }, + { "Fl", "0066_0066_006C" }, + { "fi", "0066_0069" }, + { "fl", "0066_006C" }, + { "g", "0067" }, + { "h", "0068" }, + { "i", "0069" }, + { "j", "006A" }, + { "k", "006B" }, + { "l", "006C" }, + { "m", "006D" }, + { "n", "006E" }, + { "o", "006F" }, + { "p", "0070" }, + { "q", "0071" }, + { "r", "0072" }, + { "s", "0073" }, + { "t", "0074" }, + { "u", "0075" }, + { "v", "0076" }, + { "w", "0077" }, + { "x", "0078" }, + { "y", "0079" }, + { "z", "007A" }, + { "lC", "007B" }, + { "{", "007B" }, + { "ba", "007C" }, + { "or", "007C" }, + { "|", "007C" }, + { "rC", "007D" }, + { "}", "007D" }, + { "a~", "007E" }, + { "~", "007E" }, + { "ti", "007E" }, + { "r!", "00A1" }, + { "ct", "00A2" }, + { "Po", "00A3" }, + { "Cs", "00A4" }, + { "Ye", "00A5" }, + { "bb", "00A6" }, + { "sc", "00A7" }, + { "ad", "00A8" }, + { "co", "00A9" }, + { "Of", "00AA" }, + { "Fo", "00AB" }, + { "no", "00AC" }, + { "tno", "00AC" }, + // The soft hyphen U+00AD is meaningful only in the input file, + // not in the output. + { "rg", "00AE" }, + { "a-", "00AF" }, + { "de", "00B0" }, + { "+-", "00B1" }, + { "t+-", "00B1" }, + { "S2", "00B2" }, + { "S3", "00B3" }, + { "aa", "00B4" }, + { "mc", "00B5" }, + { "ps", "00B6" }, + { "pc", "00B7" }, + { "ac", "00B8" }, + { "S1", "00B9" }, + { "Om", "00BA" }, + { "Fc", "00BB" }, + { "14", "00BC" }, + { "12", "00BD" }, + { "34", "00BE" }, + { "r?", "00BF" }, + { "`A", "00C0" }, + { "'A", "00C1" }, + { "^A", "00C2" }, + { "~A", "00C3" }, + { ":A", "00C4" }, + { "oA", "00C5" }, + { "AE", "00C6" }, + { ",C", "00C7" }, + { "`E", "00C8" }, + { "'E", "00C9" }, + { "^E", "00CA" }, + { ":E", "00CB" }, + { "`I", "00CC" }, + { "'I", "00CD" }, + { "^I", "00CE" }, + { ":I", "00CF" }, + { "-D", "00D0" }, + { "~N", "00D1" }, + { "`O", "00D2" }, + { "'O", "00D3" }, + { "^O", "00D4" }, + { "~O", "00D5" }, + { ":O", "00D6" }, + { "mu", "00D7" }, + { "tmu", "00D7" }, + { "/O", "00D8" }, + { "`U", "00D9" }, + { "'U", "00DA" }, + { "^U", "00DB" }, + { ":U", "00DC" }, + { "'Y", "00DD" }, + { "TP", "00DE" }, + { "ss", "00DF" }, + { "`a", "00E0" }, + { "'a", "00E1" }, + { "^a", "00E2" }, + { "~a", "00E3" }, + { ":a", "00E4" }, + { "oa", "00E5" }, + { "ae", "00E6" }, + { ",c", "00E7" }, + { "`e", "00E8" }, + { "'e", "00E9" }, + { "^e", "00EA" }, + { ":e", "00EB" }, + { "`i", "00EC" }, + { "'i", "00ED" }, + { "^i", "00EE" }, + { ":i", "00EF" }, + { "Sd", "00F0" }, + { "~n", "00F1" }, + { "`o", "00F2" }, + { "'o", "00F3" }, + { "^o", "00F4" }, + { "~o", "00F5" }, + { ":o", "00F6" }, + { "di", "00F7" }, + { "tdi", "00F7" }, + { "/o", "00F8" }, + { "`u", "00F9" }, + { "'u", "00FA" }, + { "^u", "00FB" }, + { ":u", "00FC" }, + { "'y", "00FD" }, + { "Tp", "00FE" }, + { ":y", "00FF" }, + { "'C", "0106" }, + { "'c", "0107" }, + { ".i", "0131" }, + { "IJ", "0132" }, + { "ij", "0133" }, + { "/L", "0141" }, + { "/l", "0142" }, + { "OE", "0152" }, + { "oe", "0153" }, + { "vS", "0160" }, + { "vs", "0161" }, + { ":Y", "0178" }, + { "vZ", "017D" }, + { "vz", "017E" }, + { "Fn", "0192" }, + { ".j", "0237" }, + { "ah", "02C7" }, + { "ab", "02D8" }, + { "a.", "02D9" }, + { "ao", "02DA" }, + { "ho", "02DB" }, + { "a\"", "02DD" }, + { "*A", "0391" }, + { "*B", "0392" }, + { "*G", "0393" }, + { "*D", "0394" }, + { "*E", "0395" }, + { "*Z", "0396" }, + { "*Y", "0397" }, + { "*H", "0398" }, + { "*I", "0399" }, + { "*K", "039A" }, + { "*L", "039B" }, + { "*M", "039C" }, + { "*N", "039D" }, + { "*C", "039E" }, + { "*O", "039F" }, + { "*P", "03A0" }, + { "*R", "03A1" }, + { "*S", "03A3" }, + { "*T", "03A4" }, + { "*U", "03A5" }, + { "*F", "03A6" }, + { "*X", "03A7" }, + { "*Q", "03A8" }, + { "*W", "03A9" }, + { "*a", "03B1" }, + { "*b", "03B2" }, + { "*g", "03B3" }, + { "*d", "03B4" }, + { "*e", "03B5" }, + { "*z", "03B6" }, + { "*y", "03B7" }, + { "*h", "03B8" }, + { "*i", "03B9" }, + { "*k", "03BA" }, + { "*l", "03BB" }, + { "*m", "03BC" }, + { "*n", "03BD" }, + { "*c", "03BE" }, + { "*o", "03BF" }, + { "*p", "03C0" }, + { "*r", "03C1" }, + { "ts", "03C2" }, + { "*s", "03C3" }, + { "*t", "03C4" }, + { "*u", "03C5" }, + // the curly phi variant + { "+f", "03C6" }, + { "*x", "03C7" }, + { "*q", "03C8" }, + { "*w", "03C9" }, + { "+h", "03D1" }, + // the stroked phi variant + { "*f", "03D5" }, + { "+p", "03D6" }, + { "+e", "03F5" }, + // '-' and 'hy' denote a HYPHEN, usually a glyph with a smaller width than + // the MINUS sign. Users who are viewing broken man pages that assume + // that '-' denotes a U+002D character can either fix the broken man pages + // or apply the workaround described in the PROBLEMS file. + { "-", "2010" }, + { "hy", "2010" }, + { "en", "2013" }, + { "em", "2014" }, + { "`", "2018" }, + { "oq", "2018" }, + { "'", "2019" }, + { "cq", "2019" }, + { "bq", "201A" }, + { "lq", "201C" }, + { "rq", "201D" }, + { "Bq", "201E" }, + { "dg", "2020" }, + { "dd", "2021" }, + { "bu", "2022" }, + { "%0", "2030" }, + { "fm", "2032" }, + { "sd", "2033" }, + { "fo", "2039" }, + { "fc", "203A" }, + { "rn", "203E" }, + { "f/", "2044" }, + { "eu", "20AC" }, + { "Eu", "20AC" }, + { "-h", "210F" }, + { "hbar", "210F" }, + { "Im", "2111" }, + { "wp", "2118" }, + { "Re", "211C" }, + { "tm", "2122" }, + { "Ah", "2135" }, + { "18", "215B" }, + { "38", "215C" }, + { "58", "215D" }, + { "78", "215E" }, + { "<-", "2190" }, + { "ua", "2191" }, + { "->", "2192" }, + { "da", "2193" }, + { "<>", "2194" }, + { "va", "2195" }, + { "CR", "21B5" }, + { "lA", "21D0" }, + { "uA", "21D1" }, + { "rA", "21D2" }, + { "dA", "21D3" }, + { "hA", "21D4" }, + { "vA", "21D5" }, + { "fa", "2200" }, + { "pd", "2202" }, + { "te", "2203" }, + { "es", "2205" }, + { "gr", "2207" }, + { "mo", "2208" }, + { "nm", "2209" }, + { "st", "220B" }, + { "product", "220F" }, + { "coproduct", "2210" }, + { "sum", "2211" }, + // 'mi' and '\-' represent a MINUS sign. But it is used in many man pages + // to denote the U+002D character that introduces a command-line option. + // For devices that support copy&paste, such as devhtml and devutf8, the + // user can apply the workaround described in the PROBLEMS file. + { "\\-", "2212" }, + { "mi", "2212" }, + { "-+", "2213" }, + { "**", "2217" }, + { "sqrt", "221A" }, + { "sr", "221A" }, + { "pt", "221D" }, + { "if", "221E" }, + { "/_", "2220" }, + { "AN", "2227" }, + { "OR", "2228" }, + { "ca", "2229" }, + { "cu", "222A" }, + { "is", "222B" }, + { "integral", "222B" }, + { "tf", "2234" }, + { "3d", "2234" }, + { "ap", "223C" }, + { "|=", "2243" }, + { "=~", "2245" }, + { "~~", "2248" }, + { "~=", "2248" }, + { "!=", "2260" }, + { "==", "2261" }, + { "ne", "2262" }, + { "<=", "2264" }, + { ">=", "2265" }, + { "<<", "226A" }, + { ">>", "226B" }, + { "sb", "2282" }, + { "sp", "2283" }, + { "nb", "2284" }, + { "nc", "2285" }, + { "ib", "2286" }, + { "ip", "2287" }, + { "c+", "2295" }, + { "c*", "2297" }, + { "pp", "22A5" }, + { "md", "22C5" }, + { "lc", "2308" }, + { "rc", "2309" }, + { "lf", "230A" }, + { "rf", "230B" }, + { "parenlefttp", "239B" }, + { "parenleftex", "239C" }, + { "parenleftbt", "239D" }, + { "parenrighttp", "239E" }, + { "parenrightex", "239F" }, + { "parenrightbt", "23A0" }, + { "bracketlefttp", "23A1" }, + { "bracketleftex", "23A2" }, + { "bracketleftbt", "23A3" }, + { "bracketrighttp", "23A4" }, + { "bracketrightex", "23A5" }, + { "bracketrightbt", "23A6" }, + { "lt", "23A7" }, + { "bracelefttp", "23A7" }, + { "lk", "23A8" }, + { "braceleftmid", "23A8" }, + { "lb", "23A9" }, + { "braceleftbt", "23A9" }, + { "bv", "23AA" }, + { "braceex", "23AA" }, + { "braceleftex", "23AA" }, + { "bracerightex", "23AA" }, + { "rt", "23AB" }, + { "bracerighttp", "23AB" }, + { "rk", "23AC" }, + { "bracerightmid", "23AC" }, + { "rb", "23AD" }, + { "bracerightbt", "23AD" }, + { "an", "23AF" }, + { "br", "2502" }, + { "sq", "25A1" }, + { "lz", "25CA" }, + { "ci", "25CB" }, + { "lh", "261C" }, + { "rh", "261E" }, + { "SP", "2660" }, + { "CL", "2663" }, + { "HE", "2665" }, + { "DI", "2666" }, + { "OK", "2713" }, + // The 'left angle bracket' and 'right angle bracket' could be mapped to + // either U+2329,U+232A or U+3008,U+3009 or U+27E8,U+27E9. But the first + // and second possibility are double-width characters (see Unicode's + // 'DerivedEastAsianWidth.txt' file) and are therefore not suitable for + // general use, whereas the third possibility is single-width. + // + // The devhtml device overrides this mapping, because + // + // http://www.w3.org/TR/html401/sgml/entities.html + // + // says that in HTML, '⟨' and '⟩' are U+2329,U+232A, + // respectively. + { "la", "27E8" }, + { "ra", "27E9" }, +}; + +// global constructor +static struct glyph_to_unicode_init { + glyph_to_unicode_init(); +} _glyph_to_unicode_init; + +glyph_to_unicode_init::glyph_to_unicode_init() +{ + for (unsigned int i = 0; + i < sizeof(glyph_to_unicode_list)/sizeof(glyph_to_unicode_list[0]); + i++) { + glyph_to_unicode *gtu = new glyph_to_unicode[1]; + gtu->value = (char *)glyph_to_unicode_list[i].value; + glyph_to_unicode_table.define(glyph_to_unicode_list[i].key, gtu); + } +} + +const char *glyph_name_to_unicode(const char *s) +{ + glyph_to_unicode *result = glyph_to_unicode_table.lookup(s); + return result ? result->value : 0; +} diff --git a/src/libs/libgroff/htmlhint.cpp b/src/libs/libgroff/htmlhint.cpp new file mode 100644 index 0000000..8ebb84e --- /dev/null +++ b/src/libs/libgroff/htmlhint.cpp @@ -0,0 +1,60 @@ +/* Copyright (C) 2000-2020 Free Software Foundation, Inc. + Written by Gaius Mulley (gaius@glam.ac.uk) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "lib.h" + +#include <stddef.h> +#include <stdlib.h> + +#include "nonposix.h" +#include "stringclass.h" +#include "html-strings.h" + +/* + * This file contains a very simple set of routines which might + * be shared by preprocessors. It allows a preprocessor to indicate + * when an inline image should be created. + * This string is intercepted by pre-grohtml and substituted for + * the image name and suppression escapes. + * + * pre-html runs troff twice, once with -Thtml (or -Txhtml) and once + * with -Tps. 'troff -Thtml' (and 'troff -Txhtml') emits a + * <src='image'.png> tag and the postscript device driver works out + * the min/max limits of the graphic region. These region limits are + * read by pre-html and an image is generated via + * + * troff -Tps -> gs -> png + */ + +/* + * html_begin_suppress - emit a start of image tag which will be seen + * by pre-html. + */ +void html_begin_suppress() +{ + put_string(HTML_IMAGE_INLINE_BEGIN, stdout); +} + +/* + * html_end_suppress - emit an end of image tag which will be seen + * by pre-html. + */ +void html_end_suppress() +{ + put_string(HTML_IMAGE_INLINE_END, stdout); +} diff --git a/src/libs/libgroff/hypot.cpp b/src/libs/libgroff/hypot.cpp new file mode 100644 index 0000000..fa0977d --- /dev/null +++ b/src/libs/libgroff/hypot.cpp @@ -0,0 +1,34 @@ +/* Copyright (C) 2005-2020 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <math.h> + +double groff_hypot(double x, double y) +{ + double result = hypot(x, y); + +#ifdef __INTERIX + /* hypot() on Interix is broken */ + if (isnan(result) && !isnan(x) && !isnan(y)) + return 0.0; +#endif + + return result; +} diff --git a/src/libs/libgroff/iftoa.c b/src/libs/libgroff/iftoa.c new file mode 100644 index 0000000..87aec58 --- /dev/null +++ b/src/libs/libgroff/iftoa.c @@ -0,0 +1,76 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "lib.h" + +#ifdef __cplusplus +extern "C" { +#endif + +const char *if_to_a(int i, int decimal_point) +{ + static char buf[INT_DIGITS + 3]; // INT_DIGITS + '-', '.', '\0' + char *p = buf + INT_DIGITS + 2; + int point = 0; + buf[INT_DIGITS + 2] = '\0'; + /* assert(decimal_point <= INT_DIGITS); */ + if (i >= 0) { + do { + *--p = '0' + (i % 10); + i /= 10; + if (++point == decimal_point) + *--p = '.'; + } while (i != 0 || point < decimal_point); + } + else { /* i < 0 */ + do { + *--p = '0' - (i % 10); + i /= 10; + if (++point == decimal_point) + *--p = '.'; + } while (i != 0 || point < decimal_point); + *--p = '-'; + } + if (decimal_point > 0) { + char *q; + /* there must be a dot, so this will terminate */ + for (q = buf + INT_DIGITS + 2; q[-1] == '0'; --q) + ; + if (q[-1] == '.') { + if (q - 1 == p) { + q[-1] = '0'; + q[0] = '\0'; + } + else + q[-1] = '\0'; + } + else + *q = '\0'; + } + return p; +} + +#ifdef __cplusplus +} +#endif + +// Local Variables: +// fill-column: 72 +// mode: C++ +// End: +// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: diff --git a/src/libs/libgroff/invalid.cpp b/src/libs/libgroff/invalid.cpp new file mode 100644 index 0000000..59e4619 --- /dev/null +++ b/src/libs/libgroff/invalid.cpp @@ -0,0 +1,59 @@ +/* Copyright (C) 2000-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "lib.h" + +// Table of invalid input characters. + +char invalid_char_table[256]= { +#ifndef IS_EBCDIC_HOST + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +#else + 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +#endif +}; diff --git a/src/libs/libgroff/itoa.c b/src/libs/libgroff/itoa.c new file mode 100644 index 0000000..a573b2c --- /dev/null +++ b/src/libs/libgroff/itoa.c @@ -0,0 +1,67 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "lib.h" + +#ifdef __cplusplus +extern "C" { +#endif + +const char *i_to_a(int i) +{ + /* Room for INT_DIGITS digits, - and '\0' */ + static char buf[INT_DIGITS + 2]; + char *p = buf + INT_DIGITS + 1; /* points to terminating '\0' */ + if (i >= 0) { + do { + *--p = '0' + (i % 10); + i /= 10; + } while (i != 0); + return p; + } + else { /* i < 0 */ + do { + *--p = '0' - (i % 10); + i /= 10; + } while (i != 0); + *--p = '-'; + } + return p; +} + +const char *ui_to_a(unsigned int i) +{ + /* Room for UINT_DIGITS digits and '\0' */ + static char buf[UINT_DIGITS + 1]; + char *p = buf + UINT_DIGITS; /* points to terminating '\0' */ + do { + *--p = '0' + (i % 10); + i /= 10; + } while (i != 0); + return p; +} + +#ifdef __cplusplus +} +#endif + +// Local Variables: +// fill-column: 72 +// mode: C++ +// End: +// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: diff --git a/src/libs/libgroff/lf.cpp b/src/libs/libgroff/lf.cpp new file mode 100644 index 0000000..9c255fb --- /dev/null +++ b/src/libs/libgroff/lf.cpp @@ -0,0 +1,78 @@ +// -*- C++ -*- +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "lib.h" +#include "cset.h" +#include "stringclass.h" +#include "lf.h" + +#include <ctype.h> + +extern void change_filename(const char *); +extern void change_lineno(int); + +int interpret_lf_args(const char *p) +{ + while (*p == ' ') + p++; + if (!csdigit(*p)) + return 0; + int ln = 0; + do { + ln *= 10; + ln += *p++ - '0'; + } while (csdigit(*p)); + if (*p != ' ' && *p != '\n' && *p != '\0') + return 0; + while (*p == ' ') + p++; + if (*p == '\0' || *p == '\n') { + change_lineno(ln); + return 1; + } + const char *q; + for (q = p; + *q != '\0' && *q != ' ' && *q != '\n' && *q != '\\'; + q++) + ; + string tem(p, q - p); + while (*q == ' ') + q++; + if (*q != '\n' && *q != '\0') + return 0; + tem += '\0'; + change_filename(tem.contents()); + change_lineno(ln); + return 1; +} + +#if defined(__MSDOS__) || (defined(_WIN32) && !defined(__CYGWIN__)) +void normalize_for_lf (string &fn) +{ + int fnlen = fn.length(); + for (int i = 0; i < fnlen; i++) { + if (fn[i] == '\\') + fn[i] = '/'; + } +} +#else +void normalize_for_lf (string &) +{ +} +#endif diff --git a/src/libs/libgroff/libgroff.am b/src/libs/libgroff/libgroff.am new file mode 100644 index 0000000..be6d9e2 --- /dev/null +++ b/src/libs/libgroff/libgroff.am @@ -0,0 +1,182 @@ +# Copyright (C) 2014-2020 Free Software Foundation, Inc. +# +# This file is part of groff. +# +# groff is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# groff is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +libgroff_srcdir = $(top_srcdir)/src/libs/libgroff +noinst_LIBRARIES += libgroff.a +libgroff_a_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -D__GETOPT_PREFIX=groff_ \ + -DENABLE_RELOCATABLE=1 \ + -DLIBDIR=\"$(libdir)\" + +# Build from OBJS +libgroff_a_SOURCES = \ + src/libs/libgroff/assert.cpp \ + src/libs/libgroff/change_lf.cpp \ + src/libs/libgroff/cmap.cpp \ + src/libs/libgroff/color.cpp \ + src/libs/libgroff/cset.cpp\ + src/libs/libgroff/curtime.cpp \ + src/libs/libgroff/device.cpp \ + src/libs/libgroff/errarg.cpp \ + src/libs/libgroff/error.cpp \ + src/libs/libgroff/fatal.cpp \ + src/libs/libgroff/filename.cpp \ + src/libs/libgroff/font.cpp \ + src/libs/libgroff/fontfile.cpp \ + src/libs/libgroff/geometry.cpp \ + src/libs/libgroff/getopt.c \ + src/libs/libgroff/getopt1.c \ + src/libs/libgroff/glyphuni.cpp \ + src/libs/libgroff/htmlhint.cpp \ + src/libs/libgroff/hypot.cpp \ + src/libs/libgroff/iftoa.c \ + src/libs/libgroff/invalid.cpp \ + src/libs/libgroff/itoa.c \ + src/libs/libgroff/lf.cpp \ + src/libs/libgroff/lineno.cpp \ + src/libs/libgroff/localcharset.c \ + src/libs/libgroff/macropath.cpp \ + src/libs/libgroff/matherr.c \ + src/libs/libgroff/maxfilename.cpp \ + src/libs/libgroff/maxpathname.cpp \ + src/libs/libgroff/mksdir.cpp \ + src/libs/libgroff/nametoindex.cpp \ + src/libs/libgroff/paper.cpp \ + src/libs/libgroff/prime.cpp \ + src/libs/libgroff/progname.c \ + src/libs/libgroff/ptable.cpp \ + src/libs/libgroff/quotearg.c \ + src/libs/libgroff/relocate.cpp \ + src/libs/libgroff/searchpath.cpp \ + src/libs/libgroff/spawnvp.c \ + src/libs/libgroff/string.cpp \ + src/libs/libgroff/strsave.cpp \ + src/libs/libgroff/symbol.cpp \ + src/libs/libgroff/tmpfile.cpp \ + src/libs/libgroff/tmpname.cpp \ + src/libs/libgroff/unicode.cpp \ + src/libs/libgroff/uniglyph.cpp \ + src/libs/libgroff/uniuni.cpp \ + src/libs/libgroff/relocatable.h +if USE_GROFF_ALLOCATOR +libgroff_a_SOURCES += \ + src/libs/libgroff/new.cpp +endif +nodist_libgroff_a_SOURCES = src/libs/libgroff/version.cpp + +# TODO: these .c files could be removed (use gnulib instead). +EXTRA_DIST += \ + src/libs/libgroff/mkstemp.cpp \ + src/libs/libgroff/fmod.c \ + src/libs/libgroff/getcwd.c \ + src/libs/libgroff/putenv.c \ + src/libs/libgroff/strcasecmp.c \ + src/libs/libgroff/strerror.c \ + src/libs/libgroff/strncasecmp.c \ + src/libs/libgroff/strtol.c \ + src/libs/libgroff/config.charset \ + src/libs/libgroff/ref-add.sin \ + src/libs/libgroff/ref-del.sin \ + src/libs/libgroff/make-uniuni + +CLEANFILES += \ + src/libs/libgroff/version.cpp \ + charset.alias \ + ref-add.sed \ + ref-del.sed + +# .o files have a 'libgroff_a-' prefix because we set +# libgroff_a_CPPFLAGS. +src/libs/libgroff/libgroff_a-device.$(OBJEXT): defs.h +src/libs/libgroff/libgroff_a-fontfile.$(OBJEXT): defs.h +src/libs/libgroff/libgroff_a-macropath.$(OBJEXT): defs.h +src/libs/libgroff/libgroff_a-relocate.$(OBJEXT): defs.h + +src/libs/libgroff/version.cpp: $(top_srcdir)/.version + $(AM_V_at)printf 'const char *version_string = "%s.%s";\n' \ + $(MAJOR_VERSION) $(MINOR_VERSION) > $@.tmp + $(AM_V_at)printf 'const char *revision_string = "%s";\n' \ + $(REVISION) >> $@.tmp + $(AM_V_at)printf \ + 'extern "C" {\nconst char *Version_string = "%s";\n}\n' \ + $(VERSION) >> $@.tmp + $(AM_V_GEN)mv $@.tmp $@ + +# Data for localcharset.c. Taken from libiconv/libcharset. + +LIBGROFF_PACKAGE = groff + +all: charset.alias ref-add.sed ref-del.sed + +charset.alias: $(libgroff_srcdir)/config.charset + $(AM_V_GEN)$(SHELL) $(libgroff_srcdir)/config.charset \ + '$(HOST)' > t-$@ \ + && mv t-$@ $@ + +ref-add.sed: $(libgroff_srcdir)/ref-add.sin + $(AM_V_GEN)sed -e '/^#/d' \ + -e 's/@''PACKAGE''@/$(LIBGROFF_PACKAGE)/g' \ + $(libgroff_srcdir)/ref-add.sin > t-$@ \ + && mv t-$@ $@ + +ref-del.sed: $(libgroff_srcdir)/ref-del.sin + $(AM_V_GEN)sed -e '/^#/d' \ + -e 's/@''PACKAGE''@/$(LIBGROFF_PACKAGE)/g' \ + $(libgroff_srcdir)/ref-del.sin > t-$@ \ + && mv t-$@ $@ + +install-data-local: install_charset_data +install_charset_data: + -test $(GLIBC21) != no || $(mkinstalldirs) $(DESTDIR)$(libdir) + if test -f $(DESTDIR)$(libdir)/charset.alias; then \ + sed -f ref-add.sed $(DESTDIR)$(libdir)/charset.alias \ + > $(DESTDIR)$(libdir)/t-charset.alias; \ + $(INSTALL_DATA) $(DESTDIR)$(libdir)/t-charset.alias \ + $(DESTDIR)$(libdir)/charset.alias; \ + rm -f $(DESTDIR)$(libdir)/t-charset.alias; \ + else \ + if test $(GLIBC21) = no; then \ + sed -f ref-add.sed charset.alias \ + > $(DESTDIR)$(libdir)/t-charset.alias; \ + $(INSTALL_DATA) $(DESTDIR)$(libdir)/t-charset.alias \ + $(DESTDIR)$(libdir)/charset.alias; \ + rm -f $(DESTDIR)$(libdir)/t-charset.alias; \ + fi; \ + fi + +uninstall-local: uninstall_charset_data +uninstall_charset_data: + -if test -f $(DESTDIR)$(libdir)/charset.alias; then \ + sed -f ref-del.sed $(DESTDIR)$(libdir)/charset.alias \ + > $(DESTDIR)$(libdir)/t-charset.alias; \ + if grep '^# Packages using this file: $$' \ + $(DESTDIR)$(libdir)/t-charset.alias > /dev/null; then \ + rm -f $(DESTDIR)$(libdir)/charset.alias; \ + else \ + $(INSTALL_DATA) $(DESTDIR)$(libdir)/t-charset.alias \ + $(DESTDIR)$(libdir)/charset.alias; \ + fi; \ + rm -f $(DESTDIR)$(libdir)/t-charset.alias; \ + fi + + +# Local Variables: +# mode: makefile-automake +# fill-column: 72 +# End: +# vim: set autoindent filetype=automake textwidth=72: diff --git a/src/libs/libgroff/lineno.cpp b/src/libs/libgroff/lineno.cpp new file mode 100644 index 0000000..6e356c7 --- /dev/null +++ b/src/libs/libgroff/lineno.cpp @@ -0,0 +1,20 @@ +/* Copyright (C) 2014-2020 Free Software Foundation, Inc. + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 2 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +The GNU General Public License version 2 (GPL2) is available in the +internet at <http://www.gnu.org/licenses/gpl-2.0.txt>. */ + +// This global stores the line number of the input file being +// processed by troff, an output driver, or other program. +int current_lineno = 0; diff --git a/src/libs/libgroff/localcharset.c b/src/libs/libgroff/localcharset.c new file mode 100644 index 0000000..1bc07a4 --- /dev/null +++ b/src/libs/libgroff/localcharset.c @@ -0,0 +1,579 @@ +/* Determine a canonical name for the current locale's character encoding. + + Copyright (C) 2000-2020 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>. */ + +#include <config.h> + +/* Specification. */ +#include "localcharset.h" + +#include <fcntl.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#if defined __APPLE__ && defined __MACH__ && HAVE_LANGINFO_CODESET +# define DARWIN7 /* Darwin 7 or newer, i.e. Mac OS X 10.3 or newer */ +#endif + +#if defined _WIN32 || defined __WIN32__ +# define WINDOWS_NATIVE +# include <locale.h> +#endif + +#if defined __EMX__ +/* Assume EMX program runs on OS/2, even if compiled under DOS. */ +# ifndef OS2 +# define OS2 +# endif +#endif + +#if !defined WINDOWS_NATIVE +# include <unistd.h> +# if HAVE_LANGINFO_CODESET +# include <langinfo.h> +# else +# if 0 /* see comment below */ +# include <locale.h> +# endif +# endif +# ifdef __CYGWIN__ +# define WIN32_LEAN_AND_MEAN +# include <windows.h> +# endif +#elif defined WINDOWS_NATIVE +# define WIN32_LEAN_AND_MEAN +# include <windows.h> +#endif +#if defined OS2 +# define INCL_DOS +# include <os2.h> +#endif + +/* For MB_CUR_MAX_L */ +#if defined DARWIN7 +# include <xlocale.h> +#endif + +#if ENABLE_RELOCATABLE +# include "relocatable.h" +#else +# define relocate(pathname) (pathname) +#endif + +/* Get LIBDIR. */ +#ifndef LIBDIR +# include "configmake.h" +#endif + +/* Define O_NOFOLLOW to 0 on platforms where it does not exist. */ +#ifndef O_NOFOLLOW +# define O_NOFOLLOW 0 +#endif + +#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__ + /* Native Windows, Cygwin, OS/2, DOS */ +# define ISSLASH(C) ((C) == '/' || (C) == '\\') +#endif + +#ifndef DIRECTORY_SEPARATOR +# define DIRECTORY_SEPARATOR '/' +#endif + +#ifndef ISSLASH +# define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR) +#endif + +#if HAVE_DECL_GETC_UNLOCKED +# undef getc +# define getc getc_unlocked +#endif + +/* The following static variable is declared 'volatile' to avoid a + possible multithread problem in the function get_charset_aliases. If we + are running in a threaded environment, and if two threads initialize + 'charset_aliases' simultaneously, both will produce the same value, + and everything will be ok if the two assignments to 'charset_aliases' + are atomic. But I don't know what will happen if the two assignments mix. */ +#if __STDC__ != 1 +# define volatile /* empty */ +#endif +/* Pointer to the contents of the charset.alias file, if it has already been + read, else NULL. Its format is: + ALIAS_1 '\0' CANONICAL_1 '\0' ... ALIAS_n '\0' CANONICAL_n '\0' '\0' */ +static const char * volatile charset_aliases; + +/* Return a pointer to the contents of the charset.alias file. */ +static const char * +get_charset_aliases (void) +{ + const char *cp; + + cp = charset_aliases; + if (cp == NULL) + { +#if !(defined DARWIN7 || defined VMS || defined WINDOWS_NATIVE || defined __CYGWIN__) + const char *dir; + const char *base = "charset.alias"; + char *file_name; + + /* Make it possible to override the charset.alias location. This is + necessary for running the testsuite before "make install". */ + dir = getenv ("CHARSETALIASDIR"); + if (dir == NULL || dir[0] == '\0') + dir = relocate (LIBDIR); + + /* Concatenate dir and base into freshly allocated file_name. */ + { + size_t dir_len = strlen (dir); + size_t base_len = strlen (base); + int add_slash = (dir_len > 0 && !ISSLASH (dir[dir_len - 1])); + file_name = (char *) malloc (dir_len + add_slash + base_len + 1); + if (file_name != NULL) + { + memcpy (file_name, dir, dir_len); + if (add_slash) + file_name[dir_len] = DIRECTORY_SEPARATOR; + memcpy (file_name + dir_len + add_slash, base, base_len + 1); + } + } + + if (file_name == NULL) + /* Out of memory. Treat the file as empty. */ + cp = ""; + else + { + int fd; + + /* Open the file. Reject symbolic links on platforms that support + O_NOFOLLOW. This is a security feature. Without it, an attacker + could retrieve parts of the contents (namely, the tail of the + first line that starts with "* ") of an arbitrary file by placing + a symbolic link to that file under the name "charset.alias" in + some writable directory and defining the environment variable + CHARSETALIASDIR to point to that directory. */ + fd = open (file_name, + O_RDONLY | (HAVE_WORKING_O_NOFOLLOW ? O_NOFOLLOW : 0)); + if (fd < 0) + /* File not found. Treat it as empty. */ + cp = ""; + else + { + FILE *fp; + + fp = fdopen (fd, "r"); + if (fp == NULL) + { + /* Out of memory. Treat the file as empty. */ + close (fd); + cp = ""; + } + else + { + /* Parse the file's contents. */ + char *res_ptr = NULL; + size_t res_size = 0; + + for (;;) + { + int c; + char buf1[50+1]; + char buf2[50+1]; + size_t l1, l2; + char *old_res_ptr; + + c = getc (fp); + if (c == EOF) + break; + if (c == '\n' || c == ' ' || c == '\t') + continue; + if (c == '#') + { + /* Skip comment, to end of line. */ + do + c = getc (fp); + while (!(c == EOF || c == '\n')); + if (c == EOF) + break; + continue; + } + ungetc (c, fp); + if (fscanf (fp, "%50s %50s", buf1, buf2) < 2) + break; + l1 = strlen (buf1); + l2 = strlen (buf2); + old_res_ptr = res_ptr; + if (res_size == 0) + { + res_size = l1 + 1 + l2 + 1; + res_ptr = (char *) malloc (res_size + 1); + } + else + { + res_size += l1 + 1 + l2 + 1; + res_ptr = (char *) realloc (res_ptr, res_size + 1); + } + if (res_ptr == NULL) + { + /* Out of memory. */ + res_size = 0; + free (old_res_ptr); + break; + } + strcpy (res_ptr + res_size - (l2 + 1) - (l1 + 1), buf1); + strcpy (res_ptr + res_size - (l2 + 1), buf2); + } + fclose (fp); + if (res_size == 0) + cp = ""; + else + { + *(res_ptr + res_size) = '\0'; + cp = res_ptr; + } + } + } + + free (file_name); + } + +#else + +# if defined DARWIN7 + /* To avoid the trouble of installing a file that is shared by many + GNU packages -- many packaging systems have problems with this --, + simply inline the aliases here. */ + cp = "ISO8859-1" "\0" "ISO-8859-1" "\0" + "ISO8859-2" "\0" "ISO-8859-2" "\0" + "ISO8859-4" "\0" "ISO-8859-4" "\0" + "ISO8859-5" "\0" "ISO-8859-5" "\0" + "ISO8859-7" "\0" "ISO-8859-7" "\0" + "ISO8859-9" "\0" "ISO-8859-9" "\0" + "ISO8859-13" "\0" "ISO-8859-13" "\0" + "ISO8859-15" "\0" "ISO-8859-15" "\0" + "KOI8-R" "\0" "KOI8-R" "\0" + "KOI8-U" "\0" "KOI8-U" "\0" + "CP866" "\0" "CP866" "\0" + "CP949" "\0" "CP949" "\0" + "CP1131" "\0" "CP1131" "\0" + "CP1251" "\0" "CP1251" "\0" + "eucCN" "\0" "GB2312" "\0" + "GB2312" "\0" "GB2312" "\0" + "eucJP" "\0" "EUC-JP" "\0" + "eucKR" "\0" "EUC-KR" "\0" + "Big5" "\0" "BIG5" "\0" + "Big5HKSCS" "\0" "BIG5-HKSCS" "\0" + "GBK" "\0" "GBK" "\0" + "GB18030" "\0" "GB18030" "\0" + "SJIS" "\0" "SHIFT_JIS" "\0" + "ARMSCII-8" "\0" "ARMSCII-8" "\0" + "PT154" "\0" "PT154" "\0" + /*"ISCII-DEV" "\0" "?" "\0"*/ + "*" "\0" "UTF-8" "\0"; +# endif + +# if defined VMS + /* To avoid the troubles of an extra file charset.alias_vms in the + sources of many GNU packages, simply inline the aliases here. */ + /* The list of encodings is taken from the OpenVMS 7.3-1 documentation + "Compaq C Run-Time Library Reference Manual for OpenVMS systems" + section 10.7 "Handling Different Character Sets". */ + cp = "ISO8859-1" "\0" "ISO-8859-1" "\0" + "ISO8859-2" "\0" "ISO-8859-2" "\0" + "ISO8859-5" "\0" "ISO-8859-5" "\0" + "ISO8859-7" "\0" "ISO-8859-7" "\0" + "ISO8859-8" "\0" "ISO-8859-8" "\0" + "ISO8859-9" "\0" "ISO-8859-9" "\0" + /* Japanese */ + "eucJP" "\0" "EUC-JP" "\0" + "SJIS" "\0" "SHIFT_JIS" "\0" + "DECKANJI" "\0" "DEC-KANJI" "\0" + "SDECKANJI" "\0" "EUC-JP" "\0" + /* Chinese */ + "eucTW" "\0" "EUC-TW" "\0" + "DECHANYU" "\0" "DEC-HANYU" "\0" + "DECHANZI" "\0" "GB2312" "\0" + /* Korean */ + "DECKOREAN" "\0" "EUC-KR" "\0"; +# endif + +# if defined WINDOWS_NATIVE || defined __CYGWIN__ + /* To avoid the troubles of installing a separate file in the same + directory as the DLL and of retrieving the DLL's directory at + runtime, simply inline the aliases here. */ + + cp = "CP936" "\0" "GBK" "\0" + "CP1361" "\0" "JOHAB" "\0" + "CP20127" "\0" "ASCII" "\0" + "CP20866" "\0" "KOI8-R" "\0" + "CP20936" "\0" "GB2312" "\0" + "CP21866" "\0" "KOI8-RU" "\0" + "CP28591" "\0" "ISO-8859-1" "\0" + "CP28592" "\0" "ISO-8859-2" "\0" + "CP28593" "\0" "ISO-8859-3" "\0" + "CP28594" "\0" "ISO-8859-4" "\0" + "CP28595" "\0" "ISO-8859-5" "\0" + "CP28596" "\0" "ISO-8859-6" "\0" + "CP28597" "\0" "ISO-8859-7" "\0" + "CP28598" "\0" "ISO-8859-8" "\0" + "CP28599" "\0" "ISO-8859-9" "\0" + "CP28605" "\0" "ISO-8859-15" "\0" + "CP38598" "\0" "ISO-8859-8" "\0" + "CP51932" "\0" "EUC-JP" "\0" + "CP51936" "\0" "GB2312" "\0" + "CP51949" "\0" "EUC-KR" "\0" + "CP51950" "\0" "EUC-TW" "\0" + "CP54936" "\0" "GB18030" "\0" + "CP65001" "\0" "UTF-8" "\0"; +# endif +#endif + + charset_aliases = cp; + } + + return cp; +} + +/* Determine the current locale's character encoding, and canonicalize it + into one of the canonical names listed in config.charset. + The result must not be freed; it is statically allocated. + If the canonical name cannot be determined, the result is a non-canonical + name. */ + +#ifdef STATIC +STATIC +#endif +const char * +locale_charset (void) +{ + const char *codeset; + const char *aliases; + +#if !(defined WINDOWS_NATIVE || defined OS2) + +# if HAVE_LANGINFO_CODESET + + /* Most systems support nl_langinfo (CODESET) nowadays. */ + codeset = nl_langinfo (CODESET); + +# ifdef __CYGWIN__ + /* Cygwin < 1.7 does not have locales. nl_langinfo (CODESET) always + returns "US-ASCII". Return the suffix of the locale name from the + environment variables (if present) or the codepage as a number. */ + if (codeset != NULL && strcmp (codeset, "US-ASCII") == 0) + { + const char *locale; + static char buf[2 + 10 + 1]; + + locale = getenv ("LC_ALL"); + if (locale == NULL || locale[0] == '\0') + { + locale = getenv ("LC_CTYPE"); + if (locale == NULL || locale[0] == '\0') + locale = getenv ("LANG"); + } + if (locale != NULL && locale[0] != '\0') + { + /* If the locale name contains an encoding after the dot, return + it. */ + const char *dot = strchr (locale, '.'); + + if (dot != NULL) + { + const char *modifier; + + dot++; + /* Look for the possible @... trailer and remove it, if any. */ + modifier = strchr (dot, '@'); + if (modifier == NULL) + return dot; + if (modifier - dot < sizeof (buf)) + { + memcpy (buf, dot, modifier - dot); + buf [modifier - dot] = '\0'; + return buf; + } + } + } + + /* The Windows API has a function returning the locale's codepage as a + number: GetACP(). This encoding is used by Cygwin, unless the user + has set the environment variable CYGWIN=codepage:oem (which very few + people do). + Output directed to console windows needs to be converted (to + GetOEMCP() if the console is using a raster font, or to + GetConsoleOutputCP() if it is using a TrueType font). Cygwin does + this conversion transparently (see winsup/cygwin/fhandler_console.cc), + converting to GetConsoleOutputCP(). This leads to correct results, + except when SetConsoleOutputCP has been called and a raster font is + in use. */ + sprintf (buf, "CP%u", GetACP ()); + codeset = buf; + } +# endif + +# else + + /* On old systems which lack it, use setlocale or getenv. */ + const char *locale = NULL; + + /* But most old systems don't have a complete set of locales. Some + (like SunOS 4 or DJGPP) have only the C locale. Therefore we don't + use setlocale here; it would return "C" when it doesn't support the + locale name the user has set. */ +# if 0 + locale = setlocale (LC_CTYPE, NULL); +# endif + if (locale == NULL || locale[0] == '\0') + { + locale = getenv ("LC_ALL"); + if (locale == NULL || locale[0] == '\0') + { + locale = getenv ("LC_CTYPE"); + if (locale == NULL || locale[0] == '\0') + locale = getenv ("LANG"); + } + } + + /* On some old systems, one used to set locale = "iso8859_1". On others, + you set it to "language_COUNTRY.charset". In any case, we resolve it + through the charset.alias file. */ + codeset = locale; + +# endif + +#elif defined WINDOWS_NATIVE + + static char buf[2 + 10 + 1]; + + /* The Windows API has a function returning the locale's codepage as + a number, but the value doesn't change according to what the + 'setlocale' call specified. So we use it as a last resort, in + case the string returned by 'setlocale' doesn't specify the + codepage. */ + char *current_locale = setlocale (LC_ALL, NULL); + char *pdot; + + /* If they set different locales for different categories, + 'setlocale' will return a semi-colon separated list of locale + values. To make sure we use the correct one, we choose LC_CTYPE. */ + if (strchr (current_locale, ';')) + current_locale = setlocale (LC_CTYPE, NULL); + + pdot = strrchr (current_locale, '.'); + if (pdot) + sprintf (buf, "CP%s", pdot + 1); + else + { + /* The Windows API has a function returning the locale's codepage as a + number: GetACP(). + When the output goes to a console window, it needs to be provided in + GetOEMCP() encoding if the console is using a raster font, or in + GetConsoleOutputCP() encoding if it is using a TrueType font. + But in GUI programs and for output sent to files and pipes, GetACP() + encoding is the best bet. */ + sprintf (buf, "CP%u", GetACP ()); + } + codeset = buf; + +#elif defined OS2 + + const char *locale; + static char buf[2 + 10 + 1]; + ULONG cp[3]; + ULONG cplen; + + /* Allow user to override the codeset, as set in the operating system, + with standard language environment variables. */ + locale = getenv ("LC_ALL"); + if (locale == NULL || locale[0] == '\0') + { + locale = getenv ("LC_CTYPE"); + if (locale == NULL || locale[0] == '\0') + locale = getenv ("LANG"); + } + if (locale != NULL && locale[0] != '\0') + { + /* If the locale name contains an encoding after the dot, return it. */ + const char *dot = strchr (locale, '.'); + + if (dot != NULL) + { + const char *modifier; + + dot++; + /* Look for the possible @... trailer and remove it, if any. */ + modifier = strchr (dot, '@'); + if (modifier == NULL) + return dot; + if (modifier - dot < sizeof (buf)) + { + memcpy (buf, dot, modifier - dot); + buf [modifier - dot] = '\0'; + return buf; + } + } + + /* Resolve through the charset.alias file. */ + codeset = locale; + } + else + { + /* OS/2 has a function returning the locale's codepage as a number. */ + if (DosQueryCp (sizeof (cp), cp, &cplen)) + codeset = ""; + else + { + sprintf (buf, "CP%u", cp[0]); + codeset = buf; + } + } + +#endif + + if (codeset == NULL) + /* The canonical name cannot be determined. */ + codeset = ""; + + /* Resolve alias. */ + for (aliases = get_charset_aliases (); + *aliases != '\0'; + aliases += strlen (aliases) + 1, aliases += strlen (aliases) + 1) + if (strcmp (codeset, aliases) == 0 + || (aliases[0] == '*' && aliases[1] == '\0')) + { + codeset = aliases + strlen (aliases) + 1; + break; + } + + /* Don't return an empty string. GNU libc and GNU libiconv interpret + the empty string as denoting "the locale's character encoding", + thus GNU libiconv would call this function a second time. */ + if (codeset[0] == '\0') + codeset = "ASCII"; + +#ifdef DARWIN7 + /* Mac OS X sets MB_CUR_MAX to 1 when LC_ALL=C, and "UTF-8" + (the default codeset) does not work when MB_CUR_MAX is 1. */ + if (strcmp (codeset, "UTF-8") == 0 && MB_CUR_MAX_L (uselocale (NULL)) <= 1) + codeset = "ASCII"; +#endif + + return codeset; +} diff --git a/src/libs/libgroff/macropath.cpp b/src/libs/libgroff/macropath.cpp new file mode 100644 index 0000000..a9c9b35 --- /dev/null +++ b/src/libs/libgroff/macropath.cpp @@ -0,0 +1,29 @@ +// -*- C++ -*- +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "lib.h" +#include "searchpath.h" +#include "macropath.h" +#include "defs.h" + +#define MACROPATH_ENVVAR "GROFF_TMAC_PATH" + +search_path macro_path(MACROPATH_ENVVAR, MACROPATH, 1, 1); +search_path safer_macro_path(MACROPATH_ENVVAR, MACROPATH, 1, 0); +search_path config_macro_path(MACROPATH_ENVVAR, MACROPATH, 0, 0); diff --git a/src/libs/libgroff/make-uniuni b/src/libs/libgroff/make-uniuni new file mode 100755 index 0000000..386eacd --- /dev/null +++ b/src/libs/libgroff/make-uniuni @@ -0,0 +1,162 @@ +#! /bin/sh +# +# make-uniuni -- script for creating the file uniuni.cpp +# +# Copyright (C) 2005-2020 Free Software Foundation, Inc. +# Written by Werner Lemberg <wl@gnu.org> +# +# This file is part of groff. +# +# groff is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# groff is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# +# usage: +# +# make-uniuni <version-string> < UnicodeData.txt > uniuni.cpp +# +# 'UnicodeData.txt' is the central database file from the Unicode standard. +# Unfortunately, it doesn't contain a version number which must be thus +# provided manually as a parameter to the filter. +# +# This program needs a C preprocessor. +# + +CPP=cpp + +prog="$0" + +if test $# -ne 1; then + echo "usage: $0 <version-string> < UnicodeData.txt > uniuni.cpp" + exit 1 +fi + +version_string="$1" + +# Remove ranges and control characters, +# then extract the decomposition field, +# then remove lines without decomposition, +# then remove all compatibility decompositions. +sed -e '/^[^;]*;</d' \ +| sed -e 's/;[^;]*;[^;]*;[^;]*;[^;]*;\([^;]*\);.*$/;\1/' \ +| sed -e '/^[^;]*;$/d' \ +| sed -e '/^[^;]*;</d' > $$1 + +# Prepare input for running cpp. +cat $$1 \ +| sed -e 's/^\([^;]*\);/#define \1 /' \ + -e 's/ / u/g' > $$2 +cat $$1 \ +| sed -e 's/^\([^;]*\);.*$/\1 u\1/' >> $$2 + +# Run C preprocessor to recursively decompose. +$CPP $$2 $$3 + +# Convert it back to original format. +cat $$3 \ +| sed -e '/#/d' \ + -e '/^$/d' \ + -e 's/ \+/ /g' \ + -e 's/ *$//' \ + -e 's/u//g' \ + -e 's/^\([^ ]*\) /\1;/' > $$4 + +# Write preamble. +cat <<END +// -*- C++ -*- +/* Copyright (C) 2002-2014 Free Software Foundation, Inc. + Written by Werner Lemberg <wl@gnu.org> + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +// This code has been algorithmically derived from the file +// UnicodeData.txt, version $version_string, available from unicode.org, +// on `date '+%Y-%m-%d'`. + +#include "lib.h" +#include "stringclass.h" +#include "ptable.h" + +#include "unicode.h" + +struct unicode_decompose { + char *value; +}; + +declare_ptable(unicode_decompose) +implement_ptable(unicode_decompose) + +PTABLE(unicode_decompose) unicode_decompose_table; + +// the first digit in the composite string gives the number of composites + +struct S { + const char *key; + const char *value; +} unicode_decompose_list[] = { +END + +# Emit Unicode data. +cat $$4 \ +| sed -e 's/ /_/g' \ + -e 's/\(.*\);\(.*_.*_.*_.*\)$/ { "\1", "4\2" },/' \ + -e 's/\(.*\);\(.*_.*_.*\)$/ { "\1", "3\2" },/' \ + -e 's/\(.*\);\(.*_.*\)$/ { "\1", "2\2" },/' \ + -e 's/\(.*\);\(.*\)$/ { "\1", "1\2" },/' + +# Write postamble. +cat <<END +}; + +// global constructor + +static struct unicode_decompose_init { + unicode_decompose_init(); +} _unicode_decompose_init; + +unicode_decompose_init::unicode_decompose_init() +{ + for (unsigned int i = 0; + i < sizeof(unicode_decompose_list)/sizeof(unicode_decompose_list[0]); + i++) { + unicode_decompose *dec = new unicode_decompose[1]; + dec->value = (char *)unicode_decompose_list[i].value; + unicode_decompose_table.define(unicode_decompose_list[i].key, dec); + } +} + +const char *decompose_unicode(const char *s) +{ + unicode_decompose *result = unicode_decompose_table.lookup(s); + return result ? result->value : 0; +} +END + + +# Remove temporary files. +rm $$1 $$2 $$3 $$4 + +# EOF diff --git a/src/libs/libgroff/matherr.c b/src/libs/libgroff/matherr.c new file mode 100644 index 0000000..a1adbf8 --- /dev/null +++ b/src/libs/libgroff/matherr.c @@ -0,0 +1,48 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <math.h> +#include <errno.h> + +#ifdef HAVE_STRUCT_EXCEPTION +#ifdef TLOSS + +int matherr(exc) +struct exception *exc; +{ + switch (exc->type) { + case SING: + case DOMAIN: + errno = EDOM; + break; + case OVERFLOW: + case UNDERFLOW: + case TLOSS: + case PLOSS: + errno = ERANGE; + break; + } + return 1; +} + +#endif /* TLOSS */ +#endif /* HAVE_STRUCT_EXCEPTION */ diff --git a/src/libs/libgroff/maxfilename.cpp b/src/libs/libgroff/maxfilename.cpp new file mode 100644 index 0000000..5e1defe --- /dev/null +++ b/src/libs/libgroff/maxfilename.cpp @@ -0,0 +1,75 @@ +// -*- C++ -*- +/* Copyright (C) 1992-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* file_name_max(dir) does the same as pathconf(dir, _PC_NAME_MAX) */ + +#include "lib.h" + +#include <sys/types.h> + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#ifdef _POSIX_VERSION + +size_t file_name_max(const char *fname) +{ + return pathconf(fname, _PC_NAME_MAX); +} + +#else /* not _POSIX_VERSION */ + +#ifdef HAVE_DIRENT_H +#include <dirent.h> +#else /* not HAVE_DIRENT_H */ +#ifdef HAVE_SYS_DIR_H +#include <sys/dir.h> +#endif /* HAVE_SYS_DIR_H */ +#endif /* not HAVE_DIRENT_H */ + +#ifndef NAME_MAX +#ifdef MAXNAMLEN +#define NAME_MAX MAXNAMLEN +#endif +#endif + +#ifndef NAME_MAX +#ifdef MAXNAMELEN +#define NAME_MAX MAXNAMELEN +#endif +#endif + +#ifndef NAME_MAX +#include <stdio.h> +#ifdef FILENAME_MAX +#define NAME_MAX FILENAME_MAX +#endif +#endif + +#ifndef NAME_MAX +#define NAME_MAX 14 +#endif + +size_t file_name_max(const char *) +{ + return NAME_MAX; +} + +#endif /* not _POSIX_VERSION */ diff --git a/src/libs/libgroff/maxpathname.cpp b/src/libs/libgroff/maxpathname.cpp new file mode 100644 index 0000000..8041eeb --- /dev/null +++ b/src/libs/libgroff/maxpathname.cpp @@ -0,0 +1,70 @@ +// -*- C++ -*- +/* Copyright (C) 2005-2020 Free Software Foundation, Inc. + Written by Werner Lemberg (wl@gnu.org) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* path_name_max(dir) does the same as pathconf(dir, _PC_PATH_MAX) */ + +#include "lib.h" + +#include <sys/types.h> + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#ifdef _POSIX_VERSION + +size_t path_name_max() +{ + return pathconf("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf("/",_PC_PATH_MAX); +} + +#else /* not _POSIX_VERSION */ + +#include <stdlib.h> + +#ifdef HAVE_DIRENT_H +# include <dirent.h> +#else /* not HAVE_DIRENT_H */ +# ifdef HAVE_SYS_DIR_H +# include <sys/dir.h> +# endif /* HAVE_SYS_DIR_H */ +#endif /* not HAVE_DIRENT_H */ + +#ifndef PATH_MAX +# ifdef MAXPATHLEN +# define PATH_MAX MAXPATHLEN +# else /* !MAXPATHLEN */ +# ifdef MAX_PATH +# define PATH_MAX MAX_PATH +# else /* !MAX_PATH */ +# ifdef _MAX_PATH +# define PATH_MAX _MAX_PATH +# else /* !_MAX_PATH */ +# define PATH_MAX 255 +# endif /* !_MAX_PATH */ +# endif /* !MAX_PATH */ +# endif /* !MAXPATHLEN */ +#endif /* !PATH_MAX */ + +size_t path_name_max() +{ + return PATH_MAX; +} + +#endif /* not _POSIX_VERSION */ diff --git a/src/libs/libgroff/mksdir.cpp b/src/libs/libgroff/mksdir.cpp new file mode 100644 index 0000000..5fa6d28 --- /dev/null +++ b/src/libs/libgroff/mksdir.cpp @@ -0,0 +1,33 @@ +/* Copyright (C) 2001-2020 Free Software Foundation, Inc. + Written by Werner Lemberg (wl@gnu.org) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + + +/* This file is heavily based on the file mkstemp.c which is part of the + fileutils package. */ + + +extern int gen_tempname(char *, int = 0); + +/* Generate a unique temporary directory name from TEMPLATE. + The last six characters of TEMPLATE must be "XXXXXX"; + they are replaced with a string that makes the filename unique. + Then open the directory and return a fd. */ +int mksdir(char *tmpl) +{ + return gen_tempname(tmpl, 1); +} diff --git a/src/libs/libgroff/mkstemp.cpp b/src/libs/libgroff/mkstemp.cpp new file mode 100644 index 0000000..089a10a --- /dev/null +++ b/src/libs/libgroff/mkstemp.cpp @@ -0,0 +1,33 @@ +/* Copyright (C) 2001-2020 Free Software Foundation, Inc. + Written by Werner Lemberg (wl@gnu.org) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + + +/* This file is heavily based on the file mkstemp.c which is part of the + fileutils package. */ + + +extern int gen_tempname(char *, int); + +/* Generate a unique temporary file name from TEMPLATE. + The last six characters of TEMPLATE must be "XXXXXX"; + they are replaced with a string that makes the filename unique. + Then open the file and return a fd. */ +int mkstemp(char *tmpl) +{ + return gen_tempname(tmpl, 0); +} diff --git a/src/libs/libgroff/nametoindex.cpp b/src/libs/libgroff/nametoindex.cpp new file mode 100644 index 0000000..095a432 --- /dev/null +++ b/src/libs/libgroff/nametoindex.cpp @@ -0,0 +1,167 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "lib.h" + +#include <assert.h> +#include <ctype.h> +#include <stdlib.h> + +#include "errarg.h" +#include "error.h" +#include "font.h" +#include "ptable.h" +#include "itable.h" + +// Every glyphinfo is actually a charinfo. +class charinfo : glyph { +public: + const char *name; // The glyph name, or a null pointer. + friend class character_indexer; +}; + +// PTABLE(charinfo) is a hash table mapping 'const char *' to 'charinfo *'. +declare_ptable(charinfo) +implement_ptable(charinfo) + +// ITABLE(charinfo) is a hash table mapping 'int >= 0' to 'charinfo *'. +declare_itable(charinfo) +implement_itable(charinfo) + +// This class is as a registry storing all named and numbered glyphs known +// so far, and assigns a unique index to each glyph. +class character_indexer { +public: + character_indexer(); + ~character_indexer(); + // --------------------- Lookup or creation of a glyph. + glyph *ascii_char_glyph(unsigned char); + glyph *named_char_glyph(const char *); + glyph *numbered_char_glyph(int); +private: + int next_index; // Number of glyphs already allocated. + PTABLE(charinfo) table; // Table mapping name to glyph. + glyph *ascii_glyph[256]; // Shorthand table for looking up "charNNN" + // glyphs. + ITABLE(charinfo) ntable; // Table mapping number to glyph. + enum { NSMALL = 256 }; + glyph *small_number_glyph[NSMALL]; // Shorthand table for looking up + // numbered glyphs with small numbers. +}; + +character_indexer::character_indexer() +: next_index(0) +{ + int i; + for (i = 0; i < 256; i++) + ascii_glyph[i] = UNDEFINED_GLYPH; + for (i = 0; i < NSMALL; i++) + small_number_glyph[i] = UNDEFINED_GLYPH; +} + +character_indexer::~character_indexer() +{ +} + +glyph *character_indexer::ascii_char_glyph(unsigned char c) +{ + if (ascii_glyph[c] == UNDEFINED_GLYPH) { + char buf[4+3+1]; + memcpy(buf, "char", 4); + strcpy(buf + 4, i_to_a(c)); + charinfo *ci = new charinfo; + ci->index = next_index++; + ci->number = -1; + ci->name = strsave(buf); + ascii_glyph[c] = ci; + } + return ascii_glyph[c]; +} + +inline glyph *character_indexer::named_char_glyph(const char *s) +{ + // Glyphs with name 'charNNN' are only stored in ascii_glyph[], not + // in the table. Therefore treat them specially here. + if (s[0] == 'c' && s[1] == 'h' && s[2] == 'a' && s[3] == 'r') { + char *val; + long n = strtol(s + 4, &val, 10); + if (val != s + 4 && *val == '\0' && n >= 0 && n < 256) + return ascii_char_glyph((unsigned char)n); + } + charinfo *ci = table.lookupassoc(&s); + if (0 == ci) { + ci = new charinfo[1]; + ci->index = next_index++; + ci->number = -1; + ci->name = table.define(s, ci); + } + return ci; +} + +inline glyph *character_indexer::numbered_char_glyph(int n) +{ + if (n >= 0 && n < NSMALL) { + if (small_number_glyph[n] == UNDEFINED_GLYPH) { + charinfo *ci = new charinfo; + ci->index = next_index++; + ci->number = n; + ci->name = 0; + small_number_glyph[n] = ci; + } + return small_number_glyph[n]; + } + charinfo *ci = ntable.lookup(n); + if (0 == ci) { + ci = new charinfo[1]; + ci->index = next_index++; + ci->number = n; + ci->name = 0; + ntable.define(n, ci); + } + return ci; +} + +static character_indexer indexer; + +glyph *number_to_glyph(int n) +{ + return indexer.numbered_char_glyph(n); +} + +// troff overrides this function with its own version. + +glyph *name_to_glyph(const char *s) +{ + assert(s != 0 && s[0] != '\0' && s[0] != ' '); + if (s[1] == '\0') + // \200 and char128 are synonyms + return indexer.ascii_char_glyph(s[0]); + return indexer.named_char_glyph(s); +} + +const char *glyph_to_name(glyph *g) +{ + charinfo *ci = (charinfo *)g; // Every glyph is actually a charinfo. + return ci->name; +} + +// Local Variables: +// fill-column: 72 +// mode: C++ +// End: +// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: diff --git a/src/libs/libgroff/new.cpp b/src/libs/libgroff/new.cpp new file mode 100644 index 0000000..2af976c --- /dev/null +++ b/src/libs/libgroff/new.cpp @@ -0,0 +1,75 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "lib.h" + +#include <stddef.h> +#include <stdlib.h> + +#include "posix.h" +#include "nonposix.h" + +extern "C" const char *program_name; + +static void ewrite(const char *s) +{ + write(2, s, strlen(s)); +} + +void *operator new(size_t size) +{ + // Avoid relying on the behaviour of malloc(0). + if (size == 0) + size++; + char *p = (char *)malloc(unsigned(size)); + if (p == 0) { + if (program_name) { + ewrite(program_name); + ewrite(": "); + } + ewrite("out of memory\n"); + _exit(-1); + } + return p; +} + +void operator delete(void *p) throw() +{ + if (p) + free(p); +} + +void operator delete(void *p, + __attribute__((__unused__)) long unsigned int size) +{ + // It's ugly to duplicate the code from delete(void *) above, but if + // we don't, g++ 6.3 can't figure out we're calling through it to + // free(). + // + // In function 'void operator delete(void*, long unsigned int)': + // warning: deleting 'void*' is undefined [-Wdelete-incomplete] + //delete p; + if (p) + free(p); +} + +// Local Variables: +// fill-column: 72 +// mode: C++ +// End: +// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: diff --git a/src/libs/libgroff/paper.cpp b/src/libs/libgroff/paper.cpp new file mode 100644 index 0000000..842f369 --- /dev/null +++ b/src/libs/libgroff/paper.cpp @@ -0,0 +1,82 @@ +// -*- C++ -*- +/* Copyright (C) 2002-2020 Free Software Foundation, Inc. + Written by Werner Lemberg (wl@gnu.org) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "lib.h" +#include "paper.h" + +paper papersizes[NUM_PAPERSIZES]; + +// length and width in mm +static void add_iso_paper(char series, int offset, + int start_length, int start_width) +{ + int length = start_length; + int width = start_width; + for (int i = 0; i < 8; i++) + { + char *p = new char[3]; + p[0] = series; + p[1] = '0' + i; + p[2] = '\0'; + papersizes[offset + i].name = p; + // convert mm to inch + papersizes[offset + i].length = (double)length / 25.4; + papersizes[offset + i].width = (double)width / 25.4; + // after division by two, values must be rounded down to the next + // integer (as specified by ISO) + int tmp = length; + length = width; + width = tmp / 2; + } +} + +// length and width in inch +static void add_american_paper(const char *name, int idx, + double length, double width ) +{ + char *p = new char[strlen(name) + 1]; + strcpy(p, name); + papersizes[idx].name = p; + papersizes[idx].length = length; + papersizes[idx].width = width; +} + +int papersize_init::initialised = 0; + +papersize_init::papersize_init() +{ + if (initialised) + return; + initialised = 1; + add_iso_paper('a', 0, 1189, 841); + add_iso_paper('b', 8, 1414, 1000); + add_iso_paper('c', 16, 1297, 917); + add_iso_paper('d', 24, 1090, 771); + add_american_paper("letter", 32, 11, 8.5); + add_american_paper("legal", 33, 14, 8.5); + add_american_paper("tabloid", 34, 17, 11); + add_american_paper("ledger", 35, 11, 17); + add_american_paper("statement", 36, 8.5, 5.5); + add_american_paper("executive", 37, 10, 7.5); + // the next three entries are for grolj4 + add_american_paper("com10", 38, 9.5, 4.125); + add_american_paper("monarch", 39, 7.5, 3.875); + // this is an ISO format, but it easier to use add_american_paper + add_american_paper("dl", 40, 220/25.4, 110/25.4); +} diff --git a/src/libs/libgroff/prime.cpp b/src/libs/libgroff/prime.cpp new file mode 100644 index 0000000..5ae068d --- /dev/null +++ b/src/libs/libgroff/prime.cpp @@ -0,0 +1,55 @@ +/* Copyright (C) 2014-2020 Free Software Foundation, Inc. + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 2 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +The GNU General Public License version 2 (GPL2) is available in the +internet at <http://www.gnu.org/licenses/gpl-2.0.txt>. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <math.h> + +bool is_prime(unsigned n) +{ + assert(n > 1); + if (n <= 3) + return true; + if (!(n & 1)) + return false; + if (n % 3 == 0) + return false; + unsigned lim = unsigned(sqrt((double)n)); + unsigned d = 5; + for (;;) { + if (d > lim) + break; + if (n % d == 0) + return false; + d += 2; + if (d > lim) + break; + if (n % d == 0) + return false; + d += 4; + } + return true; +} + +// Local Variables: +// fill-column: 72 +// mode: C++ +// End: +// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: diff --git a/src/libs/libgroff/progname.c b/src/libs/libgroff/progname.c new file mode 100644 index 0000000..f4320c1 --- /dev/null +++ b/src/libs/libgroff/progname.c @@ -0,0 +1,18 @@ +/* Copyright (C) 2014-2020 Free Software Foundation, Inc. + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 2 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +The GNU General Public License version 2 (GPL2) is available in the +internet at <http://www.gnu.org/licenses/gpl-2.0.txt>. */ + +const char *program_name = 0; diff --git a/src/libs/libgroff/ptable.cpp b/src/libs/libgroff/ptable.cpp new file mode 100644 index 0000000..52d09f8 --- /dev/null +++ b/src/libs/libgroff/ptable.cpp @@ -0,0 +1,57 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include "ptable.h" +#include "errarg.h" +#include "error.h" + +unsigned long hash_string(const char *s) +{ + // This is the mythical Aho-Hopcroft-Ullman hash function. + // TODO: Improve. See http://www.haible.de/bruno/hashfunc.html + assert(s != 0); + unsigned long h = 0, g; + while (*s != 0) { + h <<= 4; + h += *s++; + if ((g = h & 0xf0000000) != 0) { + h ^= g >> 24; + h ^= g; + } + } + return h; +} + +static const unsigned table_sizes[] = { + 101, 503, 1009, 2003, 3001, 4001, 5003, 10007, 20011, 40009, + 80021, 160001, 500009, 1000003, 2000003, 4000037, 8000009, + 16000057, 32000011, 64000031, 128000003, 0 +}; + +unsigned next_ptable_size(unsigned n) +{ + const unsigned *p; + for (p = table_sizes; *p <= n; p++) + if (*p == 0) + fatal("cannot expand table"); + return *p; +} + +// end of ptable.cpp diff --git a/src/libs/libgroff/putenv.c b/src/libs/libgroff/putenv.c new file mode 100644 index 0000000..692a126 --- /dev/null +++ b/src/libs/libgroff/putenv.c @@ -0,0 +1,97 @@ +/* Copyright (C) 1991-2020 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* Hacked slightly by jjc@jclark.com for groff. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> + +#ifdef __STDC__ +#include <stddef.h> +typedef void *PTR; +typedef size_t SIZE_T; +#else /* not __STDC__ */ +typedef char *PTR; +typedef int SIZE_T; +#endif /* not __STDC__ */ + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#else /* not HAVE_STDLIB_H */ +PTR malloc(); +#endif /* not HAVE_STDLIB_H */ + +#ifndef NULL +#define NULL 0 +#endif + +extern char **environ; + +/* Put STRING, which is of the form 'NAME=VALUE', in the environment. */ + +int putenv(const char *string) +{ + char *name_end = strchr(string, '='); + SIZE_T size; + char **ep; + + if (name_end == NULL) + { + /* Remove the variable from the environment. */ + size = strlen(string); + for (ep = environ; *ep != NULL; ++ep) + if (!strncmp(*ep, string, size) && (*ep)[size] == '=') + { + while (ep[1] != NULL) + { + ep[0] = ep[1]; + ++ep; + } + *ep = NULL; + return 0; + } + } + + size = 0; + for (ep = environ; *ep != NULL; ++ep) + if (!strncmp(*ep, string, name_end - string) + && (*ep)[name_end - string] == '=') + break; + else + ++size; + + if (*ep == NULL) + { + static char **last_environ = NULL; + char **new_environ = (char **) malloc((size + 2) * sizeof(char *)); + if (new_environ == NULL) + return -1; + (void) memcpy((PTR) new_environ, (PTR) environ, size * sizeof(char *)); + new_environ[size] = (char *) string; + new_environ[size + 1] = NULL; + if (last_environ != NULL) + free((PTR) last_environ); + last_environ = new_environ; + environ = new_environ; + } + else + *ep = (char *) string; + + return 0; +} diff --git a/src/libs/libgroff/quotearg.c b/src/libs/libgroff/quotearg.c new file mode 100644 index 0000000..75eaca8 --- /dev/null +++ b/src/libs/libgroff/quotearg.c @@ -0,0 +1,213 @@ +/* Copyright (C) 2004-2020 Free Software Foundation, Inc. + Written by: Jeff Conrad (jeff_conrad@msn.com) + and Keith Marshall (keith.d.marshall@ntlworld.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <limits.h> + +/* Define the default mechanism, and messages, for error reporting + * (user may substitute a preferred alternative, by defining his own + * implementation of the macros REPORT_ERROR, QUOTE_ARG_MALLOC_FAILED + * and QUOTE_ARG_REALLOC_FAILED, in the header file 'nonposix.h'). + */ + +#include "nonposix.h" + +#ifndef REPORT_ERROR +# define REPORT_ERROR(WHY) fprintf(stderr, "%s:%s\n", program_name, WHY) +#endif +#ifndef QUOTE_ARG_MALLOC_ERROR +# define QUOTE_ARG_MALLOC_ERROR "malloc: Buffer allocation failed" +#endif +#ifndef QUOTE_ARG_REALLOC_ERROR +# define QUOTE_ARG_REALLOC_ERROR "realloc: Buffer resize failed" +#endif + +extern char *program_name; /* main program must define this */ + +/* Prototypes */ +char *quote_arg(char *); +void purge_quoted_args(char **); + +#undef FALSE +#undef TRUE +#define FALSE 0 +#define TRUE 1 + +static int +needs_quoting(const char *string) +{ + /* Scan 'string' to see whether it needs quoting for MSVC 'spawn'/'exec' + * (i.e., whether it contains whitespace or embedded quotes). + */ + + if (string == NULL) /* ignore NULL strings */ + return FALSE; + + if (*string == '\0') /* explicit arguments of zero length */ + return TRUE; /* need quoting, so they aren't discarded */ + + while (*string) { + /* Scan non-NULL strings, up to '\0' terminator, + * returning 'TRUE' if quote or white space found. + */ + + if (*string == '"' || isspace(*string)) + return TRUE; + + /* otherwise, continue scanning to end of string */ + + ++string; + } + + /* Fall through, if no quotes or white space found, + * in which case, return 'FALSE'. + */ + + return FALSE; +} + +char * +quote_arg(char *string) +{ + /* Enclose arguments in double quotes so that the parsing done in the + * MSVC runtime startup code doesn't split them at whitespace. Escape + * embedded double quotes so that they emerge intact from the parsing. + */ + + int backslashes; + char *quoted, *p, *q; + + if (needs_quoting(string)) { + /* Need to create a quoted copy of 'string'; + * maximum buffer space needed is twice the original length, + * plus two enclosing quotes and one '\0' terminator. + */ + + if ((quoted = (char *)malloc(2 * strlen(string) + 3)) == NULL) { + /* Couldn't get a buffer for the quoted string, + * so complain, and bail out gracefully. + */ + + REPORT_ERROR(QUOTE_ARG_MALLOC_ERROR); + exit(1); + } + + /* Ok to proceed: + * insert the opening quote, then copy the source string, + * adding escapes as required. + */ + + *quoted = '"'; + for (backslashes = 0, p = string, q = quoted; *p; p++) { + if (*p == '\\') { + /* Just count backslashes when we find them. + * We will copy them out later, when we know if the count + * needs to be adjusted, to escape an embedded quote. + */ + + ++backslashes; + } + else if (*p == '"') { + /* This embedded quote character must be escaped, + * but first double up any immediately preceding backslashes, + * with one extra, as the escape character. + */ + + for (backslashes += backslashes + 1; backslashes; backslashes--) + *++q = '\\'; + + /* and now, add the quote character itself */ + + *++q = '"'; + } + else { + /* Any other character is simply copied, + * but first, if we have any pending backslashes, + * we must now insert them, without any count adjustment. + */ + + while (backslashes) { + *++q = '\\'; + --backslashes; + } + + /* and then, copy the current character */ + + *++q = *p; + } + } + + /* At end of argument: + * If any backslashes remain to be copied out, append them now, + * doubling the actual count to protect against reduction by MSVC, + * as a consequence of the immediately following closing quote. + */ + + for (backslashes += backslashes; backslashes; backslashes--) + *++q = '\\'; + + /* Finally, + * add the closing quote, terminate the quoted string, + * and adjust its size to what was actually required, + * ready for return. + */ + + *++q = '"'; + *++q = '\0'; + if ((string = (char *)realloc(quoted, strlen(quoted) + 1)) == NULL) { + /* but bail out gracefully, on error */ + + REPORT_ERROR(QUOTE_ARG_REALLOC_ERROR); + exit(1); + } + } + + /* 'string' now refers to the argument, + * quoted and escaped, as required. + */ + + return string; +} + +void +purge_quoted_args(char **argv) +{ + /* To avoid memory leaks, + * free all memory previously allocated by 'quoted_arg()', + * within the scope of the referring argument vector, 'argv'. + */ + + if (argv) + while (*argv) { + /* Any argument beginning with a double quote + * SHOULD have been allocated by 'quoted_arg()'. + */ + + if (**argv == '"') + free( *argv ); /* so free its allocation */ + ++argv; /* and continue to the next argument */ + } +} + +/* quotearg.c: end of file */ diff --git a/src/libs/libgroff/ref-add.sin b/src/libs/libgroff/ref-add.sin new file mode 100644 index 0000000..50aa7d1 --- /dev/null +++ b/src/libs/libgroff/ref-add.sin @@ -0,0 +1,29 @@ +# Add this package to a list of references stored in a text file. +# +# Copyright (C) 2000-2020 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, see <http://www.gnu.org/licenses/>. +# +# Written by Bruno Haible <haible@clisp.cons.org>. +# +/^# Packages using this file: / { + s/# Packages using this file:// + ta + :a + s/ @PACKAGE@ / @PACKAGE@ / + tb + s/ $/ @PACKAGE@ / + :b + s/^/# Packages using this file:/ +} diff --git a/src/libs/libgroff/ref-del.sin b/src/libs/libgroff/ref-del.sin new file mode 100644 index 0000000..1601469 --- /dev/null +++ b/src/libs/libgroff/ref-del.sin @@ -0,0 +1,24 @@ +# Remove this package from a list of references stored in a text file. +# +# Copyright (C) 2000-2020 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, see <http://www.gnu.org/licenses/>. +# +# Written by Bruno Haible <haible@clisp.cons.org>. +# +/^# Packages using this file: / { + s/# Packages using this file:// + s/ @PACKAGE@ / / + s/^/# Packages using this file:/ +} diff --git a/src/libs/libgroff/relocatable.h b/src/libs/libgroff/relocatable.h new file mode 100644 index 0000000..f152194 --- /dev/null +++ b/src/libs/libgroff/relocatable.h @@ -0,0 +1,19 @@ +/* Copyright (C) 2014-2020 Free Software Foundation, Inc. + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 2 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +The GNU General Public License version 2 (GPL2) is available in the +internet at <http://www.gnu.org/licenses/gpl-2.0.txt>. */ + +#include "relocate.h" +#define relocate(path) relocatep(path) diff --git a/src/libs/libgroff/relocate.cpp b/src/libs/libgroff/relocate.cpp new file mode 100644 index 0000000..32a0e2e --- /dev/null +++ b/src/libs/libgroff/relocate.cpp @@ -0,0 +1,244 @@ +/* Provide relocation for macro and font files. + Copyright (C) 2005-2020 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +// Made after relocation code in kpathsea and gettext. + +#include "lib.h" + +#include <assert.h> +#include <errno.h> +#include <stdlib.h> + +#include "defs.h" +#include "posix.h" +#include "nonposix.h" +#include "relocate.h" + +#if defined _WIN32 +# define WIN32_LEAN_AND_MEAN +# include <windows.h> +#endif + +#define INSTALLPATHLEN (sizeof(INSTALLPATH) - 1) +#ifndef DEBUG +# define DEBUG 0 +#endif + +extern "C" const char *program_name; + +// The prefix (parent directory) corresponding to the binary. +char *curr_prefix = 0; +size_t curr_prefix_len = 0; + +// Return the directory part of a filename, or '.' if no path separators. +char *xdirname(char *s) +{ + static const char dot[] = "."; + if (!s) + return 0; + // DIR_SEPS[] are possible directory separator characters, see nonposix.h. + // We want the rightmost separator of all possible ones. + // Example: d:/foo\\bar. + char *p = strrchr(s, DIR_SEPS[0]); + const char *sep = &DIR_SEPS[1]; + while (*sep) { + char *p1 = strrchr(s, *sep); + if (p1 && (!p || p1 > p)) + p = p1; + sep++; + } + if (p) + *p = '\0'; + else + s = (char *)dot; + return s; +} + +// Return the full path of NAME along the path PATHP. +// Adapted from search_path::open_file in searchpath.cpp. +char *searchpath(const char *name, const char *pathp) +{ + char *path; + if (!name || !*name) + return 0; +#if DEBUG + fprintf(stderr, "searchpath: pathp: '%s'\n", pathp); + fprintf(stderr, "searchpath: trying '%s'\n", name); +#endif + // Try first NAME as such; success if NAME is an absolute filename, + // or if NAME is found in the current directory. + if (!access (name, F_OK)) { + path = new char[path_name_max()]; +#ifdef _WIN32 + path = _fullpath(path, name, path_name_max()); +#else + path = realpath(name, path); +#endif +#if DEBUG + fprintf(stderr, "searchpath: found '%s'\n", path); +#endif + return path; + } + // Secondly, try the current directory. + // Now search along PATHP. + size_t namelen = strlen(name); + char *p = (char *)pathp; + for (;;) { + char *end = strchr(p, PATH_SEP_CHAR); + if (!end) + end = strchr(p, '\0'); + int need_slash = end > p && strchr(DIR_SEPS, end[-1]) == 0; + path = new char[end - p + need_slash + namelen + 1]; + memcpy(path, p, end - p); + if (need_slash) + path[end - p] = '/'; + strcpy(path + (end - p) + need_slash, name); +#if DEBUG + fprintf(stderr, "searchpath: trying '%s'\n", path); +#endif + if (!access(path, F_OK)) { +#if DEBUG + fprintf(stderr, "searchpath: found '%s'\n", name); +#endif + return path; + } + delete[] path; + if (*end == '\0') + break; + p = end + 1; + } + return 0; +} + +// Search NAME along PATHP with the elements of PATHEXT in turn added. +char *searchpathext(const char *name, const char *pathext, const char *pathp) +{ + char *found = 0; + char *tmpathext = strsave(pathext); // strtok modifies this string, + // so make a copy + char *ext = strtok(tmpathext, PATH_SEP); + while (ext) { + char *namex = new char[strlen(name) + strlen(ext) + 1]; + strcpy(namex, name); + strcat(namex, ext); + found = searchpath(namex, pathp); + delete[] namex; + if (found) + break; + ext = strtok(0, PATH_SEP); + } + delete[] tmpathext; + return found; +} + +// Convert an MS path to a POSIX path. +char *msw2posixpath(char *path) +{ + char *s = path; + while (*s) { + if (*s == '\\') + *s = '/'; + s++; + } + return path; +} + +// Compute the current prefix. +void set_current_prefix() +{ + // Obtain the full path of the current binary; + // using GetModuleFileName on MS-Windows, + // and searching along PATH on other systems. +#ifdef _WIN32 + char *pathextstr; + curr_prefix = new char[path_name_max()]; + int len = GetModuleFileName(0, curr_prefix, path_name_max()); + if (len) + len = GetShortPathName(curr_prefix, curr_prefix, path_name_max()); +# if DEBUG + fprintf(stderr, "curr_prefix: %s\n", curr_prefix); +# endif /* DEBUG */ + if (!curr_prefix && !strchr(program_name, '.')) { // try with extensions + pathextstr = strsave(getenv("PATHEXT")); + if (!pathextstr) + pathextstr = strsave(PATH_EXT); + curr_prefix = searchpathext(program_name, pathextstr, getenv("PATH")); + delete[] pathextstr; + } +#else /* !_WIN32 */ + curr_prefix = searchpath(program_name, getenv("PATH")); + if (!curr_prefix) + return; +#endif /* !_WIN32 */ + msw2posixpath(curr_prefix); +#if DEBUG + fprintf(stderr, "curr_prefix: %s\n", curr_prefix); +#endif + curr_prefix = xdirname(curr_prefix); // directory of executable + curr_prefix = xdirname(curr_prefix); // parent directory of executable + curr_prefix_len = strlen(curr_prefix); +#if DEBUG + fprintf(stderr, "curr_prefix: %s\n", curr_prefix); + fprintf(stderr, "curr_prefix_len: %d\n", curr_prefix_len); +#endif +} + +// Strip the installation prefix and replace it +// with the current installation prefix; return the relocated path. +char *relocatep(const char *path) +{ +#if DEBUG + fprintf(stderr, "relocatep: path = %s\n", path); + fprintf(stderr, "relocatep: INSTALLPATH = %s\n", INSTALLPATH); + fprintf(stderr, "relocatep: INSTALLPATHLEN = %d\n", INSTALLPATHLEN); +#endif + if (!curr_prefix) + set_current_prefix(); + if (strncmp(INSTALLPATH, path, INSTALLPATHLEN)) + return strsave(path); + char *relative_path = (char *)path + INSTALLPATHLEN; + size_t relative_path_len = strlen(relative_path); + char *relocated_path = (char *)malloc(curr_prefix_len + + relative_path_len + 1); + assert(0 != curr_prefix); + strcpy(relocated_path, curr_prefix); + strcat(relocated_path, relative_path); +#if DEBUG + fprintf(stderr, "relocated_path: %s\n", relocated_path); +#endif /* DEBUG */ + return relocated_path; +} + +// Return the original pathname if it exists; +// otherwise return the relocated path. +char *relocate(const char *path) +{ + char *p; + if (access(path, F_OK)) + p = relocatep(path); + else + p = strsave(path); +#if DEBUG + fprintf (stderr, "relocate: %s\n", p); +#endif + return p; +} + +// Local Variables: +// fill-column: 72 +// mode: C++ +// End: +// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: diff --git a/src/libs/libgroff/searchpath.cpp b/src/libs/libgroff/searchpath.cpp new file mode 100644 index 0000000..6062e8d --- /dev/null +++ b/src/libs/libgroff/searchpath.cpp @@ -0,0 +1,215 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "lib.h" + +#include <assert.h> +#include <errno.h> +#include <stdlib.h> + +#include "searchpath.h" +#include "nonposix.h" + +#ifdef _WIN32 +# include "relocate.h" +#else +# define relocate(path) strsave(path) +#endif + +search_path::search_path(const char *envvar, const char *standard, + int add_home, int add_current) +{ + char *home = 0; + if (add_home) + home = getenv("HOME"); + char *e = 0; + if (envvar) + e = getenv(envvar); + dirs = new char[((e && *e) ? strlen(e) + 1 : 0) + + (add_current ? 1 + 1 : 0) + + ((home && *home) ? strlen(home) + 1 : 0) + + ((standard && *standard) ? strlen(standard) : 0) + + 1]; + *dirs = '\0'; + if (e && *e) { + strcat(dirs, e); + strcat(dirs, PATH_SEP); + } + if (add_current) { + strcat(dirs, "."); + strcat(dirs, PATH_SEP); + } + if (home && *home) { + strcat(dirs, home); + strcat(dirs, PATH_SEP); + } + if (standard && *standard) + strcat(dirs, standard); + init_len = strlen(dirs); +} + +search_path::~search_path() +{ + // dirs is always allocated + delete[] dirs; +} + +void search_path::command_line_dir(const char *s) +{ + char *old = dirs; + unsigned old_len = strlen(old); + unsigned slen = strlen(s); + dirs = new char[old_len + 1 + slen + 1]; + memcpy(dirs, old, old_len - init_len); + char *p = dirs; + p += old_len - init_len; + if (init_len == 0) + *p++ = PATH_SEP_CHAR; + memcpy(p, s, slen); + p += slen; + if (init_len > 0) { + *p++ = PATH_SEP_CHAR; + memcpy(p, old + old_len - init_len, init_len); + p += init_len; + } + *p++ = '\0'; + delete[] old; +} + +FILE *search_path::open_file(const char *name, char **pathp) +{ + assert(name != 0); + if (IS_ABSOLUTE(name) || *dirs == '\0') { + FILE *fp = fopen(name, "r"); + if (fp) { + if (pathp) + *pathp = strsave(name); + return fp; + } + else + return 0; + } + unsigned namelen = strlen(name); + char *p = dirs; + for (;;) { + char *end = strchr(p, PATH_SEP_CHAR); + if (!end) + end = strchr(p, '\0'); + int need_slash = end > p && strchr(DIR_SEPS, end[-1]) == 0; + char *origpath = new char[(end - p) + need_slash + namelen + 1]; + memcpy(origpath, p, end - p); + if (need_slash) + origpath[end - p] = '/'; + strcpy(origpath + (end - p) + need_slash, name); +#if 0 + fprintf(stderr, "origpath '%s'\n", origpath); +#endif + char *path = relocate(origpath); + delete[] origpath; +#if 0 + fprintf(stderr, "trying '%s'\n", path); +#endif + FILE *fp = fopen(path, "r"); + int err = errno; + if (fp) { + if (pathp) + *pathp = path; + else { + free(path); + errno = err; + } + return fp; + } + free(path); + errno = err; + if (*end == '\0') + break; + p = end + 1; + } + return 0; +} + +FILE *search_path::open_file_cautious(const char *name, char **pathp, + const char *mode) +{ + if (!mode) + mode = "r"; + bool reading = (strchr(mode, 'r') != 0); + if (name == 0 || strcmp(name, "-") == 0) { + if (pathp) + *pathp = strsave(reading ? "stdin" : "stdout"); + return (reading ? stdin : stdout); + } + if (!reading || IS_ABSOLUTE(name) || *dirs == '\0') { + FILE *fp = fopen(name, mode); + if (fp) { + if (pathp) + *pathp = strsave(name); + return fp; + } + else + return 0; + } + unsigned namelen = strlen(name); + char *p = dirs; + for (;;) { + char *end = strchr(p, PATH_SEP_CHAR); + if (!end) + end = strchr(p, '\0'); + int need_slash = end > p && strchr(DIR_SEPS, end[-1]) == 0; + char *origpath = new char[(end - p) + need_slash + namelen + 1]; + memcpy(origpath, p, end - p); + if (need_slash) + origpath[end - p] = '/'; + strcpy(origpath + (end - p) + need_slash, name); +#if 0 + fprintf(stderr, "origpath '%s'\n", origpath); +#endif + char *path = relocate(origpath); + delete[] origpath; +#if 0 + fprintf(stderr, "trying '%s'\n", path); +#endif + FILE *fp = fopen(path, mode); + int err = errno; + if (fp) { + if (pathp) + *pathp = path; + else { + free(path); + errno = err; + } + return fp; + } + free(path); + errno = err; + if (err != ENOENT) + return 0; + if (*end == '\0') + break; + p = end + 1; + } + errno = ENOENT; + return 0; +} + +// Local Variables: +// fill-column: 72 +// mode: C++ +// End: +// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: diff --git a/src/libs/libgroff/spawnvp.c b/src/libs/libgroff/spawnvp.c new file mode 100644 index 0000000..1fffa2b --- /dev/null +++ b/src/libs/libgroff/spawnvp.c @@ -0,0 +1,120 @@ +/* Copyright (C) 2004-2020 Free Software Foundation, Inc. + Written by: Keith Marshall (keith.d.marshall@ntlworld.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> + +#ifdef HAVE_PROCESS_H +# include <process.h> +#endif + +#if defined(__MSDOS__) \ + || (defined(_WIN32) && !defined(_UWIN) && !defined(__CYGWIN__)) \ + || defined(__EMX__) + +#define SPAWN_FUNCTION_WRAPPERS 1 + +/* Define the default mechanism, and messages, for error reporting + * (user may substitute a preferred alternative, by defining his own + * implementation of the macros REPORT_ERROR and ARGV_MALLOC_ERROR, + * in the header file 'nonposix.h'). + */ + +#include "nonposix.h" + +#ifndef REPORT_ERROR +# define REPORT_ERROR(WHY) fprintf(stderr, "%s:%s\n", program_name, WHY) +#endif +#ifndef ARGV_MALLOC_ERROR +# define ARGV_MALLOC_ERROR "malloc: Allocation for 'argv' failed" +#endif + +extern char *program_name; + +extern char *quote_arg(char *string); +extern void purge_quoted_args(char **argv); + +int +spawnvp_wrapper(int mode, char *path, char **argv) +{ + /* Invoke the system 'spawnvp' service + * enclosing the passed arguments in double quotes, as required, + * so that the (broken) default parsing in the MSVC runtime doesn't + * split them at whitespace. */ + + char **quoted_argv; /* used to build a quoted local copy of 'argv' */ + + int i; /* used as an index into 'argv' or 'quoted_argv' */ + int status = -1; /* initialise return code, in case we fail */ + int argc = 0; /* initialise argument count; may be none */ + + /* First count the number of arguments + * which are actually present in the passed 'argv'. */ + + if (argv) + for (quoted_argv = argv; *quoted_argv; ++argc, ++quoted_argv) + ; + + /* If we do not now have an argument count, + * then we must fall through and fail. */ + + if (argc) { + /* We do have at least one argument: + * We will use a copy of the 'argv', in which to do the quoting, + * so we must allocate space for it. */ + + if ((quoted_argv = (char **)malloc(++argc * sizeof(char **))) == NULL) { + /* If we didn't get enough space, + * then complain, and bail out gracefully. */ + + REPORT_ERROR(ARGV_MALLOC_ERROR); + exit(1); + } + + /* Now copy the passed 'argv' into our new vector, + * quoting its contents as required. */ + + for (i = 0; i < argc; i++) + quoted_argv[i] = quote_arg(argv[i]); + + /* Invoke the MSVC 'spawnvp' service + * passing our now appropriately quoted copy of 'argv'. */ + + status = spawnvp(mode, path, quoted_argv); + + /* Clean up our memory allocations + * for the quoted copy of 'argv', which is no longer required. */ + + purge_quoted_args(quoted_argv); + free(quoted_argv); + } + + /* Finally, + * return the status code returned by 'spawnvp', + * or a failure code if we fell through. */ + + return status; +} + +#endif /* __MSDOS__ || _WIN32 */ + +/* spawnvp.c: end of file */ diff --git a/src/libs/libgroff/strcasecmp.c b/src/libs/libgroff/strcasecmp.c new file mode 100644 index 0000000..22c0997 --- /dev/null +++ b/src/libs/libgroff/strcasecmp.c @@ -0,0 +1,65 @@ +/* strcasecmp.c -- case insensitive string comparator + Copyright (C) 1998-2020 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#ifdef LENGTH_LIMIT +# define STRXCASECMP_FUNCTION strncasecmp +# define STRXCASECMP_DECLARE_N , size_t n +# define LENGTH_LIMIT_EXPR(Expr) Expr +#else +# define STRXCASECMP_FUNCTION strcasecmp +# define STRXCASECMP_DECLARE_N /* empty */ +# define LENGTH_LIMIT_EXPR(Expr) 0 +#endif + +#include <stddef.h> +#include <ctype.h> + +#define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch)) + +/* Compare {{no more than N characters of }}strings S1 and S2, + ignoring case, returning less than, equal to or + greater than zero if S1 is lexicographically less + than, equal to or greater than S2. */ + +int +STRXCASECMP_FUNCTION (const char *s1, const char *s2 STRXCASECMP_DECLARE_N) +{ + register const unsigned char *p1 = (const unsigned char *) s1; + register const unsigned char *p2 = (const unsigned char *) s2; + unsigned char c1, c2; + + if (p1 == p2 || LENGTH_LIMIT_EXPR (n == 0)) + return 0; + + do + { + c1 = TOLOWER (*p1); + c2 = TOLOWER (*p2); + + if (LENGTH_LIMIT_EXPR (--n == 0) || c1 == '\0') + break; + + ++p1; + ++p2; + } + while (c1 == c2); + + return c1 - c2; +} diff --git a/src/libs/libgroff/strerror.c b/src/libs/libgroff/strerror.c new file mode 100644 index 0000000..a8887e5 --- /dev/null +++ b/src/libs/libgroff/strerror.c @@ -0,0 +1,46 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> /* for MinGW */ + +#define INT_DIGITS 19 /* enough for 64 bit integer */ + +#ifndef HAVE_SYS_NERR +extern int sys_nerr; +#endif +#ifndef HAVE_SYS_ERRLIST +extern char *sys_errlist[]; +#endif + +char *strerror(n) + int n; +{ + static char buf[sizeof("Error ") + 1 + INT_DIGITS]; + if (n >= 0 && n < sys_nerr && sys_errlist[n] != 0) + return sys_errlist[n]; + else { + sprintf(buf, "Error %d", n); + return buf; + } +} diff --git a/src/libs/libgroff/string.cpp b/src/libs/libgroff/string.cpp new file mode 100644 index 0000000..33c0565 --- /dev/null +++ b/src/libs/libgroff/string.cpp @@ -0,0 +1,354 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> + +#include "lib.h" + +#include "stringclass.h" + +static char *salloc(int len, int *sizep); +static void sfree(char *ptr, int size); +static char *sfree_alloc(char *ptr, int size, int len, int *sizep); +static char *srealloc(char *ptr, int size, int oldlen, int newlen, int *sizep); + +static char *salloc(int len, int *sizep) +{ + if (len == 0) { + *sizep = 0; + return 0; + } + else + return new char[*sizep = len*2]; +} + +static void sfree(char *ptr, int) +{ + delete[] ptr; +} + +static char *sfree_alloc(char *ptr, int oldsz, int len, int *sizep) +{ + if (oldsz >= len) { + *sizep = oldsz; + return ptr; + } + delete[] ptr; + if (len == 0) { + *sizep = 0; + return 0; + } + else + return new char[*sizep = len*2]; +} + +static char *srealloc(char *ptr, int oldsz, int oldlen, int newlen, int *sizep) +{ + if (oldsz >= newlen) { + *sizep = oldsz; + return ptr; + } + if (newlen == 0) { + delete[] ptr; + *sizep = 0; + return 0; + } + else { + char *p = new char[*sizep = newlen*2]; + if (oldlen < newlen && oldlen != 0) + memcpy(p, ptr, oldlen); + delete[] ptr; + return p; + } +} + +string::string() : ptr(0), len(0), sz(0) +{ +} + +string::string(const char *p, int n) : len(n) +{ + assert(n >= 0); + ptr = salloc(n, &sz); + if (n != 0) + memcpy(ptr, p, n); +} + +string::string(const char *p) +{ + if (p == 0) { + len = 0; + ptr = 0; + sz = 0; + } + else { + len = strlen(p); + ptr = salloc(len, &sz); + if (len != 0) + memcpy(ptr, p, len); + } +} + +string::string(char c) : len(1) +{ + ptr = salloc(1, &sz); + *ptr = c; +} + +string::string(const string &s) : len(s.len) +{ + ptr = salloc(len, &sz); + if (len != 0) + memcpy(ptr, s.ptr, len); +} + +string::~string() +{ + sfree(ptr, sz); +} + +string &string::operator=(const string &s) +{ + ptr = sfree_alloc(ptr, sz, s.len, &sz); + len = s.len; + if (len != 0) + memcpy(ptr, s.ptr, len); + return *this; +} + +string &string::operator=(const char *p) +{ + if (p == 0) { + sfree(ptr, len); + len = 0; + ptr = 0; + sz = 0; + } + else { + int slen = strlen(p); + ptr = sfree_alloc(ptr, sz, slen, &sz); + len = slen; + if (len != 0) + memcpy(ptr, p, len); + } + return *this; +} + +string &string::operator=(char c) +{ + ptr = sfree_alloc(ptr, sz, 1, &sz); + len = 1; + *ptr = c; + return *this; +} + +void string::move(string &s) +{ + sfree(ptr, sz); + ptr = s.ptr; + len = s.len; + sz = s.sz; + s.ptr = 0; + s.len = 0; + s.sz = 0; +} + +void string::grow1() +{ + ptr = srealloc(ptr, sz, len, len + 1, &sz); +} + +string &string::operator+=(const char *p) +{ + if (p != 0) { + int n = strlen(p); + int newlen = len + n; + if (newlen > sz) + ptr = srealloc(ptr, sz, len, newlen, &sz); + memcpy(ptr + len, p, n); + len = newlen; + } + return *this; +} + +string &string::operator+=(const string &s) +{ + if (s.len != 0) { + int newlen = len + s.len; + if (newlen > sz) + ptr = srealloc(ptr, sz, len, newlen, &sz); + memcpy(ptr + len, s.ptr, s.len); + len = newlen; + } + return *this; +} + +void string::append(const char *p, int n) +{ + if (n > 0) { + int newlen = len + n; + if (newlen > sz) + ptr = srealloc(ptr, sz, len, newlen, &sz); + memcpy(ptr + len, p, n); + len = newlen; + } +} + +string::string(const char *s1, int n1, const char *s2, int n2) +{ + assert(n1 >= 0 && n2 >= 0); + len = n1 + n2; + if (len == 0) { + sz = 0; + ptr = 0; + } + else { + ptr = salloc(len, &sz); + if (n1 == 0) + memcpy(ptr, s2, n2); + else { + memcpy(ptr, s1, n1); + if (n2 != 0) + memcpy(ptr + n1, s2, n2); + } + } +} + +int operator<=(const string &s1, const string &s2) +{ + return (s1.len <= s2.len + ? s1.len == 0 || memcmp(s1.ptr, s2.ptr, s1.len) <= 0 + : s2.len != 0 && memcmp(s1.ptr, s2.ptr, s2.len) < 0); +} + +int operator<(const string &s1, const string &s2) +{ + return (s1.len < s2.len + ? s1.len == 0 || memcmp(s1.ptr, s2.ptr, s1.len) <= 0 + : s2.len != 0 && memcmp(s1.ptr, s2.ptr, s2.len) < 0); +} + +int operator>=(const string &s1, const string &s2) +{ + return (s1.len >= s2.len + ? s2.len == 0 || memcmp(s1.ptr, s2.ptr, s2.len) >= 0 + : s1.len != 0 && memcmp(s1.ptr, s2.ptr, s1.len) > 0); +} + +int operator>(const string &s1, const string &s2) +{ + return (s1.len > s2.len + ? s2.len == 0 || memcmp(s1.ptr, s2.ptr, s2.len) >= 0 + : s1.len != 0 && memcmp(s1.ptr, s2.ptr, s1.len) > 0); +} + +void string::set_length(int i) +{ + assert(i >= 0); + if (i > sz) + ptr = srealloc(ptr, sz, len, i, &sz); + len = i; +} + +void string::clear() +{ + len = 0; +} + +int string::search(char c) const +{ + char *p = ptr ? (char *)memchr(ptr, c, len) : 0; + return p ? p - ptr : -1; +} + +// we silently strip nuls + +char *string::extract() const +{ + char *p = ptr; + int n = len; + int nnuls = 0; + int i; + for (i = 0; i < n; i++) + if (p[i] == '\0') + nnuls++; + char *q =(char*)malloc(n + 1 - nnuls); + if (q != 0 /* nullptr */) { + char *r = q; + for (i = 0; i < n; i++) + if (p[i] != '\0') + *r++ = p[i]; + *r = '\0'; + } + return q; +} + +void string::remove_spaces() +{ + int l = len - 1; + while (l >= 0 && ptr[l] == ' ') + l--; + char *p = ptr; + if (l > 0) + while (*p == ' ') { + p++; + l--; + } + if (len - 1 != l) { + if (l >= 0) { + len = l + 1; + char *tmp = new char[sz]; + memcpy(tmp, p, len); + delete[] ptr; + ptr = tmp; + } + else { + len = 0; + if (ptr) { + delete[] ptr; + ptr = 0; + sz = 0; + } + } + } +} + +void put_string(const string &s, FILE *fp) +{ + int len = s.length(); + const char *ptr = s.contents(); + for (int i = 0; i < len; i++) + putc(ptr[i], fp); +} + +string as_string(int i) +{ + static char buf[INT_DIGITS + 2]; + sprintf(buf, "%d", i); + return string(buf); +} + +// Local Variables: +// fill-column: 72 +// mode: C++ +// End: +// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: diff --git a/src/libs/libgroff/strncasecmp.c b/src/libs/libgroff/strncasecmp.c new file mode 100644 index 0000000..ec8aae2 --- /dev/null +++ b/src/libs/libgroff/strncasecmp.c @@ -0,0 +1,19 @@ +/* Copyright (C) 2014-2020 Free Software Foundation, Inc. + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 2 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +The GNU General Public License version 2 (GPL2) is available in the +internet at <http://www.gnu.org/licenses/gpl-2.0.txt>. */ + +#define LENGTH_LIMIT +#include "strcasecmp.c" diff --git a/src/libs/libgroff/strsave.cpp b/src/libs/libgroff/strsave.cpp new file mode 100644 index 0000000..95a529b --- /dev/null +++ b/src/libs/libgroff/strsave.cpp @@ -0,0 +1,40 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <stdlib.h> + +char *strsave(const char *s) +{ + if (s == 0) + return 0; + char *p = (char*)malloc(strlen(s) + 1); + if (p != 0) + strcpy(p, s); + return p; +} + +// Local Variables: +// fill-column: 72 +// mode: C++ +// End: +// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: diff --git a/src/libs/libgroff/strtol.c b/src/libs/libgroff/strtol.c new file mode 100644 index 0000000..1820732 --- /dev/null +++ b/src/libs/libgroff/strtol.c @@ -0,0 +1,131 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <ctype.h> +#include <errno.h> + +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif + +#ifndef LONG_MAX +#define LONG_MAX 2147483647 +#endif + +#ifndef LONG_MIN +#define LONG_MIN (-LONG_MAX-1) +#endif + +#ifdef isascii +#define ISASCII(c) isascii(c) +#else +#define ISASCII(c) (1) +#endif + +long strtol(str, ptr, base) + char *str, **ptr; + int base; +{ + char *start = str; + int neg = 0; + long val; + char *p; + static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + + while (ISASCII((unsigned char)*str) && isspace((unsigned char)*str)) + str++; + + if (*str == '-') { + neg = 1; + str++; + } + if (base == 0) { + if (*str == '0') { + if (str[1] == 'x' || str[1] == 'X') { + str += 2; + base = 16; + } + else + base = 8; + } + else + base = 10; + } + if (base < 2 || base > 36) + base = 10; + else if (base == 16 && *str == '0' && (str[1] == 'x' || str[1] == 'X')) + str += 2; + + p = strchr(digits, (ISASCII((unsigned char)*str) + && isupper((unsigned char)*str) + ? tolower((unsigned char)*str) + : *str)); + if (p == 0 || (val = (p - digits)) >= base) { + if (base == 16 && str > start && (str[-1] == 'x' || str[-1] == 'X')) { + if (ptr) + *ptr = str - 1; + } + else { + if (ptr) + *ptr = start; + errno = ERANGE; + } + return 0; + } + if (neg) + val = -val; + + while (*++str != '\0') { + int n; + + p = strchr(digits, (ISASCII((unsigned char)*str) + && isupper((unsigned char)*str) + ? tolower((unsigned char)*str) : *str)); + if (p == 0) + break; + n = p - digits; + if (n >= base) + break; + if (neg) { + if (-(unsigned long)val > (-(unsigned long)LONG_MIN - n)/base) { + val = LONG_MIN; + errno = ERANGE; + } + else + val = val*base - n; + } + else { + if (val > (LONG_MAX - n)/base) { + val = LONG_MAX; + errno = ERANGE; + } + else + val = val*base + n; + } + } + + if (ptr) + *ptr = str; + + return val; +} diff --git a/src/libs/libgroff/symbol.cpp b/src/libs/libgroff/symbol.cpp new file mode 100644 index 0000000..4f50627 --- /dev/null +++ b/src/libs/libgroff/symbol.cpp @@ -0,0 +1,157 @@ +// -*- C++ -*- +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "lib.h" + +#include "errarg.h" +#include "error.h" +#include "symbol.h" + +const char **symbol::table = 0; +int symbol::table_used = 0; +int symbol::table_size = 0; +char *symbol::block = 0; +int symbol::block_size = 0; + +const symbol NULL_SYMBOL; +const symbol EMPTY_SYMBOL(""); + +#ifdef BLOCK_SIZE +#undef BLOCK_SIZE +#endif + +const int BLOCK_SIZE = 1024; +// the table will increase in size as necessary +// the size will be chosen from the following array +// add some more if you want +static const unsigned int table_sizes[] = { + 101, 503, 1009, 2003, 3001, 4001, 5003, 10007, 20011, 40009, 80021, + 160001, 500009, 1000003, 1500007, 2000003, 0 +}; +const double FULL_MAX = 0.3; // don't let the table get more than this full + +static unsigned int hash_string(const char *p) +{ + // compute a hash code; this assumes 32-bit unsigned ints + // see p436 of Compilers by Aho, Sethi & Ullman + // give special treatment to two-character names + unsigned int hc = 0, g; + if (*p != 0) { + hc = *p++; + if (*p != 0) { + hc <<= 7; + hc += *p++; + for (; *p != 0; p++) { + hc <<= 4; + hc += *p; + if ((g = (hc & 0xf0000000)) == 0) { + hc ^= g >> 24; + hc ^= g; + } + } + } + } + return hc; +} + +// Tell compiler that a variable is intentionally unused. +inline void unused(void *) { } + +symbol::symbol(const char *p, int how) +{ + if (p == 0) { + s = 0; + return; + } + if (*p == 0) { + s = ""; + return; + } + if (table == 0) { + table_size = table_sizes[0]; + table = (const char **)new char*[table_size]; + for (int i = 0; i < table_size; i++) + table[i] = 0; + table_used = 0; + } + unsigned int hc = hash_string(p); + const char **pp; + for (pp = table + hc % table_size; + *pp != 0; + (pp == table ? pp = table + table_size - 1 : --pp)) + if (strcmp(p, *pp) == 0) { + s = *pp; + return; + } + if (how == MUST_ALREADY_EXIST) { + s = 0; + return; + } + if (table_used >= table_size - 1 || table_used >= table_size*FULL_MAX) { + const char **old_table = table; + unsigned int old_table_size = table_size; + int i; + for (i = 1; table_sizes[i] <= old_table_size; i++) + if (table_sizes[i] == 0) + fatal("too many symbols"); + table_size = table_sizes[i]; + table_used = 0; + table = (const char **)new char*[table_size]; + for (i = 0; i < table_size; i++) + table[i] = 0; + for (pp = old_table + old_table_size - 1; + pp >= old_table; + --pp) { + symbol temp(*pp, 1); /* insert it into the new table */ + unused(&temp); + } + delete[] old_table; + for (pp = table + hc % table_size; + *pp != 0; + (pp == table ? pp = table + table_size - 1 : --pp)) + ; + } + ++table_used; + if (how == DONT_STORE) { + s = *pp = p; + } + else { + int len = strlen(p)+1; + if (block == 0 || block_size < len) { + block_size = len > BLOCK_SIZE ? len : BLOCK_SIZE; + block = new char [block_size]; + } + (void)strcpy(block, p); + s = *pp = block; + block += len; + block_size -= len; + } +} + +symbol concat(symbol s1, symbol s2) +{ + char *buf = new char [strlen(s1.contents()) + strlen(s2.contents()) + 1]; + strcpy(buf, s1.contents()); + strcat(buf, s2.contents()); + symbol res(buf); + delete[] buf; + return res; +} + +symbol default_symbol("default"); diff --git a/src/libs/libgroff/tmpfile.cpp b/src/libs/libgroff/tmpfile.cpp new file mode 100644 index 0000000..5e807ae --- /dev/null +++ b/src/libs/libgroff/tmpfile.cpp @@ -0,0 +1,188 @@ +// -*- C++ -*- +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "lib.h" + +#include <errno.h> +#include <stdlib.h> + +#include "posix.h" +#include "errarg.h" +#include "error.h" +#include "nonposix.h" + +// If this is set, create temporary files there +#define GROFF_TMPDIR_ENVVAR "GROFF_TMPDIR" +// otherwise if this is set, create temporary files there +#define TMPDIR_ENVVAR "TMPDIR" +// otherwise, on MS-DOS or MS-Windows ... +#if defined(__MSDOS__) || defined(_WIN32) +// if either of these is set, create temporary files there +// (giving priority to WIN32_TMPDIR_ENVVAR) +#define WIN32_TMPDIR_ENVVAR "TMP" +#define MSDOS_TMPDIR_ENVVAR "TEMP" +#endif +// otherwise if P_tmpdir is defined, create temporary files there +#ifdef P_tmpdir +# define DEFAULT_TMPDIR P_tmpdir +#else +// otherwise create temporary files here. +# define DEFAULT_TMPDIR "/tmp" +#endif +// Use this as the prefix for temporary filenames. +#define TMPFILE_PREFIX_SHORT "" +#define TMPFILE_PREFIX_LONG "groff" + +char *tmpfile_prefix; +size_t tmpfile_prefix_len; +int use_short_postfix = 0; + +struct temp_init { + temp_init(); + ~temp_init(); +} _temp_init; + +temp_init::temp_init() +{ + // First, choose a location for creating temporary files... + const char *tem; + // using the first match for any of the environment specs in listed order. + if ( + (tem = getenv(GROFF_TMPDIR_ENVVAR)) == 0 + && (tem = getenv(TMPDIR_ENVVAR)) == 0 +#if defined(__MSDOS__) || defined(_WIN32) + // If we didn't find a match for either of the above + // (which are preferred, regardless of the host operating system), + // and we are hosted on either MS-Windows or MS-DOS, + // then try the Microsoft conventions. + && (tem = getenv(WIN32_TMPDIR_ENVVAR)) == 0 + && (tem = getenv(MSDOS_TMPDIR_ENVVAR)) == 0 +#endif + ) + // If we didn't find an environment spec fall back to this default. + tem = DEFAULT_TMPDIR; + size_t tem_len = strlen(tem); + const char *tem_end = tem + tem_len - 1; + int need_slash = (strchr(DIR_SEPS, *tem_end) == 0) ? 1 : 0; + char *tem2 = new char[tem_len + need_slash + 1]; + strcpy(tem2, tem); + if (need_slash) + strcat(tem2, "/"); + const char *tem3 = TMPFILE_PREFIX_LONG; + if (file_name_max(tem2) <= 14) { + tem3 = TMPFILE_PREFIX_SHORT; + use_short_postfix = 1; + } + tmpfile_prefix_len = tem_len + need_slash + strlen(tem3); + tmpfile_prefix = new char[tmpfile_prefix_len + 1]; + strcpy(tmpfile_prefix, tem2); + strcat(tmpfile_prefix, tem3); + delete[] tem2; +} + +temp_init::~temp_init() +{ + delete[] tmpfile_prefix; +} + +/* + * Generate a temporary name template with a postfix + * immediately after the TMPFILE_PREFIX. + * It uses the groff preferences for a temporary directory. + * Note that no file name is either created or opened, + * only the *template* is returned. + */ + +char *xtmptemplate(const char *postfix_long, const char *postfix_short) +{ + const char *postfix = use_short_postfix ? postfix_short : postfix_long; + int postlen = 0; + if (postfix) + postlen = strlen(postfix); + char *templ = new char[tmpfile_prefix_len + postlen + 6 + 1]; + strcpy(templ, tmpfile_prefix); + if (postlen > 0) + strcat(templ, postfix); + strcat(templ, "XXXXXX"); + return templ; +} + +// The trick with unlinking the temporary file while it is still in +// use is not portable, it will fail on MS-DOS and most MS-Windows +// filesystems. So it cannot be used on non-Posix systems. +// Instead, we maintain a list of files to be deleted on exit. +// This should be portable to all platforms. + +struct xtmpfile_list { + char *fname; + xtmpfile_list *next; + xtmpfile_list(char *fn) : fname(fn), next(0) {} +}; + +xtmpfile_list *xtmpfiles_to_delete = 0; + +struct xtmpfile_list_init { + ~xtmpfile_list_init(); +} _xtmpfile_list_init; + +xtmpfile_list_init::~xtmpfile_list_init() +{ + xtmpfile_list *x = xtmpfiles_to_delete; + while (x != 0) { + if (unlink(x->fname) < 0) + error("cannot unlink '%1': %2", x->fname, strerror(errno)); + xtmpfile_list *tmp = x; + x = x->next; + delete[] tmp->fname; + delete tmp; + } +} + +static void add_tmp_file(const char *name) +{ + char *s = new char[strlen(name)+1]; + strcpy(s, name); + xtmpfile_list *x = new xtmpfile_list(s); + x->next = xtmpfiles_to_delete; + xtmpfiles_to_delete = x; +} + +// Open a temporary file and with fatal error on failure. + +FILE *xtmpfile(char **namep, + const char *postfix_long, const char *postfix_short, + int do_unlink) +{ + char *templ = xtmptemplate(postfix_long, postfix_short); + errno = 0; + int fd = mkstemp(templ); + if (fd < 0) + fatal("cannot create temporary file: %1", strerror(errno)); + errno = 0; + FILE *fp = fdopen(fd, FOPEN_RWB); // many callers of xtmpfile use binary I/O + if (!fp) + fatal("fdopen: %1", strerror(errno)); + if (do_unlink) + add_tmp_file(templ); + if (namep) + *namep = templ; + else + delete[] templ; + return fp; +} diff --git a/src/libs/libgroff/tmpname.cpp b/src/libs/libgroff/tmpname.cpp new file mode 100644 index 0000000..69dc9a4 --- /dev/null +++ b/src/libs/libgroff/tmpname.cpp @@ -0,0 +1,117 @@ +/* Copyright (C) 2001-2020 Free Software Foundation, Inc. + Written by Werner Lemberg (wl@gnu.org) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + + +/* This file is heavily based on the function __gen_tempname() in the + file tempname.c which is part of the fileutils package. */ + + +#include "lib.h" + +#include <stddef.h> +#include <stdlib.h> +#include <errno.h> +#include <time.h> + +#include "posix.h" +#include "nonposix.h" + +#ifndef TMP_MAX +# define TMP_MAX 238328 +#endif + +#if HAVE_SYS_TIME_H +# include <sys/time.h> +#endif + +#ifdef HAVE_GETTIMEOFDAY +#ifdef NEED_DECLARATION_GETTIMEOFDAY +extern "C" { + int gettimeofday(struct timeval *, void *); +} +#endif +#endif + +#if HAVE_CC_INTTYPES_H +# include <inttypes.h> +#endif + +/* Use the widest available unsigned type if uint64_t is not + available. The algorithm below extracts a number less than 62**6 + (approximately 2**35.725) from uint64_t, so ancient hosts where + uintmax_t is only 32 bits lose about 3.725 bits of randomness, + which is better than not having mkstemp at all. */ +#if !defined UINT64_MAX && !defined uint64_t +# define uint64_t uintmax_t +#endif + +/* These are the characters used in temporary filenames. */ +static const char letters[] = +"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + +int gen_tempname(char *tmpl, int dir) +{ + static uint64_t value; + + size_t len = strlen(tmpl); + if (len < 6 || strcmp(&tmpl[len - 6], "XXXXXX")) + return -1; /* EINVAL */ + + /* This is where the Xs start. */ + char *XXXXXX = &tmpl[len - 6]; + + /* Get some more or less random data. */ +#if HAVE_GETTIMEOFDAY + timeval tv; + gettimeofday(&tv, 0); + uint64_t random_time_bits = ((uint64_t)tv.tv_usec << 16) ^ tv.tv_sec; +#else + uint64_t random_time_bits = time(0); +#endif + value += random_time_bits ^ getpid(); + + for (int count = 0; count < TMP_MAX; value += 7777, ++count) { + uint64_t v = value; + + /* Fill in the random bits. */ + XXXXXX[0] = letters[v % 62]; + v /= 62; + XXXXXX[1] = letters[v % 62]; + v /= 62; + XXXXXX[2] = letters[v % 62]; + v /= 62; + XXXXXX[3] = letters[v % 62]; + v /= 62; + XXXXXX[4] = letters[v % 62]; + v /= 62; + XXXXXX[5] = letters[v % 62]; + + int fd = dir ? mkdir(tmpl, S_IRUSR | S_IWUSR | S_IXUSR) + : open(tmpl, + O_RDWR | O_CREAT | O_EXCL | O_BINARY, + S_IRUSR | S_IWUSR); + + if (fd >= 0) + return fd; + else if (errno != EEXIST) + return -1; + } + + /* We got out of the loop because we ran out of combinations to try. */ + return -1; /* EEXIST */ +} diff --git a/src/libs/libgroff/unicode.cpp b/src/libs/libgroff/unicode.cpp new file mode 100644 index 0000000..29e80c7 --- /dev/null +++ b/src/libs/libgroff/unicode.cpp @@ -0,0 +1,65 @@ +// -*- C++ -*- +/* Copyright (C) 2002-2020 Free Software Foundation, Inc. + Written by Werner Lemberg <wl@gnu.org> + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "lib.h" +#include "cset.h" +#include "stringclass.h" + +#include "unicode.h" + +const char *check_unicode_name(const char *u) +{ + if (*u != 'u') + return 0; + const char *p = ++u; + for (;;) { + int val = 0; + const char *start = p; + for (;;) { + // only uppercase hex digits allowed + if (!csxdigit(*p)) + return 0; + if (csdigit(*p)) + val = val*0x10 + (*p-'0'); + else if (csupper(*p)) + val = val*0x10 + (*p-'A'+10); + else + return 0; + // biggest Unicode value is U+10FFFF + if (val > 0x10FFFF) + return 0; + p++; + if (*p == '\0' || *p == '_') + break; + } + // surrogates not allowed + if ((val >= 0xD800 && val <= 0xDBFF) || (val >= 0xDC00 && val <= 0xDFFF)) + return 0; + if (val > 0xFFFF) { + if (*start == '0') // no leading zeros allowed if > 0xFFFF + return 0; + } + else if (p - start != 4) // otherwise, check for exactly 4 hex digits + return 0; + if (*p == '\0') + break; + p++; + } + return u; +} diff --git a/src/libs/libgroff/uniglyph.cpp b/src/libs/libgroff/uniglyph.cpp new file mode 100644 index 0000000..bab2bc4 --- /dev/null +++ b/src/libs/libgroff/uniglyph.cpp @@ -0,0 +1,497 @@ +// -*- C++ -*- +/* Copyright (C) 2002-2020 Free Software Foundation, Inc. + Written by Werner Lemberg <wl@gnu.org> + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "lib.h" +#include "stringclass.h" +#include "ptable.h" + +#include "unicode.h" + +struct unicode_to_glyph { + char *value; +}; + +declare_ptable(unicode_to_glyph) +implement_ptable(unicode_to_glyph) + +PTABLE(unicode_to_glyph) unicode_to_glyph_table; + +struct S { + const char *key; + const char *value; +} unicode_to_glyph_list[] = { + { "0021", "!" }, +//{ "0022", "\"" }, + { "0022", "dq" }, +//{ "0023", "#" }, + { "0023", "sh" }, +//{ "0024", "$" }, + { "0024", "Do" }, + { "0025", "%" }, + { "0026", "&" }, + { "0027", "aq" }, + { "0028", "(" }, + { "0029", ")" }, + { "002A", "*" }, +//{ "002B", "+" }, + { "002B", "pl" }, + { "002C", "," }, + { "002E", "." }, +//{ "002F", "/" }, + { "002F", "sl" }, + { "0030", "0" }, + { "0031", "1" }, + { "0032", "2" }, + { "0033", "3" }, + { "0034", "4" }, + { "0035", "5" }, + { "0036", "6" }, + { "0037", "7" }, + { "0038", "8" }, + { "0039", "9" }, + { "003A", ":" }, + { "003B", ";" }, + { "003C", "<" }, +//{ "003D", "=" }, + { "003D", "eq" }, + { "003D_0338", "!=" }, + { "003E", ">" }, + { "003F", "?" }, +//{ "0040", "@" }, + { "0040", "at" }, + { "0041", "A" }, + { "0041_0300", "`A" }, + { "0041_0301", "'A" }, + { "0041_0302", "^A" }, + { "0041_0303", "~A" }, + { "0041_0308", ":A" }, + { "0041_030A", "oA" }, + { "0042", "B" }, + { "0043", "C" }, + { "0043_0301", "'C" }, + { "0043_0327", ",C" }, + { "0044", "D" }, + { "0045", "E" }, + { "0045_0300", "`E" }, + { "0045_0301", "'E" }, + { "0045_0302", "^E" }, + { "0045_0308", ":E" }, + { "0046", "F" }, + { "0047", "G" }, + { "0048", "H" }, + { "0049", "I" }, + { "0049_0300", "`I" }, + { "0049_0301", "'I" }, + { "0049_0302", "^I" }, + { "0049_0308", ":I" }, + { "004A", "J" }, + { "004B", "K" }, + { "004C", "L" }, + { "004D", "M" }, + { "004E", "N" }, + { "004E_0303", "~N" }, + { "004F", "O" }, + { "004F_0300", "`O" }, + { "004F_0301", "'O" }, + { "004F_0302", "^O" }, + { "004F_0303", "~O" }, + { "004F_0308", ":O" }, + { "0050", "P" }, + { "0051", "Q" }, + { "0052", "R" }, + { "0053", "S" }, + { "0053_030C", "vS" }, + { "0054", "T" }, + { "0055", "U" }, + { "0055_0300", "`U" }, + { "0055_0301", "'U" }, + { "0055_0302", "^U" }, + { "0055_0308", ":U" }, + { "0056", "V" }, + { "0057", "W" }, + { "0058", "X" }, + { "0059", "Y" }, + { "0059_0301", "'Y" }, + { "0059_0308", ":Y" }, + { "005A", "Z" }, + { "005A_030C", "vZ" }, + { "005B", "lB" }, +//{ "005B", "[" }, + { "005C", "rs" }, +//{ "005C", "\\" }, + { "005D", "rB" }, +//{ "005D", "]" }, +//{ "005E", "^" }, +//{ "005E", "a^" }, + { "005E", "ha" }, +//{ "005F", "_" }, +//{ "005F", "ru" }, + { "005F", "ul" }, + { "0060", "ga" }, + { "0061", "a" }, + { "0061_0300", "`a" }, + { "0061_0301", "'a" }, + { "0061_0302", "^a" }, + { "0061_0303", "~a" }, + { "0061_0308", ":a" }, + { "0061_030A", "oa" }, + { "0062", "b" }, + { "0063", "c" }, + { "0063_0301", "'c" }, + { "0063_0327", ",c" }, + { "0064", "d" }, + { "0065", "e" }, + { "0065_0300", "`e" }, + { "0065_0301", "'e" }, + { "0065_0302", "^e" }, + { "0065_0308", ":e" }, + { "0066", "f" }, + { "0066_0066", "ff" }, + { "0066_0066_0069", "Fi" }, + { "0066_0066_006C", "Fl" }, + { "0066_0069", "fi" }, + { "0066_006C", "fl" }, + { "0067", "g" }, + { "0068", "h" }, + { "0069", "i" }, + { "0069_0300", "`i" }, + { "0069_0301", "'i" }, + { "0069_0302", "^i" }, + { "0069_0308", ":i" }, + { "006A", "j" }, + { "006B", "k" }, + { "006C", "l" }, + { "006D", "m" }, + { "006E", "n" }, + { "006E_0303", "~n" }, + { "006F", "o" }, + { "006F_0300", "`o" }, + { "006F_0301", "'o" }, + { "006F_0302", "^o" }, + { "006F_0303", "~o" }, + { "006F_0308", ":o" }, + { "0070", "p" }, + { "0071", "q" }, + { "0072", "r" }, + { "0073", "s" }, + { "0073_030C", "vs" }, + { "0074", "t" }, + { "0075", "u" }, + { "0075_0300", "`u" }, + { "0075_0301", "'u" }, + { "0075_0302", "^u" }, + { "0075_0308", ":u" }, + { "0076", "v" }, + { "0077", "w" }, + { "0078", "x" }, + { "0079", "y" }, + { "0079_0301", "'y" }, + { "0079_0308", ":y" }, + { "007A", "z" }, + { "007A_030C", "vz" }, + { "007B", "lC" }, +//{ "007B", "{" }, + { "007C", "ba" }, +//{ "007C", "or" }, +//{ "007C", "|" }, + { "007D", "rC" }, +//{ "007D", "}" }, +//{ "007E", "a~" }, + { "007E", "ti" }, +//{ "007E", "~" }, + { "00A1", "r!" }, + { "00A2", "ct" }, + { "00A3", "Po" }, + { "00A4", "Cs" }, + { "00A5", "Ye" }, + { "00A6", "bb" }, + { "00A7", "sc" }, + { "00A8", "ad" }, + { "00A9", "co" }, + { "00AA", "Of" }, + { "00AB", "Fo" }, + { "00AC", "no" }, +//{ "00AC", "tno" }, + // In groff, U+00AD is an input character only; it is not mapped to + // a glyph but to '\%'. + { "00AE", "rg" }, + { "00AF", "a-" }, + { "00B0", "de" }, + { "00B1", "+-" }, +//{ "00B1", "t+-" }, + { "00B2", "S2" }, + { "00B3", "S3" }, + { "00B4", "aa" }, + { "00B5", "mc" }, + { "00B6", "ps" }, + { "00B7", "pc" }, + { "00B8", "ac" }, + { "00B9", "S1" }, + { "00BA", "Om" }, + { "00BB", "Fc" }, + { "00BC", "14" }, + { "00BD", "12" }, + { "00BE", "34" }, + { "00BF", "r?" }, + { "00C6", "AE" }, + { "00D0", "-D" }, + { "00D7", "mu" }, +//{ "00D7", "tmu" }, + { "00D8", "/O" }, + { "00DE", "TP" }, + { "00DF", "ss" }, + { "00E6", "ae" }, + { "00F0", "Sd" }, + { "00F7", "di" }, +//{ "00F7", "tdi" }, + { "00F8", "/o" }, + { "00FE", "Tp" }, + { "0131", ".i" }, + { "0132", "IJ" }, + { "0133", "ij" }, + { "0141", "/L" }, + { "0142", "/l" }, + { "0152", "OE" }, + { "0153", "oe" }, + { "0192", "Fn" }, + { "0237", ".j" }, + { "02C7", "ah" }, + { "02D8", "ab" }, + { "02D9", "a." }, + { "02DA", "ao" }, + { "02DB", "ho" }, + { "02DD", "a\"" }, + { "0391", "*A" }, + { "0392", "*B" }, + { "0393", "*G" }, + { "0394", "*D" }, + { "0395", "*E" }, + { "0396", "*Z" }, + { "0397", "*Y" }, + { "0398", "*H" }, + { "0399", "*I" }, + { "039A", "*K" }, + { "039B", "*L" }, + { "039C", "*M" }, + { "039D", "*N" }, + { "039E", "*C" }, + { "039F", "*O" }, + { "03A0", "*P" }, + { "03A1", "*R" }, + { "03A3", "*S" }, + { "03A4", "*T" }, + { "03A5", "*U" }, + { "03A6", "*F" }, + { "03A7", "*X" }, + { "03A8", "*Q" }, + { "03A9", "*W" }, + { "03B1", "*a" }, + { "03B2", "*b" }, + { "03B3", "*g" }, + { "03B4", "*d" }, + { "03B5", "*e" }, + { "03B6", "*z" }, + { "03B7", "*y" }, + { "03B8", "*h" }, + { "03B9", "*i" }, + { "03BA", "*k" }, + { "03BB", "*l" }, + { "03BC", "*m" }, + { "03BD", "*n" }, + { "03BE", "*c" }, + { "03BF", "*o" }, + { "03C0", "*p" }, + { "03C1", "*r" }, + { "03C2", "ts" }, + { "03C3", "*s" }, + { "03C4", "*t" }, + { "03C5", "*u" }, + { "03C6", "+f" }, + { "03C7", "*x" }, + { "03C8", "*q" }, + { "03C9", "*w" }, + { "03D1", "+h" }, + { "03D5", "*f" }, + { "03D6", "+p" }, + { "03F5", "+e" }, +//{ "2010", "-" }, + { "2010", "hy" }, + { "2013", "en" }, + { "2014", "em" }, +//{ "2018", "`" }, + { "2018", "oq" }, +//{ "2019", "'" }, + { "2019", "cq" }, + { "201A", "bq" }, + { "201C", "lq" }, + { "201D", "rq" }, + { "201E", "Bq" }, + { "2020", "dg" }, + { "2021", "dd" }, + { "2022", "bu" }, + { "2030", "%0" }, + { "2032", "fm" }, + { "2033", "sd" }, + { "2039", "fo" }, + { "203A", "fc" }, + { "203E", "rn" }, + { "2044", "f/" }, + { "20AC", "Eu" }, +//{ "20AC", "eu" }, + { "210F", "-h" }, +//{ "210F", "hbar" }, + { "2111", "Im" }, + { "2118", "wp" }, + { "211C", "Re" }, + { "2122", "tm" }, + { "2135", "Ah" }, + { "215B", "18" }, + { "215C", "38" }, + { "215D", "58" }, + { "215E", "78" }, + { "2190", "<-" }, + { "2191", "ua" }, + { "2192", "->" }, + { "2193", "da" }, + { "2194", "<>" }, + { "2195", "va" }, + { "21B5", "CR" }, + { "21D0", "lA" }, + { "21D1", "uA" }, + { "21D2", "rA" }, + { "21D3", "dA" }, + { "21D4", "hA" }, + { "21D5", "vA" }, + { "2200", "fa" }, + { "2202", "pd" }, + { "2203", "te" }, + { "2205", "es" }, + { "2207", "gr" }, + { "2208", "mo" }, + { "2208_0338", "nm" }, + { "220B", "st" }, + { "220F", "product" }, + { "2210", "coproduct" }, + { "2211", "sum" }, + { "2212", "mi" }, +//{ "2212", "\\-" }, + { "2213", "-+" }, + { "2217", "**" }, + { "221A", "sr" }, + { "221D", "pt" }, + { "221E", "if" }, + { "2220", "/_" }, + { "2227", "AN" }, + { "2228", "OR" }, + { "2229", "ca" }, + { "222A", "cu" }, + { "222B", "is" }, +//{ "222B", "integral" }, +//{ "2234", "3d" }, + { "2234", "tf" }, + { "223C", "ap" }, + { "2243", "|=" }, + { "2245", "=~" }, +//{ "2248", "~=" }, + { "2248", "~~" }, + { "2261", "==" }, + { "2261_0338", "ne" }, + { "2264", "<=" }, + { "2265", ">=" }, + { "226A", ">>" }, + { "226B", "<<" }, + { "2282", "sb" }, + { "2282_0338", "nb" }, + { "2283", "sp" }, + { "2283_0338", "nc" }, + { "2286", "ib" }, + { "2287", "ip" }, + { "2295", "c+" }, + { "2297", "c*" }, + { "22A5", "pp" }, + { "22C5", "md" }, + { "2308", "lc" }, + { "2309", "rc" }, + { "230A", "lf" }, + { "230B", "rf" }, + { "239B", "parenlefttp" }, + { "239C", "parenleftex" }, + { "239D", "parenleftbt" }, + { "239E", "parenrighttp" }, + { "239F", "parenrightex" }, + { "23A0", "parenrightbt" }, +//{ "23A1", "bracketlefttp" }, + { "23A2", "bracketleftex" }, +//{ "23A3", "bracketleftbt" }, +//{ "23A4", "bracketrighttp" }, + { "23A5", "bracketrightex" }, +//{ "23A6", "bracketrightbt" }, + { "23A7", "lt" }, +//{ "23A7", "bracelefttp" }, + { "23A8", "lk" }, +//{ "23A8", "braceleftmid" }, + { "23A9", "lb" }, +//{ "23A9", "braceleftbt" }, + { "23AA", "bv" }, +//{ "23AA", "braceex" }, +//{ "23AA", "braceleftex" }, +//{ "23AA", "bracerightex" }, + { "23AB", "rt" }, +//{ "23AB", "bracerighttp" }, + { "23AC", "rk" }, +//{ "23AC", "bracerightmid" }, + { "23AD", "rb" }, +//{ "23AD", "bracerightbt" }, + { "23AF", "an" }, + { "2502", "br" }, + { "25A1", "sq" }, + { "25CA", "lz" }, + { "25CB", "ci" }, + { "261C", "lh" }, + { "261E", "rh" }, + { "2660", "SP" }, + { "2663", "CL" }, + { "2665", "HE" }, + { "2666", "DI" }, + { "2713", "OK" }, + { "27E8", "la" }, + { "27E9", "ra" }, +}; + +// global constructor +static struct unicode_to_glyph_init { + unicode_to_glyph_init(); +} _unicode_to_glyph_init; + +unicode_to_glyph_init::unicode_to_glyph_init() +{ + for (unsigned int i = 0; + i < sizeof(unicode_to_glyph_list)/sizeof(unicode_to_glyph_list[0]); + i++) { + unicode_to_glyph *utg = new unicode_to_glyph[1]; + utg->value = (char *)unicode_to_glyph_list[i].value; + unicode_to_glyph_table.define(unicode_to_glyph_list[i].key, utg); + } +} + +const char *unicode_to_glyph_name(const char *s) +{ + unicode_to_glyph *result = unicode_to_glyph_table.lookup(s); + return result ? result->value : 0; +} diff --git a/src/libs/libgroff/uniuni.cpp b/src/libs/libgroff/uniuni.cpp new file mode 100644 index 0000000..e3b2708 --- /dev/null +++ b/src/libs/libgroff/uniuni.cpp @@ -0,0 +1,2128 @@ +// -*- C++ -*- +/* Copyright (C) 2002-2020 Free Software Foundation, Inc. + Written by Werner Lemberg <wl@gnu.org> + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +// This code has been algorithmically derived from the file +// UnicodeData.txt, version 7.0.0, available from unicode.org, +// on 2014-12-16. + +#include "lib.h" +#include "stringclass.h" +#include "ptable.h" + +#include "unicode.h" + +struct unicode_decompose { + char *value; +}; + +declare_ptable(unicode_decompose) +implement_ptable(unicode_decompose) + +PTABLE(unicode_decompose) unicode_decompose_table; + +// the first digit in the composite string gives the number of composites + +struct S { + const char *key; + const char *value; +} unicode_decompose_list[] = { + { "00C0", "20041_0300" }, + { "00C1", "20041_0301" }, + { "00C2", "20041_0302" }, + { "00C3", "20041_0303" }, + { "00C4", "20041_0308" }, + { "00C5", "20041_030A" }, + { "00C7", "20043_0327" }, + { "00C8", "20045_0300" }, + { "00C9", "20045_0301" }, + { "00CA", "20045_0302" }, + { "00CB", "20045_0308" }, + { "00CC", "20049_0300" }, + { "00CD", "20049_0301" }, + { "00CE", "20049_0302" }, + { "00CF", "20049_0308" }, + { "00D1", "2004E_0303" }, + { "00D2", "2004F_0300" }, + { "00D3", "2004F_0301" }, + { "00D4", "2004F_0302" }, + { "00D5", "2004F_0303" }, + { "00D6", "2004F_0308" }, + { "00D9", "20055_0300" }, + { "00DA", "20055_0301" }, + { "00DB", "20055_0302" }, + { "00DC", "20055_0308" }, + { "00DD", "20059_0301" }, + { "00E0", "20061_0300" }, + { "00E1", "20061_0301" }, + { "00E2", "20061_0302" }, + { "00E3", "20061_0303" }, + { "00E4", "20061_0308" }, + { "00E5", "20061_030A" }, + { "00E7", "20063_0327" }, + { "00E8", "20065_0300" }, + { "00E9", "20065_0301" }, + { "00EA", "20065_0302" }, + { "00EB", "20065_0308" }, + { "00EC", "20069_0300" }, + { "00ED", "20069_0301" }, + { "00EE", "20069_0302" }, + { "00EF", "20069_0308" }, + { "00F1", "2006E_0303" }, + { "00F2", "2006F_0300" }, + { "00F3", "2006F_0301" }, + { "00F4", "2006F_0302" }, + { "00F5", "2006F_0303" }, + { "00F6", "2006F_0308" }, + { "00F9", "20075_0300" }, + { "00FA", "20075_0301" }, + { "00FB", "20075_0302" }, + { "00FC", "20075_0308" }, + { "00FD", "20079_0301" }, + { "00FF", "20079_0308" }, + { "0100", "20041_0304" }, + { "0101", "20061_0304" }, + { "0102", "20041_0306" }, + { "0103", "20061_0306" }, + { "0104", "20041_0328" }, + { "0105", "20061_0328" }, + { "0106", "20043_0301" }, + { "0107", "20063_0301" }, + { "0108", "20043_0302" }, + { "0109", "20063_0302" }, + { "010A", "20043_0307" }, + { "010B", "20063_0307" }, + { "010C", "20043_030C" }, + { "010D", "20063_030C" }, + { "010E", "20044_030C" }, + { "010F", "20064_030C" }, + { "0112", "20045_0304" }, + { "0113", "20065_0304" }, + { "0114", "20045_0306" }, + { "0115", "20065_0306" }, + { "0116", "20045_0307" }, + { "0117", "20065_0307" }, + { "0118", "20045_0328" }, + { "0119", "20065_0328" }, + { "011A", "20045_030C" }, + { "011B", "20065_030C" }, + { "011C", "20047_0302" }, + { "011D", "20067_0302" }, + { "011E", "20047_0306" }, + { "011F", "20067_0306" }, + { "0120", "20047_0307" }, + { "0121", "20067_0307" }, + { "0122", "20047_0327" }, + { "0123", "20067_0327" }, + { "0124", "20048_0302" }, + { "0125", "20068_0302" }, + { "0128", "20049_0303" }, + { "0129", "20069_0303" }, + { "012A", "20049_0304" }, + { "012B", "20069_0304" }, + { "012C", "20049_0306" }, + { "012D", "20069_0306" }, + { "012E", "20049_0328" }, + { "012F", "20069_0328" }, + { "0130", "20049_0307" }, + { "0134", "2004A_0302" }, + { "0135", "2006A_0302" }, + { "0136", "2004B_0327" }, + { "0137", "2006B_0327" }, + { "0139", "2004C_0301" }, + { "013A", "2006C_0301" }, + { "013B", "2004C_0327" }, + { "013C", "2006C_0327" }, + { "013D", "2004C_030C" }, + { "013E", "2006C_030C" }, + { "0143", "2004E_0301" }, + { "0144", "2006E_0301" }, + { "0145", "2004E_0327" }, + { "0146", "2006E_0327" }, + { "0147", "2004E_030C" }, + { "0148", "2006E_030C" }, + { "014C", "2004F_0304" }, + { "014D", "2006F_0304" }, + { "014E", "2004F_0306" }, + { "014F", "2006F_0306" }, + { "0150", "2004F_030B" }, + { "0151", "2006F_030B" }, + { "0154", "20052_0301" }, + { "0155", "20072_0301" }, + { "0156", "20052_0327" }, + { "0157", "20072_0327" }, + { "0158", "20052_030C" }, + { "0159", "20072_030C" }, + { "015A", "20053_0301" }, + { "015B", "20073_0301" }, + { "015C", "20053_0302" }, + { "015D", "20073_0302" }, + { "015E", "20053_0327" }, + { "015F", "20073_0327" }, + { "0160", "20053_030C" }, + { "0161", "20073_030C" }, + { "0162", "20054_0327" }, + { "0163", "20074_0327" }, + { "0164", "20054_030C" }, + { "0165", "20074_030C" }, + { "0168", "20055_0303" }, + { "0169", "20075_0303" }, + { "016A", "20055_0304" }, + { "016B", "20075_0304" }, + { "016C", "20055_0306" }, + { "016D", "20075_0306" }, + { "016E", "20055_030A" }, + { "016F", "20075_030A" }, + { "0170", "20055_030B" }, + { "0171", "20075_030B" }, + { "0172", "20055_0328" }, + { "0173", "20075_0328" }, + { "0174", "20057_0302" }, + { "0175", "20077_0302" }, + { "0176", "20059_0302" }, + { "0177", "20079_0302" }, + { "0178", "20059_0308" }, + { "0179", "2005A_0301" }, + { "017A", "2007A_0301" }, + { "017B", "2005A_0307" }, + { "017C", "2007A_0307" }, + { "017D", "2005A_030C" }, + { "017E", "2007A_030C" }, + { "01A0", "2004F_031B" }, + { "01A1", "2006F_031B" }, + { "01AF", "20055_031B" }, + { "01B0", "20075_031B" }, + { "01CD", "20041_030C" }, + { "01CE", "20061_030C" }, + { "01CF", "20049_030C" }, + { "01D0", "20069_030C" }, + { "01D1", "2004F_030C" }, + { "01D2", "2006F_030C" }, + { "01D3", "20055_030C" }, + { "01D4", "20075_030C" }, + { "01D5", "30055_0308_0304" }, + { "01D6", "30075_0308_0304" }, + { "01D7", "30055_0308_0301" }, + { "01D8", "30075_0308_0301" }, + { "01D9", "30055_0308_030C" }, + { "01DA", "30075_0308_030C" }, + { "01DB", "30055_0308_0300" }, + { "01DC", "30075_0308_0300" }, + { "01DE", "30041_0308_0304" }, + { "01DF", "30061_0308_0304" }, + { "01E0", "30041_0307_0304" }, + { "01E1", "30061_0307_0304" }, + { "01E2", "200C6_0304" }, + { "01E3", "200E6_0304" }, + { "01E6", "20047_030C" }, + { "01E7", "20067_030C" }, + { "01E8", "2004B_030C" }, + { "01E9", "2006B_030C" }, + { "01EA", "2004F_0328" }, + { "01EB", "2006F_0328" }, + { "01EC", "3004F_0328_0304" }, + { "01ED", "3006F_0328_0304" }, + { "01EE", "201B7_030C" }, + { "01EF", "20292_030C" }, + { "01F0", "2006A_030C" }, + { "01F4", "20047_0301" }, + { "01F5", "20067_0301" }, + { "01F8", "2004E_0300" }, + { "01F9", "2006E_0300" }, + { "01FA", "30041_030A_0301" }, + { "01FB", "30061_030A_0301" }, + { "01FC", "200C6_0301" }, + { "01FD", "200E6_0301" }, + { "01FE", "200D8_0301" }, + { "01FF", "200F8_0301" }, + { "0200", "20041_030F" }, + { "0201", "20061_030F" }, + { "0202", "20041_0311" }, + { "0203", "20061_0311" }, + { "0204", "20045_030F" }, + { "0205", "20065_030F" }, + { "0206", "20045_0311" }, + { "0207", "20065_0311" }, + { "0208", "20049_030F" }, + { "0209", "20069_030F" }, + { "020A", "20049_0311" }, + { "020B", "20069_0311" }, + { "020C", "2004F_030F" }, + { "020D", "2006F_030F" }, + { "020E", "2004F_0311" }, + { "020F", "2006F_0311" }, + { "0210", "20052_030F" }, + { "0211", "20072_030F" }, + { "0212", "20052_0311" }, + { "0213", "20072_0311" }, + { "0214", "20055_030F" }, + { "0215", "20075_030F" }, + { "0216", "20055_0311" }, + { "0217", "20075_0311" }, + { "0218", "20053_0326" }, + { "0219", "20073_0326" }, + { "021A", "20054_0326" }, + { "021B", "20074_0326" }, + { "021E", "20048_030C" }, + { "021F", "20068_030C" }, + { "0226", "20041_0307" }, + { "0227", "20061_0307" }, + { "0228", "20045_0327" }, + { "0229", "20065_0327" }, + { "022A", "3004F_0308_0304" }, + { "022B", "3006F_0308_0304" }, + { "022C", "3004F_0303_0304" }, + { "022D", "3006F_0303_0304" }, + { "022E", "2004F_0307" }, + { "022F", "2006F_0307" }, + { "0230", "3004F_0307_0304" }, + { "0231", "3006F_0307_0304" }, + { "0232", "20059_0304" }, + { "0233", "20079_0304" }, + { "0340", "10300" }, + { "0341", "10301" }, + { "0343", "10313" }, + { "0344", "20308_0301" }, + { "0374", "102B9" }, + { "037E", "1003B" }, + { "0385", "200A8_0301" }, + { "0386", "20391_0301" }, + { "0387", "100B7" }, + { "0388", "20395_0301" }, + { "0389", "20397_0301" }, + { "038A", "20399_0301" }, + { "038C", "2039F_0301" }, + { "038E", "203A5_0301" }, + { "038F", "203A9_0301" }, + { "0390", "303B9_0308_0301" }, + { "03AA", "20399_0308" }, + { "03AB", "203A5_0308" }, + { "03AC", "203B1_0301" }, + { "03AD", "203B5_0301" }, + { "03AE", "203B7_0301" }, + { "03AF", "203B9_0301" }, + { "03B0", "303C5_0308_0301" }, + { "03CA", "203B9_0308" }, + { "03CB", "203C5_0308" }, + { "03CC", "203BF_0301" }, + { "03CD", "203C5_0301" }, + { "03CE", "203C9_0301" }, + { "03D3", "203D2_0301" }, + { "03D4", "203D2_0308" }, + { "0400", "20415_0300" }, + { "0401", "20415_0308" }, + { "0403", "20413_0301" }, + { "0407", "20406_0308" }, + { "040C", "2041A_0301" }, + { "040D", "20418_0300" }, + { "040E", "20423_0306" }, + { "0419", "20418_0306" }, + { "0439", "20438_0306" }, + { "0450", "20435_0300" }, + { "0451", "20435_0308" }, + { "0453", "20433_0301" }, + { "0457", "20456_0308" }, + { "045C", "2043A_0301" }, + { "045D", "20438_0300" }, + { "045E", "20443_0306" }, + { "0476", "20474_030F" }, + { "0477", "20475_030F" }, + { "04C1", "20416_0306" }, + { "04C2", "20436_0306" }, + { "04D0", "20410_0306" }, + { "04D1", "20430_0306" }, + { "04D2", "20410_0308" }, + { "04D3", "20430_0308" }, + { "04D6", "20415_0306" }, + { "04D7", "20435_0306" }, + { "04DA", "204D8_0308" }, + { "04DB", "204D9_0308" }, + { "04DC", "20416_0308" }, + { "04DD", "20436_0308" }, + { "04DE", "20417_0308" }, + { "04DF", "20437_0308" }, + { "04E2", "20418_0304" }, + { "04E3", "20438_0304" }, + { "04E4", "20418_0308" }, + { "04E5", "20438_0308" }, + { "04E6", "2041E_0308" }, + { "04E7", "2043E_0308" }, + { "04EA", "204E8_0308" }, + { "04EB", "204E9_0308" }, + { "04EC", "2042D_0308" }, + { "04ED", "2044D_0308" }, + { "04EE", "20423_0304" }, + { "04EF", "20443_0304" }, + { "04F0", "20423_0308" }, + { "04F1", "20443_0308" }, + { "04F2", "20423_030B" }, + { "04F3", "20443_030B" }, + { "04F4", "20427_0308" }, + { "04F5", "20447_0308" }, + { "04F8", "2042B_0308" }, + { "04F9", "2044B_0308" }, + { "0622", "20627_0653" }, + { "0623", "20627_0654" }, + { "0624", "20648_0654" }, + { "0625", "20627_0655" }, + { "0626", "2064A_0654" }, + { "06C0", "206D5_0654" }, + { "06C2", "206C1_0654" }, + { "06D3", "206D2_0654" }, + { "0929", "20928_093C" }, + { "0931", "20930_093C" }, + { "0934", "20933_093C" }, + { "0958", "20915_093C" }, + { "0959", "20916_093C" }, + { "095A", "20917_093C" }, + { "095B", "2091C_093C" }, + { "095C", "20921_093C" }, + { "095D", "20922_093C" }, + { "095E", "2092B_093C" }, + { "095F", "2092F_093C" }, + { "09CB", "209C7_09BE" }, + { "09CC", "209C7_09D7" }, + { "09DC", "209A1_09BC" }, + { "09DD", "209A2_09BC" }, + { "09DF", "209AF_09BC" }, + { "0A33", "20A32_0A3C" }, + { "0A36", "20A38_0A3C" }, + { "0A59", "20A16_0A3C" }, + { "0A5A", "20A17_0A3C" }, + { "0A5B", "20A1C_0A3C" }, + { "0A5E", "20A2B_0A3C" }, + { "0B48", "20B47_0B56" }, + { "0B4B", "20B47_0B3E" }, + { "0B4C", "20B47_0B57" }, + { "0B5C", "20B21_0B3C" }, + { "0B5D", "20B22_0B3C" }, + { "0B94", "20B92_0BD7" }, + { "0BCA", "20BC6_0BBE" }, + { "0BCB", "20BC7_0BBE" }, + { "0BCC", "20BC6_0BD7" }, + { "0C48", "20C46_0C56" }, + { "0CC0", "20CBF_0CD5" }, + { "0CC7", "20CC6_0CD5" }, + { "0CC8", "20CC6_0CD6" }, + { "0CCA", "20CC6_0CC2" }, + { "0CCB", "30CC6_0CC2_0CD5" }, + { "0D4A", "20D46_0D3E" }, + { "0D4B", "20D47_0D3E" }, + { "0D4C", "20D46_0D57" }, + { "0DDA", "20DD9_0DCA" }, + { "0DDC", "20DD9_0DCF" }, + { "0DDD", "30DD9_0DCF_0DCA" }, + { "0DDE", "20DD9_0DDF" }, + { "0F43", "20F42_0FB7" }, + { "0F4D", "20F4C_0FB7" }, + { "0F52", "20F51_0FB7" }, + { "0F57", "20F56_0FB7" }, + { "0F5C", "20F5B_0FB7" }, + { "0F69", "20F40_0FB5" }, + { "0F73", "20F71_0F72" }, + { "0F75", "20F71_0F74" }, + { "0F76", "20FB2_0F80" }, + { "0F78", "20FB3_0F80" }, + { "0F81", "20F71_0F80" }, + { "0F93", "20F92_0FB7" }, + { "0F9D", "20F9C_0FB7" }, + { "0FA2", "20FA1_0FB7" }, + { "0FA7", "20FA6_0FB7" }, + { "0FAC", "20FAB_0FB7" }, + { "0FB9", "20F90_0FB5" }, + { "1026", "21025_102E" }, + { "1B06", "21B05_1B35" }, + { "1B08", "21B07_1B35" }, + { "1B0A", "21B09_1B35" }, + { "1B0C", "21B0B_1B35" }, + { "1B0E", "21B0D_1B35" }, + { "1B12", "21B11_1B35" }, + { "1B3B", "21B3A_1B35" }, + { "1B3D", "21B3C_1B35" }, + { "1B40", "21B3E_1B35" }, + { "1B41", "21B3F_1B35" }, + { "1B43", "21B42_1B35" }, + { "1E00", "20041_0325" }, + { "1E01", "20061_0325" }, + { "1E02", "20042_0307" }, + { "1E03", "20062_0307" }, + { "1E04", "20042_0323" }, + { "1E05", "20062_0323" }, + { "1E06", "20042_0331" }, + { "1E07", "20062_0331" }, + { "1E08", "30043_0327_0301" }, + { "1E09", "30063_0327_0301" }, + { "1E0A", "20044_0307" }, + { "1E0B", "20064_0307" }, + { "1E0C", "20044_0323" }, + { "1E0D", "20064_0323" }, + { "1E0E", "20044_0331" }, + { "1E0F", "20064_0331" }, + { "1E10", "20044_0327" }, + { "1E11", "20064_0327" }, + { "1E12", "20044_032D" }, + { "1E13", "20064_032D" }, + { "1E14", "30045_0304_0300" }, + { "1E15", "30065_0304_0300" }, + { "1E16", "30045_0304_0301" }, + { "1E17", "30065_0304_0301" }, + { "1E18", "20045_032D" }, + { "1E19", "20065_032D" }, + { "1E1A", "20045_0330" }, + { "1E1B", "20065_0330" }, + { "1E1C", "30045_0327_0306" }, + { "1E1D", "30065_0327_0306" }, + { "1E1E", "20046_0307" }, + { "1E1F", "20066_0307" }, + { "1E20", "20047_0304" }, + { "1E21", "20067_0304" }, + { "1E22", "20048_0307" }, + { "1E23", "20068_0307" }, + { "1E24", "20048_0323" }, + { "1E25", "20068_0323" }, + { "1E26", "20048_0308" }, + { "1E27", "20068_0308" }, + { "1E28", "20048_0327" }, + { "1E29", "20068_0327" }, + { "1E2A", "20048_032E" }, + { "1E2B", "20068_032E" }, + { "1E2C", "20049_0330" }, + { "1E2D", "20069_0330" }, + { "1E2E", "30049_0308_0301" }, + { "1E2F", "30069_0308_0301" }, + { "1E30", "2004B_0301" }, + { "1E31", "2006B_0301" }, + { "1E32", "2004B_0323" }, + { "1E33", "2006B_0323" }, + { "1E34", "2004B_0331" }, + { "1E35", "2006B_0331" }, + { "1E36", "2004C_0323" }, + { "1E37", "2006C_0323" }, + { "1E38", "3004C_0323_0304" }, + { "1E39", "3006C_0323_0304" }, + { "1E3A", "2004C_0331" }, + { "1E3B", "2006C_0331" }, + { "1E3C", "2004C_032D" }, + { "1E3D", "2006C_032D" }, + { "1E3E", "2004D_0301" }, + { "1E3F", "2006D_0301" }, + { "1E40", "2004D_0307" }, + { "1E41", "2006D_0307" }, + { "1E42", "2004D_0323" }, + { "1E43", "2006D_0323" }, + { "1E44", "2004E_0307" }, + { "1E45", "2006E_0307" }, + { "1E46", "2004E_0323" }, + { "1E47", "2006E_0323" }, + { "1E48", "2004E_0331" }, + { "1E49", "2006E_0331" }, + { "1E4A", "2004E_032D" }, + { "1E4B", "2006E_032D" }, + { "1E4C", "3004F_0303_0301" }, + { "1E4D", "3006F_0303_0301" }, + { "1E4E", "3004F_0303_0308" }, + { "1E4F", "3006F_0303_0308" }, + { "1E50", "3004F_0304_0300" }, + { "1E51", "3006F_0304_0300" }, + { "1E52", "3004F_0304_0301" }, + { "1E53", "3006F_0304_0301" }, + { "1E54", "20050_0301" }, + { "1E55", "20070_0301" }, + { "1E56", "20050_0307" }, + { "1E57", "20070_0307" }, + { "1E58", "20052_0307" }, + { "1E59", "20072_0307" }, + { "1E5A", "20052_0323" }, + { "1E5B", "20072_0323" }, + { "1E5C", "30052_0323_0304" }, + { "1E5D", "30072_0323_0304" }, + { "1E5E", "20052_0331" }, + { "1E5F", "20072_0331" }, + { "1E60", "20053_0307" }, + { "1E61", "20073_0307" }, + { "1E62", "20053_0323" }, + { "1E63", "20073_0323" }, + { "1E64", "30053_0301_0307" }, + { "1E65", "30073_0301_0307" }, + { "1E66", "30053_030C_0307" }, + { "1E67", "30073_030C_0307" }, + { "1E68", "30053_0323_0307" }, + { "1E69", "30073_0323_0307" }, + { "1E6A", "20054_0307" }, + { "1E6B", "20074_0307" }, + { "1E6C", "20054_0323" }, + { "1E6D", "20074_0323" }, + { "1E6E", "20054_0331" }, + { "1E6F", "20074_0331" }, + { "1E70", "20054_032D" }, + { "1E71", "20074_032D" }, + { "1E72", "20055_0324" }, + { "1E73", "20075_0324" }, + { "1E74", "20055_0330" }, + { "1E75", "20075_0330" }, + { "1E76", "20055_032D" }, + { "1E77", "20075_032D" }, + { "1E78", "30055_0303_0301" }, + { "1E79", "30075_0303_0301" }, + { "1E7A", "30055_0304_0308" }, + { "1E7B", "30075_0304_0308" }, + { "1E7C", "20056_0303" }, + { "1E7D", "20076_0303" }, + { "1E7E", "20056_0323" }, + { "1E7F", "20076_0323" }, + { "1E80", "20057_0300" }, + { "1E81", "20077_0300" }, + { "1E82", "20057_0301" }, + { "1E83", "20077_0301" }, + { "1E84", "20057_0308" }, + { "1E85", "20077_0308" }, + { "1E86", "20057_0307" }, + { "1E87", "20077_0307" }, + { "1E88", "20057_0323" }, + { "1E89", "20077_0323" }, + { "1E8A", "20058_0307" }, + { "1E8B", "20078_0307" }, + { "1E8C", "20058_0308" }, + { "1E8D", "20078_0308" }, + { "1E8E", "20059_0307" }, + { "1E8F", "20079_0307" }, + { "1E90", "2005A_0302" }, + { "1E91", "2007A_0302" }, + { "1E92", "2005A_0323" }, + { "1E93", "2007A_0323" }, + { "1E94", "2005A_0331" }, + { "1E95", "2007A_0331" }, + { "1E96", "20068_0331" }, + { "1E97", "20074_0308" }, + { "1E98", "20077_030A" }, + { "1E99", "20079_030A" }, + { "1E9B", "2017F_0307" }, + { "1EA0", "20041_0323" }, + { "1EA1", "20061_0323" }, + { "1EA2", "20041_0309" }, + { "1EA3", "20061_0309" }, + { "1EA4", "30041_0302_0301" }, + { "1EA5", "30061_0302_0301" }, + { "1EA6", "30041_0302_0300" }, + { "1EA7", "30061_0302_0300" }, + { "1EA8", "30041_0302_0309" }, + { "1EA9", "30061_0302_0309" }, + { "1EAA", "30041_0302_0303" }, + { "1EAB", "30061_0302_0303" }, + { "1EAC", "30041_0323_0302" }, + { "1EAD", "30061_0323_0302" }, + { "1EAE", "30041_0306_0301" }, + { "1EAF", "30061_0306_0301" }, + { "1EB0", "30041_0306_0300" }, + { "1EB1", "30061_0306_0300" }, + { "1EB2", "30041_0306_0309" }, + { "1EB3", "30061_0306_0309" }, + { "1EB4", "30041_0306_0303" }, + { "1EB5", "30061_0306_0303" }, + { "1EB6", "30041_0323_0306" }, + { "1EB7", "30061_0323_0306" }, + { "1EB8", "20045_0323" }, + { "1EB9", "20065_0323" }, + { "1EBA", "20045_0309" }, + { "1EBB", "20065_0309" }, + { "1EBC", "20045_0303" }, + { "1EBD", "20065_0303" }, + { "1EBE", "30045_0302_0301" }, + { "1EBF", "30065_0302_0301" }, + { "1EC0", "30045_0302_0300" }, + { "1EC1", "30065_0302_0300" }, + { "1EC2", "30045_0302_0309" }, + { "1EC3", "30065_0302_0309" }, + { "1EC4", "30045_0302_0303" }, + { "1EC5", "30065_0302_0303" }, + { "1EC6", "30045_0323_0302" }, + { "1EC7", "30065_0323_0302" }, + { "1EC8", "20049_0309" }, + { "1EC9", "20069_0309" }, + { "1ECA", "20049_0323" }, + { "1ECB", "20069_0323" }, + { "1ECC", "2004F_0323" }, + { "1ECD", "2006F_0323" }, + { "1ECE", "2004F_0309" }, + { "1ECF", "2006F_0309" }, + { "1ED0", "3004F_0302_0301" }, + { "1ED1", "3006F_0302_0301" }, + { "1ED2", "3004F_0302_0300" }, + { "1ED3", "3006F_0302_0300" }, + { "1ED4", "3004F_0302_0309" }, + { "1ED5", "3006F_0302_0309" }, + { "1ED6", "3004F_0302_0303" }, + { "1ED7", "3006F_0302_0303" }, + { "1ED8", "3004F_0323_0302" }, + { "1ED9", "3006F_0323_0302" }, + { "1EDA", "3004F_031B_0301" }, + { "1EDB", "3006F_031B_0301" }, + { "1EDC", "3004F_031B_0300" }, + { "1EDD", "3006F_031B_0300" }, + { "1EDE", "3004F_031B_0309" }, + { "1EDF", "3006F_031B_0309" }, + { "1EE0", "3004F_031B_0303" }, + { "1EE1", "3006F_031B_0303" }, + { "1EE2", "3004F_031B_0323" }, + { "1EE3", "3006F_031B_0323" }, + { "1EE4", "20055_0323" }, + { "1EE5", "20075_0323" }, + { "1EE6", "20055_0309" }, + { "1EE7", "20075_0309" }, + { "1EE8", "30055_031B_0301" }, + { "1EE9", "30075_031B_0301" }, + { "1EEA", "30055_031B_0300" }, + { "1EEB", "30075_031B_0300" }, + { "1EEC", "30055_031B_0309" }, + { "1EED", "30075_031B_0309" }, + { "1EEE", "30055_031B_0303" }, + { "1EEF", "30075_031B_0303" }, + { "1EF0", "30055_031B_0323" }, + { "1EF1", "30075_031B_0323" }, + { "1EF2", "20059_0300" }, + { "1EF3", "20079_0300" }, + { "1EF4", "20059_0323" }, + { "1EF5", "20079_0323" }, + { "1EF6", "20059_0309" }, + { "1EF7", "20079_0309" }, + { "1EF8", "20059_0303" }, + { "1EF9", "20079_0303" }, + { "1F00", "203B1_0313" }, + { "1F01", "203B1_0314" }, + { "1F02", "303B1_0313_0300" }, + { "1F03", "303B1_0314_0300" }, + { "1F04", "303B1_0313_0301" }, + { "1F05", "303B1_0314_0301" }, + { "1F06", "303B1_0313_0342" }, + { "1F07", "303B1_0314_0342" }, + { "1F08", "20391_0313" }, + { "1F09", "20391_0314" }, + { "1F0A", "30391_0313_0300" }, + { "1F0B", "30391_0314_0300" }, + { "1F0C", "30391_0313_0301" }, + { "1F0D", "30391_0314_0301" }, + { "1F0E", "30391_0313_0342" }, + { "1F0F", "30391_0314_0342" }, + { "1F10", "203B5_0313" }, + { "1F11", "203B5_0314" }, + { "1F12", "303B5_0313_0300" }, + { "1F13", "303B5_0314_0300" }, + { "1F14", "303B5_0313_0301" }, + { "1F15", "303B5_0314_0301" }, + { "1F18", "20395_0313" }, + { "1F19", "20395_0314" }, + { "1F1A", "30395_0313_0300" }, + { "1F1B", "30395_0314_0300" }, + { "1F1C", "30395_0313_0301" }, + { "1F1D", "30395_0314_0301" }, + { "1F20", "203B7_0313" }, + { "1F21", "203B7_0314" }, + { "1F22", "303B7_0313_0300" }, + { "1F23", "303B7_0314_0300" }, + { "1F24", "303B7_0313_0301" }, + { "1F25", "303B7_0314_0301" }, + { "1F26", "303B7_0313_0342" }, + { "1F27", "303B7_0314_0342" }, + { "1F28", "20397_0313" }, + { "1F29", "20397_0314" }, + { "1F2A", "30397_0313_0300" }, + { "1F2B", "30397_0314_0300" }, + { "1F2C", "30397_0313_0301" }, + { "1F2D", "30397_0314_0301" }, + { "1F2E", "30397_0313_0342" }, + { "1F2F", "30397_0314_0342" }, + { "1F30", "203B9_0313" }, + { "1F31", "203B9_0314" }, + { "1F32", "303B9_0313_0300" }, + { "1F33", "303B9_0314_0300" }, + { "1F34", "303B9_0313_0301" }, + { "1F35", "303B9_0314_0301" }, + { "1F36", "303B9_0313_0342" }, + { "1F37", "303B9_0314_0342" }, + { "1F38", "20399_0313" }, + { "1F39", "20399_0314" }, + { "1F3A", "30399_0313_0300" }, + { "1F3B", "30399_0314_0300" }, + { "1F3C", "30399_0313_0301" }, + { "1F3D", "30399_0314_0301" }, + { "1F3E", "30399_0313_0342" }, + { "1F3F", "30399_0314_0342" }, + { "1F40", "203BF_0313" }, + { "1F41", "203BF_0314" }, + { "1F42", "303BF_0313_0300" }, + { "1F43", "303BF_0314_0300" }, + { "1F44", "303BF_0313_0301" }, + { "1F45", "303BF_0314_0301" }, + { "1F48", "2039F_0313" }, + { "1F49", "2039F_0314" }, + { "1F4A", "3039F_0313_0300" }, + { "1F4B", "3039F_0314_0300" }, + { "1F4C", "3039F_0313_0301" }, + { "1F4D", "3039F_0314_0301" }, + { "1F50", "203C5_0313" }, + { "1F51", "203C5_0314" }, + { "1F52", "303C5_0313_0300" }, + { "1F53", "303C5_0314_0300" }, + { "1F54", "303C5_0313_0301" }, + { "1F55", "303C5_0314_0301" }, + { "1F56", "303C5_0313_0342" }, + { "1F57", "303C5_0314_0342" }, + { "1F59", "203A5_0314" }, + { "1F5B", "303A5_0314_0300" }, + { "1F5D", "303A5_0314_0301" }, + { "1F5F", "303A5_0314_0342" }, + { "1F60", "203C9_0313" }, + { "1F61", "203C9_0314" }, + { "1F62", "303C9_0313_0300" }, + { "1F63", "303C9_0314_0300" }, + { "1F64", "303C9_0313_0301" }, + { "1F65", "303C9_0314_0301" }, + { "1F66", "303C9_0313_0342" }, + { "1F67", "303C9_0314_0342" }, + { "1F68", "203A9_0313" }, + { "1F69", "203A9_0314" }, + { "1F6A", "303A9_0313_0300" }, + { "1F6B", "303A9_0314_0300" }, + { "1F6C", "303A9_0313_0301" }, + { "1F6D", "303A9_0314_0301" }, + { "1F6E", "303A9_0313_0342" }, + { "1F6F", "303A9_0314_0342" }, + { "1F70", "203B1_0300" }, + { "1F71", "203B1_0301" }, + { "1F72", "203B5_0300" }, + { "1F73", "203B5_0301" }, + { "1F74", "203B7_0300" }, + { "1F75", "203B7_0301" }, + { "1F76", "203B9_0300" }, + { "1F77", "203B9_0301" }, + { "1F78", "203BF_0300" }, + { "1F79", "203BF_0301" }, + { "1F7A", "203C5_0300" }, + { "1F7B", "203C5_0301" }, + { "1F7C", "203C9_0300" }, + { "1F7D", "203C9_0301" }, + { "1F80", "303B1_0313_0345" }, + { "1F81", "303B1_0314_0345" }, + { "1F82", "403B1_0313_0300_0345" }, + { "1F83", "403B1_0314_0300_0345" }, + { "1F84", "403B1_0313_0301_0345" }, + { "1F85", "403B1_0314_0301_0345" }, + { "1F86", "403B1_0313_0342_0345" }, + { "1F87", "403B1_0314_0342_0345" }, + { "1F88", "30391_0313_0345" }, + { "1F89", "30391_0314_0345" }, + { "1F8A", "40391_0313_0300_0345" }, + { "1F8B", "40391_0314_0300_0345" }, + { "1F8C", "40391_0313_0301_0345" }, + { "1F8D", "40391_0314_0301_0345" }, + { "1F8E", "40391_0313_0342_0345" }, + { "1F8F", "40391_0314_0342_0345" }, + { "1F90", "303B7_0313_0345" }, + { "1F91", "303B7_0314_0345" }, + { "1F92", "403B7_0313_0300_0345" }, + { "1F93", "403B7_0314_0300_0345" }, + { "1F94", "403B7_0313_0301_0345" }, + { "1F95", "403B7_0314_0301_0345" }, + { "1F96", "403B7_0313_0342_0345" }, + { "1F97", "403B7_0314_0342_0345" }, + { "1F98", "30397_0313_0345" }, + { "1F99", "30397_0314_0345" }, + { "1F9A", "40397_0313_0300_0345" }, + { "1F9B", "40397_0314_0300_0345" }, + { "1F9C", "40397_0313_0301_0345" }, + { "1F9D", "40397_0314_0301_0345" }, + { "1F9E", "40397_0313_0342_0345" }, + { "1F9F", "40397_0314_0342_0345" }, + { "1FA0", "303C9_0313_0345" }, + { "1FA1", "303C9_0314_0345" }, + { "1FA2", "403C9_0313_0300_0345" }, + { "1FA3", "403C9_0314_0300_0345" }, + { "1FA4", "403C9_0313_0301_0345" }, + { "1FA5", "403C9_0314_0301_0345" }, + { "1FA6", "403C9_0313_0342_0345" }, + { "1FA7", "403C9_0314_0342_0345" }, + { "1FA8", "303A9_0313_0345" }, + { "1FA9", "303A9_0314_0345" }, + { "1FAA", "403A9_0313_0300_0345" }, + { "1FAB", "403A9_0314_0300_0345" }, + { "1FAC", "403A9_0313_0301_0345" }, + { "1FAD", "403A9_0314_0301_0345" }, + { "1FAE", "403A9_0313_0342_0345" }, + { "1FAF", "403A9_0314_0342_0345" }, + { "1FB0", "203B1_0306" }, + { "1FB1", "203B1_0304" }, + { "1FB2", "303B1_0300_0345" }, + { "1FB3", "203B1_0345" }, + { "1FB4", "303B1_0301_0345" }, + { "1FB6", "203B1_0342" }, + { "1FB7", "303B1_0342_0345" }, + { "1FB8", "20391_0306" }, + { "1FB9", "20391_0304" }, + { "1FBA", "20391_0300" }, + { "1FBB", "20391_0301" }, + { "1FBC", "20391_0345" }, + { "1FBE", "103B9" }, + { "1FC1", "200A8_0342" }, + { "1FC2", "303B7_0300_0345" }, + { "1FC3", "203B7_0345" }, + { "1FC4", "303B7_0301_0345" }, + { "1FC6", "203B7_0342" }, + { "1FC7", "303B7_0342_0345" }, + { "1FC8", "20395_0300" }, + { "1FC9", "20395_0301" }, + { "1FCA", "20397_0300" }, + { "1FCB", "20397_0301" }, + { "1FCC", "20397_0345" }, + { "1FCD", "21FBF_0300" }, + { "1FCE", "21FBF_0301" }, + { "1FCF", "21FBF_0342" }, + { "1FD0", "203B9_0306" }, + { "1FD1", "203B9_0304" }, + { "1FD2", "303B9_0308_0300" }, + { "1FD3", "303B9_0308_0301" }, + { "1FD6", "203B9_0342" }, + { "1FD7", "303B9_0308_0342" }, + { "1FD8", "20399_0306" }, + { "1FD9", "20399_0304" }, + { "1FDA", "20399_0300" }, + { "1FDB", "20399_0301" }, + { "1FDD", "21FFE_0300" }, + { "1FDE", "21FFE_0301" }, + { "1FDF", "21FFE_0342" }, + { "1FE0", "203C5_0306" }, + { "1FE1", "203C5_0304" }, + { "1FE2", "303C5_0308_0300" }, + { "1FE3", "303C5_0308_0301" }, + { "1FE4", "203C1_0313" }, + { "1FE5", "203C1_0314" }, + { "1FE6", "203C5_0342" }, + { "1FE7", "303C5_0308_0342" }, + { "1FE8", "203A5_0306" }, + { "1FE9", "203A5_0304" }, + { "1FEA", "203A5_0300" }, + { "1FEB", "203A5_0301" }, + { "1FEC", "203A1_0314" }, + { "1FED", "200A8_0300" }, + { "1FEE", "200A8_0301" }, + { "1FEF", "10060" }, + { "1FF2", "303C9_0300_0345" }, + { "1FF3", "203C9_0345" }, + { "1FF4", "303C9_0301_0345" }, + { "1FF6", "203C9_0342" }, + { "1FF7", "303C9_0342_0345" }, + { "1FF8", "2039F_0300" }, + { "1FF9", "2039F_0301" }, + { "1FFA", "203A9_0300" }, + { "1FFB", "203A9_0301" }, + { "1FFC", "203A9_0345" }, + { "1FFD", "100B4" }, + { "2000", "12002" }, + { "2001", "12003" }, + { "2126", "103A9" }, + { "212A", "1004B" }, + { "212B", "20041_030A" }, + { "219A", "22190_0338" }, + { "219B", "22192_0338" }, + { "21AE", "22194_0338" }, + { "21CD", "221D0_0338" }, + { "21CE", "221D4_0338" }, + { "21CF", "221D2_0338" }, + { "2204", "22203_0338" }, + { "2209", "22208_0338" }, + { "220C", "2220B_0338" }, + { "2224", "22223_0338" }, + { "2226", "22225_0338" }, + { "2241", "2223C_0338" }, + { "2244", "22243_0338" }, + { "2247", "22245_0338" }, + { "2249", "22248_0338" }, + { "2260", "2003D_0338" }, + { "2262", "22261_0338" }, + { "226D", "2224D_0338" }, + { "226E", "2003C_0338" }, + { "226F", "2003E_0338" }, + { "2270", "22264_0338" }, + { "2271", "22265_0338" }, + { "2274", "22272_0338" }, + { "2275", "22273_0338" }, + { "2278", "22276_0338" }, + { "2279", "22277_0338" }, + { "2280", "2227A_0338" }, + { "2281", "2227B_0338" }, + { "2284", "22282_0338" }, + { "2285", "22283_0338" }, + { "2288", "22286_0338" }, + { "2289", "22287_0338" }, + { "22AC", "222A2_0338" }, + { "22AD", "222A8_0338" }, + { "22AE", "222A9_0338" }, + { "22AF", "222AB_0338" }, + { "22E0", "2227C_0338" }, + { "22E1", "2227D_0338" }, + { "22E2", "22291_0338" }, + { "22E3", "22292_0338" }, + { "22EA", "222B2_0338" }, + { "22EB", "222B3_0338" }, + { "22EC", "222B4_0338" }, + { "22ED", "222B5_0338" }, + { "2329", "13008" }, + { "232A", "13009" }, + { "2ADC", "22ADD_0338" }, + { "304C", "2304B_3099" }, + { "304E", "2304D_3099" }, + { "3050", "2304F_3099" }, + { "3052", "23051_3099" }, + { "3054", "23053_3099" }, + { "3056", "23055_3099" }, + { "3058", "23057_3099" }, + { "305A", "23059_3099" }, + { "305C", "2305B_3099" }, + { "305E", "2305D_3099" }, + { "3060", "2305F_3099" }, + { "3062", "23061_3099" }, + { "3065", "23064_3099" }, + { "3067", "23066_3099" }, + { "3069", "23068_3099" }, + { "3070", "2306F_3099" }, + { "3071", "2306F_309A" }, + { "3073", "23072_3099" }, + { "3074", "23072_309A" }, + { "3076", "23075_3099" }, + { "3077", "23075_309A" }, + { "3079", "23078_3099" }, + { "307A", "23078_309A" }, + { "307C", "2307B_3099" }, + { "307D", "2307B_309A" }, + { "3094", "23046_3099" }, + { "309E", "2309D_3099" }, + { "30AC", "230AB_3099" }, + { "30AE", "230AD_3099" }, + { "30B0", "230AF_3099" }, + { "30B2", "230B1_3099" }, + { "30B4", "230B3_3099" }, + { "30B6", "230B5_3099" }, + { "30B8", "230B7_3099" }, + { "30BA", "230B9_3099" }, + { "30BC", "230BB_3099" }, + { "30BE", "230BD_3099" }, + { "30C0", "230BF_3099" }, + { "30C2", "230C1_3099" }, + { "30C5", "230C4_3099" }, + { "30C7", "230C6_3099" }, + { "30C9", "230C8_3099" }, + { "30D0", "230CF_3099" }, + { "30D1", "230CF_309A" }, + { "30D3", "230D2_3099" }, + { "30D4", "230D2_309A" }, + { "30D6", "230D5_3099" }, + { "30D7", "230D5_309A" }, + { "30D9", "230D8_3099" }, + { "30DA", "230D8_309A" }, + { "30DC", "230DB_3099" }, + { "30DD", "230DB_309A" }, + { "30F4", "230A6_3099" }, + { "30F7", "230EF_3099" }, + { "30F8", "230F0_3099" }, + { "30F9", "230F1_3099" }, + { "30FA", "230F2_3099" }, + { "30FE", "230FD_3099" }, + { "F900", "18C48" }, + { "F901", "166F4" }, + { "F902", "18ECA" }, + { "F903", "18CC8" }, + { "F904", "16ED1" }, + { "F905", "14E32" }, + { "F906", "153E5" }, + { "F907", "19F9C" }, + { "F908", "19F9C" }, + { "F909", "15951" }, + { "F90A", "191D1" }, + { "F90B", "15587" }, + { "F90C", "15948" }, + { "F90D", "161F6" }, + { "F90E", "17669" }, + { "F90F", "17F85" }, + { "F910", "1863F" }, + { "F911", "187BA" }, + { "F912", "188F8" }, + { "F913", "1908F" }, + { "F914", "16A02" }, + { "F915", "16D1B" }, + { "F916", "170D9" }, + { "F917", "173DE" }, + { "F918", "1843D" }, + { "F919", "1916A" }, + { "F91A", "199F1" }, + { "F91B", "14E82" }, + { "F91C", "15375" }, + { "F91D", "16B04" }, + { "F91E", "1721B" }, + { "F91F", "1862D" }, + { "F920", "19E1E" }, + { "F921", "15D50" }, + { "F922", "16FEB" }, + { "F923", "185CD" }, + { "F924", "18964" }, + { "F925", "162C9" }, + { "F926", "181D8" }, + { "F927", "1881F" }, + { "F928", "15ECA" }, + { "F929", "16717" }, + { "F92A", "16D6A" }, + { "F92B", "172FC" }, + { "F92C", "190CE" }, + { "F92D", "14F86" }, + { "F92E", "151B7" }, + { "F92F", "152DE" }, + { "F930", "164C4" }, + { "F931", "16AD3" }, + { "F932", "17210" }, + { "F933", "176E7" }, + { "F934", "18001" }, + { "F935", "18606" }, + { "F936", "1865C" }, + { "F937", "18DEF" }, + { "F938", "19732" }, + { "F939", "19B6F" }, + { "F93A", "19DFA" }, + { "F93B", "1788C" }, + { "F93C", "1797F" }, + { "F93D", "17DA0" }, + { "F93E", "183C9" }, + { "F93F", "19304" }, + { "F940", "19E7F" }, + { "F941", "18AD6" }, + { "F942", "158DF" }, + { "F943", "15F04" }, + { "F944", "17C60" }, + { "F945", "1807E" }, + { "F946", "17262" }, + { "F947", "178CA" }, + { "F948", "18CC2" }, + { "F949", "196F7" }, + { "F94A", "158D8" }, + { "F94B", "15C62" }, + { "F94C", "16A13" }, + { "F94D", "16DDA" }, + { "F94E", "16F0F" }, + { "F94F", "17D2F" }, + { "F950", "17E37" }, + { "F951", "1964B" }, + { "F952", "152D2" }, + { "F953", "1808B" }, + { "F954", "151DC" }, + { "F955", "151CC" }, + { "F956", "17A1C" }, + { "F957", "17DBE" }, + { "F958", "183F1" }, + { "F959", "19675" }, + { "F95A", "18B80" }, + { "F95B", "162CF" }, + { "F95C", "16A02" }, + { "F95D", "18AFE" }, + { "F95E", "14E39" }, + { "F95F", "15BE7" }, + { "F960", "16012" }, + { "F961", "17387" }, + { "F962", "17570" }, + { "F963", "15317" }, + { "F964", "178FB" }, + { "F965", "14FBF" }, + { "F966", "15FA9" }, + { "F967", "14E0D" }, + { "F968", "16CCC" }, + { "F969", "16578" }, + { "F96A", "17D22" }, + { "F96B", "153C3" }, + { "F96C", "1585E" }, + { "F96D", "17701" }, + { "F96E", "18449" }, + { "F96F", "18AAA" }, + { "F970", "16BBA" }, + { "F971", "18FB0" }, + { "F972", "16C88" }, + { "F973", "162FE" }, + { "F974", "182E5" }, + { "F975", "163A0" }, + { "F976", "17565" }, + { "F977", "14EAE" }, + { "F978", "15169" }, + { "F979", "151C9" }, + { "F97A", "16881" }, + { "F97B", "17CE7" }, + { "F97C", "1826F" }, + { "F97D", "18AD2" }, + { "F97E", "191CF" }, + { "F97F", "152F5" }, + { "F980", "15442" }, + { "F981", "15973" }, + { "F982", "15EEC" }, + { "F983", "165C5" }, + { "F984", "16FFE" }, + { "F985", "1792A" }, + { "F986", "195AD" }, + { "F987", "19A6A" }, + { "F988", "19E97" }, + { "F989", "19ECE" }, + { "F98A", "1529B" }, + { "F98B", "166C6" }, + { "F98C", "16B77" }, + { "F98D", "18F62" }, + { "F98E", "15E74" }, + { "F98F", "16190" }, + { "F990", "16200" }, + { "F991", "1649A" }, + { "F992", "16F23" }, + { "F993", "17149" }, + { "F994", "17489" }, + { "F995", "179CA" }, + { "F996", "17DF4" }, + { "F997", "1806F" }, + { "F998", "18F26" }, + { "F999", "184EE" }, + { "F99A", "19023" }, + { "F99B", "1934A" }, + { "F99C", "15217" }, + { "F99D", "152A3" }, + { "F99E", "154BD" }, + { "F99F", "170C8" }, + { "F9A0", "188C2" }, + { "F9A1", "18AAA" }, + { "F9A2", "15EC9" }, + { "F9A3", "15FF5" }, + { "F9A4", "1637B" }, + { "F9A5", "16BAE" }, + { "F9A6", "17C3E" }, + { "F9A7", "17375" }, + { "F9A8", "14EE4" }, + { "F9A9", "156F9" }, + { "F9AA", "15BE7" }, + { "F9AB", "15DBA" }, + { "F9AC", "1601C" }, + { "F9AD", "173B2" }, + { "F9AE", "17469" }, + { "F9AF", "17F9A" }, + { "F9B0", "18046" }, + { "F9B1", "19234" }, + { "F9B2", "196F6" }, + { "F9B3", "19748" }, + { "F9B4", "19818" }, + { "F9B5", "14F8B" }, + { "F9B6", "179AE" }, + { "F9B7", "191B4" }, + { "F9B8", "196B8" }, + { "F9B9", "160E1" }, + { "F9BA", "14E86" }, + { "F9BB", "150DA" }, + { "F9BC", "15BEE" }, + { "F9BD", "15C3F" }, + { "F9BE", "16599" }, + { "F9BF", "16A02" }, + { "F9C0", "171CE" }, + { "F9C1", "17642" }, + { "F9C2", "184FC" }, + { "F9C3", "1907C" }, + { "F9C4", "19F8D" }, + { "F9C5", "16688" }, + { "F9C6", "1962E" }, + { "F9C7", "15289" }, + { "F9C8", "1677B" }, + { "F9C9", "167F3" }, + { "F9CA", "16D41" }, + { "F9CB", "16E9C" }, + { "F9CC", "17409" }, + { "F9CD", "17559" }, + { "F9CE", "1786B" }, + { "F9CF", "17D10" }, + { "F9D0", "1985E" }, + { "F9D1", "1516D" }, + { "F9D2", "1622E" }, + { "F9D3", "19678" }, + { "F9D4", "1502B" }, + { "F9D5", "15D19" }, + { "F9D6", "16DEA" }, + { "F9D7", "18F2A" }, + { "F9D8", "15F8B" }, + { "F9D9", "16144" }, + { "F9DA", "16817" }, + { "F9DB", "17387" }, + { "F9DC", "19686" }, + { "F9DD", "15229" }, + { "F9DE", "1540F" }, + { "F9DF", "15C65" }, + { "F9E0", "16613" }, + { "F9E1", "1674E" }, + { "F9E2", "168A8" }, + { "F9E3", "16CE5" }, + { "F9E4", "17406" }, + { "F9E5", "175E2" }, + { "F9E6", "17F79" }, + { "F9E7", "188CF" }, + { "F9E8", "188E1" }, + { "F9E9", "191CC" }, + { "F9EA", "196E2" }, + { "F9EB", "1533F" }, + { "F9EC", "16EBA" }, + { "F9ED", "1541D" }, + { "F9EE", "171D0" }, + { "F9EF", "17498" }, + { "F9F0", "185FA" }, + { "F9F1", "196A3" }, + { "F9F2", "19C57" }, + { "F9F3", "19E9F" }, + { "F9F4", "16797" }, + { "F9F5", "16DCB" }, + { "F9F6", "181E8" }, + { "F9F7", "17ACB" }, + { "F9F8", "17B20" }, + { "F9F9", "17C92" }, + { "F9FA", "172C0" }, + { "F9FB", "17099" }, + { "F9FC", "18B58" }, + { "F9FD", "14EC0" }, + { "F9FE", "18336" }, + { "F9FF", "1523A" }, + { "FA00", "15207" }, + { "FA01", "15EA6" }, + { "FA02", "162D3" }, + { "FA03", "17CD6" }, + { "FA04", "15B85" }, + { "FA05", "16D1E" }, + { "FA06", "166B4" }, + { "FA07", "18F3B" }, + { "FA08", "1884C" }, + { "FA09", "1964D" }, + { "FA0A", "1898B" }, + { "FA0B", "15ED3" }, + { "FA0C", "15140" }, + { "FA0D", "155C0" }, + { "FA10", "1585A" }, + { "FA12", "16674" }, + { "FA15", "151DE" }, + { "FA16", "1732A" }, + { "FA17", "176CA" }, + { "FA18", "1793C" }, + { "FA19", "1795E" }, + { "FA1A", "17965" }, + { "FA1B", "1798F" }, + { "FA1C", "19756" }, + { "FA1D", "17CBE" }, + { "FA1E", "17FBD" }, + { "FA20", "18612" }, + { "FA22", "18AF8" }, + { "FA25", "19038" }, + { "FA26", "190FD" }, + { "FA2A", "198EF" }, + { "FA2B", "198FC" }, + { "FA2C", "19928" }, + { "FA2D", "19DB4" }, + { "FA2E", "190DE" }, + { "FA2F", "196B7" }, + { "FA30", "14FAE" }, + { "FA31", "150E7" }, + { "FA32", "1514D" }, + { "FA33", "152C9" }, + { "FA34", "152E4" }, + { "FA35", "15351" }, + { "FA36", "1559D" }, + { "FA37", "15606" }, + { "FA38", "15668" }, + { "FA39", "15840" }, + { "FA3A", "158A8" }, + { "FA3B", "15C64" }, + { "FA3C", "15C6E" }, + { "FA3D", "16094" }, + { "FA3E", "16168" }, + { "FA3F", "1618E" }, + { "FA40", "161F2" }, + { "FA41", "1654F" }, + { "FA42", "165E2" }, + { "FA43", "16691" }, + { "FA44", "16885" }, + { "FA45", "16D77" }, + { "FA46", "16E1A" }, + { "FA47", "16F22" }, + { "FA48", "1716E" }, + { "FA49", "1722B" }, + { "FA4A", "17422" }, + { "FA4B", "17891" }, + { "FA4C", "1793E" }, + { "FA4D", "17949" }, + { "FA4E", "17948" }, + { "FA4F", "17950" }, + { "FA50", "17956" }, + { "FA51", "1795D" }, + { "FA52", "1798D" }, + { "FA53", "1798E" }, + { "FA54", "17A40" }, + { "FA55", "17A81" }, + { "FA56", "17BC0" }, + { "FA57", "17DF4" }, + { "FA58", "17E09" }, + { "FA59", "17E41" }, + { "FA5A", "17F72" }, + { "FA5B", "18005" }, + { "FA5C", "181ED" }, + { "FA5D", "18279" }, + { "FA5E", "18279" }, + { "FA5F", "18457" }, + { "FA60", "18910" }, + { "FA61", "18996" }, + { "FA62", "18B01" }, + { "FA63", "18B39" }, + { "FA64", "18CD3" }, + { "FA65", "18D08" }, + { "FA66", "18FB6" }, + { "FA67", "19038" }, + { "FA68", "196E3" }, + { "FA69", "197FF" }, + { "FA6A", "1983B" }, + { "FA6B", "16075" }, + { "FA6C", "1242EE" }, + { "FA6D", "18218" }, + { "FA70", "14E26" }, + { "FA71", "151B5" }, + { "FA72", "15168" }, + { "FA73", "14F80" }, + { "FA74", "15145" }, + { "FA75", "15180" }, + { "FA76", "152C7" }, + { "FA77", "152FA" }, + { "FA78", "1559D" }, + { "FA79", "15555" }, + { "FA7A", "15599" }, + { "FA7B", "155E2" }, + { "FA7C", "1585A" }, + { "FA7D", "158B3" }, + { "FA7E", "15944" }, + { "FA7F", "15954" }, + { "FA80", "15A62" }, + { "FA81", "15B28" }, + { "FA82", "15ED2" }, + { "FA83", "15ED9" }, + { "FA84", "15F69" }, + { "FA85", "15FAD" }, + { "FA86", "160D8" }, + { "FA87", "1614E" }, + { "FA88", "16108" }, + { "FA89", "1618E" }, + { "FA8A", "16160" }, + { "FA8B", "161F2" }, + { "FA8C", "16234" }, + { "FA8D", "163C4" }, + { "FA8E", "1641C" }, + { "FA8F", "16452" }, + { "FA90", "16556" }, + { "FA91", "16674" }, + { "FA92", "16717" }, + { "FA93", "1671B" }, + { "FA94", "16756" }, + { "FA95", "16B79" }, + { "FA96", "16BBA" }, + { "FA97", "16D41" }, + { "FA98", "16EDB" }, + { "FA99", "16ECB" }, + { "FA9A", "16F22" }, + { "FA9B", "1701E" }, + { "FA9C", "1716E" }, + { "FA9D", "177A7" }, + { "FA9E", "17235" }, + { "FA9F", "172AF" }, + { "FAA0", "1732A" }, + { "FAA1", "17471" }, + { "FAA2", "17506" }, + { "FAA3", "1753B" }, + { "FAA4", "1761D" }, + { "FAA5", "1761F" }, + { "FAA6", "176CA" }, + { "FAA7", "176DB" }, + { "FAA8", "176F4" }, + { "FAA9", "1774A" }, + { "FAAA", "17740" }, + { "FAAB", "178CC" }, + { "FAAC", "17AB1" }, + { "FAAD", "17BC0" }, + { "FAAE", "17C7B" }, + { "FAAF", "17D5B" }, + { "FAB0", "17DF4" }, + { "FAB1", "17F3E" }, + { "FAB2", "18005" }, + { "FAB3", "18352" }, + { "FAB4", "183EF" }, + { "FAB5", "18779" }, + { "FAB6", "18941" }, + { "FAB7", "18986" }, + { "FAB8", "18996" }, + { "FAB9", "18ABF" }, + { "FABA", "18AF8" }, + { "FABB", "18ACB" }, + { "FABC", "18B01" }, + { "FABD", "18AFE" }, + { "FABE", "18AED" }, + { "FABF", "18B39" }, + { "FAC0", "18B8A" }, + { "FAC1", "18D08" }, + { "FAC2", "18F38" }, + { "FAC3", "19072" }, + { "FAC4", "19199" }, + { "FAC5", "19276" }, + { "FAC6", "1967C" }, + { "FAC7", "196E3" }, + { "FAC8", "19756" }, + { "FAC9", "197DB" }, + { "FACA", "197FF" }, + { "FACB", "1980B" }, + { "FACC", "1983B" }, + { "FACD", "19B12" }, + { "FACE", "19F9C" }, + { "FACF", "12284A" }, + { "FAD0", "122844" }, + { "FAD1", "1233D5" }, + { "FAD2", "13B9D" }, + { "FAD3", "14018" }, + { "FAD4", "14039" }, + { "FAD5", "125249" }, + { "FAD6", "125CD0" }, + { "FAD7", "127ED3" }, + { "FAD8", "19F43" }, + { "FAD9", "19F8E" }, + { "FB1D", "205D9_05B4" }, + { "FB1F", "205F2_05B7" }, + { "FB2A", "205E9_05C1" }, + { "FB2B", "205E9_05C2" }, + { "FB2C", "305E9_05BC_05C1" }, + { "FB2D", "305E9_05BC_05C2" }, + { "FB2E", "205D0_05B7" }, + { "FB2F", "205D0_05B8" }, + { "FB30", "205D0_05BC" }, + { "FB31", "205D1_05BC" }, + { "FB32", "205D2_05BC" }, + { "FB33", "205D3_05BC" }, + { "FB34", "205D4_05BC" }, + { "FB35", "205D5_05BC" }, + { "FB36", "205D6_05BC" }, + { "FB38", "205D8_05BC" }, + { "FB39", "205D9_05BC" }, + { "FB3A", "205DA_05BC" }, + { "FB3B", "205DB_05BC" }, + { "FB3C", "205DC_05BC" }, + { "FB3E", "205DE_05BC" }, + { "FB40", "205E0_05BC" }, + { "FB41", "205E1_05BC" }, + { "FB43", "205E3_05BC" }, + { "FB44", "205E4_05BC" }, + { "FB46", "205E6_05BC" }, + { "FB47", "205E7_05BC" }, + { "FB48", "205E8_05BC" }, + { "FB49", "205E9_05BC" }, + { "FB4A", "205EA_05BC" }, + { "FB4B", "205D5_05B9" }, + { "FB4C", "205D1_05BF" }, + { "FB4D", "205DB_05BF" }, + { "FB4E", "205E4_05BF" }, + { "1109A", "211099_110BA" }, + { "1109C", "21109B_110BA" }, + { "110AB", "2110A5_110BA" }, + { "1112E", "211131_11127" }, + { "1112F", "211132_11127" }, + { "1134B", "211347_1133E" }, + { "1134C", "211347_11357" }, + { "114BB", "2114B9_114BA" }, + { "114BC", "2114B9_114B0" }, + { "114BE", "2114B9_114BD" }, + { "115BA", "2115B8_115AF" }, + { "115BB", "2115B9_115AF" }, + { "1D15E", "21D157_1D165" }, + { "1D15F", "21D158_1D165" }, + { "1D160", "31D158_1D165_1D16E" }, + { "1D161", "31D158_1D165_1D16F" }, + { "1D162", "31D158_1D165_1D170" }, + { "1D163", "31D158_1D165_1D171" }, + { "1D164", "31D158_1D165_1D172" }, + { "1D1BB", "21D1B9_1D165" }, + { "1D1BC", "21D1BA_1D165" }, + { "1D1BD", "31D1B9_1D165_1D16E" }, + { "1D1BE", "31D1BA_1D165_1D16E" }, + { "1D1BF", "31D1B9_1D165_1D16F" }, + { "1D1C0", "31D1BA_1D165_1D16F" }, + { "2F800", "14E3D" }, + { "2F801", "14E38" }, + { "2F802", "14E41" }, + { "2F803", "120122" }, + { "2F804", "14F60" }, + { "2F805", "14FAE" }, + { "2F806", "14FBB" }, + { "2F807", "15002" }, + { "2F808", "1507A" }, + { "2F809", "15099" }, + { "2F80A", "150E7" }, + { "2F80B", "150CF" }, + { "2F80C", "1349E" }, + { "2F80D", "12063A" }, + { "2F80E", "1514D" }, + { "2F80F", "15154" }, + { "2F810", "15164" }, + { "2F811", "15177" }, + { "2F812", "12051C" }, + { "2F813", "134B9" }, + { "2F814", "15167" }, + { "2F815", "1518D" }, + { "2F816", "12054B" }, + { "2F817", "15197" }, + { "2F818", "151A4" }, + { "2F819", "14ECC" }, + { "2F81A", "151AC" }, + { "2F81B", "151B5" }, + { "2F81C", "1291DF" }, + { "2F81D", "151F5" }, + { "2F81E", "15203" }, + { "2F81F", "134DF" }, + { "2F820", "1523B" }, + { "2F821", "15246" }, + { "2F822", "15272" }, + { "2F823", "15277" }, + { "2F824", "13515" }, + { "2F825", "152C7" }, + { "2F826", "152C9" }, + { "2F827", "152E4" }, + { "2F828", "152FA" }, + { "2F829", "15305" }, + { "2F82A", "15306" }, + { "2F82B", "15317" }, + { "2F82C", "15349" }, + { "2F82D", "15351" }, + { "2F82E", "1535A" }, + { "2F82F", "15373" }, + { "2F830", "1537D" }, + { "2F831", "1537F" }, + { "2F832", "1537F" }, + { "2F833", "1537F" }, + { "2F834", "120A2C" }, + { "2F835", "17070" }, + { "2F836", "153CA" }, + { "2F837", "153DF" }, + { "2F838", "120B63" }, + { "2F839", "153EB" }, + { "2F83A", "153F1" }, + { "2F83B", "15406" }, + { "2F83C", "1549E" }, + { "2F83D", "15438" }, + { "2F83E", "15448" }, + { "2F83F", "15468" }, + { "2F840", "154A2" }, + { "2F841", "154F6" }, + { "2F842", "15510" }, + { "2F843", "15553" }, + { "2F844", "15563" }, + { "2F845", "15584" }, + { "2F846", "15584" }, + { "2F847", "15599" }, + { "2F848", "155AB" }, + { "2F849", "155B3" }, + { "2F84A", "155C2" }, + { "2F84B", "15716" }, + { "2F84C", "15606" }, + { "2F84D", "15717" }, + { "2F84E", "15651" }, + { "2F84F", "15674" }, + { "2F850", "15207" }, + { "2F851", "158EE" }, + { "2F852", "157CE" }, + { "2F853", "157F4" }, + { "2F854", "1580D" }, + { "2F855", "1578B" }, + { "2F856", "15832" }, + { "2F857", "15831" }, + { "2F858", "158AC" }, + { "2F859", "1214E4" }, + { "2F85A", "158F2" }, + { "2F85B", "158F7" }, + { "2F85C", "15906" }, + { "2F85D", "1591A" }, + { "2F85E", "15922" }, + { "2F85F", "15962" }, + { "2F860", "1216A8" }, + { "2F861", "1216EA" }, + { "2F862", "159EC" }, + { "2F863", "15A1B" }, + { "2F864", "15A27" }, + { "2F865", "159D8" }, + { "2F866", "15A66" }, + { "2F867", "136EE" }, + { "2F868", "136FC" }, + { "2F869", "15B08" }, + { "2F86A", "15B3E" }, + { "2F86B", "15B3E" }, + { "2F86C", "1219C8" }, + { "2F86D", "15BC3" }, + { "2F86E", "15BD8" }, + { "2F86F", "15BE7" }, + { "2F870", "15BF3" }, + { "2F871", "121B18" }, + { "2F872", "15BFF" }, + { "2F873", "15C06" }, + { "2F874", "15F53" }, + { "2F875", "15C22" }, + { "2F876", "13781" }, + { "2F877", "15C60" }, + { "2F878", "15C6E" }, + { "2F879", "15CC0" }, + { "2F87A", "15C8D" }, + { "2F87B", "121DE4" }, + { "2F87C", "15D43" }, + { "2F87D", "121DE6" }, + { "2F87E", "15D6E" }, + { "2F87F", "15D6B" }, + { "2F880", "15D7C" }, + { "2F881", "15DE1" }, + { "2F882", "15DE2" }, + { "2F883", "1382F" }, + { "2F884", "15DFD" }, + { "2F885", "15E28" }, + { "2F886", "15E3D" }, + { "2F887", "15E69" }, + { "2F888", "13862" }, + { "2F889", "122183" }, + { "2F88A", "1387C" }, + { "2F88B", "15EB0" }, + { "2F88C", "15EB3" }, + { "2F88D", "15EB6" }, + { "2F88E", "15ECA" }, + { "2F88F", "12A392" }, + { "2F890", "15EFE" }, + { "2F891", "122331" }, + { "2F892", "122331" }, + { "2F893", "18201" }, + { "2F894", "15F22" }, + { "2F895", "15F22" }, + { "2F896", "138C7" }, + { "2F897", "1232B8" }, + { "2F898", "1261DA" }, + { "2F899", "15F62" }, + { "2F89A", "15F6B" }, + { "2F89B", "138E3" }, + { "2F89C", "15F9A" }, + { "2F89D", "15FCD" }, + { "2F89E", "15FD7" }, + { "2F89F", "15FF9" }, + { "2F8A0", "16081" }, + { "2F8A1", "1393A" }, + { "2F8A2", "1391C" }, + { "2F8A3", "16094" }, + { "2F8A4", "1226D4" }, + { "2F8A5", "160C7" }, + { "2F8A6", "16148" }, + { "2F8A7", "1614C" }, + { "2F8A8", "1614E" }, + { "2F8A9", "1614C" }, + { "2F8AA", "1617A" }, + { "2F8AB", "1618E" }, + { "2F8AC", "161B2" }, + { "2F8AD", "161A4" }, + { "2F8AE", "161AF" }, + { "2F8AF", "161DE" }, + { "2F8B0", "161F2" }, + { "2F8B1", "161F6" }, + { "2F8B2", "16210" }, + { "2F8B3", "1621B" }, + { "2F8B4", "1625D" }, + { "2F8B5", "162B1" }, + { "2F8B6", "162D4" }, + { "2F8B7", "16350" }, + { "2F8B8", "122B0C" }, + { "2F8B9", "1633D" }, + { "2F8BA", "162FC" }, + { "2F8BB", "16368" }, + { "2F8BC", "16383" }, + { "2F8BD", "163E4" }, + { "2F8BE", "122BF1" }, + { "2F8BF", "16422" }, + { "2F8C0", "163C5" }, + { "2F8C1", "163A9" }, + { "2F8C2", "13A2E" }, + { "2F8C3", "16469" }, + { "2F8C4", "1647E" }, + { "2F8C5", "1649D" }, + { "2F8C6", "16477" }, + { "2F8C7", "13A6C" }, + { "2F8C8", "1654F" }, + { "2F8C9", "1656C" }, + { "2F8CA", "12300A" }, + { "2F8CB", "165E3" }, + { "2F8CC", "166F8" }, + { "2F8CD", "16649" }, + { "2F8CE", "13B19" }, + { "2F8CF", "16691" }, + { "2F8D0", "13B08" }, + { "2F8D1", "13AE4" }, + { "2F8D2", "15192" }, + { "2F8D3", "15195" }, + { "2F8D4", "16700" }, + { "2F8D5", "1669C" }, + { "2F8D6", "180AD" }, + { "2F8D7", "143D9" }, + { "2F8D8", "16717" }, + { "2F8D9", "1671B" }, + { "2F8DA", "16721" }, + { "2F8DB", "1675E" }, + { "2F8DC", "16753" }, + { "2F8DD", "1233C3" }, + { "2F8DE", "13B49" }, + { "2F8DF", "167FA" }, + { "2F8E0", "16785" }, + { "2F8E1", "16852" }, + { "2F8E2", "16885" }, + { "2F8E3", "12346D" }, + { "2F8E4", "1688E" }, + { "2F8E5", "1681F" }, + { "2F8E6", "16914" }, + { "2F8E7", "13B9D" }, + { "2F8E8", "16942" }, + { "2F8E9", "169A3" }, + { "2F8EA", "169EA" }, + { "2F8EB", "16AA8" }, + { "2F8EC", "1236A3" }, + { "2F8ED", "16ADB" }, + { "2F8EE", "13C18" }, + { "2F8EF", "16B21" }, + { "2F8F0", "1238A7" }, + { "2F8F1", "16B54" }, + { "2F8F2", "13C4E" }, + { "2F8F3", "16B72" }, + { "2F8F4", "16B9F" }, + { "2F8F5", "16BBA" }, + { "2F8F6", "16BBB" }, + { "2F8F7", "123A8D" }, + { "2F8F8", "121D0B" }, + { "2F8F9", "123AFA" }, + { "2F8FA", "16C4E" }, + { "2F8FB", "123CBC" }, + { "2F8FC", "16CBF" }, + { "2F8FD", "16CCD" }, + { "2F8FE", "16C67" }, + { "2F8FF", "16D16" }, + { "2F900", "16D3E" }, + { "2F901", "16D77" }, + { "2F902", "16D41" }, + { "2F903", "16D69" }, + { "2F904", "16D78" }, + { "2F905", "16D85" }, + { "2F906", "123D1E" }, + { "2F907", "16D34" }, + { "2F908", "16E2F" }, + { "2F909", "16E6E" }, + { "2F90A", "13D33" }, + { "2F90B", "16ECB" }, + { "2F90C", "16EC7" }, + { "2F90D", "123ED1" }, + { "2F90E", "16DF9" }, + { "2F90F", "16F6E" }, + { "2F910", "123F5E" }, + { "2F911", "123F8E" }, + { "2F912", "16FC6" }, + { "2F913", "17039" }, + { "2F914", "1701E" }, + { "2F915", "1701B" }, + { "2F916", "13D96" }, + { "2F917", "1704A" }, + { "2F918", "1707D" }, + { "2F919", "17077" }, + { "2F91A", "170AD" }, + { "2F91B", "120525" }, + { "2F91C", "17145" }, + { "2F91D", "124263" }, + { "2F91E", "1719C" }, + { "2F91F", "1243AB" }, + { "2F920", "17228" }, + { "2F921", "17235" }, + { "2F922", "17250" }, + { "2F923", "124608" }, + { "2F924", "17280" }, + { "2F925", "17295" }, + { "2F926", "124735" }, + { "2F927", "124814" }, + { "2F928", "1737A" }, + { "2F929", "1738B" }, + { "2F92A", "13EAC" }, + { "2F92B", "173A5" }, + { "2F92C", "13EB8" }, + { "2F92D", "13EB8" }, + { "2F92E", "17447" }, + { "2F92F", "1745C" }, + { "2F930", "17471" }, + { "2F931", "17485" }, + { "2F932", "174CA" }, + { "2F933", "13F1B" }, + { "2F934", "17524" }, + { "2F935", "124C36" }, + { "2F936", "1753E" }, + { "2F937", "124C92" }, + { "2F938", "17570" }, + { "2F939", "12219F" }, + { "2F93A", "17610" }, + { "2F93B", "124FA1" }, + { "2F93C", "124FB8" }, + { "2F93D", "125044" }, + { "2F93E", "13FFC" }, + { "2F93F", "14008" }, + { "2F940", "176F4" }, + { "2F941", "1250F3" }, + { "2F942", "1250F2" }, + { "2F943", "125119" }, + { "2F944", "125133" }, + { "2F945", "1771E" }, + { "2F946", "1771F" }, + { "2F947", "1771F" }, + { "2F948", "1774A" }, + { "2F949", "14039" }, + { "2F94A", "1778B" }, + { "2F94B", "14046" }, + { "2F94C", "14096" }, + { "2F94D", "12541D" }, + { "2F94E", "1784E" }, + { "2F94F", "1788C" }, + { "2F950", "178CC" }, + { "2F951", "140E3" }, + { "2F952", "125626" }, + { "2F953", "17956" }, + { "2F954", "12569A" }, + { "2F955", "1256C5" }, + { "2F956", "1798F" }, + { "2F957", "179EB" }, + { "2F958", "1412F" }, + { "2F959", "17A40" }, + { "2F95A", "17A4A" }, + { "2F95B", "17A4F" }, + { "2F95C", "12597C" }, + { "2F95D", "125AA7" }, + { "2F95E", "125AA7" }, + { "2F95F", "17AEE" }, + { "2F960", "14202" }, + { "2F961", "125BAB" }, + { "2F962", "17BC6" }, + { "2F963", "17BC9" }, + { "2F964", "14227" }, + { "2F965", "125C80" }, + { "2F966", "17CD2" }, + { "2F967", "142A0" }, + { "2F968", "17CE8" }, + { "2F969", "17CE3" }, + { "2F96A", "17D00" }, + { "2F96B", "125F86" }, + { "2F96C", "17D63" }, + { "2F96D", "14301" }, + { "2F96E", "17DC7" }, + { "2F96F", "17E02" }, + { "2F970", "17E45" }, + { "2F971", "14334" }, + { "2F972", "126228" }, + { "2F973", "126247" }, + { "2F974", "14359" }, + { "2F975", "1262D9" }, + { "2F976", "17F7A" }, + { "2F977", "12633E" }, + { "2F978", "17F95" }, + { "2F979", "17FFA" }, + { "2F97A", "18005" }, + { "2F97B", "1264DA" }, + { "2F97C", "126523" }, + { "2F97D", "18060" }, + { "2F97E", "1265A8" }, + { "2F97F", "18070" }, + { "2F980", "12335F" }, + { "2F981", "143D5" }, + { "2F982", "180B2" }, + { "2F983", "18103" }, + { "2F984", "1440B" }, + { "2F985", "1813E" }, + { "2F986", "15AB5" }, + { "2F987", "1267A7" }, + { "2F988", "1267B5" }, + { "2F989", "123393" }, + { "2F98A", "12339C" }, + { "2F98B", "18201" }, + { "2F98C", "18204" }, + { "2F98D", "18F9E" }, + { "2F98E", "1446B" }, + { "2F98F", "18291" }, + { "2F990", "1828B" }, + { "2F991", "1829D" }, + { "2F992", "152B3" }, + { "2F993", "182B1" }, + { "2F994", "182B3" }, + { "2F995", "182BD" }, + { "2F996", "182E6" }, + { "2F997", "126B3C" }, + { "2F998", "182E5" }, + { "2F999", "1831D" }, + { "2F99A", "18363" }, + { "2F99B", "183AD" }, + { "2F99C", "18323" }, + { "2F99D", "183BD" }, + { "2F99E", "183E7" }, + { "2F99F", "18457" }, + { "2F9A0", "18353" }, + { "2F9A1", "183CA" }, + { "2F9A2", "183CC" }, + { "2F9A3", "183DC" }, + { "2F9A4", "126C36" }, + { "2F9A5", "126D6B" }, + { "2F9A6", "126CD5" }, + { "2F9A7", "1452B" }, + { "2F9A8", "184F1" }, + { "2F9A9", "184F3" }, + { "2F9AA", "18516" }, + { "2F9AB", "1273CA" }, + { "2F9AC", "18564" }, + { "2F9AD", "126F2C" }, + { "2F9AE", "1455D" }, + { "2F9AF", "14561" }, + { "2F9B0", "126FB1" }, + { "2F9B1", "1270D2" }, + { "2F9B2", "1456B" }, + { "2F9B3", "18650" }, + { "2F9B4", "1865C" }, + { "2F9B5", "18667" }, + { "2F9B6", "18669" }, + { "2F9B7", "186A9" }, + { "2F9B8", "18688" }, + { "2F9B9", "1870E" }, + { "2F9BA", "186E2" }, + { "2F9BB", "18779" }, + { "2F9BC", "18728" }, + { "2F9BD", "1876B" }, + { "2F9BE", "18786" }, + { "2F9BF", "145D7" }, + { "2F9C0", "187E1" }, + { "2F9C1", "18801" }, + { "2F9C2", "145F9" }, + { "2F9C3", "18860" }, + { "2F9C4", "18863" }, + { "2F9C5", "127667" }, + { "2F9C6", "188D7" }, + { "2F9C7", "188DE" }, + { "2F9C8", "14635" }, + { "2F9C9", "188FA" }, + { "2F9CA", "134BB" }, + { "2F9CB", "1278AE" }, + { "2F9CC", "127966" }, + { "2F9CD", "146BE" }, + { "2F9CE", "146C7" }, + { "2F9CF", "18AA0" }, + { "2F9D0", "18AED" }, + { "2F9D1", "18B8A" }, + { "2F9D2", "18C55" }, + { "2F9D3", "127CA8" }, + { "2F9D4", "18CAB" }, + { "2F9D5", "18CC1" }, + { "2F9D6", "18D1B" }, + { "2F9D7", "18D77" }, + { "2F9D8", "127F2F" }, + { "2F9D9", "120804" }, + { "2F9DA", "18DCB" }, + { "2F9DB", "18DBC" }, + { "2F9DC", "18DF0" }, + { "2F9DD", "1208DE" }, + { "2F9DE", "18ED4" }, + { "2F9DF", "18F38" }, + { "2F9E0", "1285D2" }, + { "2F9E1", "1285ED" }, + { "2F9E2", "19094" }, + { "2F9E3", "190F1" }, + { "2F9E4", "19111" }, + { "2F9E5", "12872E" }, + { "2F9E6", "1911B" }, + { "2F9E7", "19238" }, + { "2F9E8", "192D7" }, + { "2F9E9", "192D8" }, + { "2F9EA", "1927C" }, + { "2F9EB", "193F9" }, + { "2F9EC", "19415" }, + { "2F9ED", "128BFA" }, + { "2F9EE", "1958B" }, + { "2F9EF", "14995" }, + { "2F9F0", "195B7" }, + { "2F9F1", "128D77" }, + { "2F9F2", "149E6" }, + { "2F9F3", "196C3" }, + { "2F9F4", "15DB2" }, + { "2F9F5", "19723" }, + { "2F9F6", "129145" }, + { "2F9F7", "12921A" }, + { "2F9F8", "14A6E" }, + { "2F9F9", "14A76" }, + { "2F9FA", "197E0" }, + { "2F9FB", "12940A" }, + { "2F9FC", "14AB2" }, + { "2F9FD", "129496" }, + { "2F9FE", "1980B" }, + { "2F9FF", "1980B" }, + { "2FA00", "19829" }, + { "2FA01", "1295B6" }, + { "2FA02", "198E2" }, + { "2FA03", "14B33" }, + { "2FA04", "19929" }, + { "2FA05", "199A7" }, + { "2FA06", "199C2" }, + { "2FA07", "199FE" }, + { "2FA08", "14BCE" }, + { "2FA09", "129B30" }, + { "2FA0A", "19B12" }, + { "2FA0B", "19C40" }, + { "2FA0C", "19CFD" }, + { "2FA0D", "14CCE" }, + { "2FA0E", "14CED" }, + { "2FA0F", "19D67" }, + { "2FA10", "12A0CE" }, + { "2FA11", "14CF8" }, + { "2FA12", "12A105" }, + { "2FA13", "12A20E" }, + { "2FA14", "12A291" }, + { "2FA15", "19EBB" }, + { "2FA16", "14D56" }, + { "2FA17", "19EF9" }, + { "2FA18", "19EFE" }, + { "2FA19", "19F05" }, + { "2FA1A", "19F0F" }, + { "2FA1B", "19F16" }, + { "2FA1C", "19F3B" }, + { "2FA1D", "12A600" }, +}; + +// global constructor + +static struct unicode_decompose_init { + unicode_decompose_init(); +} _unicode_decompose_init; + +unicode_decompose_init::unicode_decompose_init() +{ + for (unsigned int i = 0; + i < sizeof(unicode_decompose_list)/sizeof(unicode_decompose_list[0]); + i++) { + unicode_decompose *dec = new unicode_decompose[1]; + dec->value = (char *)unicode_decompose_list[i].value; + unicode_decompose_table.define(unicode_decompose_list[i].key, dec); + } +} + +const char *decompose_unicode(const char *s) +{ + unicode_decompose *result = unicode_decompose_table.lookup(s); + return result ? result->value : 0; +} diff --git a/src/libs/libxutil/DviChar.c b/src/libs/libxutil/DviChar.c new file mode 100644 index 0000000..fe086fc --- /dev/null +++ b/src/libs/libxutil/DviChar.c @@ -0,0 +1,679 @@ +/* Copyright (C) 2014-2020 Free Software Foundation, Inc. + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 2 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +The GNU General Public License version 2 (GPL2) is available in the +internet at <http://www.gnu.org/licenses/gpl-2.0.txt>. */ + +/* + * DviChar.c + * + * Map DVI (ditroff output) character names to + * font indexes and back + */ + +#include <config.h> + +#include <stdlib.h> +#include <string.h> +#include "DviChar.h" + +extern char *xmalloc(int); + +#define allocHash() ((DviCharNameHash *) xmalloc (sizeof (DviCharNameHash))) + +struct map_list { + struct map_list *next; + DviCharNameMap *map; +}; + +static struct map_list *world; + +static int standard_maps_loaded = 0; +static void load_standard_maps (void); +static int hash_name (const char *); +static void dispose_hash(DviCharNameMap *); +static void compute_hash(DviCharNameMap *); + +DviCharNameMap * +DviFindMap (char *encoding) +{ + struct map_list *m; + + if (!standard_maps_loaded) + load_standard_maps (); + for (m = world; m; m=m->next) + if (!strcmp (m->map->encoding, encoding)) + return m->map; + return 0; +} + +void +DviRegisterMap (DviCharNameMap *map) +{ + struct map_list *m; + + if (!standard_maps_loaded) + load_standard_maps (); + for (m = world; m; m = m->next) + if (!strcmp (m->map->encoding, map->encoding)) + break; + if (!m) { + m = (struct map_list *) xmalloc (sizeof *m); + m->next = world; + world = m; + } + dispose_hash (map); + m->map = map; + compute_hash (map); +} + +static void +dispose_hash (DviCharNameMap *map) +{ + DviCharNameHash **buckets; + DviCharNameHash *h, *next; + int i; + + buckets = map->buckets; + for (i = 0; i < DVI_HASH_SIZE; i++) { + for (h = buckets[i]; h; h=next) { + next = h->next; + free (h); + } + } +} + +static int +hash_name (const char *name) +{ + int i = 0; + + while (*name) + i = (i << 1) ^ *name++; + if (i < 0) + i = -i; + return i; +} + +static void +compute_hash (DviCharNameMap *map) +{ + DviCharNameHash **buckets; + int c, s, i; + DviCharNameHash *h; + + buckets = map->buckets; + for (i = 0; i < DVI_HASH_SIZE; i++) + buckets[i] = 0; + for (c = 0; c < DVI_MAP_SIZE; c++) + for (s = 0; s < DVI_MAX_SYNONYMS; s++) { + if (!map->dvi_names[c][s]) + break; + i = hash_name (map->dvi_names[c][s]) % DVI_HASH_SIZE; + h = allocHash (); + h->next = buckets[i]; + buckets[i] = h; + h->name = map->dvi_names[c][s]; + h->position = c; + } + +} + +int +DviCharIndex (DviCharNameMap *map, const char *name) +{ + int i; + DviCharNameHash *h; + + i = hash_name (name) % DVI_HASH_SIZE; + for (h = map->buckets[i]; h; h=h->next) + if (!strcmp (h->name, name)) + return h->position; + return -1; +} + +static DviCharNameMap ISO8859_1_map = { + "iso8859-1", + 0, +{ +{ 0, /* 0 */}, +{ 0, /* 1 */}, +{ 0, /* 2 */}, +{ 0, /* 3 */}, +{ 0, /* 4 */}, +{ 0, /* 5 */}, +{ 0, /* 6 */}, +{ 0, /* 7 */}, +{ 0, /* 8 */}, +{ 0, /* 9 */}, +{ 0, /* 10 */}, +{ 0, /* 11 */}, +{ 0, /* 12 */}, +{ 0, /* 13 */}, +{ 0, /* 14 */}, +{ 0, /* 15 */}, +{ 0, /* 16 */}, +{ 0, /* 17 */}, +{ 0, /* 18 */}, +{ 0, /* 19 */}, +{ 0, /* 20 */}, +{ 0, /* 21 */}, +{ 0, /* 22 */}, +{ 0, /* 23 */}, +{ 0, /* 24 */}, +{ 0, /* 25 */}, +{ 0, /* 26 */}, +{ 0, /* 27 */}, +{ 0, /* 28 */}, +{ 0, /* 29 */}, +{ 0, /* 30 */}, +{ 0, /* 31 */}, +{ 0, /* 32 */}, +{ "!", /* 33 */}, +{ "\"", "dq", /* 34 */}, +{ "#", "sh", /* 35 */}, +{ "$", "Do", /* 36 */}, +{ "%", /* 37 */}, +{ "&", /* 38 */}, +{ "'", "aq", "cq", "oq", /* 39 */}, +{ "(", /* 40 */}, +{ ")", /* 41 */}, +{ "*", /* 42 */}, +{ "+", /* 43 */}, +{ ",", /* 44 */}, +{ "\\-", /* 45 */}, +{ ".", /* 46 */}, +{ "/", "sl", /* 47 */}, +{ "0", /* 48 */}, +{ "1", /* 49 */}, +{ "2", /* 50 */}, +{ "3", /* 51 */}, +{ "4", /* 52 */}, +{ "5", /* 53 */}, +{ "6", /* 54 */}, +{ "7", /* 55 */}, +{ "8", /* 56 */}, +{ "9", /* 57 */}, +{ ":", /* 58 */}, +{ ";", /* 59 */}, +{ "<", /* 60 */}, +{ "=", /* 61 */}, +{ ">", /* 62 */}, +{ "?", /* 63 */}, +{ "@", "at", /* 64 */}, +{ "A", /* 65 */}, +{ "B", /* 66 */}, +{ "C", /* 67 */}, +{ "D", /* 68 */}, +{ "E", /* 69 */}, +{ "F", /* 70 */}, +{ "G", /* 71 */}, +{ "H", /* 72 */}, +{ "I", /* 73 */}, +{ "J", /* 74 */}, +{ "K", /* 75 */}, +{ "L", /* 76 */}, +{ "M", /* 77 */}, +{ "N", /* 78 */}, +{ "O", /* 79 */}, +{ "P", /* 80 */}, +{ "Q", /* 81 */}, +{ "R", /* 82 */}, +{ "S", /* 83 */}, +{ "T", /* 84 */}, +{ "U", /* 85 */}, +{ "V", /* 86 */}, +{ "W", /* 87 */}, +{ "X", /* 88 */}, +{ "Y", /* 89 */}, +{ "Z", /* 90 */}, +{ "[", "lB", /* 91 */}, +{ "\\", "rs", /* 92 */}, +{ "]", "rB", /* 93 */}, +{ "^", "a^", "ha", /* 94 */}, +{ "_", /* 95 */}, +{ "`", "ga", /* 96 */}, +{ "a", /* 97 */}, +{ "b", /* 98 */}, +{ "c", /* 99 */}, +{ "d", /* 100 */}, +{ "e", /* 101 */}, +{ "f", /* 102 */}, +{ "g", /* 103 */}, +{ "h", /* 104 */}, +{ "i", /* 105 */}, +{ "j", /* 106 */}, +{ "k", /* 107 */}, +{ "l", /* 108 */}, +{ "m", /* 109 */}, +{ "n", /* 110 */}, +{ "o", /* 111 */}, +{ "p", /* 112 */}, +{ "q", /* 113 */}, +{ "r", /* 114 */}, +{ "s", /* 115 */}, +{ "t", /* 116 */}, +{ "u", /* 117 */}, +{ "v", /* 118 */}, +{ "w", /* 119 */}, +{ "x", /* 120 */}, +{ "y", /* 121 */}, +{ "z", /* 122 */}, +{ "{", "lC", /* 123 */}, +{ "|", "ba", /* 124 */}, +{ "}", "rC", /* 125 */}, +{ "~", "a~", "ti", /* 126 */}, +{ 0, /* 127 */}, +{ 0, /* 128 */}, +{ 0, /* 129 */}, +{ 0, /* 130 */}, +{ 0, /* 131 */}, +{ 0, /* 132 */}, +{ 0, /* 133 */}, +{ 0, /* 134 */}, +{ 0, /* 135 */}, +{ 0, /* 136 */}, +{ 0, /* 137 */}, +{ 0, /* 138 */}, +{ 0, /* 139 */}, +{ 0, /* 140 */}, +{ 0, /* 141 */}, +{ 0, /* 142 */}, +{ 0, /* 143 */}, +{ 0, /* 144 */}, +{ 0, /* 145 */}, +{ 0, /* 146 */}, +{ 0, /* 147 */}, +{ 0, /* 148 */}, +{ 0, /* 149 */}, +{ 0, /* 150 */}, +{ 0, /* 151 */}, +{ 0, /* 152 */}, +{ 0, /* 153 */}, +{ 0, /* 154 */}, +{ 0, /* 155 */}, +{ 0, /* 156 */}, +{ 0, /* 157 */}, +{ 0, /* 158 */}, +{ 0, /* 159 */}, +{ 0, /* 160 */}, +{ "r!", /* 161 */}, +{ "ct", /* 162 */}, +{ "Po", /* 163 */}, +{ "Cs", /* 164 */}, +{ "Ye", /* 165 */}, +{ "bb", /* 166 */}, +{ "sc", /* 167 */}, +{ "ad", /* 168 */}, +{ "co", /* 169 */}, +{ "Of", /* 170 */}, +{ "Fo", /* 171 */}, +{ "tno", /* 172 */}, +{ "-", "hy", /* 173 */}, +{ "rg", /* 174 */}, +{ "a-", /* 175 */}, +{ "de", /* 176 */}, +{ "t+-", /* 177 */}, +{ "S2", /* 178 */}, +{ "S3", /* 179 */}, +{ "aa", /* 180 */}, +{ "mc", /* 181 */}, +{ "ps", /* 182 */}, +{ "pc", /* 183 */}, +{ "ac", /* 184 */}, +{ "S1", /* 185 */}, +{ "Om", /* 186 */}, +{ "Fc", /* 187 */}, +{ "14", /* 188 */}, +{ "12", /* 189 */}, +{ "34", /* 190 */}, +{ "r?", /* 191 */}, +{ "`A", /* 192 */}, +{ "'A", /* 193 */}, +{ "^A", /* 194 */}, +{ "~A", /* 195 */}, +{ ":A", /* 196 */}, +{ "oA", /* 197 */}, +{ "AE", /* 198 */}, +{ ",C", /* 199 */}, +{ "`E", /* 200 */}, +{ "'E", /* 201 */}, +{ "^E", /* 202 */}, +{ ":E", /* 203 */}, +{ "`I", /* 204 */}, +{ "'I", /* 205 */}, +{ "^I", /* 206 */}, +{ ":I", /* 207 */}, +{ "-D", /* 208 */}, +{ "~N", /* 209 */}, +{ "`O", /* 210 */}, +{ "'O", /* 211 */}, +{ "^O", /* 212 */}, +{ "~O", /* 213 */}, +{ ":O", /* 214 */}, +{ "tmu", /* 215 */}, +{ "/O", /* 216 */}, +{ "`U", /* 217 */}, +{ "'U", /* 218 */}, +{ "^U", /* 219 */}, +{ ":U", /* 220 */}, +{ "'Y", /* 221 */}, +{ "TP", /* 222 */}, +{ "ss", /* 223 */}, +{ "`a", /* 224 */}, +{ "'a", /* 225 */}, +{ "^a", /* 226 */}, +{ "~a", /* 227 */}, +{ ":a", /* 228 */}, +{ "oa", /* 229 */}, +{ "ae", /* 230 */}, +{ ",c", /* 231 */}, +{ "`e", /* 232 */}, +{ "'e", /* 233 */}, +{ "^e", /* 234 */}, +{ ":e", /* 235 */}, +{ "`i", /* 236 */}, +{ "'i", /* 237 */}, +{ "^i", /* 238 */}, +{ ":i", /* 239 */}, +{ "Sd", /* 240 */}, +{ "~n", /* 241 */}, +{ "`o", /* 242 */}, +{ "'o", /* 243 */}, +{ "^o", /* 244 */}, +{ "~o", /* 245 */}, +{ ":o", /* 246 */}, +{ "tdi", /* 247 */}, +{ "/o", /* 248 */}, +{ "`u", /* 249 */}, +{ "'u", /* 250 */}, +{ "^u", /* 251 */}, +{ ":u", /* 252 */}, +{ "'y", /* 253 */}, +{ "Tp", /* 254 */}, +{ ":y", /* 255 */}, +}, + {0} /* buckets */}; + +static DviCharNameMap Adobe_Symbol_map = { + "adobe-fontspecific", + 1, +{ +{ 0, /* 0 */}, +{ 0, /* 1 */}, +{ 0, /* 2 */}, +{ 0, /* 3 */}, +{ 0, /* 4 */}, +{ 0, /* 5 */}, +{ 0, /* 6 */}, +{ 0, /* 7 */}, +{ 0, /* 8 */}, +{ 0, /* 9 */}, +{ 0, /* 10 */}, +{ 0, /* 11 */}, +{ 0, /* 12 */}, +{ 0, /* 13 */}, +{ 0, /* 14 */}, +{ 0, /* 15 */}, +{ 0, /* 16 */}, +{ 0, /* 17 */}, +{ 0, /* 18 */}, +{ 0, /* 19 */}, +{ 0, /* 20 */}, +{ 0, /* 21 */}, +{ 0, /* 22 */}, +{ 0, /* 23 */}, +{ 0, /* 24 */}, +{ 0, /* 25 */}, +{ 0, /* 26 */}, +{ 0, /* 27 */}, +{ 0, /* 28 */}, +{ 0, /* 29 */}, +{ 0, /* 30 */}, +{ 0, /* 31 */}, +{ 0, /* 32 */}, +{ "!", /* 33 */}, +{ "fa", /* 34 */}, +{ "#", "sh", /* 35 */}, +{ "te", /* 36 */}, +{ "%", /* 37 */}, +{ "&", /* 38 */}, +{ "st", /* 39 */}, +{ "(", /* 40 */}, +{ ")", /* 41 */}, +{ "**", /* 42 */}, +{ "+", "pl", /* 43 */}, +{ ",", /* 44 */}, +{ "\\-", "mi", /* 45 */}, +{ ".", /* 46 */}, +{ "/", "sl", /* 47 */}, +{ "0", /* 48 */}, +{ "1", /* 49 */}, +{ "2", /* 50 */}, +{ "3", /* 51 */}, +{ "4", /* 52 */}, +{ "5", /* 53 */}, +{ "6", /* 54 */}, +{ "7", /* 55 */}, +{ "8", /* 56 */}, +{ "9", /* 57 */}, +{ ":", /* 58 */}, +{ ";", /* 59 */}, +{ "<", /* 60 */}, +{ "=", "eq", /* 61 */}, +{ ">", /* 62 */}, +{ "?", /* 63 */}, +{ "=~", /* 64 */}, +{ "*A", /* 65 */}, +{ "*B", /* 66 */}, +{ "*X", /* 67 */}, +{ "*D", /* 68 */}, +{ "*E", /* 69 */}, +{ "*F", /* 70 */}, +{ "*G", /* 71 */}, +{ "*Y", /* 72 */}, +{ "*I", /* 73 */}, +{ "+h", /* 74 */}, +{ "*K", /* 75 */}, +{ "*L", /* 76 */}, +{ "*M", /* 77 */}, +{ "*N", /* 78 */}, +{ "*O", /* 79 */}, +{ "*P", /* 80 */}, +{ "*H", /* 81 */}, +{ "*R", /* 82 */}, +{ "*S", /* 83 */}, +{ "*T", /* 84 */}, +{ 0, /* 85 */}, +{ "ts", /* 86 */}, +{ "*W", /* 87 */}, +{ "*C", /* 88 */}, +{ "*Q", /* 89 */}, +{ "*Z", /* 90 */}, +{ "[", "lB", /* 91 */}, +{ "tf", "3d", /* 92 */}, +{ "]", "rB", /* 93 */}, +{ "pp", /* 94 */}, +{ "_", /* 95 */}, +{ "radicalex", /* 96 */}, +{ "*a", /* 97 */}, +{ "*b", /* 98 */}, +{ "*x", /* 99 */}, +{ "*d", /* 100 */}, +{ "*e", /* 101 */}, +{ "*f", /* 102 */}, +{ "*g", /* 103 */}, +{ "*y", /* 104 */}, +{ "*i", /* 105 */}, +{ "+f", /* 106 */}, +{ "*k", /* 107 */}, +{ "*l", /* 108 */}, +{ "*m", /* 109 */}, +{ "*n", /* 110 */}, +{ "*o", /* 111 */}, +{ "*p", /* 112 */}, +{ "*h", /* 113 */}, +{ "*r", /* 114 */}, +{ "*s", /* 115 */}, +{ "*t", /* 116 */}, +{ "*u", /* 117 */}, +{ "+p", /* 118 */}, +{ "*w", /* 119 */}, +{ "*c", /* 120 */}, +{ "*q", /* 121 */}, +{ "*z", /* 122 */}, +{ "lC", "{", /* 123 */}, +{ "ba", "|", /* 124 */}, +{ "rC", "}", /* 125 */}, +{ "ap", /* 126 */}, +{ 0, /* 127 */}, +{ 0, /* 128 */}, +{ 0, /* 129 */}, +{ 0, /* 130 */}, +{ 0, /* 131 */}, +{ 0, /* 132 */}, +{ 0, /* 133 */}, +{ 0, /* 134 */}, +{ 0, /* 135 */}, +{ 0, /* 136 */}, +{ 0, /* 137 */}, +{ 0, /* 138 */}, +{ 0, /* 139 */}, +{ 0, /* 140 */}, +{ 0, /* 141 */}, +{ 0, /* 142 */}, +{ 0, /* 143 */}, +{ 0, /* 144 */}, +{ 0, /* 145 */}, +{ 0, /* 146 */}, +{ 0, /* 147 */}, +{ 0, /* 148 */}, +{ 0, /* 149 */}, +{ 0, /* 150 */}, +{ 0, /* 151 */}, +{ 0, /* 152 */}, +{ 0, /* 153 */}, +{ 0, /* 154 */}, +{ 0, /* 155 */}, +{ 0, /* 156 */}, +{ 0, /* 157 */}, +{ 0, /* 158 */}, +{ 0, /* 159 */}, +{ 0, /* 160 */}, +{ "*U", /* 161 */}, +{ "fm", /* 162 */}, +{ "<=", /* 163 */}, +{ "f/", /* 164 */}, +{ "if", /* 165 */}, +{ "Fn", /* 166 */}, +{ "CL", /* 167 */}, +{ "DI", /* 168 */}, +{ "HE", /* 169 */}, +{ "SP", /* 170 */}, +{ "<>", /* 171 */}, +{ "<-", /* 172 */}, +{ "ua", "arrowverttp", /* 173 */}, +{ "->", /* 174 */}, +{ "da", "arrowvertbt", /* 175 */}, +{ "de", /* 176 */}, +{ "+-", /* 177 */}, +{ "sd", /* 178 */}, +{ ">=", /* 179 */}, +{ "mu", /* 180 */}, +{ "pt", /* 181 */}, +{ "pd", /* 182 */}, +{ "bu", /* 183 */}, +{ "di", /* 184 */}, +{ "!=", /* 185 */}, +{ "==", /* 186 */}, +{ "~=", "~~", /* 187 */}, +{ 0, /* 188 */}, +{ "arrowvertex", /* 189 */}, +{ "an", /* 190 */}, +{ "CR", /* 191 */}, +{ "Ah", /* 192 */}, +{ "Im", /* 193 */}, +{ "Re", /* 194 */}, +{ "wp", /* 195 */}, +{ "c*", /* 196 */}, +{ "c+", /* 197 */}, +{ "es", /* 198 */}, +{ "ca", /* 199 */}, +{ "cu", /* 200 */}, +{ "sp", /* 201 */}, +{ "ip", /* 202 */}, +{ "nb", /* 203 */}, +{ "sb", /* 204 */}, +{ "ib", /* 205 */}, +{ "mo", /* 206 */}, +{ "nm", /* 207 */}, +{ "/_", /* 208 */}, +{ "gr", /* 209 */}, +{ "rg", /* 210 */}, +{ "co", /* 211 */}, +{ "tm", /* 212 */}, +{ 0, /* 213 */}, +{ "sr", "sqrt", /* 214 */}, +{ "md", /* 215 */}, +{ "no", /* 216 */}, +{ "AN", /* 217 */}, +{ "OR", /* 218 */}, +{ "hA", /* 219 */}, +{ "lA", /* 220 */}, +{ "uA", /* 221 */}, +{ "rA", /* 222 */}, +{ "dA", /* 223 */}, +{ "lz", /* 224 */}, +{ "la", /* 225 */}, +{ 0, /* 226 */}, +{ 0, /* 227 */}, +{ 0, /* 228 */}, +{ 0, /* 229 */}, +{ "parenlefttp", /* 230 */}, +{ "parenleftex", /* 231 */}, +{ "parenleftbt", /* 232 */}, +{ "bracketlefttp", "lc", /* 233 */}, +{ "bracketleftex", /* 234 */}, +{ "bracketleftbt", "lf", /* 235 */}, +{ "bracelefttp", "lt", /* 236 */}, +{ "braceleftmid", "lk", /* 237 */}, +{ "braceleftbt", "lb", /* 238 */}, +{ "bracerightex", "braceleftex", "braceex", "bv", /* 239 */}, +{ 0, /* 240 */}, +{ "ra", /* 241 */}, +{ "is", "integral", /* 242 */}, +{ 0, /* 243 */}, +{ 0, /* 244 */}, +{ 0, /* 245 */}, +{ "parenrighttp", /* 246 */}, +{ "parenrightex", /* 247 */}, +{ "parenrightbt", /* 248 */}, +{ "bracketrighttp", "rc", /* 249 */}, +{ "bracketrightex", /* 250 */}, +{ "bracketrightbt", "rf", /* 251 */}, +{ "bracerighttp", "rt", /* 252 */}, +{ "bracerightmid", "rk", /* 253 */}, +{ "bracerightbt", "rb", /* 254 */}, +{ 0, /* 255 */}, +}, + {0} /* buckets */}; + + +static void +load_standard_maps (void) +{ + standard_maps_loaded = 1; + DviRegisterMap (&ISO8859_1_map); + DviRegisterMap (&Adobe_Symbol_map); +} diff --git a/src/libs/libxutil/XFontName.c b/src/libs/libxutil/XFontName.c new file mode 100644 index 0000000..81ccdaa --- /dev/null +++ b/src/libs/libxutil/XFontName.c @@ -0,0 +1,260 @@ +/* Copyright (C) 2014-2020 Free Software Foundation, Inc. + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 2 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +The GNU General Public License version 2 (GPL2) is available in the +internet at <http://www.gnu.org/licenses/gpl-2.0.txt>. */ + +/* + * XFontName.c + * + * build/parse X Font name strings + */ + +#include <config.h> + +#include <X11/Xlib.h> +#include <X11/Xos.h> +#include "XFontName.h" +#include <ctype.h> + +static char * +extractStringField (char *name, char *buffer, int size, + unsigned int *attrp, unsigned int bit) +{ + char *buf = buffer; + + if (!*name) + return 0; + while (*name && *name != '-' && size > 0) { + *buf++ = *name++; + --size; + } + if (size <= 0) + return 0; + *buf = '\0'; + if (buffer[0] != '*' || buffer[1] != '\0') + *attrp |= bit; + if (*name == '-') + return name+1; + return name; +} + +static char * +extractUnsignedField (char *name, unsigned int *result, + unsigned int *attrp, unsigned int bit) +{ + char buf[256]; + char *c; + unsigned int i; + + name = extractStringField (name, buf, sizeof (buf), attrp, bit); + if (!name) + return 0; + if (!(*attrp & bit)) + return name; + i = 0; + for (c = buf; *c; c++) { + if (!isdigit (*c)) + return 0; + i = i * 10 + (*c - '0'); + } + *result = i; + return name; +} + +Bool +XParseFontName (XFontNameString fontNameString, XFontName *fontName, + unsigned int *fontNameAttributes) +{ + char *name = fontNameString; + XFontName temp; + unsigned int attributes = 0; + +#define GetString(field,bit)\ + if (!(name = extractStringField \ + (name, temp.field, sizeof (temp.field),\ + &attributes, bit))) \ + return False; + +#define GetUnsigned(field,bit)\ + if (!(name = extractUnsignedField \ + (name, &temp.field, \ + &attributes, bit))) \ + return False; + + GetString (Registry, FontNameRegistry) + GetString (Foundry, FontNameFoundry) + GetString (FamilyName, FontNameFamilyName) + GetString (WeightName, FontNameWeightName) + GetString (Slant, FontNameSlant) + GetString (SetwidthName, FontNameSetwidthName) + GetString (AddStyleName, FontNameAddStyleName) + GetUnsigned (PixelSize, FontNamePixelSize) + GetUnsigned (PointSize, FontNamePointSize) + GetUnsigned (ResolutionX, FontNameResolutionX) + GetUnsigned (ResolutionY, FontNameResolutionY) + GetString (Spacing, FontNameSpacing) + GetUnsigned (AverageWidth, FontNameAverageWidth) + GetString (CharSetRegistry, FontNameCharSetRegistry) + if (!*name) { + temp.CharSetEncoding[0] = '\0'; + attributes |= FontNameCharSetEncoding; + } else { + GetString (CharSetEncoding, FontNameCharSetEncoding) + } + *fontName = temp; + *fontNameAttributes = attributes; + return True; +} + +static char * +utoa (unsigned int u, char *s, int size) +{ + char *t; + + t = s + size; + *--t = '\0'; + do + *--t = (u % 10) + '0'; + while (u /= 10); + return t; +} + +Bool +XFormatFontName (XFontName *fontName, unsigned int fontNameAttributes, + XFontNameString fontNameString) +{ + char tmp[256]; + char *name = tmp, *f; + int left = sizeof (tmp) - 1; + char number[32]; + +#define PutString(field, bit)\ + f = (fontNameAttributes & bit) ? \ + fontName->field \ + : (char *)"*"; \ + if ((left -= strlen (f)) < 0) \ + return False; \ + while (*f) \ + if ((*name++ = *f++) == '-') \ + return False; +#define PutHyphen()\ + if (--left < 0) \ + return False; \ + *name++ = '-'; + +#define PutUnsigned(field, bit) \ + f = (fontNameAttributes & bit) ? \ + utoa (fontName->field, number, sizeof (number)) \ + : (char *)"*"; \ + if ((left -= strlen (f)) < 0) \ + return False; \ + while (*f) \ + *name++ = *f++; + + PutString (Registry, FontNameRegistry) + PutHyphen (); + PutString (Foundry, FontNameFoundry) + PutHyphen (); + PutString (FamilyName, FontNameFamilyName) + PutHyphen (); + PutString (WeightName, FontNameWeightName) + PutHyphen (); + PutString (Slant, FontNameSlant) + PutHyphen (); + PutString (SetwidthName, FontNameSetwidthName) + PutHyphen (); + PutString (AddStyleName, FontNameAddStyleName) + PutHyphen (); + PutUnsigned (PixelSize, FontNamePixelSize) + PutHyphen (); + PutUnsigned (PointSize, FontNamePointSize) + PutHyphen (); + PutUnsigned (ResolutionX, FontNameResolutionX) + PutHyphen (); + PutUnsigned (ResolutionY, FontNameResolutionY) + PutHyphen (); + PutString (Spacing, FontNameSpacing) + PutHyphen (); + PutUnsigned (AverageWidth, FontNameAverageWidth) + PutHyphen (); + PutString (CharSetRegistry, FontNameCharSetRegistry) + PutHyphen (); + PutString (CharSetEncoding, FontNameCharSetEncoding) + *name = '\0'; + strcpy (fontNameString, tmp); + return True; +} + +Bool +XCompareFontName (XFontName *name1, XFontName *name2, + unsigned int fontNameAttributes) +{ +#define CompareString(field,bit) \ + if (fontNameAttributes & bit) \ + if (strcmp (name1->field, name2->field)) \ + return False; + +#define CompareUnsigned(field,bit) \ + if (fontNameAttributes & bit) \ + if (name1->field != name2->field) \ + return False; + + CompareString (Registry, FontNameRegistry) + CompareString (Foundry, FontNameFoundry) + CompareString (FamilyName, FontNameFamilyName) + CompareString (WeightName, FontNameWeightName) + CompareString (Slant, FontNameSlant) + CompareString (SetwidthName, FontNameSetwidthName) + CompareString (AddStyleName, FontNameAddStyleName) + CompareUnsigned (PixelSize, FontNamePixelSize) + CompareUnsigned (PointSize, FontNamePointSize) + CompareUnsigned (ResolutionX, FontNameResolutionX) + CompareUnsigned (ResolutionY, FontNameResolutionY) + CompareString (Spacing, FontNameSpacing) + CompareUnsigned (AverageWidth, FontNameAverageWidth) + CompareString (CharSetRegistry, FontNameCharSetRegistry) + CompareString (CharSetEncoding, FontNameCharSetEncoding) + return True; +} + +Bool +XCopyFontName (XFontName *name1, XFontName *name2, + unsigned int fontNameAttributes) +{ +#define CopyString(field,bit) \ + if (fontNameAttributes & bit) \ + strcpy (name2->field, name1->field); + +#define CopyUnsigned(field,bit) \ + if (fontNameAttributes & bit) \ + name2->field = name1->field; + + CopyString (Registry, FontNameRegistry) + CopyString (Foundry, FontNameFoundry) + CopyString (FamilyName, FontNameFamilyName) + CopyString (WeightName, FontNameWeightName) + CopyString (Slant, FontNameSlant) + CopyString (SetwidthName, FontNameSetwidthName) + CopyString (AddStyleName, FontNameAddStyleName) + CopyUnsigned (PixelSize, FontNamePixelSize) + CopyUnsigned (PointSize, FontNamePointSize) + CopyUnsigned (ResolutionX, FontNameResolutionX) + CopyUnsigned (ResolutionY, FontNameResolutionY) + CopyString (Spacing, FontNameSpacing) + CopyUnsigned (AverageWidth, FontNameAverageWidth) + CopyString (CharSetRegistry, FontNameCharSetRegistry) + CopyString (CharSetEncoding, FontNameCharSetEncoding) + return True; +} diff --git a/src/libs/libxutil/libxutil.am b/src/libs/libxutil/libxutil.am new file mode 100644 index 0000000..5963530 --- /dev/null +++ b/src/libs/libxutil/libxutil.am @@ -0,0 +1,35 @@ +# Automake rules for 'libxutil' +# +# Copyright (C) 2014-2020 Free Software Foundation, Inc. +# +# 'groff' is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# 'groff' is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see +# <http://www.gnu.org/licenses/gpl-2.0.html>. +# +######################################################################## + +if !WITHOUT_X11 +noinst_LIBRARIES += libxutil.a +libxutil_a_CPPFLAGS = $(AM_CPPFLAGS) $(X_CFLAGS) +libxutil_a_SOURCES = \ + src/libs/libxutil/DviChar.c \ + src/libs/libxutil/XFontName.c \ + src/libs/libxutil/xmalloc.c +endif + + +# Local Variables: +# mode: makefile-automake +# fill-column: 72 +# End: +# vim: set autoindent filetype=automake textwidth=72: diff --git a/src/libs/libxutil/xmalloc.c b/src/libs/libxutil/xmalloc.c new file mode 100644 index 0000000..0852c62 --- /dev/null +++ b/src/libs/libxutil/xmalloc.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2014-2020 Free Software Foundation, Inc. + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 2 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +The GNU General Public License version 2 (GPL2) is available in the +internet at <http://www.gnu.org/licenses/gpl-2.0.txt>. */ + +#include <config.h> + +#include <X11/Xlib.h> +#include <X11/Intrinsic.h> + +char *xmalloc(int n); + +char *xmalloc(int n) +{ + return XtMalloc(n); +} |