summaryrefslogtreecommitdiff
path: root/Build/source/texk/lcdf-typetools/lcdf-typetools-2.104/libefont/psres.cc
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/lcdf-typetools/lcdf-typetools-2.104/libefont/psres.cc')
-rw-r--r--Build/source/texk/lcdf-typetools/lcdf-typetools-2.104/libefont/psres.cc419
1 files changed, 419 insertions, 0 deletions
diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.104/libefont/psres.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.104/libefont/psres.cc
new file mode 100644
index 00000000000..2136a6b3237
--- /dev/null
+++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.104/libefont/psres.cc
@@ -0,0 +1,419 @@
+// -*- related-file-name: "../include/efont/psres.hh" -*-
+
+/* psres.{cc,hh} -- PSres.upr files
+ *
+ * Copyright (c) 1999-2012 Eddie Kohler
+ *
+ * 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 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <efont/psres.hh>
+#include <lcdf/slurper.hh>
+/* Get the correct functions for directory searching */
+#if HAVE_DIRENT_H
+# include <dirent.h>
+# define DIR_NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define DIR_NAMLEN(dirent) (dirent)->d_namlen
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+#include <string.h>
+namespace Efont {
+
+PsresDatabase::PsresDatabase()
+ : _section_map(0)
+{
+ _sections.push_back((PsresDatabaseSection *)0);
+}
+
+PsresDatabase::~PsresDatabase()
+{
+ for (int i = 1; i < _sections.size(); i++)
+ delete _sections[i];
+}
+
+
+PsresDatabaseSection::PsresDatabaseSection(PermString section_name)
+ : _section_name(section_name), _map(0)
+{
+ _directories.push_back(PermString());
+ _values.push_back(String());
+ _value_escaped.push_back(true);
+}
+
+
+/* read_ps_line - gathers a line in `slurper', returns true if it is a normal
+ line, false on end of file or a separator line (starts with `.'). Handles
+ continuation lines but not backslash escaping. Stores location of first
+ non-backslashed equals sign in `*equals_pos', or -1 if none. */
+
+static bool
+read_psres_line(Slurper &slurper, int *equals_pos)
+{
+ if (equals_pos) *equals_pos = -1;
+
+ char *s = slurper.next_line();
+ if (!s) return false;
+
+ bool is_terminator = s[0] == '.';
+ unsigned len, pos = 0, last_escape = ~0;
+ bool found_eq = false;
+
+ while (true) {
+ len = slurper.cur_line_length();
+ if (len == 0) break;
+
+ // process backslash escapes
+ for (; pos < len - 1; pos++) {
+ if (s[pos] == '\\') {
+ // quote the next character
+ pos++;
+ last_escape = pos;
+ } else if (!found_eq && s[pos] == '=') {
+ // an equals sign: store its position
+ if (equals_pos) *equals_pos = pos;
+ found_eq = true;
+ } else if (s[pos] == '%') {
+ // unescaped '%' is a comment; return immediately after shortening line
+ len = pos;
+ goto done;
+ }
+ }
+
+ // stop processing if not a continuation line
+ if (pos == len || s[pos] != '\\') break;
+
+ slurper.shorten_line(pos);
+ s = slurper.append_next_line();
+ }
+
+ if (pos < len && !found_eq && s[pos] == '=' && equals_pos)
+ *equals_pos = pos;
+
+ done:
+ // eat trailing whitespace, except for the space in `\ ' if it ends the line
+ // -- unless the `\' is the second `\' in a `\\'!
+ for (pos = len; pos > 0 && (s[pos-1] == ' ' || s[pos-1] == '\t'); pos--)
+ /* nada */;
+ if (pos == last_escape)
+ pos++;
+ slurper.shorten_line(pos);
+ return !is_terminator;
+}
+
+/* psres_escape: backslash escaping */
+
+static unsigned
+psres_escape(char *s, unsigned len)
+{
+ unsigned pos = 0, delta = 0;
+ while (pos < len) {
+ if (s[pos] == '\\') pos++, delta++;
+ if (delta) s[pos-delta] = s[pos];
+ pos++;
+ }
+ s[pos-delta] = 0;
+ return len-delta;
+}
+
+void
+PsresDatabaseSection::add_psres_file_section
+ (Slurper &slurper, PermString directory, bool override)
+{
+ int equals_pos;
+ bool first_line = true;
+
+ while (read_psres_line(slurper, &equals_pos)) {
+ char *s = slurper.cur_line();
+
+ // check for a directory line
+ if (first_line) {
+ first_line = false;
+ if (s[0] == '/') {
+ psres_escape(s + 1, slurper.cur_line_length() - 1);
+ directory = PermString(s + 1);
+ continue;
+ }
+ }
+
+ if (equals_pos < 0) {
+ // report error?
+ continue;
+ }
+
+ // get the key
+ unsigned len = psres_escape(s, equals_pos);
+ PermString key = PermString(s, len);
+ int index = _map[key];
+ if (!override && index > 0)
+ continue;
+
+ // double equals means absolute pathname
+ if (s[equals_pos + 1] == '=')
+ equals_pos++;
+
+ // get the value. Don't escape it yet
+ len = slurper.cur_line_length() - (equals_pos + 1);
+ String value = String(s + equals_pos + 1, len);
+
+ // stick key and value into our data structure
+ if (index == 0) {
+ index = _directories.size();
+ _directories.push_back(directory);
+ _values.push_back(value);
+ _value_escaped.push_back(false);
+ _map.insert(key, index);
+ } else {
+ _directories[index] = directory;
+ _values[index] = value;
+ _value_escaped[index] = false;
+ }
+ }
+}
+
+
+PsresDatabaseSection *
+PsresDatabase::force_section(PermString name)
+{
+ if (_section_map[name] > 0)
+ return _sections[_section_map[name]];
+ else {
+ PsresDatabaseSection *s = new PsresDatabaseSection(name);
+ int index = _sections.size();
+ _sections.push_back(s);
+ _section_map.insert(name, index);
+ return s;
+ }
+}
+
+bool
+PsresDatabase::add_one_psres_file(Slurper &slurper, bool override)
+{
+ if (!read_psres_line(slurper, 0))
+ return /* error */ false;
+
+ char *s = slurper.cur_line();
+ unsigned len = slurper.cur_line_length();
+ if (len < 12 || memcmp(s, "PS-Resources", 12) != 0)
+ return /* error */ false;
+
+ bool exclusive = (len >= 22 && memcmp(s+12, "-Exclusive", 10) == 0);
+
+ // skip list of sections
+ while (read_psres_line(slurper, 0))
+ /* nada */;
+
+ // now, read each section
+ PermString directory = slurper.filename().directory();
+
+ while (read_psres_line(slurper, 0)) {
+ s = slurper.cur_line();
+ len = psres_escape(s, slurper.cur_line_length());
+ PsresDatabaseSection *section = force_section(PermString(s, len));
+ section->add_psres_file_section(slurper, directory, override);
+ }
+
+ return exclusive;
+}
+
+bool
+PsresDatabase::add_psres_file(Filename &filename, bool override)
+{
+ Slurper slurpy(filename);
+ return add_one_psres_file(slurpy, override);
+}
+
+
+#ifndef WIN32
+
+void
+PsresDatabase::add_psres_directory(PermString directory)
+{
+ DIR *dir = opendir(directory.c_str());
+ if (!dir) return;
+
+ while (struct dirent *dirent = readdir(dir)) {
+ int len = DIR_NAMLEN(dirent);
+ if (len > 4 && dirent->d_name[0] != '.'
+ && memcmp(dirent->d_name + len - 4, ".upr", 4) == 0
+ && (len != 9 || memcmp(dirent->d_name, "PSres.upr", 9) != 0)) {
+ Filename fn(directory, PermString(dirent->d_name, len));
+ add_psres_file(fn, false);
+ }
+ }
+
+ closedir(dir);
+}
+
+#else /* WIN32 */
+
+void
+PsresDatabase::add_psres_directory(PermString directory)
+{
+ WIN32_FIND_DATA find_file_data;
+ HANDLE hnd;
+ int proceed = TRUE;
+
+ PermString search_str = permcat(directory, "/*.*");
+ hnd = FindFirstFile(search_str.c_str(), &find_file_data);
+
+ if (hnd == INVALID_HANDLE_VALUE) {
+ return;
+ }
+ while (proceed) {
+ int len = strlen(find_file_data.cFileName);
+ if (len > 4 && find_file_data.cFileName[0] != '.'
+ && _strnicmp(find_file_data.cFileName + len - 4, ".upr", 4) == 0
+ && (len != 9 || _strnicmp(find_file_data.cFileName, "PSres.upr", 9) != 0)) {
+ Filename fn(directory, PermString(find_file_data.cFileName, len));
+ add_psres_file(fn, false);
+ }
+ proceed = FindNextFile (hnd, &find_file_data);
+ }
+ FindClose(hnd);
+}
+
+#endif /* WIN32 */
+
+
+void
+PsresDatabase::add_psres_path(const char *path, const char *default_path,
+ bool override)
+{
+ if (!path && !default_path)
+ return;
+ else if (!path) {
+ path = default_path;
+ default_path = 0;
+ }
+
+ if (override && _sections.size() > 1) {
+ PsresDatabase new_db;
+ new_db.add_psres_path(path, default_path, false);
+ add_database(&new_db, true);
+ return;
+ }
+
+ while (*path) {
+ const char *epath = path;
+ while (*epath && *epath != ':') epath++;
+
+ PermString directory(path, epath - path);
+ Filename filename(directory, "PSres.upr");
+ if (epath == path) {
+ add_psres_path(default_path, 0, false);
+ default_path = 0; // don't use default path twice
+ } else if (!filename.readable() || !add_psres_file(filename, false))
+ add_psres_directory(directory);
+
+ path = (*epath ? epath+1 : epath);
+ }
+}
+
+
+void
+PsresDatabase::add_database(PsresDatabase *db, bool override)
+{
+ for (int i = 1; i < db->_sections.size(); i++) {
+ PermString section_name = db->_sections[i]->section_name();
+ PsresDatabaseSection *section = force_section(section_name);
+ section->add_section(db->_sections[i], override);
+ }
+}
+
+void
+PsresDatabaseSection::add_section(PsresDatabaseSection *s, bool override)
+{
+ for (HashMap<PermString, int>::const_iterator i = s->_map.begin(); i; i++) {
+ int value = i.value();
+ if (_map[i.key()] <= 0) {
+ int my_index = _directories.size();
+ _directories.push_back(s->_directories[value]);
+ _values.push_back(s->_values[value]);
+ _value_escaped.push_back(s->_value_escaped[value]);
+ _map.insert(i.key(), my_index);
+ } else if (override) {
+ int my_index = _map[i.key()];
+ _directories[my_index] = s->_directories[value];
+ _values[my_index] = s->_values[value];
+ _value_escaped[my_index] = s->_value_escaped[value];
+ }
+ }
+}
+
+
+const String &
+PsresDatabaseSection::value(int index)
+{
+ if (_value_escaped[index])
+ return _values[index];
+ else {
+ char *data = _values[index].mutable_data();
+ int len = psres_escape(data, _values[index].length());
+ _values[index] = _values[index].substring(0, len);
+ _value_escaped[index] = true;
+ return _values[index];
+ }
+}
+
+Filename
+PsresDatabaseSection::filename_value(PermString key)
+{
+ int index = _map[key];
+ if (!index)
+ return Filename();
+ else if (!_directories[index])
+ return Filename(value(index));
+ else
+ return Filename(_directories[index], value(index));
+}
+
+const String &
+PsresDatabase::value(PermString sec, PermString key) const
+{
+ PsresDatabaseSection *s = section(sec);
+ if (s)
+ return s->value(key);
+ else
+ return String::make_empty();
+}
+
+const String &
+PsresDatabase::unescaped_value(PermString sec, PermString key) const
+{
+ PsresDatabaseSection *s = section(sec);
+ if (s)
+ return s->unescaped_value(key);
+ else
+ return String::make_empty();
+}
+
+Filename
+PsresDatabase::filename_value(PermString sec, PermString key) const
+{
+ PsresDatabaseSection *s = section(sec);
+ if (s)
+ return s->filename_value(key);
+ else
+ return Filename();
+}
+
+}