Tim Mayberry
569167a603
This fixes the libpbd testCanonicalPathUTF8 and libardour open_session_utf8_path unit tests You can now have Sessions with localized names containing characters that aren't in the system codepage on Windows. It also fixes the issue where a Session would not open when it was moved into a path with characters that aren't in the system codepage. The only use case for calling canonical_path/realpath on the session path AFAICT is for resolving relative paths that are passed via the command line/terminal. I'm doubtful that works correctly on Windows because of character encoding issues with the current API we use for that(not glib), so it is slightly ironic that this issue was caused by an incorrect implementation of a function that is not really necessary on Windows at this point in time.
165 lines
3.9 KiB
C++
165 lines
3.9 KiB
C++
/*
|
|
Copyright (C) 2013-2014 Paul Davis
|
|
|
|
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.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*/
|
|
|
|
#include <vector>
|
|
#include <iostream>
|
|
#include <climits>
|
|
#include <cerrno>
|
|
#include <cstdlib>
|
|
|
|
#include <regex.h>
|
|
|
|
#include <glibmm/fileutils.h>
|
|
#include <glibmm/miscutils.h>
|
|
|
|
#include "pbd/compose.h"
|
|
#include "pbd/debug.h"
|
|
#include "pbd/pathexpand.h"
|
|
#include "pbd/strsplit.h"
|
|
#include "pbd/tokenizer.h"
|
|
|
|
using std::string;
|
|
using std::vector;
|
|
|
|
string
|
|
PBD::path_expand (string path)
|
|
{
|
|
if (path.empty()) {
|
|
return path;
|
|
}
|
|
|
|
/* tilde expansion */
|
|
|
|
if (path[0] == '~') {
|
|
if (path.length() == 1) {
|
|
return Glib::get_home_dir();
|
|
}
|
|
|
|
if (path[1] == '/') {
|
|
path.replace (0, 1, Glib::get_home_dir());
|
|
} else {
|
|
/* can't handle ~roger, so just leave it */
|
|
}
|
|
}
|
|
|
|
/* now do $VAR substitution, since wordexp isn't reliable */
|
|
|
|
regex_t compiled_pattern;
|
|
const int nmatches = 100;
|
|
regmatch_t matches[nmatches];
|
|
|
|
if (regcomp (&compiled_pattern, "\\$([a-zA-Z_][a-zA-Z0-9_]*|\\{[a-zA-Z_][a-zA-Z0-9_]*\\})", REG_EXTENDED)) {
|
|
std::cerr << "bad regcomp\n";
|
|
return path;
|
|
}
|
|
|
|
while (true) {
|
|
|
|
if (regexec (&compiled_pattern, path.c_str(), nmatches, matches, 0)) {
|
|
break;
|
|
}
|
|
|
|
/* matches[0] gives the entire match */
|
|
|
|
string match = path.substr (matches[0].rm_so, matches[0].rm_eo - matches[0].rm_so);
|
|
|
|
/* try to get match from the environment */
|
|
|
|
if (match[1] == '{') {
|
|
/* ${FOO} form */
|
|
match = match.substr (2, match.length() - 3);
|
|
}
|
|
|
|
char* matched_value = getenv (match.c_str());
|
|
|
|
if (matched_value) {
|
|
path.replace (matches[0].rm_so, matches[0].rm_eo - matches[0].rm_so, matched_value);
|
|
} else {
|
|
path.replace (matches[0].rm_so, matches[0].rm_eo - matches[0].rm_so, string());
|
|
}
|
|
|
|
/* go back and do it again with whatever remains after the
|
|
* substitution
|
|
*/
|
|
}
|
|
|
|
regfree (&compiled_pattern);
|
|
|
|
/* canonicalize */
|
|
|
|
return canonical_path (path);
|
|
}
|
|
|
|
string
|
|
PBD::search_path_expand (string path)
|
|
{
|
|
if (path.empty()) {
|
|
return path;
|
|
}
|
|
|
|
vector<string> s;
|
|
vector<string> n;
|
|
|
|
split (path, s, G_SEARCHPATH_SEPARATOR);
|
|
|
|
for (vector<string>::iterator i = s.begin(); i != s.end(); ++i) {
|
|
string exp = path_expand (*i);
|
|
if (!exp.empty()) {
|
|
n.push_back (exp);
|
|
}
|
|
}
|
|
|
|
string r;
|
|
|
|
for (vector<string>::iterator i = n.begin(); i != n.end(); ++i) {
|
|
if (!r.empty()) {
|
|
r += G_SEARCHPATH_SEPARATOR;
|
|
}
|
|
r += *i;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
std::vector <std::string>
|
|
PBD::parse_path(std::string path, bool check_if_exists)
|
|
{
|
|
vector <std::string> pathlist;
|
|
vector <std::string> tmp;
|
|
PBD::tokenize (path, string(G_SEARCHPATH_SEPARATOR_S), std::back_inserter (tmp));
|
|
|
|
for(vector<std::string>::const_iterator i = tmp.begin(); i != tmp.end(); ++i) {
|
|
if ((*i).empty()) continue;
|
|
std::string dir;
|
|
#ifndef PLATFORM_WINDOWS
|
|
if ((*i).substr(0,1) == "~") {
|
|
dir = Glib::build_filename(Glib::get_home_dir(), (*i).substr(1));
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
dir = *i;
|
|
}
|
|
if (!check_if_exists || Glib::file_test (dir, Glib::FILE_TEST_IS_DIR)) {
|
|
pathlist.push_back(dir);
|
|
}
|
|
}
|
|
return pathlist;
|
|
}
|