1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22 #include <precomp.h>
23 #include <toolkit/out_position.hxx>
24
25
26 // NOT FULLY DEFINED SERVICES
27
28
29
30 namespace output
31 {
32
33
34
35 namespace
36 {
37
38 const int C_nAssumedMaxLinkLength = 500;
39
40 void move_ToParent(
41 Node * & io_node,
42 intt i_levels = 1 );
43
44 void
move_ToParent(Node * & io_node,intt i_levels)45 move_ToParent( Node * & io_node,
46 intt i_levels )
47 {
48 for ( intt n = 0; n < i_levels; ++n )
49 {
50 csv_assert(io_node != 0);
51 io_node = io_node->Parent();
52 }
53 }
54
55
56
57 } // namepace anonymous
58
59
60
Position()61 Position::Position()
62 : sFile(),
63 pDirectory(&Node::Null_())
64 {
65 }
66
67
Position(Node & i_directory,const String & i_file)68 Position::Position( Node & i_directory,
69 const String & i_file )
70 : sFile(i_file),
71 pDirectory(&i_directory)
72 {
73 }
74
Position(const Position & i_directory,const String & i_sDifferentFile)75 Position::Position( const Position & i_directory,
76 const String & i_sDifferentFile )
77 : sFile(i_sDifferentFile),
78 pDirectory(i_directory.pDirectory)
79 {
80 }
81
82
~Position()83 Position::~Position()
84 {
85 }
86
87
88 Position &
operator =(Node & i_node)89 Position::operator=( Node & i_node )
90 {
91 pDirectory = &i_node;
92 sFile.clear();
93 return *this;
94 }
95
96 Position &
operator +=(const String & i_nodeName)97 Position::operator+=( const String & i_nodeName )
98 {
99 csv_assert(pDirectory != 0);
100
101 pDirectory = &pDirectory->Provide_Child(i_nodeName);
102 sFile.clear();
103
104 return *this;
105 }
106
107 Position &
operator -=(intt i_levels)108 Position::operator-=( intt i_levels )
109 {
110 csv_assert(pDirectory != 0);
111
112 for ( intt i = i_levels; i > 0; --i )
113 {
114 pDirectory = pDirectory->Parent();
115 if (pDirectory == 0)
116 {
117 pDirectory = &Node::Null_();
118 i = 0;
119 }
120 }
121 sFile.clear();
122
123 return *this;
124 }
125
126 String
LinkToRoot(const String &) const127 Position::LinkToRoot( const String & ) const
128 {
129 StreamLock sl(C_nAssumedMaxLinkLength);
130 return sl() << get_UpLink(Depth()) << c_str;
131 }
132
133 void
Get_LinkTo(StreamStr & o_result,const Position & i_destination,const String & i_localLabel) const134 Position::Get_LinkTo( StreamStr & o_result,
135 const Position & i_destination,
136 const String & i_localLabel ) const
137 {
138 Node * p1 = pDirectory;
139 Node * p2 = i_destination.pDirectory;
140
141 intt diff = Depth() - i_destination.Depth();
142 intt pathLength1 = 0;
143 intt pathLength2 = 0;
144
145 if ( diff > 0 )
146 {
147 pathLength1 = diff;
148 move_ToParent(p1,pathLength1);
149 }
150 else if ( diff < 0 )
151 {
152 pathLength2 = -diff;
153 move_ToParent(p2,pathLength2);
154 }
155
156 while ( p1 != p2 )
157 {
158 move_ToParent(p1);
159 move_ToParent(p2);
160 ++pathLength1;
161 ++pathLength2;
162 }
163
164 o_result << get_UpLink(pathLength1);
165 i_destination.pDirectory->Get_Path(o_result, pathLength2);
166 o_result << i_destination.sFile;
167 if (i_localLabel.length())
168 o_result << "#" << i_localLabel;
169 }
170
171 void
Get_LinkToRoot(StreamStr & o_result,const String &) const172 Position::Get_LinkToRoot( StreamStr & o_result,
173 const String & ) const
174 {
175 o_result << get_UpLink(Depth());
176 }
177
178 void
Set(Node & i_node,const String & i_file)179 Position::Set( Node & i_node,
180 const String & i_file )
181 {
182 sFile = i_file;
183 pDirectory = &i_node;
184 }
185
186
187
188
189 const char *
get_UpLink(uintt i_depth)190 get_UpLink(uintt i_depth)
191 {
192 static const uintt
193 C_nMaxDepth = 30;
194 static const char
195 C_sUpLinkArray[3*C_nMaxDepth+1] =
196 "../../../../../../../../../../"
197 "../../../../../../../../../../"
198 "../../../../../../../../../../";
199 static const char *
200 C_sUpLink = &C_sUpLinkArray[0];
201
202 if ( i_depth <= C_nMaxDepth )
203 {
204 return C_sUpLink + 3*(C_nMaxDepth - i_depth);
205 }
206 else
207 { // not THREAD fast
208 static std::vector<char>
209 aRet;
210 uintt nNeededSize = i_depth * 3 + 1;
211
212 if (aRet.size() < nNeededSize)
213 {
214 aRet.resize(nNeededSize);
215 char * pEnd = &aRet[nNeededSize-1];
216 *pEnd = '\0';
217
218 for ( char * pFill = &(*aRet.begin());
219 pFill != pEnd;
220 pFill += 3 )
221 {
222 memcpy(pFill, C_sUpLink, 3);
223 }
224 } // end if
225
226 return &aRet[aRet.size() - 1 - 3*i_depth];
227 }
228 }
229
230
231
232
233 } // namespace output
234