mirror of https://github.com/ericonr/ep.git
Fix showing current path again.
Avoid unnecessary heap allocations (though we added new ones in main()) if possible by using a PATH_MAX buffer. Check for PWD matching current directory ourselves, which allows us to save a stat syscall, by re-using the stat(".") result to compare to stat("$HOME"). Improve how we check if HOME is actually part of pwd - previous would get confused with "${HOME}char", which should not get the prompt to display '~'. Use strtok_r to scan characters now. Writing directly to p() makes more sense than writing chars to a buffer, so remove that. I'm somewhat unhappy with the rpwd and mrpwd solution, since while coding I forgot to set one or the other a couple of times. It would be nice if I could "unconst" the variable at some point, though I greatly dislike that pattern.
This commit is contained in:
parent
cd48564223
commit
46ea87ea21
8
ep.c
8
ep.c
|
@ -70,12 +70,18 @@ int main(int argc, char **argv)
|
|||
if (chroot)
|
||||
p("[chroot] ");
|
||||
|
||||
/* XXX: treat allocation failures as variables not existing in environment */
|
||||
const char *home = getenv("HOME");
|
||||
char *pwd = getenv("PWD");
|
||||
#define cond_strdup(s) s = (s ? strdup(s) : s)
|
||||
cond_strdup(home);
|
||||
cond_strdup(pwd);
|
||||
#undef cond_strdup
|
||||
|
||||
/* show we are on a different machine */
|
||||
print_ssh();
|
||||
|
||||
print_pwd(home);
|
||||
print_pwd(home, pwd);
|
||||
|
||||
/* git status */
|
||||
void *git_info;
|
||||
|
|
2
ep.h
2
ep.h
|
@ -24,7 +24,7 @@ void e(enum log_level_value, const char *, int);
|
|||
|
||||
/* from path.c */
|
||||
extern const int fish_style_dir;
|
||||
void print_pwd(const char *);
|
||||
void print_pwd(const char *, char *);
|
||||
|
||||
/* from git.c */
|
||||
void *git_thread(void *);
|
||||
|
|
90
path.c
90
path.c
|
@ -1,6 +1,8 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "ep.h"
|
||||
#include "info_strings.h"
|
||||
|
@ -8,41 +10,82 @@
|
|||
/* print current dir in fish style */
|
||||
const int fish_style_dir = 1;
|
||||
|
||||
void print_pwd(const char *home)
|
||||
static inline int file_match(const struct stat *s1, const struct stat *s2)
|
||||
{
|
||||
char *pwd = get_current_dir_name(), *rpwd = pwd;
|
||||
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) {
|
||||
/* get_current_dir_name failed */
|
||||
/* 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)) {
|
||||
if (!strncmp(home, rpwd, l) && (rpwd[l] == 0 || rpwd[l] == '/')) {
|
||||
/* found HOME in pwd */
|
||||
p("~");
|
||||
rpwd += l;
|
||||
if (!*rpwd)
|
||||
/* printing ~ is enough
|
||||
* if it goes on, it will print ~/ */
|
||||
goto end;
|
||||
/* 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;
|
||||
}
|
||||
|
||||
if (fish_style_dir) {
|
||||
/* short and sweet way of malloc-ing enough memory */
|
||||
char *frpwd = strdup(rpwd);
|
||||
/* starting from here, rpwd always starts with '/'.
|
||||
* it can be a path relative to HOME or an absolute path */
|
||||
|
||||
/* rpwd starts with a slash */
|
||||
const char *c = rpwd, *co;
|
||||
char *n = frpwd;
|
||||
for (; c; co = c, c = strchr(co+1, '/')) {
|
||||
*n++ = '/';
|
||||
*n++ = *(c+1);
|
||||
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("/");
|
||||
}
|
||||
/* copy last path completely */
|
||||
strcpy(--n, co+1);
|
||||
p(frpwd);
|
||||
free(frpwd);
|
||||
} else {
|
||||
p(rpwd);
|
||||
}
|
||||
|
@ -51,7 +94,4 @@ void print_pwd(const char *home)
|
|||
p(rpwd);
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
free(pwd);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue