Lets say I have a function:
void split_path_file(char** p, char** f, char *pf)
{
//malloc and set *p to file path, malloc and set *f to file name
//p
Maybe a bit late to the party, but the best solution I have found and have been using for years is the two functions dirname
and basename
path dirname basename
"/usr/lib" "/usr" "lib"
"/usr/" "/" "usr"
"usr" "." "usr"
"/" "/" "/"
They are great for separating parts of a path/filename. Together with realpath() they are IMHO unbeatable in simplicity and power.
http://linux.die.net/man/3/basename
http://man7.org/linux/man-pages/man3/realpath.3.html
Go backwards through the string until you reach the first '\\' then set *f to everything after it and *p to everything before and the '\\'.
The simplest way seems to be to start from the end and work towards the beginning, looking for the first delimiter character. You then have two cases: either you found one or you didn't. Something like this should do it for you:
#include <stdlib.h>
#include <string.h>
void split_path_file(char **p, char **f, char *pf) {
char *newcopy = malloc(strlen(pf) + 1);
strcpy(newcopy, pf);
for (z=newcopy+strlen(newcopy); z>newcopy; z--) {
if (*z == '/' || *z == '\\')
break;
}
if (z > newcopy) {
*p = newcopy;
*z = '\0';
*f = z+1;
} else {
*f = newcopy;
*p = NULL;
}
}
Update: @ephemient's comment below points out the above approach doesn't leave *p
and *f
suitable for calling free()
. If this is important, something a little more complicated like this will be needed:
#include <stdlib.h>
#include <string.h>
void split_path_file(char **p, char **f, char *pf) {
/* Find last delimiter. */
char *z;
for (z=pf+strlen(pf); z>=pf; z--) {
if (*z == '/' || *z == '\\')
break;
}
if (z >= pf) {
/* There is a delimiter: construct separate
path and filename fragments. */
printf("--> %i\n", z-pf);
*p = malloc(z-pf+1);
strncpy(*p, pf, z-pf);
(*p)[z-pf] = '\0';
*f = malloc(strlen(z));
strcpy(*f, z+1);
} else {
/* There is no delimiter: the entire
string must be a filename. */
*p = NULL;
*f = malloc(strlen(pf)+1);
strcpy(*f, pf);
}
}
int stripfilenameandpath (char *path, char *onlypath, char *onlyfilename) { /* documentacao path = path com path e arquivo onlypath = somente o path onlyfilename = somente o arquivo sem o path */ int ret; int i; int p; char temp[255]; char *fixo; #ifdef WIN32 const int separator = '\\'; #else const int separator = '/'; #endif fixo = path; if (path == NULL) { if (onlypath != NULL) { memset (onlypath, 0, 1); } if (onlyfilename != NULL) { memset (onlyfilename, 0, 1); } return 1; } ret = strlen (path); if (!ret) { if (onlypath != NULL) { memset (onlypath, 0, 1); } if (onlyfilename != NULL) { memset (onlyfilename, 0, 1); } return 0; } for (i = 0; i -1; i--) { if (temp[i] == separator) { temp[i + 1] = 0; break; } p++; } p = ret - p; fixo += p + 1; if (onlypath != NULL) { strcpy (onlypath, temp); } if (onlyfilename != NULL) { strcpy (onlyfilename, fixo); } return 0; }
I came up with the following, of course this assumes that pf is malloced.
void split_path_file(char** p, char **f, char *pf)
{
char *posp = strrchr(pf, '\\');
*posp = '\0';
*p = strdup(pf);
*f = strdup(posp+1);
*posp = '\\';
}
Not sure if this is a better approach than above answers.
void split_path_file(char** p, char** f, char *pf) {
char *slash = pf, *next;
while ((next = strpbrk(slash + 1, "\\/"))) slash = next;
if (pf != slash) slash++;
*p = strndup(pf, slash - pf);
*f = strdup(slash);
}
(If pf == slash
, then there is no directory component.)