aboutsummaryrefslogtreecommitdiffstats
path: root/util/folder/pathsplit.cpp
blob: 834e3b431ccd0a694a37a8bc11a42e219b0b8583 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include "pathsplit.h"

#include <util/stream/output.h>
#include <util/generic/yexception.h>

template <class T>
static inline size_t ToReserve(const T& t) {
    size_t ret = t.size() + 5;

    for (auto it = t.begin(); it != t.end(); ++it) {
        ret += it->size();
    }

    return ret;
}

void TPathSplitTraitsUnix::DoParseFirstPart(const TStringBuf part) {
    if (part == TStringBuf(".")) {
        push_back(TStringBuf("."));

        return;
    }

    if (IsAbsolutePath(part)) {
        IsAbsolute = true;
    }

    DoParsePart(part);
}

void TPathSplitTraitsUnix::DoParsePart(const TStringBuf part0) {
    DoAppendHint(part0.size() / 8);

    TStringBuf next(part0);
    TStringBuf part;

    while (TStringBuf(next).TrySplit('/', part, next)) {
        AppendComponent(part);
    }

    AppendComponent(next);
}

void TPathSplitTraitsWindows::DoParseFirstPart(const TStringBuf part0) {
    TStringBuf part(part0);

    if (part == TStringBuf(".")) {
        push_back(TStringBuf("."));

        return;
    }

    if (IsAbsolutePath(part)) {
        IsAbsolute = true;

        if (part.size() > 1 && part[1] == ':') {
            Drive = part.SubStr(0, 2);
            part = part.SubStr(2);
        }
    }

    DoParsePart(part);
}

void TPathSplitTraitsWindows::DoParsePart(const TStringBuf part0) {
    DoAppendHint(part0.size() / 8);

    size_t pos = 0;
    TStringBuf part(part0);

    while (pos < part.size()) {
        while (pos < part.size() && this->IsPathSep(part[pos])) {
            ++pos;
        }

        const char* begin = part.data() + pos;

        while (pos < part.size() && !this->IsPathSep(part[pos])) {
            ++pos;
        }

        AppendComponent(TStringBuf(begin, part.data() + pos));
    }
}

TString TPathSplitStore::DoReconstruct(const TStringBuf slash) const {
    TString r;

    r.reserve(ToReserve(*this));

    if (IsAbsolute) {
        r.AppendNoAlias(Drive);
        r.AppendNoAlias(slash);
    }

    for (auto i = begin(); i != end(); ++i) {
        if (i != begin()) {
            r.AppendNoAlias(slash);
        }

        r.AppendNoAlias(*i);
    }

    return r;
}

void TPathSplitStore::AppendComponent(const TStringBuf comp) {
    if (!comp || comp == TStringBuf(".")) {
        ; // ignore
    } else if (comp == TStringBuf("..") && !empty() && back() != TStringBuf("..")) {
        pop_back();
    } else {
        // push back first .. also
        push_back(comp);
    }
}

TStringBuf TPathSplitStore::Extension() const {
    return size() > 0 ? CutExtension(back()) : TStringBuf();
}

template <>
void Out<TPathSplit>(IOutputStream& o, const TPathSplit& ps) {
    o << ps.Reconstruct();
}

TString JoinPaths(const TPathSplit& p1, const TPathSplit& p2) {
    if (p2.IsAbsolute) {
        ythrow yexception() << "can not join " << p1 << " and " << p2;
    }

    return TPathSplit(p1).AppendMany(p2.begin(), p2.end()).Reconstruct();
}

TStringBuf CutExtension(const TStringBuf fileName) {
    if (fileName.empty()) {
        return fileName;
    }

    TStringBuf name;
    TStringBuf extension;
    fileName.RSplit('.', name, extension);
    if (name.empty()) {
        // dot at a start or not found
        return name;
    } else {
        return extension;
    }
}