Hello! There is a code

char cwd[1024]; getcwd(cwd, sizeof(cwd)); 

When called, returns: /home/example/exampledir/ . How to replace /home/example with ~/ if this is the user's home directory.

  • getenv("HOME") ? - user6550
  • And how to bite off a piece of char ? - user26699
  • "Bite" nothing. It is necessary to write ~ in the first byte of cwd[] (after all the necessary comparisons-calculations), and the tail of cwd (the part of the path inside $HOME ) to shift (read man memmove ) to cwd + 1 - avp

2 answers 2

Slightly expand:

 #include <stdio.h> #include <string.h> #include <stdlib.h> char * cwd2home( char * path, size_t path_length ) { char cwd[PATH_MAX]; char * home = getenv( "HOME" ); size_t home_length = strlen( home ); getcwd( cwd, sizeof(cwd) ); if( !strncmp( cwd, home, home_length ) ) { strncpy( path, "~", path_length ); strncat( path, cwd + home_length, path_length - sizeof("~") ); } else { strncpy( path, cwd, path_length ); } path[path_length-1] = 0; return path; } int main() { char path[PATH_MAX]; printf( "%s\n", cwd2home(path, sizeof(path)) ); return 0; } 
  • Plows, but not correctly, if the user is not at home. - user26699
  • Well, that means sanachal needs to check where he is. Or are you waiting for all of the code to be written here for you? - user6550
  • Sorry, did not understand this from the answer) - user26699
  • See the new answer. It can still be slightly improved, but this is already too lazy :) - user6550

Just in case, (it seems to me that it would be more careful with checks and perhaps somehow even corresponds to man getcwd ) I would write (name for the function better think up yourself):

 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <pwd.h> #include <unistd.h> char * get2cwd (char *buf, size_t size) { if (buf = getcwd(buf, size)) { struct passwd *p = getpwuid(getuid()); char *home; if (p && (home = p->pw_dir)) { int home_len = strlen(home), cwdlen = strlen(buf); if (home_len < cwdlen && buf[home_len] == '/' && strncmp(buf, home, home_len) == 0) { memmove(buf + 1, buf + home_len, cwdlen - home_len + 1); *buf = '~'; } } else perror(p ? "no home" : "getpwuid(getuid())"); } return buf; } 

Update

About get_current_dir_name() , words in manpage

PWD is set

and doubts @klopp (see comments), is it possible to use it.

As promised yesterday, I looked at the code from eglibc-2.11.1 / io / getdirname.c

 /* Return a malloc'd string containing the current directory name. If the environment variable `PWD' is set, and its value is correct, that value is used. */ char * get_current_dir_name (void) { char *pwd; struct stat64 dotstat, pwdstat; pwd = getenv ("PWD"); if (pwd != NULL && stat64 (".", &dotstat) == 0 && stat64 (pwd, &pwdstat) == 0 && pwdstat.st_dev == dotstat.st_dev && pwdstat.st_ino == dotstat.st_ino) /* The PWD value is correct. Use it. */ return __strdup (pwd); return __getcwd ((char *) NULL, 0); } 

IMHO everything is obvious. If a "." and getenv ("PWD") is the same table of contents, then we take the extracted path by someone else (well, of course, the shell), otherwise we call the costly system call - getcwd.
(If everyone understands why expensive is great, if not, ask (look for yourself too, and better calculate the correct answer) and discuss here whether this can be accelerated.

And then, I see something quite here beginner hackers disappeared. The impression that nothing is interesting to anyone).

  • Yeah. Another unobvious: get_current_dir_name() and / or getenv("PWD") is not worth it, although it is simpler. - user6550
  • @klopp, but what about your comments getenv("PWD") ? I do not understand this at all. / In fact, this ( get2cwd() ) has the same prototype as that of getcwd() and works completely independently of the shell that sets environment variables (we are repelling ourselves from the performer’s uid, and if necessary, you can easily change to euid) . - avp
  • My thought was to use get_current_dir_name() instead of getcwd() , so as not to bother with the size of the buffer. But he stopped: in fact, she takes the PWD environment. And this variable does not change if chdir() occurs inside the program. In the case of getcwd() all programmatic directory changes are tracked correctly. - user6550
  • @klopp, but this (how to correctly interpret the words of the authors man-page about PWD) is a really interesting question (will you try to formulate and ask?) (and I’ll read the sorts tomorrow). / Actually get_current_dir() works absolutely true regardless of PWD and the sequence of calls to chdir inside the process. - avp
  • @klopp added something about get_current_dir_name() to the Update response. - avp