~ubuntu-branches/ubuntu/wily/bombono-dvd/wily

« back to all changes in this revision

Viewing changes to libs/boost-lib/libs/filesystem/v3/src/path.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessio Treglia
  • Date: 2010-11-04 11:46:25 UTC
  • mto: This revision was merged to the branch mainline in revision 8.
  • Revision ID: james.westby@ubuntu.com-20101104114625-8xfdhvhpsm51i0nu
Tags: upstream-0.8.0
ImportĀ upstreamĀ versionĀ 0.8.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//  filesystem path.cpp  -------------------------------------------------------------  //
 
2
 
 
3
//  Copyright Beman Dawes 2008
 
4
 
 
5
//  Distributed under the Boost Software License, Version 1.0.
 
6
//  See http://www.boost.org/LICENSE_1_0.txt
 
7
 
 
8
//  Library home page: http://www.boost.org/libs/filesystem
 
9
 
 
10
#include <boost/config.hpp>
 
11
#if !defined( BOOST_NO_STD_WSTRING )
 
12
// Boost.Filesystem V3 and later requires std::wstring support.
 
13
// During the transition to V3, libraries are compiled with both V2 and V3 sources.
 
14
// On old compilers that don't support V3 anyhow, we just skip everything so the compile
 
15
// will succeed and the library can be built.
 
16
 
 
17
// define BOOST_FILESYSTEM_SOURCE so that <boost/system/config.hpp> knows
 
18
// the library is being built (possibly exporting rather than importing code)
 
19
#define BOOST_FILESYSTEM_SOURCE 
 
20
 
 
21
#ifndef BOOST_SYSTEM_NO_DEPRECATED 
 
22
# define BOOST_SYSTEM_NO_DEPRECATED
 
23
#endif
 
24
 
 
25
#include <boost/filesystem/v3/config.hpp>
 
26
#include <boost/filesystem/v3/path.hpp>
 
27
#include <boost/scoped_array.hpp>
 
28
#include <boost/system/error_code.hpp>
 
29
#include <boost/assert.hpp>
 
30
#include <cstddef>
 
31
#include <cstring>
 
32
#include <cassert>
 
33
 
 
34
#ifdef BOOST_WINDOWS_API
 
35
# include "windows_file_codecvt.hpp"
 
36
# include <windows.h>
 
37
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
 
38
# include <boost/filesystem/detail/utf8_codecvt_facet.hpp>
 
39
#endif
 
40
 
 
41
#ifdef BOOST_FILESYSTEM_DEBUG
 
42
# include <iostream>
 
43
# include <iomanip>
 
44
#endif
 
45
 
 
46
namespace fs = boost::filesystem3;
 
47
 
 
48
using boost::filesystem3::path;
 
49
 
 
50
using std::string;
 
51
using std::wstring;
 
52
 
 
53
using boost::system::error_code;
 
54
 
 
55
#ifndef BOOST_FILESYSTEM_CODECVT_BUF_SIZE
 
56
# define BOOST_FILESYSTEM_CODECVT_BUF_SIZE 256
 
57
#endif
 
58
 
 
59
//--------------------------------------------------------------------------------------//
 
60
//                                                                                      //
 
61
//                                class path helpers                                    //
 
62
//                                                                                      //
 
63
//--------------------------------------------------------------------------------------//
 
64
 
 
65
namespace
 
66
{
 
67
  //------------------------------------------------------------------------------------//
 
68
  //                        miscellaneous class path helpers                            //
 
69
  //------------------------------------------------------------------------------------//
 
70
 
 
71
  typedef path::value_type        value_type;
 
72
  typedef path::string_type       string_type;
 
73
  typedef string_type::size_type  size_type;
 
74
 
 
75
  const std::size_t default_codecvt_buf_size = BOOST_FILESYSTEM_CODECVT_BUF_SIZE;
 
76
 
 
77
# ifdef BOOST_WINDOWS_API
 
78
 
 
79
  const wchar_t separator = L'/';
 
80
  const wchar_t preferred_separator = L'\\';
 
81
  const wchar_t* const separators = L"/\\";
 
82
  const wchar_t* separator_string = L"/";
 
83
  const wchar_t* preferred_separator_string = L"\\";
 
84
  const wchar_t colon = L':';
 
85
  const wchar_t dot = L'.';
 
86
  const fs::path dot_path(L".");
 
87
  const fs::path dot_dot_path(L"..");
 
88
 
 
89
# else
 
90
 
 
91
  const char separator = '/';
 
92
  const char preferred_separator = '/';
 
93
  const char* const separators = "/";
 
94
  const char* separator_string = "/";
 
95
  const char* preferred_separator_string = "/";
 
96
  const char colon = ':';
 
97
  const char dot = '.';
 
98
  const fs::path dot_path(".");
 
99
  const fs::path dot_dot_path("..");
 
100
 
 
101
# endif
 
102
 
 
103
  inline bool is_separator(fs::path::value_type c)
 
104
  {
 
105
    return c == separator
 
106
#     ifdef BOOST_WINDOWS_API
 
107
      || c == preferred_separator
 
108
#     endif
 
109
      ;
 
110
  }
 
111
 
 
112
  bool is_non_root_separator(const string_type& str, size_type pos);
 
113
    // pos is position of the separator
 
114
 
 
115
  size_type filename_pos(const string_type& str,
 
116
                          size_type end_pos); // end_pos is past-the-end position
 
117
  //  Returns: 0 if str itself is filename (or empty)
 
118
 
 
119
  size_type root_directory_start(const string_type& path, size_type size);
 
120
  //  Returns:  npos if no root_directory found
 
121
 
 
122
  void first_element(
 
123
      const string_type& src,
 
124
      size_type& element_pos,
 
125
      size_type& element_size,
 
126
#     if !BOOST_WORKAROUND(BOOST_MSVC, <= 1310) // VC++ 7.1
 
127
      size_type size = string_type::npos
 
128
#     else
 
129
      size_type size = -1
 
130
#     endif
 
131
    );
 
132
 
 
133
}  // unnamed namespace
 
134
 
 
135
//--------------------------------------------------------------------------------------//
 
136
//                                                                                      //
 
137
//                            class path implementation                                 //
 
138
//                                                                                      //
 
139
//--------------------------------------------------------------------------------------//
 
140
 
 
141
namespace boost
 
142
{
 
143
namespace filesystem3
 
144
{
 
145
 
 
146
  path & path::operator/=(const path & p)
 
147
  {
 
148
    if (p.empty())
 
149
      return *this;
 
150
    if (!is_separator(*p.m_pathname.begin()))
 
151
      m_append_separator_if_needed();
 
152
    m_pathname += p.m_pathname;
 
153
    return *this;
 
154
  }
 
155
 
 
156
# ifdef BOOST_WINDOWS_API
 
157
 
 
158
  void path::m_portable()
 
159
  {
 
160
    for (string_type::iterator it = m_pathname.begin();
 
161
          it != m_pathname.end(); ++it)
 
162
    {
 
163
      if (*it == L'\\')
 
164
        *it = L'/';
 
165
    }
 
166
  }
 
167
 
 
168
  const std::string path::generic_string(const codecvt_type& cvt) const
 
169
  { 
 
170
    path tmp(*this);
 
171
    tmp.m_portable();
 
172
    return tmp.string(cvt);
 
173
  }
 
174
 
 
175
  const std::wstring path::generic_wstring() const
 
176
  { 
 
177
    path tmp(*this);
 
178
    tmp.m_portable();
 
179
    return tmp.wstring();
 
180
  }
 
181
 
 
182
# endif  // BOOST_WINDOWS_API
 
183
 
 
184
  //  m_append_separator_if_needed  ----------------------------------------------------//
 
185
 
 
186
  path::string_type::size_type path::m_append_separator_if_needed()
 
187
  {
 
188
    if (!m_pathname.empty() &&
 
189
#     ifdef BOOST_WINDOWS_API
 
190
      *(m_pathname.end()-1) != colon && 
 
191
#     endif
 
192
      !is_separator(*(m_pathname.end()-1)))
 
193
    {
 
194
      string_type::size_type tmp(m_pathname.size());
 
195
      m_pathname += preferred_separator;
 
196
      return tmp;
 
197
    }
 
198
    return 0;
 
199
  }
 
200
 
 
201
  //  m_erase_redundant_separator  -----------------------------------------------------//
 
202
 
 
203
  void path::m_erase_redundant_separator(string_type::size_type sep_pos)
 
204
  {
 
205
    if (sep_pos                         // a separator was added
 
206
      && sep_pos < m_pathname.size()         // and something was appended
 
207
      && (m_pathname[sep_pos+1] == separator // and it was also separator
 
208
#      ifdef BOOST_WINDOWS_API
 
209
       || m_pathname[sep_pos+1] == preferred_separator  // or preferred_separator
 
210
#      endif
 
211
)) { m_pathname.erase(sep_pos, 1); } // erase the added separator
 
212
  }
 
213
 
 
214
  //  modifiers  -----------------------------------------------------------------------//
 
215
 
 
216
# ifdef BOOST_WINDOWS_API
 
217
  path & path::make_preferred()
 
218
  {
 
219
    for (string_type::iterator it = m_pathname.begin();
 
220
          it != m_pathname.end(); ++it)
 
221
    {
 
222
      if (*it == L'/')
 
223
        *it = L'\\';
 
224
    }
 
225
    return *this;
 
226
  }
 
227
# endif
 
228
 
 
229
  path& path::remove_filename()
 
230
  {
 
231
    m_pathname.erase(m_parent_path_end());
 
232
    return *this;
 
233
  }
 
234
 
 
235
  path & path::replace_extension(const path & source)
 
236
  {
 
237
    // erase existing extension if any
 
238
    size_type pos(m_pathname.rfind(dot));
 
239
    if (pos != string_type::npos)
 
240
      m_pathname.erase(pos);
 
241
 
 
242
    // append source extension if any
 
243
    pos = source.m_pathname.rfind(dot);
 
244
    if (pos != string_type::npos)
 
245
      m_pathname += source.c_str() + pos;
 
246
 
 
247
    return *this;
 
248
  }
 
249
 
 
250
  //  decomposition  -------------------------------------------------------------------//
 
251
 
 
252
  path  path::root_path() const
 
253
  { 
 
254
    path temp(root_name());
 
255
    if (!root_directory().empty()) temp.m_pathname += root_directory().c_str();
 
256
    return temp;
 
257
  } 
 
258
 
 
259
  path path::root_name() const
 
260
  {
 
261
    iterator itr(begin());
 
262
 
 
263
    return (itr.m_pos != m_pathname.size()
 
264
      && (
 
265
          (itr.m_element.m_pathname.size() > 1
 
266
            && is_separator(itr.m_element.m_pathname[0])
 
267
            && is_separator(itr.m_element.m_pathname[1])
 
268
   )
 
269
#       ifdef BOOST_WINDOWS_API
 
270
        || itr.m_element.m_pathname[itr.m_element.m_pathname.size()-1] == colon
 
271
#       endif
 
272
  ))
 
273
      ? itr.m_element
 
274
      : path();
 
275
  }
 
276
 
 
277
  path path::root_directory() const
 
278
  {
 
279
    size_type pos(root_directory_start(m_pathname, m_pathname.size()));
 
280
 
 
281
    return pos == string_type::npos
 
282
      ? path()
 
283
      : path(m_pathname.c_str() + pos, m_pathname.c_str() + pos + 1);
 
284
  }
 
285
 
 
286
  path path::relative_path() const
 
287
  {
 
288
    iterator itr(begin());
 
289
 
 
290
    for (; itr.m_pos != m_pathname.size()
 
291
      && (is_separator(itr.m_element.m_pathname[0])
 
292
#     ifdef BOOST_WINDOWS_API
 
293
      || itr.m_element.m_pathname[itr.m_element.m_pathname.size()-1] == colon
 
294
#     endif
 
295
    ); ++itr) {}
 
296
 
 
297
    return path(m_pathname.c_str() + itr.m_pos);
 
298
  }
 
299
 
 
300
  string_type::size_type path::m_parent_path_end() const
 
301
  {
 
302
    size_type end_pos(filename_pos(m_pathname, m_pathname.size()));
 
303
 
 
304
    bool filename_was_separator(m_pathname.size()
 
305
      && is_separator(m_pathname[end_pos]));
 
306
 
 
307
    // skip separators unless root directory
 
308
    size_type root_dir_pos(root_directory_start(m_pathname, end_pos));
 
309
    for (; 
 
310
      end_pos > 0
 
311
      && (end_pos-1) != root_dir_pos
 
312
      && is_separator(m_pathname[end_pos-1])
 
313
      ;
 
314
      --end_pos) {}
 
315
 
 
316
   return (end_pos == 1 && root_dir_pos == 0 && filename_was_separator)
 
317
     ? string_type::npos
 
318
     : end_pos;
 
319
  }
 
320
 
 
321
  path path::parent_path() const
 
322
  {
 
323
   size_type end_pos(m_parent_path_end());
 
324
   return end_pos == string_type::npos
 
325
     ? path()
 
326
     : path(m_pathname.c_str(), m_pathname.c_str() + end_pos);
 
327
  }
 
328
 
 
329
  path path::filename() const
 
330
  {
 
331
    size_type pos(filename_pos(m_pathname, m_pathname.size()));
 
332
    return (m_pathname.size()
 
333
              && pos
 
334
              && is_separator(m_pathname[pos])
 
335
              && is_non_root_separator(m_pathname, pos))
 
336
      ? dot_path
 
337
      : path(m_pathname.c_str() + pos);
 
338
  }
 
339
 
 
340
  path path::stem() const
 
341
  {
 
342
    path name(filename());
 
343
    if (name == dot_path || name == dot_dot_path) return name;
 
344
    size_type pos(name.m_pathname.rfind(dot));
 
345
    return pos == string_type::npos
 
346
      ? name
 
347
      : path(name.m_pathname.c_str(), name.m_pathname.c_str() + pos);
 
348
  }
 
349
 
 
350
  path path::extension() const
 
351
  {
 
352
    path name(filename());
 
353
    if (name == dot_path || name == dot_dot_path) return path();
 
354
    size_type pos(name.m_pathname.rfind(dot));
 
355
    return pos == string_type::npos
 
356
      ? path()
 
357
      : path(name.m_pathname.c_str() + pos);
 
358
  }
 
359
 
 
360
  // m_normalize  ----------------------------------------------------------------------//
 
361
 
 
362
  path& path::m_normalize()
 
363
  {
 
364
    if (m_pathname.empty()) return *this;
 
365
      
 
366
    path temp;
 
367
    iterator start(begin());
 
368
    iterator last(end());
 
369
    iterator stop(last--);
 
370
    for (iterator itr(start); itr != stop; ++itr)
 
371
    {
 
372
      // ignore "." except at start and last
 
373
      if (itr->native().size() == 1
 
374
        && (itr->native())[0] == dot
 
375
        && itr != start
 
376
        && itr != last) continue;
 
377
 
 
378
      // ignore a name and following ".."
 
379
      if (!temp.empty()
 
380
        && itr->native().size() == 2
 
381
        && (itr->native())[0] == dot
 
382
        && (itr->native())[1] == dot) // dot dot
 
383
      {
 
384
        string_type lf(temp.filename().native());  
 
385
        if (lf.size() > 0  
 
386
          && (lf.size() != 1
 
387
            || (lf[0] != dot
 
388
              && lf[0] != separator))
 
389
          && (lf.size() != 2 
 
390
            || (lf[0] != dot
 
391
              && lf[1] != dot
 
392
#             ifdef BOOST_WINDOWS_API
 
393
              && lf[1] != colon
 
394
#             endif
 
395
               )
 
396
             )
 
397
          )
 
398
        {
 
399
          temp.remove_filename();
 
400
          // if not root directory, must also remove "/" if any
 
401
          if (temp.m_pathname.size() > 0
 
402
            && temp.m_pathname[temp.m_pathname.size()-1]
 
403
              == separator)
 
404
          {
 
405
            string_type::size_type rds(
 
406
              root_directory_start(temp.m_pathname, temp.m_pathname.size()));
 
407
            if (rds == string_type::npos
 
408
              || rds != temp.m_pathname.size()-1) 
 
409
              { temp.m_pathname.erase(temp.m_pathname.size()-1); }
 
410
          }
 
411
 
 
412
          iterator next(itr);
 
413
          if (temp.empty() && ++next != stop
 
414
            && next == last && *last == dot_path) temp /= dot_path;
 
415
          continue;
 
416
        }
 
417
      }
 
418
 
 
419
      temp /= *itr;
 
420
    };
 
421
 
 
422
    if (temp.empty()) temp /= dot_path;
 
423
    m_pathname = temp.m_pathname;
 
424
    return *this;
 
425
  }
 
426
 
 
427
}  // namespace filesystem3
 
428
}  // namespace boost
 
429
  
 
430
//--------------------------------------------------------------------------------------//
 
431
//                                                                                      //
 
432
//                         class path helpers implementation                            //
 
433
//                                                                                      //
 
434
//--------------------------------------------------------------------------------------//
 
435
 
 
436
namespace
 
437
{
 
438
 
 
439
  //  is_non_root_separator  -------------------------------------------------//
 
440
 
 
441
  bool is_non_root_separator(const string_type & str, size_type pos)
 
442
    // pos is position of the separator
 
443
  {
 
444
    BOOST_ASSERT(!str.empty() && is_separator(str[pos])
 
445
      && "precondition violation");
 
446
 
 
447
    // subsequent logic expects pos to be for leftmost slash of a set
 
448
    while (pos > 0 && is_separator(str[pos-1]))
 
449
      --pos;
 
450
 
 
451
    return  pos != 0
 
452
      && (pos <= 2 || !is_separator(str[1])
 
453
        || str.find_first_of(separators, 2) != pos)
 
454
#     ifdef BOOST_WINDOWS_API
 
455
      && (pos !=2 || str[1] != colon)
 
456
#     endif
 
457
        ;
 
458
  }
 
459
 
 
460
  //  filename_pos  --------------------------------------------------------------------//
 
461
 
 
462
  size_type filename_pos(const string_type & str,
 
463
                          size_type end_pos) // end_pos is past-the-end position
 
464
    // return 0 if str itself is filename (or empty)
 
465
  {
 
466
    // case: "//"
 
467
    if (end_pos == 2 
 
468
      && is_separator(str[0])
 
469
      && is_separator(str[1])) return 0;
 
470
 
 
471
    // case: ends in "/"
 
472
    if (end_pos && is_separator(str[end_pos-1]))
 
473
      return end_pos-1;
 
474
    
 
475
    // set pos to start of last element
 
476
    size_type pos(str.find_last_of(separators, end_pos-1));
 
477
 
 
478
#   ifdef BOOST_WINDOWS_API
 
479
    if (pos == string_type::npos)
 
480
      pos = str.find_last_of(colon, end_pos-2);
 
481
#   endif
 
482
 
 
483
    return (pos == string_type::npos // path itself must be a filename (or empty)
 
484
      || (pos == 1 && is_separator(str[0]))) // or net
 
485
        ? 0 // so filename is entire string
 
486
        : pos + 1; // or starts after delimiter
 
487
  }
 
488
 
 
489
  //  root_directory_start  ------------------------------------------------------------//
 
490
 
 
491
  size_type root_directory_start(const string_type & path, size_type size)
 
492
  // return npos if no root_directory found
 
493
  {
 
494
 
 
495
#   ifdef BOOST_WINDOWS_API
 
496
    // case "c:/"
 
497
    if (size > 2
 
498
      && path[1] == colon
 
499
      && is_separator(path[2])) return 2;
 
500
#   endif
 
501
 
 
502
    // case "//"
 
503
    if (size == 2
 
504
      && is_separator(path[0])
 
505
      && is_separator(path[1])) return string_type::npos;
 
506
 
 
507
    // case "//net {/}"
 
508
    if (size > 3
 
509
      && is_separator(path[0])
 
510
      && is_separator(path[1])
 
511
      && !is_separator(path[2]))
 
512
    {
 
513
      string_type::size_type pos(path.find_first_of(separators, 2));
 
514
      return pos < size ? pos : string_type::npos;
 
515
    }
 
516
    
 
517
    // case "/"
 
518
    if (size > 0 && is_separator(path[0])) return 0;
 
519
 
 
520
    return string_type::npos;
 
521
  }
 
522
 
 
523
  //  first_element --------------------------------------------------------------------//
 
524
  //   sets pos and len of first element, excluding extra separators
 
525
  //   if src.empty(), sets pos,len, to 0,0.
 
526
 
 
527
  void first_element(
 
528
      const string_type & src,
 
529
      size_type & element_pos,
 
530
      size_type & element_size,
 
531
      size_type size
 
532
)
 
533
  {
 
534
    if (size == string_type::npos) size = src.size();
 
535
    element_pos = 0;
 
536
    element_size = 0;
 
537
    if (src.empty()) return;
 
538
 
 
539
    string_type::size_type cur(0);
 
540
    
 
541
    // deal with // [network]
 
542
    if (size >= 2 && is_separator(src[0])
 
543
      && is_separator(src[1])
 
544
      && (size == 2
 
545
        || !is_separator(src[2])))
 
546
    { 
 
547
      cur += 2;
 
548
      element_size += 2;
 
549
    }
 
550
 
 
551
    // leading (not non-network) separator
 
552
    else if (is_separator(src[0]))
 
553
    {
 
554
      ++element_size;
 
555
      // bypass extra leading separators
 
556
      while (cur+1 < size
 
557
        && is_separator(src[cur+1]))
 
558
      {
 
559
        ++cur;
 
560
        ++element_pos;
 
561
      }
 
562
      return;
 
563
    }
 
564
 
 
565
    // at this point, we have either a plain name, a network name,
 
566
    // or (on Windows only) a device name
 
567
 
 
568
    // find the end
 
569
    while (cur < size
 
570
#     ifdef BOOST_WINDOWS_API
 
571
      && src[cur] != colon
 
572
#     endif
 
573
      && !is_separator(src[cur]))
 
574
    {
 
575
      ++cur;
 
576
      ++element_size;
 
577
    }
 
578
 
 
579
#   ifdef BOOST_WINDOWS_API
 
580
    if (cur == size) return;
 
581
    // include device delimiter
 
582
    if (src[cur] == colon)
 
583
      { ++element_size; }
 
584
#   endif
 
585
 
 
586
    return;
 
587
  }
 
588
 
 
589
}  // unnammed namespace
 
590
 
 
591
//--------------------------------------------------------------------------------------//
 
592
//                                                                                      //
 
593
//                        class path::iterator implementation                           //
 
594
//                                                                                      //
 
595
//--------------------------------------------------------------------------------------//
 
596
 
 
597
namespace boost
 
598
{
 
599
namespace filesystem3
 
600
{
 
601
 
 
602
  path::iterator path::begin() const
 
603
  {
 
604
    iterator itr;
 
605
    itr.m_path_ptr = this;
 
606
    size_type element_size;
 
607
    first_element(m_pathname, itr.m_pos, element_size);
 
608
    itr.m_element = m_pathname.substr(itr.m_pos, element_size);
 
609
    if (itr.m_element.m_pathname == preferred_separator_string)
 
610
      itr.m_element.m_pathname = separator_string;  // needed for Windows, harmless on POSIX
 
611
    return itr;
 
612
  }
 
613
 
 
614
  path::iterator path::end() const
 
615
  {
 
616
    iterator itr;
 
617
    itr.m_path_ptr = this;
 
618
    itr.m_pos = m_pathname.size();
 
619
    return itr;
 
620
  }
 
621
 
 
622
  void path::m_path_iterator_increment(path::iterator & it)
 
623
  {
 
624
    BOOST_ASSERT(it.m_pos < it.m_path_ptr->m_pathname.size() && "path::basic_iterator increment past end()");
 
625
 
 
626
    // increment to position past current element
 
627
    it.m_pos += it.m_element.m_pathname.size();
 
628
 
 
629
    // if end reached, create end basic_iterator
 
630
    if (it.m_pos == it.m_path_ptr->m_pathname.size())
 
631
    {
 
632
      it.m_element.clear(); 
 
633
      return;
 
634
    }
 
635
 
 
636
    // both POSIX and Windows treat paths that begin with exactly two separators specially
 
637
    bool was_net(it.m_element.m_pathname.size() > 2
 
638
      && is_separator(it.m_element.m_pathname[0])
 
639
      && is_separator(it.m_element.m_pathname[1])
 
640
      && !is_separator(it.m_element.m_pathname[2]));
 
641
 
 
642
    // process separator (Windows drive spec is only case not a separator)
 
643
    if (is_separator(it.m_path_ptr->m_pathname[it.m_pos]))
 
644
    {
 
645
      // detect root directory
 
646
      if (was_net
 
647
#       ifdef BOOST_WINDOWS_API
 
648
        // case "c:/"
 
649
        || it.m_element.m_pathname[it.m_element.m_pathname.size()-1] == colon
 
650
#       endif
 
651
         )
 
652
      {
 
653
        it.m_element.m_pathname = separator;
 
654
        return;
 
655
      }
 
656
 
 
657
      // bypass separators
 
658
      while (it.m_pos != it.m_path_ptr->m_pathname.size()
 
659
        && is_separator(it.m_path_ptr->m_pathname[it.m_pos]))
 
660
        { ++it.m_pos; }
 
661
 
 
662
      // detect trailing separator, and treat it as ".", per POSIX spec
 
663
      if (it.m_pos == it.m_path_ptr->m_pathname.size()
 
664
        && is_non_root_separator(it.m_path_ptr->m_pathname, it.m_pos-1)) 
 
665
      {
 
666
        --it.m_pos;
 
667
        it.m_element = dot_path;
 
668
        return;
 
669
      }
 
670
    }
 
671
 
 
672
    // get next element
 
673
    size_type end_pos(it.m_path_ptr->m_pathname.find_first_of(separators, it.m_pos));
 
674
    if (end_pos == string_type::npos) end_pos = it.m_path_ptr->m_pathname.size();
 
675
    it.m_element = it.m_path_ptr->m_pathname.substr(it.m_pos, end_pos - it.m_pos);
 
676
  }
 
677
 
 
678
  void path::m_path_iterator_decrement(path::iterator & it)
 
679
  {
 
680
    BOOST_ASSERT(it.m_pos && "path::iterator decrement past begin()");
 
681
 
 
682
    size_type end_pos(it.m_pos);
 
683
 
 
684
    // if at end and there was a trailing non-root '/', return "."
 
685
    if (it.m_pos == it.m_path_ptr->m_pathname.size()
 
686
      && it.m_path_ptr->m_pathname.size() > 1
 
687
      && is_separator(it.m_path_ptr->m_pathname[it.m_pos-1])
 
688
      && is_non_root_separator(it.m_path_ptr->m_pathname, it.m_pos-1) 
 
689
       )
 
690
    {
 
691
      --it.m_pos;
 
692
      it.m_element = dot_path;
 
693
      return;
 
694
    }
 
695
 
 
696
    size_type root_dir_pos(root_directory_start(it.m_path_ptr->m_pathname, end_pos));
 
697
 
 
698
    // skip separators unless root directory
 
699
    for (
 
700
      ; 
 
701
      end_pos > 0
 
702
      && (end_pos-1) != root_dir_pos
 
703
      && is_separator(it.m_path_ptr->m_pathname[end_pos-1])
 
704
      ;
 
705
      --end_pos) {}
 
706
 
 
707
    it.m_pos = filename_pos(it.m_path_ptr->m_pathname, end_pos);
 
708
    it.m_element = it.m_path_ptr->m_pathname.substr(it.m_pos, end_pos - it.m_pos);
 
709
    if (it.m_element.m_pathname == preferred_separator_string)
 
710
      it.m_element.m_pathname = separator_string;  // needed for Windows, harmless on POSIX
 
711
  }
 
712
 
 
713
}  // namespace filesystem3
 
714
}  // namespace boost
 
715
 
 
716
//--------------------------------------------------------------------------------------//
 
717
//                                                                                      //
 
718
//                                 detail helpers                                       //
 
719
//                                                                                      //
 
720
//--------------------------------------------------------------------------------------//
 
721
 
 
722
namespace
 
723
{
 
724
 
 
725
  //------------------------------------------------------------------------------------//
 
726
  //                              locale helpers                                        //
 
727
  //------------------------------------------------------------------------------------//
 
728
 
 
729
  // std::locale construction can throw (if LC_MESSAGES is wrong, for example),
 
730
  // so a static at function scope is used to ensure that exceptions can be
 
731
  // caught. (A previous version was at namespace scope, so initialization
 
732
  // occurred before main(), preventing exceptions from being caught.)
 
733
 
 
734
  std::locale default_locale()
 
735
  {
 
736
#   ifdef BOOST_WINDOWS_API
 
737
    std::locale global_loc = std::locale();
 
738
    std::locale loc(global_loc, new windows_file_codecvt);
 
739
    return loc;
 
740
 
 
741
#   elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
 
742
    // "All BSD system functions expect their string parameters to be in UTF-8 encoding
 
743
    // and nothing else." http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html
 
744
    //
 
745
    // "The kernel will reject any filename that is not a valid UTF-8 string, and it will
 
746
    // even be normalized (to Unicode NFD) before stored on disk, at least when using HFS.
 
747
    // The right way to deal with it would be to always convert the filename to UTF-8
 
748
    // before trying to open/create a file." http://lists.apple.com/archives/unix-porting/2007/Sep/msg00023.html
 
749
    //
 
750
    // "How a file name looks at the API level depends on the API. Current Carbon APIs
 
751
    // handle file names as an array of UTF-16 characters; POSIX ones handle them as an
 
752
    // array of UTF-8, which is why UTF-8 works well in Terminal. How it's stored on disk
 
753
    // depends on the disk format; HFS+ uses UTF-16, but that's not important in most
 
754
    // cases." http://lists.apple.com/archives/applescript-users/2002/Sep/msg00319.html
 
755
    //
 
756
    // Many thanks to Peter Dimov for digging out the above references!
 
757
    std::locale global_loc = std::locale();
 
758
    std::locale loc(global_loc, new boost::filesystem::detail::utf8_codecvt_facet);
 
759
    return loc;
 
760
 
 
761
#   else
 
762
    // ISO C calls this "the locale-specific native environment":
 
763
    return std::locale("");
 
764
 
 
765
#   endif
 
766
  }
 
767
 
 
768
  std::locale & path_locale()
 
769
  {
 
770
    static std::locale loc(default_locale());
 
771
    return loc;
 
772
  }
 
773
 
 
774
}  // unnamed namespace
 
775
 
 
776
//--------------------------------------------------------------------------------------//
 
777
//                           path::imbue implementation                                 //
 
778
//--------------------------------------------------------------------------------------//
 
779
 
 
780
namespace boost
 
781
{
 
782
namespace filesystem3
 
783
{
 
784
 
 
785
  const path::codecvt_type *&
 
786
    path::wchar_t_codecvt_facet()
 
787
  {
 
788
   static const std::codecvt<wchar_t, char, std::mbstate_t> *
 
789
     facet(
 
790
       &std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t> >
 
791
        (path_locale()));
 
792
   return facet;
 
793
  }
 
794
 
 
795
  std::locale path::imbue(const std::locale & loc)
 
796
  {
 
797
    std::locale temp(path_locale());
 
798
    path_locale() = loc;
 
799
    wchar_t_codecvt_facet() = &std::use_facet
 
800
        <std::codecvt<wchar_t, char, std::mbstate_t> >(path_locale());
 
801
    return temp;
 
802
  }
 
803
 
 
804
}  // namespace filesystem3
 
805
}  // namespace boost
 
806
 
 
807
#endif  // no wide character support