~thopiekar/zypper/libzypp-manual-import

« back to all changes in this revision

Viewing changes to zypp/Pathname.cc

  • Committer: Thomas-Karl Pietrowski
  • Date: 2014-01-29 22:44:28 UTC
  • Revision ID: thopiekar@googlemail.com-20140129224428-gpcqnsdakby362n8
firstĀ import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*---------------------------------------------------------------------\
 
2
 |                          ____ _   __ __ ___                          |
 
3
 |                         |__  / \ / / . \ . \                         |
 
4
 |                           / / \ V /|  _/  _/                         |
 
5
 |                          / /__ | | | | | |                           |
 
6
 |                         /_____||_| |_| |_|                           |
 
7
 |                                                                      |
 
8
 \---------------------------------------------------------------------*/
 
9
/** \file       zypp/Pathname.cc
 
10
 *
 
11
*/
 
12
#include <iostream>
 
13
 
 
14
#include "zypp/base/String.h"
 
15
#include "zypp/Pathname.h"
 
16
#include "zypp/Url.h"
 
17
 
 
18
using std::string;
 
19
 
 
20
///////////////////////////////////////////////////////////////////
 
21
namespace zypp
 
22
{ /////////////////////////////////////////////////////////////////
 
23
  ///////////////////////////////////////////////////////////////////
 
24
  namespace filesystem
 
25
  { /////////////////////////////////////////////////////////////////
 
26
 
 
27
    ///////////////////////////////////////////////////////////////////
 
28
    //
 
29
    //  METHOD NAME : Pathname::_assign
 
30
    //  METHOD TYPE : void
 
31
    //
 
32
    void Pathname::_assign( const string & name_r )
 
33
    {
 
34
      _name.clear();
 
35
      if ( name_r.empty() )
 
36
        return;
 
37
      _name.reserve( name_r.size() );
 
38
 
 
39
      // Collect up to "/.."
 
40
      enum Pending {
 
41
        P_none  = 0,    // ""
 
42
        P_slash = 1,    // "/"
 
43
        P_dot1  = 2,    // "/."
 
44
        P_dot2  = 3     // "/.."
 
45
      } pending = P_none;
 
46
 
 
47
      // Assert relative path starting with "./"
 
48
      // We rely on this below!
 
49
      if ( name_r[0] != '/' )
 
50
      {
 
51
        _name += '.';
 
52
        pending = P_slash;
 
53
      }
 
54
 
 
55
      // Lambda handling the "/.." case:
 
56
      // []      + "/.."  ==> []
 
57
      // [.]     + "/.."  ==> [./..]
 
58
      // [foo]   is always [./foo] due to init above
 
59
      // [*/..]  + "/.."  ==> [*/../..]
 
60
      // [*/foo] + "/.."  ==> [*]
 
61
      auto goParent_f =  [&](){
 
62
        if ( _name.empty() )
 
63
          /*NOOP*/;
 
64
        else if ( _name.size() == 1 ) // content is '.'
 
65
          _name += "/..";
 
66
        else
 
67
        {
 
68
          std::string::size_type pos = _name.rfind( "/" );
 
69
          if ( pos == _name.size() - 3 && _name[pos+1] == '.' && _name[pos+2] == '.' )
 
70
            _name += "/..";
 
71
          else
 
72
            _name.erase( pos );
 
73
        }
 
74
      };
 
75
 
 
76
      for ( auto ch : name_r )
 
77
      {
 
78
        switch ( ch )
 
79
        {
 
80
          case '/':
 
81
            switch ( pending )
 
82
            {
 
83
              case P_none:      pending = P_slash; break;
 
84
              case P_slash:     break;
 
85
              case P_dot1:      pending = P_slash; break;
 
86
              case P_dot2:      goParent_f(); pending = P_slash; break;
 
87
            }
 
88
            break;
 
89
 
 
90
          case '.':
 
91
            switch ( pending )
 
92
            {
 
93
              case P_none:      _name += '.'; break;
 
94
              case P_slash:     pending = P_dot1; break;
 
95
              case P_dot1:      pending = P_dot2; break;
 
96
              case P_dot2:      _name += "/..."; pending = P_none; break;
 
97
            }
 
98
            break;
 
99
 
 
100
          default:
 
101
            switch ( pending )
 
102
            {
 
103
              case P_none:      break;
 
104
              case P_slash:     _name += '/';    pending = P_none; break;
 
105
              case P_dot1:      _name += "/.";   pending = P_none; break;
 
106
              case P_dot2:      _name += "/.."; pending = P_none; break;
 
107
            }
 
108
            _name += ch;
 
109
            break;
 
110
        }
 
111
      }
 
112
 
 
113
      switch ( pending )
 
114
      {
 
115
        case P_none:    break;
 
116
        case P_slash:   if ( _name.empty() ) _name = "/"; break;
 
117
        case P_dot1:    if ( _name.empty() ) _name = "/"; break;
 
118
        case P_dot2:    goParent_f(); if ( _name.empty() ) _name = "/"; break;
 
119
      }
 
120
      return;
 
121
    }
 
122
 
 
123
    ///////////////////////////////////////////////////////////////////
 
124
    //
 
125
    //  METHOD NAME : Pathname::dirname
 
126
    //  METHOD TYPE : Pathname
 
127
    //
 
128
    Pathname Pathname::dirname( const Pathname & name_r )
 
129
    {
 
130
      if ( name_r.empty() )
 
131
        return Pathname();
 
132
 
 
133
      Pathname ret_t( name_r );
 
134
      string::size_type idx = ret_t._name.find_last_of( '/' );
 
135
 
 
136
      if ( idx == string::npos ) {
 
137
        ret_t._name = ".";
 
138
      } else if ( idx == 0 ) {
 
139
        ret_t._name = "/";
 
140
      } else {
 
141
        ret_t._name.erase( idx );
 
142
      }
 
143
 
 
144
      return ret_t;
 
145
    }
 
146
 
 
147
    ///////////////////////////////////////////////////////////////////
 
148
    //
 
149
    //  METHOD NAME : Pathname::basename
 
150
    //  METHOD TYPE : string
 
151
    //
 
152
    string Pathname::basename( const Pathname & name_r )
 
153
    {
 
154
      if ( name_r.empty() )
 
155
        return string();
 
156
 
 
157
      string ret_t( name_r.asString() );
 
158
      string::size_type idx = ret_t.find_last_of( '/' );
 
159
      if ( idx != string::npos && ( idx != 0 || ret_t.size() != 1 ) ) {
 
160
        ret_t.erase( 0, idx+1 );
 
161
      }
 
162
 
 
163
      return ret_t;
 
164
    }
 
165
 
 
166
    ///////////////////////////////////////////////////////////////////
 
167
    //
 
168
    //  METHOD NAME : Pathname::asUrl
 
169
    //  METHOD TYPE : Url
 
170
    //
 
171
    Url Pathname::asUrl( const std::string & scheme_r ) const
 
172
    {
 
173
      Url ret;
 
174
      ret.setPathName( asString() );
 
175
      ret.setScheme( scheme_r );
 
176
      return ret;
 
177
    }
 
178
 
 
179
    Url Pathname::asUrl() const
 
180
    { return asUrl( "dir" ); }
 
181
 
 
182
    Url Pathname::asDirUrl() const
 
183
    { return asUrl( "dir" ); }
 
184
 
 
185
    Url Pathname::asFileUrl() const
 
186
    { return asUrl( "file" ); }
 
187
 
 
188
 
 
189
    std::string Pathname::showRoot( const Pathname & root_r, const Pathname & path_r )
 
190
    {
 
191
      return str::Str() << "(" << root_r << ")" << path_r;
 
192
    }
 
193
 
 
194
    std::string Pathname::showRootIf( const Pathname & root_r, const Pathname & path_r )
 
195
    {
 
196
      if ( root_r.empty() || root_r == "/" )
 
197
        return path_r.asString();
 
198
      return showRoot( root_r, path_r );
 
199
    }
 
200
 
 
201
    ///////////////////////////////////////////////////////////////////
 
202
    //
 
203
    //  METHOD NAME : Pathname::extension
 
204
    //  METHOD TYPE : string
 
205
    //
 
206
    string Pathname::extension( const Pathname & name_r )
 
207
    {
 
208
      if ( name_r.empty() )
 
209
        return string();
 
210
 
 
211
      string base( basename( name_r ) );
 
212
      string::size_type pos = base.rfind( '.' );
 
213
      switch ( pos )
 
214
      {
 
215
        case 0:
 
216
          if ( base.size() == 1 )                       // .
 
217
            return string();
 
218
          break;
 
219
        case 1:
 
220
          if ( base.size() == 2 && base[0] == '.' )     // ..
 
221
            return string();
 
222
          break;
 
223
        case string::npos:
 
224
          return string();
 
225
          break;
 
226
      }
 
227
      return base.substr( pos );
 
228
    }
 
229
 
 
230
    ///////////////////////////////////////////////////////////////////
 
231
    //
 
232
    //  METHOD NAME : Pathname::assertprefix
 
233
    //  METHOD TYPE : Pathname
 
234
    //
 
235
    Pathname Pathname::assertprefix( const Pathname & root_r, const Pathname & path_r )
 
236
    {
 
237
      if ( root_r.empty()
 
238
           || path_r == root_r
 
239
           || str::hasPrefix( path_r.asString(), root_r.asString() ) )
 
240
        return path_r;
 
241
      return root_r / path_r;
 
242
    }
 
243
 
 
244
    ///////////////////////////////////////////////////////////////////
 
245
    //
 
246
    //  METHOD NAME : Pathname::cat
 
247
    //  METHOD TYPE : Pathname
 
248
    //
 
249
    Pathname Pathname::cat( const Pathname & name_r, const Pathname & add_tv )
 
250
    {
 
251
      if ( add_tv.empty() )
 
252
        return name_r;
 
253
      if ( name_r.empty() )
 
254
        return add_tv;
 
255
 
 
256
      string ret_ti( name_r._name );
 
257
      if( add_tv._name[0] != '/' )
 
258
        ret_ti += '/';
 
259
      return ret_ti + add_tv._name;
 
260
    }
 
261
 
 
262
    ///////////////////////////////////////////////////////////////////
 
263
    //
 
264
    //  METHOD NAME : Pathname::Extend
 
265
    //  METHOD TYPE : Pathname
 
266
    //
 
267
    Pathname Pathname::extend( const Pathname & l, const string & r )
 
268
    {
 
269
      return l.asString() + r;
 
270
    }
 
271
 
 
272
    /////////////////////////////////////////////////////////////////
 
273
  } // namespace filesystem
 
274
  ///////////////////////////////////////////////////////////////////
 
275
  /////////////////////////////////////////////////////////////////
 
276
} // namespace zypp
 
277
///////////////////////////////////////////////////////////////////