-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpath.c
97 lines (90 loc) · 2.38 KB
/
path.c
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
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <sys/stat.h>
#include "ep.h"
#include "info_strings.h"
/* print current dir in fish style */
const int fish_style_dir = 1;
static inline int file_match(const struct stat *s1, const struct stat *s2)
{
return s1->st_dev == s2->st_dev && s1->st_ino == s2->st_ino;
}
void print_pwd(const char *home, char *envpwd)
{
struct stat st_pwd, st_envpwd, st_home;
char pwd[PATH_MAX];
char *mrpwd = getcwd(pwd, sizeof pwd);
/* const alias to avoid accidentally modifying m(utable)rpwd.
* remember to ALWAYS change both variables */
const char *rpwd = mrpwd;
if (!rpwd) {
/* getcwd failed */
p(unknowndir);
} else {
/* if envpwd exists and is valid (starts with '/' and matches current dir),
* replace pwd with it */
if (envpwd && envpwd[0] == '/') {
/* if we can't stat current dir, bail */
if (stat(".", &st_pwd)) {
p(unknowndir);
return;
}
if (!stat(envpwd, &st_envpwd) && file_match(&st_pwd, &st_envpwd)) {
rpwd = mrpwd = envpwd;
}
} else {
/* invalidate envpwd so it can be used to determine if st_pwd was initialized */
envpwd = NULL;
}
/* strip HOME out if possible */
if (home) {
size_t l = strlen(home);
if (!strncmp(home, rpwd, l) && (rpwd[l] == 0 || rpwd[l] == '/')) {
/* found HOME in pwd */
p("~");
/* advance both pwd pointers */
rpwd = (mrpwd += l);
/* check if we are in HOME.
* if yes, printing '~' is all we want */
if (
/* pwd is only HOME */
rpwd[0] == 0 ||
/* current dir is HOME anyway */
!stat(home, &st_home) &&
(envpwd || !stat(".", &st_pwd)) && /* only stat(".") if it hasn't happened before */
file_match(&st_home, &st_pwd))
return;
}
/* starting from here, rpwd always starts with '/'.
* it can be a path relative to HOME or an absolute path */
if (fish_style_dir) {
char *saveptr;
const char *tok, *oldtok = NULL;
while ((tok = strtok_r(mrpwd, "/", &saveptr))) {
mrpwd = NULL;
if (!strcmp(tok, "..")) {
p("/..");
} else {
char str[] = {'/', tok[0], 0};
p(str);
}
oldtok = tok;
}
/* print the last token in full */
if (oldtok)
p(oldtok+1);
/* if no token was found, we are in root */
if (mrpwd) {
p("/");
}
} else {
p(rpwd);
}
} else {
/* HOME is unset */
p(rpwd);
}
}
}