Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
path.go227 linesDownload Raw Back to path
1// Copyright 2009 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.4 5// Package path implements utility routines for manipulating slash-separated6// paths.7//8// The path package should only be used for paths separated by forward9// slashes, such as the paths in URLs. This package does not deal with10// Windows paths with drive letters or backslashes; to manipulate11// operating system paths, use the [path/filepath] package.12package path13 14import "internal/bytealg"15 16// A lazybuf is a lazily constructed path buffer.17// It supports append, reading previously appended bytes,18// and retrieving the final string. It does not allocate a buffer19// to hold the output until that output diverges from s.20type lazybuf struct {21	s   string22	buf []byte23	w   int24}25 26func (b *lazybuf) index(i int) byte {27	if b.buf != nil {28		return b.buf[i]29	}30	return b.s[i]31}32 33func (b *lazybuf) append(c byte) {34	if b.buf == nil {35		if b.w < len(b.s) && b.s[b.w] == c {36			b.w++37			return38		}39		b.buf = make([]byte, len(b.s))40		copy(b.buf, b.s[:b.w])41	}42	b.buf[b.w] = c43	b.w++44}45 46func (b *lazybuf) string() string {47	if b.buf == nil {48		return b.s[:b.w]49	}50	return string(b.buf[:b.w])51}52 53// Clean returns the shortest path name equivalent to path54// by purely lexical processing. It applies the following rules55// iteratively until no further processing can be done:56//57//  1. Replace multiple slashes with a single slash.58//  2. Eliminate each . path name element (the current directory).59//  3. Eliminate each inner .. path name element (the parent directory)60//     along with the non-.. element that precedes it.61//  4. Eliminate .. elements that begin a rooted path:62//     that is, replace "/.." by "/" at the beginning of a path.63//64// The returned path ends in a slash only if it is the root "/".65//66// If the result of this process is an empty string, Clean67// returns the string ".".68//69// See also Rob Pike, “Lexical File Names in Plan 9 or70// Getting Dot-Dot Right,”71// https://9p.io/sys/doc/lexnames.html72func Clean(path string) string {73	if path == "" {74		return "."75	}76 77	rooted := path[0] == '/'78	n := len(path)79 80	// Invariants:81	//	reading from path; r is index of next byte to process.82	//	writing to buf; w is index of next byte to write.83	//	dotdot is index in buf where .. must stop, either because84	//		it is the leading slash or it is a leading ../../.. prefix.85	out := lazybuf{s: path}86	r, dotdot := 0, 087	if rooted {88		out.append('/')89		r, dotdot = 1, 190	}91 92	for r < n {93		switch {94		case path[r] == '/':95			// empty path element96			r++97		case path[r] == '.' && (r+1 == n || path[r+1] == '/'):98			// . element99			r++100		case path[r] == '.' && path[r+1] == '.' && (r+2 == n || path[r+2] == '/'):101			// .. element: remove to last /102			r += 2103			switch {104			case out.w > dotdot:105				// can backtrack106				out.w--107				for out.w > dotdot && out.index(out.w) != '/' {108					out.w--109				}110			case !rooted:111				// cannot backtrack, but not rooted, so append .. element.112				if out.w > 0 {113					out.append('/')114				}115				out.append('.')116				out.append('.')117				dotdot = out.w118			}119		default:120			// real path element.121			// add slash if needed122			if rooted && out.w != 1 || !rooted && out.w != 0 {123				out.append('/')124			}125			// copy element126			for ; r < n && path[r] != '/'; r++ {127				out.append(path[r])128			}129		}130	}131 132	// Turn empty string into "."133	if out.w == 0 {134		return "."135	}136 137	return out.string()138}139 140// Split splits path immediately following the final slash,141// separating it into a directory and file name component.142// If there is no slash in path, Split returns an empty dir and143// file set to path.144// The returned values have the property that path = dir+file.145func Split(path string) (dir, file string) {146	i := bytealg.LastIndexByteString(path, '/')147	return path[:i+1], path[i+1:]148}149 150// Join joins any number of path elements into a single path,151// separating them with slashes. Empty elements are ignored.152// The result is Cleaned. However, if the argument list is153// empty or all its elements are empty, Join returns154// an empty string.155func Join(elem ...string) string {156	size := 0157	for _, e := range elem {158		size += len(e)159	}160	if size == 0 {161		return ""162	}163	buf := make([]byte, 0, size+len(elem)-1)164	for _, e := range elem {165		if len(buf) > 0 || e != "" {166			if len(buf) > 0 {167				buf = append(buf, '/')168			}169			buf = append(buf, e...)170		}171	}172	return Clean(string(buf))173}174 175// Ext returns the file name extension used by path.176// The extension is the suffix beginning at the final dot177// in the final slash-separated element of path;178// it is empty if there is no dot.179func Ext(path string) string {180	for i := len(path) - 1; i >= 0 && path[i] != '/'; i-- {181		if path[i] == '.' {182			return path[i:]183		}184	}185	return ""186}187 188// Base returns the last element of path.189// Trailing slashes are removed before extracting the last element.190// If the path is empty, Base returns ".".191// If the path consists entirely of slashes, Base returns "/".192func Base(path string) string {193	if path == "" {194		return "."195	}196	// Strip trailing slashes.197	for len(path) > 0 && path[len(path)-1] == '/' {198		path = path[0 : len(path)-1]199	}200	// Find the last element201	if i := bytealg.LastIndexByteString(path, '/'); i >= 0 {202		path = path[i+1:]203	}204	// If empty now, it had only slashes.205	if path == "" {206		return "/"207	}208	return path209}210 211// IsAbs reports whether the path is absolute.212func IsAbs(path string) bool {213	return len(path) > 0 && path[0] == '/'214}215 216// Dir returns all but the last element of path, typically the path's directory.217// After dropping the final element using [Split], the path is Cleaned and trailing218// slashes are removed.219// If the path is empty, Dir returns ".".220// If the path consists entirely of slashes followed by non-slash bytes, Dir221// returns a single slash. In any other case, the returned path does not end in a222// slash.223func Dir(path string) string {224	dir, _ := Split(path)225	return Clean(dir)226}227 
codekingpro/portable-devtools · Team Ai