<commit_before>/*
 *  PathResolver.cpp
 *  openc2e
 *
 *  Created by <NAME>
 *  Copyright (c) 2005 <NAME>. All rights reserved.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This 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
 *  Lesser General Public License for more details.
 *
 */

#include "PathResolver.h"

#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <set>
#include <map>
#include <cctype>
#include <string>
#include <algorithm>
#include <iostream>

using std::map;
using std::set;
using std::string;
using namespace boost::filesystem;

static set<string> dircache;
static map<string, string> cache;

static bool checkDirCache(path &dir);
static bool doCacheDir(path &dir);

/* C++ is far too verbose for its own good */
static string toLowerCase(string in) {
	transform(in.begin(), in.end(), in.begin(), (int(*)(int))tolower);
	return in;
}

static path lcpath(path &orig) {
	return path(toLowerCase(orig.string()), native);
}

static path lcleaf(path &orig) {
	path br, leaf;
	br = orig.branch_path();
	leaf = path(toLowerCase(orig.leaf()), native);
	return br / leaf;
}

bool resolveFile(path &p) {
	string s = p.string();
	if (!resolveFile(s)) {
		// Maybe something changed underneath us; reset the cache and try again
		cache.clear();
		dircache.clear();
		if (!resolveFile(s))
			return false;
	}
	p = path(s, native);
	return true;
}

bool resolveFile_(string &srcPath) {
	path orig(srcPath, native);
	if (exists(orig))
		return true;
	
	orig.normalize();
	path dir = orig.branch_path();
	path leaf = path(orig.leaf(), native);

	if (!checkDirCache(dir))
		return false;

	orig = dir / lcpath(leaf);
	string fn = orig.string();

	if (exists(orig)) {
		srcPath = fn;
		return true;
	}

	map<string, string>::iterator i = cache.find(fn);
	if (i == cache.end()) {
		assert(!exists(orig));
		return false;
	}
	srcPath = cache[fn];
	return true;
}

bool resolveFile(std::string &path) {
	std::string orig = path;
	bool res = resolveFile_(path);
#if 0
	std::cerr << orig << " -> ";
	if (!res)
		std::cerr << "(nil)";
	else
		std::cerr << path;
	std::cerr << std::endl;
#endif
	return res;
}


/* If dir is cached, do nothing.
 * If dir exists, cache it.
 * If dir does not exist, see if there's one with different capitalization.
 *
 * If we find a dir, return true. Else, false.
 */
bool checkDirCache(path &dir) {
	if (dir == path())
		dir = path(".");
//	std::cerr << "checkDirCache: " << dir.string() << std::endl;
	if (dircache.end() != dircache.find(dir.string())) {
		return true;
	}
	if (exists(dir))
		return doCacheDir(dir);
	if (dir.empty())
		return false;
	bool res = resolveFile(dir);
	if (!res)
		return false;
	return checkDirCache(dir);
}

/* Cache a dir. Return true for success.
 */
bool doCacheDir(path &dir) {
//	std::cerr << "cacheing: " << dir.string() << std::endl;
	directory_iterator it(dir);
	directory_iterator fsend;
	while (it != fsend) {
		path cur = *it++;
		string key, val;
		key = cur.string();
		val = lcleaf(cur).string();
//		std::cerr << "Cache put: " << val << " -> " << key << std::endl;
		cache[val] = key;
	}
	dircache.insert(dir.string());
	return true;
}

static void constructSearchPattern(const std::string &wild, std::vector<std::string> &l) {
	std::string::const_iterator i = wild.begin();
	l.push_back(std::string());
	while (i != wild.end()) {
		if (*i != '*')
			l.back().push_back(*i);
		else
			l.push_back(std::string());
		i++;
	}
}

static bool checkSearchPattern(const std::string &match, const std::vector<std::string> &l) {
	size_t p = 0;
	std::vector<std::string>::const_iterator it = l.begin();
	while (it != l.end()) {
		p = match.find(*it, p);
		if (p == std::string::npos)
			return false;
		it++;
	}
	if (match.substr(match.length() - l.back().length()) != l.back())
		return false;
	return true;
}

// XXX: this might not handle new files too well...
std::vector<std::string> findByWildcard(std::string dir, std::string wild) {
	wild = toLowerCase(wild);

	path dirp(dir, native);
	dirp.normalize();
	if (!resolveFile(dirp))
		return std::vector<std::string>();
	dir = dirp.string();

	if (!doCacheDir(dirp))
		return std::vector<std::string>();<commit_msg>Clear the cache before wildcard-searching<commit_after>/*
 *  PathResolver.cpp
 *  openc2e
 *
 *  Created by <NAME>
 *  Copyright (c) 2005 <NAME>. All rights reserved.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This 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
 *  Lesser General Public License for more details.
 *
 */

#include "PathResolver.h"

#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <set>
#include <map>
#include <cctype>
#include <string>
#include <algorithm>
#include <iostream>

using std::map;
using std::set;
using std::string;
using namespace boost::filesystem;

static set<string> dircache;
static map<string, string> cache;

static bool checkDirCache(path &dir);
static bool doCacheDir(path &dir);

/* C++ is far too verbose for its own good */
static string toLowerCase(string in) {
	transform(in.begin(), in.end(), in.begin(), (int(*)(int))tolower);
	return in;
}

static path lcpath(path &orig) {
	return path(toLowerCase(orig.string()), native);
}

static path lcleaf(path &orig) {
	path br, leaf;
	br = orig.branch_path();
	leaf = path(toLowerCase(orig.leaf()), native);
	return br / leaf;
}

bool resolveFile(path &p) {
	string s = p.string();
	if (!resolveFile(s)) {
		// Maybe something changed underneath us; reset the cache and try again
		cache.clear();
		dircache.clear();
		if (!resolveFile(s))
			return false;
	}
	p = path(s, native);
	return true;
}

bool resolveFile_(string &srcPath) {
	path orig(srcPath, native);
	if (exists(orig))
		return true;
	
	orig.normalize();
	path dir = orig.branch_path();
	path leaf = path(orig.leaf(), native);

	if (!checkDirCache(dir))
		return false;

	orig = dir / lcpath(leaf);
	string fn = orig.string();

	if (exists(orig)) {
		srcPath = fn;
		return true;
	}

	map<string, string>::iterator i = cache.find(fn);
	if (i == cache.end()) {
		assert(!exists(orig));
		return false;
	}
	srcPath = cache[fn];
	return true;
}

bool resolveFile(std::string &path) {
	std::string orig = path;
	bool res = resolveFile_(path);
#if 0
	std::cerr << orig << " -> ";
	if (!res)
		std::cerr << "(nil)";
	else
		std::cerr << path;
	std::cerr << std::endl;
#endif
	return res;
}


/* If dir is cached, do nothing.
 * If dir exists, cache it.
 * If dir does not exist, see if there's one with different capitalization.
 *
 * If we find a dir, return true. Else, false.
 */
bool checkDirCache(path &dir) {
	if (dir == path())
		dir = path(".");
//	std::cerr << "checkDirCache: " << dir.string() << std::endl;
	if (dircache.end() != dircache.find(dir.string())) {
		return true;
	}
	if (exists(dir))
		return doCacheDir(dir);
	if (dir.empty())
		return false;
	bool res = resolveFile(dir);
	if (!res)
		return false;
	return checkDirCache(dir);
}

/* Cache a dir. Return true for success.
 */
bool doCacheDir(path &dir) {
//	std::cerr << "cacheing: " << dir.string() << std::endl;
	directory_iterator it(dir);
	directory_iterator fsend;
	while (it != fsend) {
		path cur = *it++;
		string key, val;
		key = cur.string();
		val = lcleaf(cur).string();
//		std::cerr << "Cache put: " << val << " -> " << key << std::endl;
		cache[val] = key;
	}
	dircache.insert(dir.string());
	return true;
}

static void constructSearchPattern(const std::string &wild, std::vector<std::string> &l) {
	std::string::const_iterator i = wild.begin();
	l.push_back(std::string());
	while (i != wild.end()) {
		if (*i != '*')
			l.back().push_back(*i);
		else
			l.push_back(std::string());
		i++;
	}
}

static bool checkSearchPattern(const std::string &match, const std::vector<std::string> &l) {
	size_t p = 0;
	std::vector<std::string>::const_iterator it = l.begin();
	while (it != l.end()) {
		p = match.find(*it, p);
		if (p == std::string::npos)
			return false;
		it++;
	}
	if (match.substr(match.length() - l.back().length()) != l.back())
		return false;
	return true;
}

std::vector<std::string> findByWildcard(std::string dir, std::string wild) {
	cache.clear();
	dircache.clear();

	wild = toLowerCase(wild);

	path dirp(dir, native);
	dirp.normalize();
	if (!resolveFile(dirp))
		return std::vector<std::string>();
	dir = dirp.string();

	if (!doCacheDir(dirp))
		return std::vector<std::string>();
{'fraction_non_alphanumeric': 0.16681289756525555, 'fraction_numerical': 0.001754770783066462, 'mean_word_length': 4.128796400449944, 'pattern_counts': {'":': 0, '<': 105, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5955861', 'n_tokens_mistral': 3266, 'n_tokens_neox': 3163, 'n_words': 940}