monotone

monotone Mtn Source Tree

Root/path_component.cc

1// copyright (C) 2004 graydon hoare <graydon@pobox.com>
2// copyright (C) 2005 nathaniel smith <njs@pobox.com>
3// all rights reserved.
4// licensed to the public under the terms of the GNU GPL (>= 2)
5// see the file COPYING for details
6
7// the idea of this file is that if we're very careful about the functions
8// that are allowed to intern path components, and manipulate them when
9// pulling them out again, then we don't have to do nearly so much sanity
10// checking on them themselves.
11
12// valid path components are:
13// ""
14// anything that's a valid file_path, but is only one element long
15// "MT", which is not a valid file_path, but is a valid path component
16// anyway
17
18// this means that if we _start_ with a valid file_path, we can get valid
19// path_component's by just doing a string split/join on "/". except for
20// noticing MT/, but we'll notice that anyway when reconstructing to a
21// file_path.
22
23#include <string>
24
25#include <boost/filesystem/path.hpp>
26
27#include "path_component.hh"
28#include "interner.hh"
29
30static interner<path_component> pc_interner;
31
32// This function takes a vector of path components and joins them into a
33// single file_path. Valid input may be a single-element vector whose sole
34// element is the empty path component (""); this represents the null path,
35// which we use to represent non-existent files. Alternatively, input may be
36// a multi-element vector, in which case all elements of the vector are
37// required to be non-null. The following are valid inputs (with strings
38// replaced by their interned version, of course):
39// - [""]
40// - ["foo"]
41// - ["foo", "bar"]
42// The following are not:
43// - []
44// - ["foo", ""]
45// - ["", "bar"]
46void
47compose_path(std::vector<path_component> const & names,
48 file_path & path)
49{
50 std::vector<path_component>::const_iterator i = names.begin();
51 I(i != names.end());
52 if (names.size() > 1)
53 I(!null_name(*i));
54 std::string path_str;
55 path_str = pc_interner.lookup(*i);
56 for (++i; i != names.end(); ++i)
57 {
58 I(!null_name(*i));
59 path_str += "/";
60 path_str += pc_interner.lookup(*i);
61 }
62 path = file_path(path_str);
63}
64
65//
66// this takes a path of the form
67//
68// "p[0]/p[1]/.../p[n-1]/p[n]"
69//
70// and fills in a vector of paths corresponding to p[0] ... p[n-1],
71// along with, perhaps, a separate "leaf path" for element p[n].
72//
73// confusingly, perhaps, passing a null path ("") returns a zero-length
74// components vector, rather than a length one vector with a single null
75// component.
76void
77split_path(file_path const & p,
78 std::vector<path_component> & components)
79{
80 components.clear();
81 std::string const & p_str = p();
82 if (p_str.empty())
83 return;
84 std::string::size_type start, stop;
85 start = 0;
86 while (1)
87 {
88 stop = p_str.find('/', start);
89 if (stop < 0 || stop > p_str.length())
90 {
91 components.push_back(pc_interner.intern(p_str.substr(start)));
92 break;
93 }
94 components.push_back(pc_interner.intern(p_str.substr(start, stop - start)));
95 start = stop + 1;
96 }
97}
98
99void
100split_path(file_path const & p,
101 std::vector<path_component> & prefix,
102 path_component & leaf_path)
103{
104 split_path(p, prefix);
105 I(prefix.size() > 0);
106 leaf_path = prefix.back();
107 prefix.pop_back();
108}
109
110path_component
111make_null_component()
112{
113 static path_component null_pc = pc_interner.intern("");
114 return null_pc;
115}
116
117
118#ifdef BUILD_UNIT_TESTS
119#include "unit_tests.hh"
120#include "sanity.hh"
121
122static void
123test_a_roundtrip(std::string const in)
124{
125 file_path old_fp = file_path(in);
126 std::vector<path_component> vec;
127 split_path(old_fp, vec);
128 file_path new_fp;
129 compose_path(vec, new_fp);
130 BOOST_CHECK(old_fp == new_fp);
131}
132
133static void
134roundtrip_tests()
135{
136 test_a_roundtrip("foo");
137 test_a_roundtrip("foo/bar");
138 test_a_roundtrip("foo/MT/bar");
139}
140
141static void
142null_test()
143{
144 std::vector<path_component> vec;
145 split_path(file_path(""), vec);
146 BOOST_CHECK(vec.empty());
147}
148
149void
150add_path_component_tests(test_suite * suite)
151{
152 I(suite);
153 suite->add(BOOST_TEST_CASE(roundtrip_tests));
154 suite->add(BOOST_TEST_CASE(null_test));
155}
156
157#endif // BUILD_UNIT_TESTS

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status