1// Copyright 2020 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package main
6
7import (
8	"path/filepath"
9	"strings"
10)
11
12// hasPathPrefix reports whether the slash-separated path s
13// begins with the elements in prefix.
14// Copied from cmd/go/internal/str.HasPathPrefix.
15func hasPathPrefix(s, prefix string) bool {
16	if len(s) == len(prefix) {
17		return s == prefix
18	}
19	if prefix == "" {
20		return true
21	}
22	if len(s) > len(prefix) {
23		if prefix[len(prefix)-1] == '/' || s[len(prefix)] == '/' {
24			return s[:len(prefix)] == prefix
25		}
26	}
27	return false
28}
29
30// hasFilePathPrefix reports whether the filesystem path s
31// begins with the elements in prefix.
32// Copied from cmd/go/internal/str.HasFilePathPrefix.
33func hasFilePathPrefix(s, prefix string) bool {
34	sv := strings.ToUpper(filepath.VolumeName(s))
35	pv := strings.ToUpper(filepath.VolumeName(prefix))
36	s = s[len(sv):]
37	prefix = prefix[len(pv):]
38	switch {
39	default:
40		return false
41	case pv != "" && sv != pv:
42		return false
43	case len(s) == len(prefix):
44		return s == prefix
45	case prefix == "":
46		return true
47	case len(s) > len(prefix):
48		if prefix[len(prefix)-1] == filepath.Separator {
49			return strings.HasPrefix(s, prefix)
50		}
51		return s[len(prefix)] == filepath.Separator && s[:len(prefix)] == prefix
52	}
53}
54
55// trimFilePathPrefix returns the given filesystem path s without the leading
56// prefix.
57func trimFilePathPrefix(s, prefix string) string {
58	sv := strings.ToUpper(filepath.VolumeName(s))
59	pv := strings.ToUpper(filepath.VolumeName(prefix))
60	s = s[len(sv):]
61	prefix = prefix[len(pv):]
62
63	if !hasFilePathPrefix(s, prefix) || len(prefix) == 0 {
64		return s
65	}
66	if len(s) == len(prefix) {
67		return ""
68	}
69	if prefix[len(prefix)-1] == filepath.Separator {
70		return strings.TrimPrefix(s, prefix)
71	}
72	return s[len(prefix)+1:]
73}
74
75// trimPathPrefix returns p without the leading prefix. Unlike
76// strings.TrimPrefix, the prefix will only match on slash-separted component
77// boundaries, so trimPathPrefix("aa/b", "aa") returns "b", but
78// trimPathPrefix("aa/b", "a") returns "aa/b".
79func trimPathPrefix(p, prefix string) string {
80	if prefix == "" {
81		return p
82	}
83	if prefix == p {
84		return ""
85	}
86	return strings.TrimPrefix(p, prefix+"/")
87}
88