Пример #1
0
	explicit glob_matcher(const boost::string_ref pat)
	noexcept : m_pat{pat}
	{
		// If we are in debug mode, ensure that the pattern is valid.
		assert(m_pat.length() > 0);

		#ifndef NDEBUG
		auto i = 0u;

		/*
		** The following sequences are considered to be syntax
		** violations when they occur within glob patterns:
		**
		**   1. Special characters within groups.
		**   2. Empty groups.
		**   3. Any backslash not followed by a special character; this
		**   includes trailing backslashes.
		*/
		do switch (m_pat[i]) {
		default:
		case '*':
		case '?':     ++i;                            continue;
		case '[':     assert(pat[++i] != ']');        goto group_mode;
		// Ensure that the character escaped using a backslash is a
		// special character.
		case '\\':    assert(is_glob(pat[++i])); ++i; continue;
		regular_mode:                                 continue;
		} while (i != pat.length());
		return;
		
		// Check to ensure that the current group is valid.
	group_mode:
		for(;;) switch (m_pat[i]) {
		default:   ++i;                            continue;
		case ']':  ++i;                            goto regular_mode;
		case '\\': assert(is_glob(pat[++i])); ++i; continue;
		case '*':
		case '?':
		case '\0': assert(false && "Invalid group.");
		}

		#endif
	}
Пример #2
0
	/*
	** Determines whether the directory entry's name matches the glob
	** pattern.
	*/
	bool operator()(const directory_entry& ent)
	const noexcept
	{
		#ifndef NDEBUG
			assert(m_pat.length() > 0);
		#endif

		// Offset into pattern that we are matching.
		auto i = 0u;
		// Offset into the file name.
		auto j = 0u;
		auto s = ent.name();

		do switch(m_pat[i]) {
		default:   if (m_pat[i++] != s[j++])         return false; continue;
		case '*':  ++i; return match_wildcard(s, i, j);
		case '?':  ++i; ++j;                                       continue;
		case '[':  ++i; if (!match_group(s, i, j))   return false; continue;
		case '\\': ++i; if (m_pat[i++] != s[j++])    return false; continue;
		} while (i != m_pat.length() && j != s.length());
		return (i == m_pat.length() || m_pat[i] == '*') && j == s.length();
	}
Пример #3
0
	explicit directory_iterator(const boost::string_ref dir)
	: m_dir_len(dir.length())
	{
		// Ensure that the string resulting from concatenating the path
		// to the directory, the platform directory separator, and the
		// file name can fit in the path buffer. The trailing "+ 1" term
		// accounts for the null terminating character.
		assert(m_dir_len + 1 + PLATFORM_MAX_FILENAME_LENGTH + 1 <=
			PLATFORM_MAX_PATHNAME_LENGTH);

		// We need to copy `dir` to `m_path_buf`, because `dir` might
		// not be null-terminated.
		boost::copy(dir, m_path_buf.begin());
		m_path_buf[dir.length()] = '\0';
		m_fd = ::open(m_path_buf.begin(), O_RDONLY);

		if (m_fd < 0) {
			throw std::system_error{errno, std::system_category(),
				"failed to open directory"};
		}

		struct stat st;
		if (::fstat(m_fd, &st) == -1) {
			throw std::system_error{errno, std::system_category(),
				"failed to get directory status"};
		}

		m_bufsz = detail::rumpot(st.st_size, st.st_blksize);
		m_buf = std::unique_ptr<char[]>{new char[m_bufsz]};

		// We do not want to copy the null character, so we only copy
		// until dir + dir_len rather than dir + dir_len + 1.
		boost::copy(dir, m_path_buf.data());
		m_path_buf[m_dir_len] = PLATFORM_DIRECTORY_SEPARATOR;
		read_chunk();
	}
Пример #4
0
int list_modules(
	const boost::string_ref prog,
	const boost::string_ref desc
)
{
	if (desc.length() > 0) {
		println("Suite ${quote}: $.", get_suite(prog), desc);
	}
	else {
		println("Suite ${quote}.", get_suite(prog));
	}

	for (const auto& m : module_list{}) {
		if (m.description().length() > 0) {
			println("Module ${quote}: $.", m.name(), m.description());
		}
		else {
			println("Module ${quote}.", m.name(), m.description());
		}
	}
	return EXIT_SUCCESS;
}
Пример #5
0
	/*
	** Updates the current file at the end of the directory path string.
	*/
	void update_path(const boost::string_ref filename)
	const noexcept
	{
		boost::copy(filename, m_path_buf.data() + m_dir_len + 1);
		m_path_len = m_dir_len + filename.length();
	}
Пример #6
0
	/*
	** After this method is called, we must iteratively test each character
	** of `s` beginning at `s[j]` to check whether it matches the characters
	** after the wildcards beginning at `m_pat[i - 1]`.
	*/
	bool match_wildcard(const boost::string_ref s, unsigned i, unsigned j)
	const noexcept
	{
		/*
		** We keep track of the index `pi` after each wildcard that we
		** are trying to match, and the index `pj` into `s` at which we
		** are looking for a match. If the characters after the wildcard
		** fail to match the string beginning at `s[j]`, then we reset
		** `i` to `pi` and `j` to `pj`.
		*/

		// First index of current subpattern for which we are looking
		// for a match. A subpattern is a pattern between a wildcard and
		// another wildcard or null character.
		auto pi = i;
		// Current index at which we are looking for a match.
		auto pj = j;

		while (s[j] != '\0') switch (m_pat[i]) {
			default:
				if (m_pat[i] != s[j]) {
					++pj;
					i = pi;
					j = pj;
					continue;
				}
				else {
					++i;
					++j;
					continue;
				}
			case '*':
				++i;
				pi = i;
				pj = j;
				continue;
			case '?':
				++i;
				++j;
				continue;
			case '[':
				++i;
				if (!match_group(s, i, j)) {
					++pj;
					i = pi;
					j = pj;
				}
				continue;
			case '\\':
				/*
				** If we increment `i` by one, then we will
				** interpret the following escaped character as
				** a special character at the next iteration. To
				** prevent this, we must anticipate what should
				** happen in the next iteration.
				*/
				if (m_pat[i + 1] != s[j]) {
					++pj;
					i = pi;
					j = pj;
					continue;
				}
				else {
					i += 2;
					++j;
					continue;
				}
		}
		return i == m_pat.length();
	}
Пример #7
0
 format_intrusive_result format_value(boost::string_ref value)
 {
     return format_intrusive_result(value.data(), value.length());
 }