shithub: fsgen

ref: a976de46123b51045a1ea123ad452e8465e71b08
dir: /files.c/

View raw version
#include <u.h>
#include <libc.h>
#include "dat.h"
#include "fns.h"

VFile *files = nil;

static char**
parsepath(char *path)
{
	char **args;
	char *s;
	int numparts = 1, n;
	
	/* root element: / */
	if (path[1] == 0) {
		args = mallocz(1, 1);
		args[0] = nil;
		return args;
	}
	
	for (s = path; *s; s++) {
		if (*s == '/')
			numparts++;
	}
	
	/* root dir, each directory part, ending nil */
	args = mallocz(numparts+1, 1);
	args[numparts] = nil;
	s = strdup(path);
	n = getfields(s, args, numparts, 0, "/");
	
	assert(s == args[0]);
	if (n == numparts)
		return args;
	free(args);
	free(s);
	werrstr("invalid path");
	return nil;
}

static int
verifyfiles(char **parts)
{
	VFile *vf;
	char buf[64];
	char *s;
	char **a;
	int i, numparts = 0;
	
	for (a = parts; *a; a++)
		numparts++;
	
	s = buf;
	*s = '/';
	s++;
	for (i = 1; i < numparts - 1; i++) {
		strcpy(s, parts[i]);
		vf = addfile(buf);
		if (!vf)
			return 0;
		vf->isdir = 1;
		s += strlen(parts[i]);
		*s = '/';
		s++;
	}
	return 1;
}

VFile*
addfile(char *path)
{
	VFile *old, *new;
	
	old = getfile(path);
	if (old)
		return old;
	
	if (!files) {
		files = mallocz(sizeof(VFile), 1);
		files->isdir = 1;
		files->path = strdup("/");
		files->parts = parsepath(files->path);
	}
	old = files;
	files = mallocz(sizeof(VFile), 1);
	files->next = old;
	
	/* verifyfiles may add new files, thus changing the global files pointer */
	new = files;
	new->path = strdup(path);
	new->parts = parsepath(path);
	if (!new->parts)
		return nil;
	
	if (!verifyfiles(new->parts))
		return nil;
	
	return new;
}

VFile*
getfile(char *path)
{
	VFile *v;
	
	for (v = files; v; v = v->next)
		if (strcmp(v->path, path) == 0)
			return v;
	werrstr("file not found: %s", path);
	return nil;
}

void
foreachfile(void (*f)(VFile*,void*), void *aux)
{
	VFile *vf;
	
	for (vf = files; vf; vf = vf->next)
		f(vf, aux);
}

int
getnfiles()
{
	int n = 0;
	VFile *v;
	
	for (v = files; v; v = v->next)
		n++;
	
	return n;
}

static int
Vfmt(Fmt *f)
{
	VFile *v;
	v = va_arg(f->args, VFile*);
	return fmtprint(f, "%s (%s%s%s)", v->path,
		v->isdir ? "D," : "",
		v->hasread ? "R," : "",
		v->haswrite ? "W" : ""
	);
}

void
vfileinit()
{
	fmtinstall('V', Vfmt);
}