Blame src/erec.c

Packit c5a612
/*
Packit c5a612
 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
Packit c5a612
 *
Packit c5a612
 * This program is free software; you can redistribute it and/or modify
Packit c5a612
 * it under the terms of the GNU General Public License version 2 as
Packit c5a612
 * published by the Free Software Foundation.
Packit c5a612
 *
Packit c5a612
 * Development of this code funded by Astaro AG (http://www.astaro.com/)
Packit c5a612
 */
Packit c5a612
Packit c5a612
#define _GNU_SOURCE
Packit c5a612
#include <config.h>
Packit c5a612
#include <stdio.h>
Packit c5a612
#include <string.h>
Packit c5a612
#include <stdarg.h>
Packit c5a612
#include <stdlib.h>
Packit c5a612
Packit c5a612
#include <netlink.h>
Packit c5a612
#include <gmputil.h>
Packit c5a612
#include <erec.h>
Packit c5a612
Packit c5a612
static const struct input_descriptor internal_indesc = {
Packit c5a612
	.type	= INDESC_INTERNAL,
Packit c5a612
	.name	= "internal",
Packit c5a612
};
Packit c5a612
Packit c5a612
const struct location internal_location = {
Packit c5a612
	.indesc	= &internal_indesc,
Packit c5a612
};
Packit c5a612
Packit c5a612
static const char * const error_record_names[] = {
Packit c5a612
	[EREC_INFORMATIONAL]	= NULL,
Packit c5a612
	[EREC_WARNING]		= "Warning",
Packit c5a612
	[EREC_ERROR]		= "Error"
Packit c5a612
};
Packit c5a612
Packit c5a612
void erec_add_location(struct error_record *erec, const struct location *loc)
Packit c5a612
{
Packit c5a612
	assert(erec->num_locations < EREC_LOCATIONS_MAX);
Packit c5a612
	erec->locations[erec->num_locations] = *loc;
Packit c5a612
	erec->locations[erec->num_locations].indesc = loc->indesc;
Packit c5a612
	erec->num_locations++;
Packit c5a612
}
Packit c5a612
Packit c5a612
void erec_destroy(struct error_record *erec)
Packit c5a612
{
Packit c5a612
	xfree(erec->msg);
Packit c5a612
	xfree(erec);
Packit c5a612
}
Packit c5a612
Packit c5a612
__attribute__((format(printf, 3, 0)))
Packit c5a612
struct error_record *erec_vcreate(enum error_record_types type,
Packit c5a612
				  const struct location *loc,
Packit c5a612
				  const char *fmt, va_list ap)
Packit c5a612
{
Packit c5a612
	struct error_record *erec;
Packit c5a612
Packit c5a612
	erec = xmalloc(sizeof(*erec));
Packit c5a612
	erec->type		= type;
Packit c5a612
	erec->num_locations	= 0;
Packit c5a612
	erec_add_location(erec, loc);
Packit c5a612
Packit c5a612
	if (vasprintf(&erec->msg, fmt, ap) < 0)
Packit c5a612
		erec->msg = NULL;
Packit c5a612
Packit c5a612
	return erec;
Packit c5a612
}
Packit c5a612
Packit c5a612
__attribute__((format(printf, 3, 4)))
Packit c5a612
struct error_record *erec_create(enum error_record_types type,
Packit c5a612
				 const struct location *loc,
Packit c5a612
				 const char *fmt, ...)
Packit c5a612
{
Packit c5a612
	struct error_record *erec;
Packit c5a612
	va_list ap;
Packit c5a612
Packit c5a612
	va_start(ap, fmt);
Packit c5a612
	erec = erec_vcreate(type, loc, fmt, ap);
Packit c5a612
	va_end(ap);
Packit c5a612
	return erec;
Packit c5a612
}
Packit c5a612
Packit c5a612
void erec_print(struct output_ctx *octx, const struct error_record *erec,
Packit c5a612
		unsigned int debug_mask)
Packit c5a612
{
Packit c5a612
	const struct location *loc = erec->locations, *iloc;
Packit c5a612
	const struct input_descriptor *indesc = loc->indesc, *tmp;
Packit c5a612
	const char *line = NULL;
Packit c5a612
	char buf[1024] = {};
Packit c5a612
	char *pbuf = NULL;
Packit c5a612
	unsigned int i, end;
Packit c5a612
	FILE *f;
Packit c5a612
	int l;
Packit c5a612
Packit c5a612
	switch (indesc->type) {
Packit c5a612
	case INDESC_BUFFER:
Packit c5a612
	case INDESC_CLI:
Packit c5a612
		line = indesc->data;
Packit c5a612
		*strchrnul(line, '\n') = '\0';
Packit c5a612
		break;
Packit c5a612
	case INDESC_FILE:
Packit c5a612
		f = fopen(indesc->name, "r");
Packit c5a612
		if (!f)
Packit c5a612
			break;
Packit c5a612
Packit c5a612
		if (!fseek(f, loc->line_offset, SEEK_SET) &&
Packit c5a612
		    fread(buf, 1, sizeof(buf) - 1, f) > 0) {
Packit c5a612
			*strchrnul(buf, '\n') = '\0';
Packit c5a612
			line = buf;
Packit c5a612
		}
Packit c5a612
		fclose(f);
Packit c5a612
		break;
Packit c5a612
	case INDESC_INTERNAL:
Packit c5a612
	case INDESC_NETLINK:
Packit c5a612
		break;
Packit c5a612
	default:
Packit c5a612
		BUG("invalid input descriptor type %u\n", indesc->type);
Packit c5a612
	}
Packit c5a612
Packit c5a612
	f = octx->error_fp;
Packit c5a612
Packit c5a612
	if (indesc->type == INDESC_NETLINK) {
Packit c5a612
		fprintf(f, "%s: ", indesc->name);
Packit c5a612
		if (error_record_names[erec->type])
Packit c5a612
			fprintf(f, "%s: ", error_record_names[erec->type]);
Packit c5a612
		fprintf(f, "%s\n", erec->msg);
Packit c5a612
		for (l = 0; l < (int)erec->num_locations; l++) {
Packit c5a612
			loc = &erec->locations[l];
Packit c5a612
			netlink_dump_expr(loc->nle, f, debug_mask);
Packit c5a612
		}
Packit c5a612
		return;
Packit c5a612
	}
Packit c5a612
Packit c5a612
	if (indesc->location.indesc != NULL) {
Packit c5a612
		const char *prefix = "In file included from";
Packit c5a612
		iloc = &indesc->location;
Packit c5a612
		for (tmp = iloc->indesc;
Packit c5a612
		     tmp != NULL && tmp->type != INDESC_INTERNAL;
Packit c5a612
		     tmp = iloc->indesc) {
Packit c5a612
			fprintf(f, "%s %s:%u:%u-%u:\n", prefix,
Packit c5a612
				tmp->name,
Packit c5a612
				iloc->first_line, iloc->first_column,
Packit c5a612
				iloc->last_column);
Packit c5a612
			prefix = "                 from";
Packit c5a612
			iloc = &tmp->location;
Packit c5a612
		}
Packit c5a612
	}
Packit c5a612
	if (indesc->name != NULL)
Packit c5a612
		fprintf(f, "%s:%u:%u-%u: ", indesc->name,
Packit c5a612
			loc->first_line, loc->first_column,
Packit c5a612
			loc->last_column);
Packit c5a612
	if (error_record_names[erec->type])
Packit c5a612
		fprintf(f, "%s: ", error_record_names[erec->type]);
Packit c5a612
	fprintf(f, "%s\n", erec->msg);
Packit c5a612
Packit c5a612
	if (line) {
Packit c5a612
		fprintf(f, "%s\n", line);
Packit c5a612
Packit c5a612
		end = 0;
Packit c5a612
		for (l = erec->num_locations - 1; l >= 0; l--) {
Packit c5a612
			loc = &erec->locations[l];
Packit c5a612
			end = max(end, loc->last_column);
Packit c5a612
		}
Packit c5a612
		pbuf = xmalloc(end + 1);
Packit c5a612
		memset(pbuf, ' ', end + 1);
Packit c5a612
		for (i = 0; i < end && line[i]; i++) {
Packit c5a612
			if (line[i] == '\t')
Packit c5a612
				pbuf[i] = '\t';
Packit c5a612
		}
Packit c5a612
		for (l = erec->num_locations - 1; l >= 0; l--) {
Packit c5a612
			loc = &erec->locations[l];
Packit c5a612
			for (i = loc->first_column ? loc->first_column - 1 : 0;
Packit c5a612
			     i < loc->last_column; i++)
Packit c5a612
				pbuf[i] = l ? '~' : '^';
Packit c5a612
		}
Packit c5a612
		pbuf[end] = '\0';
Packit c5a612
		fprintf(f, "%s", pbuf);
Packit c5a612
		xfree(pbuf);
Packit c5a612
	}
Packit c5a612
	fprintf(f, "\n");
Packit c5a612
}
Packit c5a612
Packit c5a612
void erec_print_list(struct output_ctx *octx, struct list_head *list,
Packit c5a612
		     unsigned int debug_mask)
Packit c5a612
{
Packit c5a612
	struct error_record *erec, *next;
Packit c5a612
Packit c5a612
	list_for_each_entry_safe(erec, next, list, list) {
Packit c5a612
		list_del(&erec->list);
Packit c5a612
		erec_print(octx, erec, debug_mask);
Packit c5a612
		erec_destroy(erec);
Packit c5a612
	}
Packit c5a612
}
Packit c5a612
Packit c5a612
int __fmtstring(4, 5) __stmt_binary_error(struct eval_ctx *ctx,
Packit c5a612
					  const struct location *l1,
Packit c5a612
					  const struct location *l2,
Packit c5a612
					  const char *fmt, ...)
Packit c5a612
{
Packit c5a612
	struct error_record *erec;
Packit c5a612
	va_list ap;
Packit c5a612
Packit c5a612
	va_start(ap, fmt);
Packit c5a612
	erec = erec_vcreate(EREC_ERROR, l1, fmt, ap);
Packit c5a612
	if (l2 != NULL)
Packit c5a612
		erec_add_location(erec, l2);
Packit c5a612
	va_end(ap);
Packit c5a612
	erec_queue(erec, ctx->msgs);
Packit c5a612
	return -1;
Packit c5a612
}