blob: 85766432675a24018d1f0f42119fa0e90559aaec [file] [log] [blame]
tomlua729b9b2018-02-08 15:32:00 -08001// Copyright 2017 The Bazel Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14package com.google.devtools.build.lib.vfs;
15
16import com.google.common.annotations.VisibleForTesting;
17import com.google.common.base.Splitter;
18import com.google.common.collect.Iterables;
19
20@VisibleForTesting
21class UnixOsPathPolicy implements OsPathPolicy {
22
23 static final UnixOsPathPolicy INSTANCE = new UnixOsPathPolicy();
24 private static final Splitter PATH_SPLITTER = Splitter.onPattern("/+").omitEmptyStrings();
25
26 @Override
27 public int needsToNormalize(String path) {
28 int n = path.length();
29 int dotCount = 0;
30 char prevChar = 0;
31 for (int i = 0; i < n; i++) {
32 char c = path.charAt(i);
33 if (c == '\\') {
34 return NEEDS_NORMALIZE;
35 }
36 if (c == '/') {
37 if (prevChar == '/') {
38 return NEEDS_NORMALIZE;
39 }
40 if (dotCount == 1 || dotCount == 2) {
41 return NEEDS_NORMALIZE;
42 }
43 }
44 dotCount = c == '.' ? dotCount + 1 : 0;
45 prevChar = c;
46 }
47 if (prevChar == '/' || dotCount == 1 || dotCount == 2) {
48 return NEEDS_NORMALIZE;
49 }
50 return NORMALIZED;
51 }
52
53 @Override
54 public int needsToNormalizeSuffix(String normalizedSuffix) {
55 // We know that the string is normalized
56 // In this case only suffixes starting with ".." may cause
57 // normalization once concatenated with other strings
58 return normalizedSuffix.startsWith("..") ? NEEDS_NORMALIZE : NORMALIZED;
59 }
60
61 @Override
62 public String normalize(String path, int normalizationLevel) {
63 if (normalizationLevel == NORMALIZED) {
64 return path;
65 }
66 if (path.isEmpty()) {
67 return path;
68 }
69 boolean isAbsolute = path.charAt(0) == '/';
70 StringBuilder sb = new StringBuilder(path.length());
71 if (isAbsolute) {
72 sb.append('/');
73 }
74 String[] segments = Iterables.toArray(PATH_SPLITTER.splitToList(path), String.class);
75 int segmentCount = Utils.removeRelativePaths(segments, 0, isAbsolute);
76 for (int i = 0; i < segmentCount; ++i) {
77 sb.append(segments[i]);
78 sb.append('/');
79 }
80 if (segmentCount > 0) {
81 sb.deleteCharAt(sb.length() - 1);
82 }
83 return sb.toString();
84 }
85
86 @Override
87 public int getDriveStrLength(String path) {
88 if (path.length() == 0) {
89 return 0;
90 }
91 return (path.charAt(0) == '/') ? 1 : 0;
92 }
93
94 @Override
95 public int compare(String s1, String s2) {
96 return s1.compareTo(s2);
97 }
98
99 @Override
100 public int compare(char c1, char c2) {
101 return Character.compare(c1, c2);
102 }
103
104 @Override
105 public boolean equals(String s1, String s2) {
106 return s1.equals(s2);
107 }
108
109 @Override
110 public int hash(String s) {
111 return s.hashCode();
112 }
113
114 @Override
115 public boolean startsWith(String path, String prefix) {
116 return path.startsWith(prefix);
117 }
118
119 @Override
120 public boolean endsWith(String path, String suffix) {
121 return path.endsWith(suffix);
122 }
123
124 @Override
125 public char getSeparator() {
126 return '/';
127 }
128
129 @Override
130 public boolean isSeparator(char c) {
131 return c == '/';
132 }
133
134 @Override
135 public boolean isCaseSensitive() {
136 return true;
137 }
138}