1*11c03c6dSDamjan Jovanovic /************************************************************** 2*11c03c6dSDamjan Jovanovic * 3*11c03c6dSDamjan Jovanovic * Licensed to the Apache Software Foundation (ASF) under one 4*11c03c6dSDamjan Jovanovic * or more contributor license agreements. See the NOTICE file 5*11c03c6dSDamjan Jovanovic * distributed with this work for additional information 6*11c03c6dSDamjan Jovanovic * regarding copyright ownership. The ASF licenses this file 7*11c03c6dSDamjan Jovanovic * to you under the Apache License, Version 2.0 (the 8*11c03c6dSDamjan Jovanovic * "License"); you may not use this file except in compliance 9*11c03c6dSDamjan Jovanovic * with the License. You may obtain a copy of the License at 10*11c03c6dSDamjan Jovanovic * 11*11c03c6dSDamjan Jovanovic * http://www.apache.org/licenses/LICENSE-2.0 12*11c03c6dSDamjan Jovanovic * 13*11c03c6dSDamjan Jovanovic * Unless required by applicable law or agreed to in writing, 14*11c03c6dSDamjan Jovanovic * software distributed under the License is distributed on an 15*11c03c6dSDamjan Jovanovic * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*11c03c6dSDamjan Jovanovic * KIND, either express or implied. See the License for the 17*11c03c6dSDamjan Jovanovic * specific language governing permissions and limitations 18*11c03c6dSDamjan Jovanovic * under the License. 19*11c03c6dSDamjan Jovanovic * 20*11c03c6dSDamjan Jovanovic *************************************************************/ 21*11c03c6dSDamjan Jovanovic 22*11c03c6dSDamjan Jovanovic 23*11c03c6dSDamjan Jovanovic 24*11c03c6dSDamjan Jovanovic #include <precomp.h> 25*11c03c6dSDamjan Jovanovic #include <cosv/ploc_dir.hxx> 26*11c03c6dSDamjan Jovanovic 27*11c03c6dSDamjan Jovanovic // NOT FULLY DECLARED SERVICES 28*11c03c6dSDamjan Jovanovic #include <cosv/ploc.hxx> 29*11c03c6dSDamjan Jovanovic 30*11c03c6dSDamjan Jovanovic 31*11c03c6dSDamjan Jovanovic namespace csv 32*11c03c6dSDamjan Jovanovic { 33*11c03c6dSDamjan Jovanovic namespace ploc 34*11c03c6dSDamjan Jovanovic { 35*11c03c6dSDamjan Jovanovic 36*11c03c6dSDamjan Jovanovic Directory::Directory() 37*11c03c6dSDamjan Jovanovic { 38*11c03c6dSDamjan Jovanovic } 39*11c03c6dSDamjan Jovanovic 40*11c03c6dSDamjan Jovanovic Directory::Directory( const Path & i_rPath ) 41*11c03c6dSDamjan Jovanovic : aPath(i_rPath) 42*11c03c6dSDamjan Jovanovic // sPath 43*11c03c6dSDamjan Jovanovic { 44*11c03c6dSDamjan Jovanovic } 45*11c03c6dSDamjan Jovanovic 46*11c03c6dSDamjan Jovanovic Directory::Directory( const Directory & i_rDir ) 47*11c03c6dSDamjan Jovanovic : Persistent(), aPath(i_rDir.aPath) 48*11c03c6dSDamjan Jovanovic // sPath 49*11c03c6dSDamjan Jovanovic { 50*11c03c6dSDamjan Jovanovic } 51*11c03c6dSDamjan Jovanovic 52*11c03c6dSDamjan Jovanovic Directory::Directory( const char * i_rLocation ) 53*11c03c6dSDamjan Jovanovic : aPath(i_rLocation, true) 54*11c03c6dSDamjan Jovanovic { 55*11c03c6dSDamjan Jovanovic } 56*11c03c6dSDamjan Jovanovic 57*11c03c6dSDamjan Jovanovic Directory::Directory( const String & i_rLocation ) 58*11c03c6dSDamjan Jovanovic : aPath(i_rLocation.c_str(), true) 59*11c03c6dSDamjan Jovanovic { 60*11c03c6dSDamjan Jovanovic } 61*11c03c6dSDamjan Jovanovic 62*11c03c6dSDamjan Jovanovic Directory::~Directory() 63*11c03c6dSDamjan Jovanovic { 64*11c03c6dSDamjan Jovanovic } 65*11c03c6dSDamjan Jovanovic 66*11c03c6dSDamjan Jovanovic Directory & 67*11c03c6dSDamjan Jovanovic Directory::operator+=( const String & i_sName ) 68*11c03c6dSDamjan Jovanovic { 69*11c03c6dSDamjan Jovanovic InvalidatePath(); 70*11c03c6dSDamjan Jovanovic aPath.DirChain() += i_sName; 71*11c03c6dSDamjan Jovanovic return *this; 72*11c03c6dSDamjan Jovanovic } 73*11c03c6dSDamjan Jovanovic 74*11c03c6dSDamjan Jovanovic Directory & 75*11c03c6dSDamjan Jovanovic Directory::operator+=( const DirectoryChain & i_sDirChain ) 76*11c03c6dSDamjan Jovanovic { 77*11c03c6dSDamjan Jovanovic InvalidatePath(); 78*11c03c6dSDamjan Jovanovic aPath.DirChain() += i_sDirChain; 79*11c03c6dSDamjan Jovanovic return *this; 80*11c03c6dSDamjan Jovanovic } 81*11c03c6dSDamjan Jovanovic 82*11c03c6dSDamjan Jovanovic Directory & 83*11c03c6dSDamjan Jovanovic Directory::operator-=( uintt i_nLevels ) 84*11c03c6dSDamjan Jovanovic { 85*11c03c6dSDamjan Jovanovic InvalidatePath(); 86*11c03c6dSDamjan Jovanovic aPath.DirChain().PopBack(i_nLevels); 87*11c03c6dSDamjan Jovanovic return *this; 88*11c03c6dSDamjan Jovanovic } 89*11c03c6dSDamjan Jovanovic 90*11c03c6dSDamjan Jovanovic bool 91*11c03c6dSDamjan Jovanovic Directory::PhysicalCreate( bool i_bCreateParentsIfNecessary ) const 92*11c03c6dSDamjan Jovanovic { 93*11c03c6dSDamjan Jovanovic bool ret = PhysicalCreate_Dir( StrPath() ); 94*11c03c6dSDamjan Jovanovic if ( ret OR NOT i_bCreateParentsIfNecessary ) 95*11c03c6dSDamjan Jovanovic return ret; 96*11c03c6dSDamjan Jovanovic 97*11c03c6dSDamjan Jovanovic ret = Check_Parent(); 98*11c03c6dSDamjan Jovanovic if (ret) 99*11c03c6dSDamjan Jovanovic ret = PhysicalCreate_Dir( StrPath() ); 100*11c03c6dSDamjan Jovanovic return ret; 101*11c03c6dSDamjan Jovanovic } 102*11c03c6dSDamjan Jovanovic 103*11c03c6dSDamjan Jovanovic bool 104*11c03c6dSDamjan Jovanovic Directory::Check_Parent() const 105*11c03c6dSDamjan Jovanovic { 106*11c03c6dSDamjan Jovanovic // There is no parent of root directories: 107*11c03c6dSDamjan Jovanovic if ( aPath.DirChain().Size() == 0 ) 108*11c03c6dSDamjan Jovanovic return false; 109*11c03c6dSDamjan Jovanovic 110*11c03c6dSDamjan Jovanovic // Become my own parent: 111*11c03c6dSDamjan Jovanovic String sLastToken = aPath.DirChain().Back(); 112*11c03c6dSDamjan Jovanovic const_cast< Directory* >(this)->operator-=(1); 113*11c03c6dSDamjan Jovanovic 114*11c03c6dSDamjan Jovanovic // Begin behaving as parent: 115*11c03c6dSDamjan Jovanovic bool ret = Exists(); 116*11c03c6dSDamjan Jovanovic if (NOT ret) 117*11c03c6dSDamjan Jovanovic { 118*11c03c6dSDamjan Jovanovic ret = Check_Parent(); 119*11c03c6dSDamjan Jovanovic if (ret) 120*11c03c6dSDamjan Jovanovic ret = PhysicalCreate_Dir( StrPath() ); 121*11c03c6dSDamjan Jovanovic } 122*11c03c6dSDamjan Jovanovic // End behaving as parent. 123*11c03c6dSDamjan Jovanovic 124*11c03c6dSDamjan Jovanovic // Become myself again: 125*11c03c6dSDamjan Jovanovic const_cast< Directory* >(this)->operator+=(sLastToken); 126*11c03c6dSDamjan Jovanovic return ret; 127*11c03c6dSDamjan Jovanovic } 128*11c03c6dSDamjan Jovanovic 129*11c03c6dSDamjan Jovanovic } // namespace ploc 130*11c03c6dSDamjan Jovanovic } // namespace csv 131*11c03c6dSDamjan Jovanovic 132*11c03c6dSDamjan Jovanovic 133*11c03c6dSDamjan Jovanovic #ifdef WNT 134*11c03c6dSDamjan Jovanovic #include <direct.h> 135*11c03c6dSDamjan Jovanovic #include <io.h> 136*11c03c6dSDamjan Jovanovic 137*11c03c6dSDamjan Jovanovic namespace csv 138*11c03c6dSDamjan Jovanovic { 139*11c03c6dSDamjan Jovanovic namespace ploc 140*11c03c6dSDamjan Jovanovic { 141*11c03c6dSDamjan Jovanovic 142*11c03c6dSDamjan Jovanovic bool 143*11c03c6dSDamjan Jovanovic Directory::PhysicalCreate_Dir( const char * i_sStr ) const 144*11c03c6dSDamjan Jovanovic { 145*11c03c6dSDamjan Jovanovic return mkdir( i_sStr ) == 0; 146*11c03c6dSDamjan Jovanovic } 147*11c03c6dSDamjan Jovanovic 148*11c03c6dSDamjan Jovanovic void 149*11c03c6dSDamjan Jovanovic Directory::GetContainedDirectories( StringVector & o_rResult ) const 150*11c03c6dSDamjan Jovanovic { 151*11c03c6dSDamjan Jovanovic const char * c_sANYDIR = "\\*.*"; 152*11c03c6dSDamjan Jovanovic String sNew; 153*11c03c6dSDamjan Jovanovic 154*11c03c6dSDamjan Jovanovic StreamStr sFilter(200); 155*11c03c6dSDamjan Jovanovic sFilter << StrPath() 156*11c03c6dSDamjan Jovanovic << c_sANYDIR; 157*11c03c6dSDamjan Jovanovic 158*11c03c6dSDamjan Jovanovic struct _finddata_t 159*11c03c6dSDamjan Jovanovic aEntry; 160*11c03c6dSDamjan Jovanovic long hFile = _findfirst( sFilter.c_str(), &aEntry ); 161*11c03c6dSDamjan Jovanovic 162*11c03c6dSDamjan Jovanovic for ( int bFindMore = (hFile == -1 ? 1 : 0); 163*11c03c6dSDamjan Jovanovic bFindMore == 0; 164*11c03c6dSDamjan Jovanovic bFindMore = _findnext( hFile, &aEntry ) ) 165*11c03c6dSDamjan Jovanovic { 166*11c03c6dSDamjan Jovanovic if ( (aEntry.attrib & _A_SUBDIR) AND *aEntry.name != '.' ) 167*11c03c6dSDamjan Jovanovic { 168*11c03c6dSDamjan Jovanovic sNew = aEntry.name; 169*11c03c6dSDamjan Jovanovic o_rResult.push_back( sNew ); 170*11c03c6dSDamjan Jovanovic } 171*11c03c6dSDamjan Jovanovic } // end for 172*11c03c6dSDamjan Jovanovic _findclose(hFile); 173*11c03c6dSDamjan Jovanovic } 174*11c03c6dSDamjan Jovanovic 175*11c03c6dSDamjan Jovanovic void 176*11c03c6dSDamjan Jovanovic Directory::GetContainedFiles( StringVector & o_rResult, 177*11c03c6dSDamjan Jovanovic const char * i_sFilter, 178*11c03c6dSDamjan Jovanovic E_Recursivity i_eRecursivity ) const 179*11c03c6dSDamjan Jovanovic { 180*11c03c6dSDamjan Jovanovic StreamStr sNew(240); 181*11c03c6dSDamjan Jovanovic sNew << aPath; 182*11c03c6dSDamjan Jovanovic StreamStr::size_type 183*11c03c6dSDamjan Jovanovic nStartFilename = sNew.tellp(); 184*11c03c6dSDamjan Jovanovic 185*11c03c6dSDamjan Jovanovic StreamStr sFilter(200); 186*11c03c6dSDamjan Jovanovic sFilter << StrPath() 187*11c03c6dSDamjan Jovanovic << "\\" 188*11c03c6dSDamjan Jovanovic << i_sFilter; 189*11c03c6dSDamjan Jovanovic 190*11c03c6dSDamjan Jovanovic struct _finddata_t 191*11c03c6dSDamjan Jovanovic aEntry; 192*11c03c6dSDamjan Jovanovic long hFile = _findfirst( sFilter.c_str(), &aEntry ); 193*11c03c6dSDamjan Jovanovic for ( int bFindMore = (hFile == -1 ? 1 : 0); 194*11c03c6dSDamjan Jovanovic bFindMore == 0; 195*11c03c6dSDamjan Jovanovic bFindMore = _findnext( hFile, &aEntry ) ) 196*11c03c6dSDamjan Jovanovic { 197*11c03c6dSDamjan Jovanovic sNew.seekp(nStartFilename); 198*11c03c6dSDamjan Jovanovic sNew << aEntry.name; 199*11c03c6dSDamjan Jovanovic String sNewAsString( sNew.c_str() ); 200*11c03c6dSDamjan Jovanovic o_rResult.push_back(sNewAsString); 201*11c03c6dSDamjan Jovanovic } // end for 202*11c03c6dSDamjan Jovanovic 203*11c03c6dSDamjan Jovanovic _findclose(hFile); 204*11c03c6dSDamjan Jovanovic if ( i_eRecursivity == flat ) 205*11c03c6dSDamjan Jovanovic return; 206*11c03c6dSDamjan Jovanovic 207*11c03c6dSDamjan Jovanovic // gathering from subdirectories: 208*11c03c6dSDamjan Jovanovic StringVector aSubDirectories; 209*11c03c6dSDamjan Jovanovic GetContainedDirectories( aSubDirectories ); 210*11c03c6dSDamjan Jovanovic 211*11c03c6dSDamjan Jovanovic StringVector::const_iterator dEnd = aSubDirectories.end(); 212*11c03c6dSDamjan Jovanovic for ( StringVector::const_iterator d = aSubDirectories.begin(); 213*11c03c6dSDamjan Jovanovic d != dEnd; 214*11c03c6dSDamjan Jovanovic ++d ) 215*11c03c6dSDamjan Jovanovic { 216*11c03c6dSDamjan Jovanovic Directory aSub(*this); 217*11c03c6dSDamjan Jovanovic aSub += *d; 218*11c03c6dSDamjan Jovanovic aSub.GetContainedFiles( o_rResult, 219*11c03c6dSDamjan Jovanovic i_sFilter, 220*11c03c6dSDamjan Jovanovic i_eRecursivity ); 221*11c03c6dSDamjan Jovanovic } 222*11c03c6dSDamjan Jovanovic } 223*11c03c6dSDamjan Jovanovic 224*11c03c6dSDamjan Jovanovic } // namespace ploc 225*11c03c6dSDamjan Jovanovic } // namespace csv 226*11c03c6dSDamjan Jovanovic 227*11c03c6dSDamjan Jovanovic 228*11c03c6dSDamjan Jovanovic #elif defined(UNX) 229*11c03c6dSDamjan Jovanovic #include <sys/types.h> 230*11c03c6dSDamjan Jovanovic #include <sys/stat.h> 231*11c03c6dSDamjan Jovanovic #include <dirent.h> 232*11c03c6dSDamjan Jovanovic 233*11c03c6dSDamjan Jovanovic namespace csv 234*11c03c6dSDamjan Jovanovic { 235*11c03c6dSDamjan Jovanovic namespace ploc 236*11c03c6dSDamjan Jovanovic { 237*11c03c6dSDamjan Jovanovic 238*11c03c6dSDamjan Jovanovic bool 239*11c03c6dSDamjan Jovanovic Directory::PhysicalCreate_Dir( const char * i_sStr ) const 240*11c03c6dSDamjan Jovanovic { 241*11c03c6dSDamjan Jovanovic return mkdir( i_sStr, 00777 ) == 0; 242*11c03c6dSDamjan Jovanovic } 243*11c03c6dSDamjan Jovanovic 244*11c03c6dSDamjan Jovanovic void 245*11c03c6dSDamjan Jovanovic Directory::GetContainedDirectories( StringVector & o_rResult ) const 246*11c03c6dSDamjan Jovanovic { 247*11c03c6dSDamjan Jovanovic StreamStr sNew(240); 248*11c03c6dSDamjan Jovanovic sNew << aPath; 249*11c03c6dSDamjan Jovanovic StreamStr::size_type 250*11c03c6dSDamjan Jovanovic nStartFilename = sNew.tellp(); 251*11c03c6dSDamjan Jovanovic 252*11c03c6dSDamjan Jovanovic DIR * pDir = opendir( StrPath() ); 253*11c03c6dSDamjan Jovanovic dirent * pEntry = 0; 254*11c03c6dSDamjan Jovanovic struct stat aEntryStatus; 255*11c03c6dSDamjan Jovanovic 256*11c03c6dSDamjan Jovanovic while ( (pEntry = readdir(pDir)) != 0 ) 257*11c03c6dSDamjan Jovanovic { 258*11c03c6dSDamjan Jovanovic sNew.seekp(nStartFilename); 259*11c03c6dSDamjan Jovanovic sNew << pEntry->d_name; 260*11c03c6dSDamjan Jovanovic 261*11c03c6dSDamjan Jovanovic stat(sNew.c_str(), &aEntryStatus); 262*11c03c6dSDamjan Jovanovic if ( (aEntryStatus.st_mode & S_IFDIR) == S_IFDIR 263*11c03c6dSDamjan Jovanovic AND *pEntry->d_name != '.' ) 264*11c03c6dSDamjan Jovanovic { 265*11c03c6dSDamjan Jovanovic String sNew2(pEntry->d_name); 266*11c03c6dSDamjan Jovanovic o_rResult.push_back(sNew2); 267*11c03c6dSDamjan Jovanovic } // endif (aEntry.attrib == _A_SUBDIR) 268*11c03c6dSDamjan Jovanovic } // end while 269*11c03c6dSDamjan Jovanovic closedir( pDir ); 270*11c03c6dSDamjan Jovanovic } 271*11c03c6dSDamjan Jovanovic 272*11c03c6dSDamjan Jovanovic void 273*11c03c6dSDamjan Jovanovic Directory::GetContainedFiles( StringVector & o_rResult, 274*11c03c6dSDamjan Jovanovic const char * i_sFilter, 275*11c03c6dSDamjan Jovanovic E_Recursivity i_eRecursivity ) const 276*11c03c6dSDamjan Jovanovic { 277*11c03c6dSDamjan Jovanovic StreamStr sNew(240); 278*11c03c6dSDamjan Jovanovic sNew << aPath; 279*11c03c6dSDamjan Jovanovic StreamStr::size_type 280*11c03c6dSDamjan Jovanovic nStartFilename = sNew.tellp(); 281*11c03c6dSDamjan Jovanovic 282*11c03c6dSDamjan Jovanovic bool bUseFilter = strcmp( i_sFilter, "*.*" ) != 0 283*11c03c6dSDamjan Jovanovic AND strncmp( i_sFilter, "*.", 2) == 0; 284*11c03c6dSDamjan Jovanovic 285*11c03c6dSDamjan Jovanovic DIR * pDir = opendir( StrPath() ); 286*11c03c6dSDamjan Jovanovic dirent * pEntry = 0; 287*11c03c6dSDamjan Jovanovic struct stat aEntryStatus; 288*11c03c6dSDamjan Jovanovic 289*11c03c6dSDamjan Jovanovic while ( (pEntry = readdir(pDir)) != 0 ) 290*11c03c6dSDamjan Jovanovic { 291*11c03c6dSDamjan Jovanovic sNew.seekp(nStartFilename); 292*11c03c6dSDamjan Jovanovic sNew << pEntry->d_name; 293*11c03c6dSDamjan Jovanovic 294*11c03c6dSDamjan Jovanovic stat(sNew.c_str(), &aEntryStatus); 295*11c03c6dSDamjan Jovanovic if ( (aEntryStatus.st_mode & S_IFDIR) == S_IFDIR ) 296*11c03c6dSDamjan Jovanovic continue; // Don't gather directories. 297*11c03c6dSDamjan Jovanovic 298*11c03c6dSDamjan Jovanovic if ( bUseFilter ) 299*11c03c6dSDamjan Jovanovic { 300*11c03c6dSDamjan Jovanovic const char * pEnding = strrchr(pEntry->d_name,'.'); 301*11c03c6dSDamjan Jovanovic if (pEnding == 0) 302*11c03c6dSDamjan Jovanovic continue; 303*11c03c6dSDamjan Jovanovic if ( strcasecmp( pEnding + 1, i_sFilter + 2 ) != 0 ) 304*11c03c6dSDamjan Jovanovic continue; 305*11c03c6dSDamjan Jovanovic } 306*11c03c6dSDamjan Jovanovic 307*11c03c6dSDamjan Jovanovic sNew.seekp(nStartFilename); 308*11c03c6dSDamjan Jovanovic sNew << pEntry->d_name; 309*11c03c6dSDamjan Jovanovic String sNewAsString( sNew.c_str() ); 310*11c03c6dSDamjan Jovanovic o_rResult.push_back(sNewAsString); 311*11c03c6dSDamjan Jovanovic } // end while 312*11c03c6dSDamjan Jovanovic 313*11c03c6dSDamjan Jovanovic closedir( pDir ); 314*11c03c6dSDamjan Jovanovic if ( i_eRecursivity == flat ) 315*11c03c6dSDamjan Jovanovic return; 316*11c03c6dSDamjan Jovanovic 317*11c03c6dSDamjan Jovanovic // gathering from subdirectories: 318*11c03c6dSDamjan Jovanovic StringVector aSubDirectories; 319*11c03c6dSDamjan Jovanovic GetContainedDirectories( aSubDirectories ); 320*11c03c6dSDamjan Jovanovic 321*11c03c6dSDamjan Jovanovic StringVector::const_iterator dEnd = aSubDirectories.end(); 322*11c03c6dSDamjan Jovanovic for ( StringVector::const_iterator d = aSubDirectories.begin(); 323*11c03c6dSDamjan Jovanovic d != dEnd; 324*11c03c6dSDamjan Jovanovic ++d ) 325*11c03c6dSDamjan Jovanovic { 326*11c03c6dSDamjan Jovanovic Directory aSub(*this); 327*11c03c6dSDamjan Jovanovic aSub += *d; 328*11c03c6dSDamjan Jovanovic aSub.GetContainedFiles( o_rResult, 329*11c03c6dSDamjan Jovanovic i_sFilter, 330*11c03c6dSDamjan Jovanovic i_eRecursivity ); 331*11c03c6dSDamjan Jovanovic } 332*11c03c6dSDamjan Jovanovic } 333*11c03c6dSDamjan Jovanovic 334*11c03c6dSDamjan Jovanovic } // namespace ploc 335*11c03c6dSDamjan Jovanovic } // namespace csv 336*11c03c6dSDamjan Jovanovic 337*11c03c6dSDamjan Jovanovic 338*11c03c6dSDamjan Jovanovic #else 339*11c03c6dSDamjan Jovanovic #error For using csv::ploc there has to be defined: WNT or UNX. 340*11c03c6dSDamjan Jovanovic #endif 341*11c03c6dSDamjan Jovanovic 342*11c03c6dSDamjan Jovanovic 343*11c03c6dSDamjan Jovanovic namespace csv 344*11c03c6dSDamjan Jovanovic { 345*11c03c6dSDamjan Jovanovic namespace ploc 346*11c03c6dSDamjan Jovanovic { 347*11c03c6dSDamjan Jovanovic 348*11c03c6dSDamjan Jovanovic const Path & 349*11c03c6dSDamjan Jovanovic Directory::inq_MyPath() const 350*11c03c6dSDamjan Jovanovic { 351*11c03c6dSDamjan Jovanovic return aPath; 352*11c03c6dSDamjan Jovanovic } 353*11c03c6dSDamjan Jovanovic 354*11c03c6dSDamjan Jovanovic 355*11c03c6dSDamjan Jovanovic 356*11c03c6dSDamjan Jovanovic } // namespace ploc 357*11c03c6dSDamjan Jovanovic } // namespace csv 358*11c03c6dSDamjan Jovanovic 359*11c03c6dSDamjan Jovanovic 360*11c03c6dSDamjan Jovanovic 361