C Programming - Path Correction

If you enter any relative path convert that to absolute path removing those dotdot and dot. Assuming that input is following our grammer :)
eg: Input: /a/b/c/.././ and Output: /a/b

The most obvious solution seems to be stack. But i wanted to give a try with an in-place replacement logic. Here is what i came up with.
Lets start from the other end of the string.

#define COLS 2
#define TESTPATHS{{"/asd/..",""}\
,{"/.",""}\
,{"/a/b/cc/d/..","/a/b/cc"}\
,{"/a/b/cc/d/.","/a/b/cc/d"}\
,{"/a/../cc/.././asd","/asd"}\
,{"/r/../c../dc../.././asd","/c../asd"}\
,{"/a/../c.c/.././asd","/asd"}\
,{"/a/../.c.c/.././asd","/asd"}\
,{"/a/../c..c/.././asd","/asd"}\
,{"/a/../c...c/.././asd","/asd"}\
,{"/a/b/c/d/","/a/b/c/d/"}\
,{"/a/b.c/c/../d/","/a/b.c/d/"}\
,{"",""}\
,{".","."}\
,{"..",".."}\
,{"/a/../c.c/.././rs..","/rs.."}}

int check_skip(char *start, char **cur, char *stop)
{
int retcode = -1;
if (**cur != '.')
retcode = -1;
else if ((*cur + 1 <>= start) && (*(*cur + 1) == '/')
&& (*(*cur - 1) == '/')) {
*cur -= 1;
retcode = 0;
} else if ((*cur - 2 >= start) && (*(*cur + 1) == '/')
&& (*(*cur - 1) == '.') && (*(*cur - 2) == '/')) {
retcode = 1;
*cur -= 2;
}
} else if ((*cur + 1 == stop)) {
if ((*cur - 1 >= start) && (*(*cur - 1) == '/')) {
retcode = 0;
*cur -= 1;
} else if ((*cur - 2 >= start) && (*(*cur - 1) == '.')
&& (*(*cur - 2) == '/')) {
retcode = 1;
*cur -= 2;
}
}
return retcode;
}

char *find_first(const char findme, char *start, char *stop, int oper,
int *pcnt)
{
char *iter = NULL;
if (start == NULL)
return stop;

for (iter = start; iter != (stop + oper); iter += oper) {
if (*iter == findme)
-- * pcnt;
if ((*pcnt == 0) || (*iter == '.'))
break;
}
if (iter == (stop + oper))
iter = stop;
return iter;
}

char *dir_path(char *path)
{
char *dirpath = path;
int dirlen = strlen(path);

char *end = dirpath + dirlen;
char *dest = end;
char *iter = NULL;
int skipcount = 0;

//TODO: skip last slash;

for (iter = end - 1; iter != (dirpath - 1); --iter) {
int rc = check_skip(dirpath, &iter, end);
if (rc != -1) {
skipcount += rc;
continue;
} else {
//skip slash
if ((skipcount != 0) && (*iter != '/')) {
iter = find_first('/', iter, dirpath, -1, &skipcount);
continue;
}
//copy
if ((skipcount == 0) && (iter != dest)) {
*--dest = *iter;
}
}
}
if (skipcount != 0)
printf("parsing error detected\n");
return dest;
}

void test_paths()
{
char *input_strings[][COLS] = TESTPATHS;
int input_size = sizeof(input_strings) / (sizeof(char *) * COLS);

for (int i = 0; i < input_size; i++) {
char *input = strdup(input_strings[i][0]);
char *result = dir_path(input);
if (strcmp(result, input_strings[i][1]) != 0) {
printf
("TEST FAILURE: [ input = %-20s expected = %-20s result = %-20s ]\n",
input_strings[i][0], input_strings[i][1], result);
} else
printf("TEST SUCCESS: [ input = %-40s result = %-20s ]\n",
input_strings[i][0], input_strings[i][1]);
free((void *) input);
}

}

int main(int count, char *args[])
{
if (count != 2) {
printf("usage: %s \n", args[0]);
return -1;
}

char *mypath = strdup(args[1]); //for printing

char *dest = dir_path(mypath);
printf("%-20s : %s\n", "entered path", args[1]);
printf("%-20s : %s\n", "final path", dest);

printf("going to run tests\n");
test_paths();

free((void *) mypath);
return 0;
}


please post your valuable comments and thoughts.

Labels:


About this entry