diff options
Diffstat (limited to 'Build/source/texk/lcdf-typetools/lcdf-typetools-2.102/libefont/psres.cc')
-rw-r--r-- | Build/source/texk/lcdf-typetools/lcdf-typetools-2.102/libefont/psres.cc | 419 |
1 files changed, 419 insertions, 0 deletions
diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.102/libefont/psres.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.102/libefont/psres.cc new file mode 100644 index 00000000000..2136a6b3237 --- /dev/null +++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.102/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(); +} + +} |