view files.c @ 7:b8167949474a

make places work better
author David A. Holland
date Sun, 19 Dec 2010 19:08:24 -0500
parents 0601b6e8e53d
children 97243badae69
line wrap: on
line source

#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <err.h>

#include "array.h"
#include "files.h"

struct place {
	struct seenfile *file;
	unsigned line;
	unsigned column;
};

struct incdir {
	const char *name;
	bool issystem;
};

struct seenfile {
	struct place includedfrom;
	char *name;
	bool fromsystemdir;
};

DECLARRAY(incdir);
DECLARRAY(seenfile);
DEFARRAY(incdir, );
DEFARRAY(seenfile, );

static struct incdirarray quotepath, bracketpath;
static struct seenfilearray seenfiles;
static bool overall_failure;

////////////////////////////////////////////////////////////
// management

#define DESTROYALL(T) \
	static						\
	void						\
	T##array_destroyall(struct T##array *arr)	\
	{						\
		unsigned i, num;			\
		struct T *t;				\
							\
		num = T##array_num(arr);		\
		for (i=0; i<num; i++) {			\
			t = T##array_get(arr, i);	\
			T##_destroy(t);			\
		}					\
		T##array_setsize(arr, 0);		\
	}

static
struct incdir *
incdir_create(const char *name, bool issystem)
{
	struct incdir *id;

	id = domalloc(sizeof(*id));
	id->name = name;
	id->issystem = issystem;
	return id;
}

static
void
incdir_destroy(struct incdir *id)
{
	free(id);
}

static
struct seenfile *
seenfile_create(const struct place *from, char *name, bool fromsystemdir)
{
	struct seenfile *sf;

	sf = domalloc(sizeof(*sf));
	sf->includedfrom = *from;
	sf->name = name;
	sf->fromsystemdir = fromsystemdir;
	return sf;
}

static
void
seenfile_destroy(struct seenfile *sf)
{
	free(sf->name);
	free(sf);
}

void
files_init(void)
{
	incdirarray_init(&quotepath);
	incdirarray_init(&bracketpath);
}

DESTROYALL(incdir);
DESTROYALL(seenfile);

void
files_cleanup(void)
{
	seenfilearray_destroyall(&seenfiles);
	seenfilearray_cleanup(&seenfiles);

	incdirarray_destroyall(&quotepath);
	incdirarray_cleanup(&quotepath);
	incdirarray_destroyall(&bracketpath);
	incdirarray_cleanup(&bracketpath);
}

////////////////////////////////////////////////////////////
// path setup

void
files_addquotepath(const char *dir, bool issystem)
{
	struct incdir *id;

	id = incdir_create(dir, issystem);
	incdirarray_add(&quotepath, id, NULL);
}

void
files_addbracketpath(const char *dir, bool issystem)
{
	struct incdir *id;

	id = incdir_create(dir, issystem);
	incdirarray_add(&bracketpath, id, NULL);
}

////////////////////////////////////////////////////////////
// places and complaints

#define NOWHERE_LINE      0
#define BUILTIN_LINE      1
#define COMMANDLINE_LINE  2

static struct place scratchplace;
static bool scratchplace_inuse;

static
bool
place_isnowhere(const struct place *p)
{
	return p->file == NULL && p->line == NOWHERE_LINE;
}

static
bool
place_isbuiltin(const struct place *p)
{
	return p->file == NULL && p->line == BUILTIN_LINE;
}

static
bool
place_iscommandline(const struct place *p)
{
	return p->file == NULL && p->line == COMMANDLINE_LINE;
}

struct place *
place_gettemporary(void)
{
	assert(!scratchplace_inuse);
	scratchplace_inuse = true;
	return &scratchplace;
}

void
place_puttemporary(struct place *p)
{
	assert(scratchplace_inuse);
	assert(p == &scratchplace);
	scratchplace_inuse = false;
}

struct place *
place_create(void)
{
	struct place *p;

	p = domalloc(sizeof(*p));
	place_setnowhere(p);
	return p;
}

struct place *
place_clone(const struct place *op)
{
	struct place *p;

	p = domalloc(sizeof(*p));
	*p = *op;
	return p;
}

void
place_destroy(struct place *p)
{
	free(p);
}

void
place_setnowhere(struct place *p)
{
	p->file = NULL;
	p->line = NOWHERE_LINE;
	p->column = 0;
}

void
place_setbuiltin(struct place *p, unsigned num)
{
	p->file = NULL;
	p->line = BUILTIN_LINE;
	p->column = num;
}

void
place_setcommandline(struct place *p, unsigned column)
{
	p->file = NULL;
	p->line = COMMANDLINE_LINE;
	p->column = column;
}

static
void
place_print(const struct place *p)
{
	if (place_iscommandline(p)) {
		fprintf(stderr, "<command-line>:1:%u", p->column);
	} else if (place_isbuiltin(p)) {
		fprintf(stderr, "<built-in>:%u:1", p->column);
	} else {
		fprintf(stderr, "%s:%u:%u", p->file->name, p->line, p->column);
	}
}

static
void
place_printfrom(const struct place *p)
{
	if (!place_isnowhere(&p->file->includedfrom)) {
		place_printfrom(&p->file->includedfrom);
	}
	fprintf(stderr, "In file included from ");
	fprintf(stderr, ":\n");
}

void
complain(const struct place *p, const char *fmt, ...)
{
	va_list ap;

	if (!place_isnowhere(&p->file->includedfrom)) {
		place_printfrom(&p->file->includedfrom);
	}
	place_print(p);
	fprintf(stderr, ": ");
	va_start(ap, fmt);
	vfprintf(stderr, fmt, ap);
	va_end(ap);
	fprintf(stderr, "\n");
}

void
complain_fail(void)
{
	overall_failure = true;
}

bool
complain_failed(void)
{
	return overall_failure;
}

////////////////////////////////////////////////////////////
// parsing

void
file_read(struct seenfile *sf, int fd);

////////////////////////////////////////////////////////////
// path search

static
int
file_tryopen(const char *file)
{
	int fd;

	fd = open(file, O_RDONLY);
	if (fd < 0) {
		return -1;
	}
	/* XXX: do we need to do anything here or is this function pointless?*/
	return fd;
}

static
void
file_search(struct place *place, struct incdirarray *path, const char *name)
{
	unsigned i, num;
	struct incdir *id;
	struct seenfile *sf;
	char *file;
	int fd;

	assert(place != NULL);

	num = incdirarray_num(path);
	for (i=0; i<num; i++) {
		id = incdirarray_get(path, i);
		file = dostrdup3(id->name, "/", name);
		fd = file_tryopen(file);
		if (fd >= 0) {
			sf = seenfile_create(place, file, id->issystem);
			seenfilearray_add(&seenfiles, sf, NULL);
			file_read(sf, fd);
			close(fd);
			return;
		}
		free(file);
	}
	complain(place, "Include file %s not found", name);
	complain_fail();
}

void
file_readquote(struct place *place, const char *name)
{
	file_search(place, &quotepath, name);
}

void
file_readbracket(struct place *place, const char *name)
{
	file_search(place, &bracketpath, name);
}

void
file_readabsolute(struct place *place, const char *name)
{
	struct seenfile *sf;
	int fd;

	assert(place != NULL);

	fd = file_tryopen(name);
	if (fd < 0) {
		warn("%s", name);
		die();
	}
	sf = seenfile_create(place, dostrdup(name), false);
	seenfilearray_add(&seenfiles, sf, NULL);
	file_read(sf, fd);
	close(fd);
}