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 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 61 Position::Position() 62 : sFile(), 63 pDirectory(&Node::Null_()) 64 { 65 } 66 67 68 Position::Position( Node & i_directory, 69 const String & i_file ) 70 : sFile(i_file), 71 pDirectory(&i_directory) 72 { 73 } 74 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 83 Position::~Position() 84 { 85 } 86 87 88 Position & 89 Position::operator=( Node & i_node ) 90 { 91 pDirectory = &i_node; 92 sFile.clear(); 93 return *this; 94 } 95 96 Position & 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 & 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 127 Position::LinkToRoot( const String & ) const 128 { 129 StreamLock sl(C_nAssumedMaxLinkLength); 130 return sl() << get_UpLink(Depth()) << c_str; 131 } 132 133 void 134 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 172 Position::Get_LinkToRoot( StreamStr & o_result, 173 const String & ) const 174 { 175 o_result << get_UpLink(Depth()); 176 } 177 178 void 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 * 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