#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include "reclinker.h"
#define DIRSEP '/' /* this would make sense if other parts of the prog
* also used this notation...
*/
struct pathnode *
palloc(void)
{
return (struct pathnode*) MALLOC(sizeof (struct pathnode));
}
struct pathnode *
freenode(struct pathnode *p)
{
/* This function may cause segfault if the "prev" tag of p is undefined
* However, this won't occur if paths are built properly
*/
struct pathnode* q;
if (p == NULL)
return NULL;
q = p->next;
if ((p->prev) != NULL)
(p->prev)->next = NULL;
free(p->name);
free(p);
if (q != NULL)
q->prev = NULL;
return q;
}
void
freepath(struct pathnode *p)
{
while ((p = freenode(p)) != NULL);
}
/* strtok sucks (doesn't let free its output strings later on)
* strtok_r in not standard enough to my taste
* so I implement my own strtok-like macro and it does the job well
*/
#define my_strtok(p,q,w) { \
while(*p == DIRSEP) p++; \
if(*p == '\0') \
w = NULL; \
else { \
q = p; \
while(*q != DIRSEP && *q != '\0') q++; \
w = (char *) MALLOC(q - p + 1); \
strncpy(w,p,q-p); \
*(w+(q-p)) = '\0'; \
p = q; \
} \
}
struct pathnode *
strtopath(char *pathstr)
{
struct pathnode *root;
struct pathnode *p;
char *w;
char *aux;
initpath(root);
for (p = root; p != NULL; p = p->next) {
my_strtok(pathstr,aux,w);
p->next = NULL;
while (w != NULL && !(strcmp(".",w) && strcmp("..",w)) ) {
if (strcmp("..",w) == 0) {
p = p->prev;
if (p->next != NULL)
freenode(p->next);
}
free(w);
my_strtok(pathstr,aux,w);
}
if (w != NULL) {
p->next = palloc();
(p->next)->name = w;
(p->next)->prev = p;
}
}
return root;
}
void
pathcopy(struct pathnode *f, struct pathnode *t)
{
struct pathnode *p = palloc();
if (f == NULL) {
t->next = NULL;
return;
}
p->prev = t;
p->next = NULL;
p->name = strdup(f->name);
t->next = p;
if ((f->next) != NULL)
pathcopy(f->next,p);
}
struct pathnode *
relpath(struct pathnode *f, struct pathnode *t)
{
struct pathnode *p = f;
struct pathnode *q = t;
struct pathnode *r;
struct pathnode root;
/* We deal only with proper path-roots */
if (f == NULL || t == NULL)
return NULL;
while (p->next != NULL &&
q->next != NULL &&
strcmp((p->next)->name, (q->next)->name) == 0) {
p = p->next;
q = q->next;
}
root.next = NULL;
r = &root;
while (p->next != NULL) {
r->next = palloc();
(r->next)->prev = r;
r = r->next;
r->name = strdup("..");
r->next = NULL;
p = p->next;
}
pathcopy(q->next,r);
if (! root.next) {
/*
* The two paths are the same, the relative path in between
* is NULL.
* We rather add a simple dot component and refrain from using
* NULL paths.
*/
r = palloc();
root.next = r;
r->name = strdup(".");
r->next = NULL;
}
root.next->prev = NULL;
return root.next;
}
char *
pathtostr(struct pathnode *p)
/* Based on the (better) concat() sample function of the GNU libc manual */
{
size_t allocated = STARTLENGTH;
char *result = (char *) MALLOC (allocated);
char *wp;
char *newp;
assert(p);
wp = result;
for (; p != NULL; p = p->next) {
size_t len = strlen (p->name);
/* Resize the allocated memory if necessary. */
if (wp + len + 2 > result + allocated) {
allocated = (allocated + len) * 2;
newp = (char *)REALLOC(result, allocated);
wp = newp + (wp - result);
result = newp;
}
wp = (char *)memcpy(wp, p->name, len) + len; /* + 1; */
*wp++ = DIRSEP;
}
/*
* strip trailing slash unless we're at root (ie., whole pathname is
* nothing but a slash).
*/
if (--wp == result)
*(++wp) = '\0';
else
*wp = '\0';
/* Resize memory to the optimal size. */
return (char *)REALLOC(result, wp - result + 1);
}
char *
str_relpath(char *f,char *t)
/* This function is written in order to provide proper freeing of the
* auxiliary chains of structures
*/
{
struct pathnode *p;
struct pathnode *r;
struct pathnode *q;
char *w;
p = strtopath(f);
q = strtopath(t);
r = relpath(strtopath(f),strtopath(t));
w = pathtostr(r);
freepath(p);
freepath(q);
freepath(r);
return w;
}
syntax highlighted by Code2HTML, v. 0.9.1