mirror of
https://github.com/openbsd/src.git
synced 2025-01-03 06:45:37 -08:00
396 lines
7.9 KiB
C
396 lines
7.9 KiB
C
/*-
|
|
* Copyright (c) 2010 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
* by David A. Holland.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#include "utils.h"
|
|
#include "array.h"
|
|
#include "place.h"
|
|
|
|
struct placefile {
|
|
struct place includedfrom;
|
|
char *dir;
|
|
char *name;
|
|
int depth;
|
|
bool fromsystemdir;
|
|
};
|
|
DECLARRAY(placefile, static UNUSED);
|
|
DEFARRAY(placefile, static);
|
|
|
|
static struct placefilearray placefiles;
|
|
static bool overall_failure;
|
|
|
|
static const char *myprogname;
|
|
|
|
static FILE *debuglogfile;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// placefiles
|
|
|
|
static
|
|
struct placefile *
|
|
placefile_create(const struct place *from, const char *name,
|
|
bool fromsystemdir)
|
|
{
|
|
struct placefile *pf;
|
|
const char *s;
|
|
size_t len;
|
|
|
|
pf = domalloc(sizeof(*pf));
|
|
pf->includedfrom = *from;
|
|
|
|
s = strrchr(name, '/');
|
|
len = (s == NULL) ? 0 : s - name;
|
|
pf->dir = dostrndup(name, len);
|
|
|
|
pf->name = dostrdup(name);
|
|
pf->fromsystemdir = fromsystemdir;
|
|
|
|
if (from->file != NULL) {
|
|
pf->depth = from->file->depth + 1;
|
|
} else {
|
|
pf->depth = 1;
|
|
}
|
|
return pf;
|
|
}
|
|
|
|
static
|
|
void
|
|
placefile_destroy(struct placefile *pf)
|
|
{
|
|
dostrfree(pf->name);
|
|
dofree(pf, sizeof(*pf));
|
|
}
|
|
|
|
DESTROYALL_ARRAY(placefile, );
|
|
|
|
const char *
|
|
place_getparsedir(const struct place *place)
|
|
{
|
|
if (place->file == NULL) {
|
|
return ".";
|
|
}
|
|
return place->file->dir;
|
|
}
|
|
|
|
static
|
|
struct placefile *
|
|
placefile_find(const struct place *incfrom, const char *name)
|
|
{
|
|
unsigned i, num;
|
|
struct placefile *pf;
|
|
|
|
num = placefilearray_num(&placefiles);
|
|
for (i=0; i<num; i++) {
|
|
pf = placefilearray_get(&placefiles, i);
|
|
if (place_eq(incfrom, &pf->includedfrom) &&
|
|
!strcmp(name, pf->name)) {
|
|
return pf;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
place_changefile(struct place *p, const char *name)
|
|
{
|
|
struct placefile *pf;
|
|
|
|
assert(p->type == P_FILE);
|
|
if (!strcmp(name, p->file->name)) {
|
|
return;
|
|
}
|
|
pf = placefile_find(&p->file->includedfrom, name);
|
|
if (pf == NULL) {
|
|
pf = placefile_create(&p->file->includedfrom, name,
|
|
p->file->fromsystemdir);
|
|
placefilearray_add(&placefiles, pf, NULL);
|
|
}
|
|
p->file = pf;
|
|
}
|
|
|
|
const struct placefile *
|
|
place_addfile(const struct place *place, const char *file, bool issystem)
|
|
{
|
|
struct placefile *pf;
|
|
|
|
pf = placefile_create(place, file, issystem);
|
|
placefilearray_add(&placefiles, pf, NULL);
|
|
if (pf->depth > 120) {
|
|
complain(place, "Maximum include nesting depth exceeded");
|
|
die();
|
|
}
|
|
return pf;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// places
|
|
|
|
void
|
|
place_setnowhere(struct place *p)
|
|
{
|
|
p->type = P_NOWHERE;
|
|
p->file = NULL;
|
|
p->line = 0;
|
|
p->column = 0;
|
|
}
|
|
|
|
void
|
|
place_setbuiltin(struct place *p, unsigned num)
|
|
{
|
|
p->type = P_BUILTIN;
|
|
p->file = NULL;
|
|
p->line = num;
|
|
p->column = 1;
|
|
}
|
|
|
|
void
|
|
place_setcommandline(struct place *p, unsigned line, unsigned column)
|
|
{
|
|
p->type = P_COMMANDLINE;
|
|
p->file = NULL;
|
|
p->line = line;
|
|
p->column = column;
|
|
}
|
|
|
|
void
|
|
place_setfilestart(struct place *p, const struct placefile *pf)
|
|
{
|
|
p->type = P_FILE;
|
|
p->file = pf;
|
|
p->line = 1;
|
|
p->column = 1;
|
|
}
|
|
|
|
void
|
|
place_addcolumns(struct place *p, unsigned cols)
|
|
{
|
|
unsigned newcol;
|
|
|
|
newcol = p->column + cols;
|
|
if (newcol < p->column) {
|
|
/* overflow (use the old place to complain) */
|
|
complain(p, "Column numbering overflow");
|
|
die();
|
|
}
|
|
p->column = newcol;
|
|
}
|
|
|
|
void
|
|
place_addlines(struct place *p, unsigned lines)
|
|
{
|
|
unsigned nextline;
|
|
|
|
nextline = p->line + lines;
|
|
if (nextline < p->line) {
|
|
/* overflow (use the old place to complain) */
|
|
complain(p, "Line numbering overflow");
|
|
die();
|
|
}
|
|
p->line = nextline;
|
|
}
|
|
|
|
const char *
|
|
place_getname(const struct place *p)
|
|
{
|
|
switch (p->type) {
|
|
case P_NOWHERE: return "<nowhere>";
|
|
case P_BUILTIN: return "<built-in>";
|
|
case P_COMMANDLINE: return "<command-line>";
|
|
case P_FILE: return p->file->name;
|
|
}
|
|
assert(0);
|
|
return NULL;
|
|
}
|
|
|
|
bool
|
|
place_samefile(const struct place *a, const struct place *b)
|
|
{
|
|
if (a->type != b->type) {
|
|
return false;
|
|
}
|
|
if (a->file != b->file) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
place_eq(const struct place *a, const struct place *b)
|
|
{
|
|
if (!place_samefile(a, b)) {
|
|
return false;
|
|
}
|
|
if (a->line != b->line || a->column != b->column) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static
|
|
void
|
|
place_printfrom(const struct place *p)
|
|
{
|
|
const struct place *from;
|
|
|
|
if (p->file == NULL) {
|
|
return;
|
|
}
|
|
from = &p->file->includedfrom;
|
|
if (from->type != P_NOWHERE) {
|
|
place_printfrom(from);
|
|
fprintf(stderr, "In file included from %s:%u:%u:\n",
|
|
place_getname(from), from->line, from->column);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// complaints
|
|
|
|
void
|
|
complain_init(const char *pn)
|
|
{
|
|
myprogname = pn;
|
|
}
|
|
|
|
void
|
|
complain(const struct place *p, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
if (p != NULL) {
|
|
place_printfrom(p);
|
|
fprintf(stderr, "%s:%u:%u: ", place_getname(p),
|
|
p->line, p->column);
|
|
} else {
|
|
fprintf(stderr, "%s: ", myprogname);
|
|
}
|
|
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;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// debug logging
|
|
|
|
void
|
|
debuglog_open(const struct place *p, /*const*/ char *file)
|
|
{
|
|
assert(debuglogfile == NULL);
|
|
debuglogfile = fopen(file, "w");
|
|
if (debuglogfile == NULL) {
|
|
complain(p, "%s: %s", file, strerror(errno));
|
|
die();
|
|
}
|
|
}
|
|
|
|
void
|
|
debuglog_close(void)
|
|
{
|
|
if (debuglogfile != NULL) {
|
|
fclose(debuglogfile);
|
|
debuglogfile = NULL;
|
|
}
|
|
}
|
|
|
|
PF(2, 3) void
|
|
debuglog(const struct place *p, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
if (debuglogfile == NULL) {
|
|
return;
|
|
}
|
|
|
|
fprintf(debuglogfile, "%s:%u: ", place_getname(p), p->line);
|
|
va_start(ap, fmt);
|
|
vfprintf(debuglogfile, fmt, ap);
|
|
va_end(ap);
|
|
fprintf(debuglogfile, "\n");
|
|
fflush(debuglogfile);
|
|
}
|
|
|
|
PF(3, 4) void
|
|
debuglog2(const struct place *p, const struct place *p2, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
if (debuglogfile == NULL) {
|
|
return;
|
|
}
|
|
|
|
fprintf(debuglogfile, "%s:%u: ", place_getname(p), p->line);
|
|
if (place_samefile(p, p2)) {
|
|
fprintf(debuglogfile, "(block began at line %u) ",
|
|
p2->line);
|
|
} else {
|
|
fprintf(debuglogfile, "(block began at %s:%u)",
|
|
place_getname(p2), p2->line);
|
|
}
|
|
va_start(ap, fmt);
|
|
vfprintf(debuglogfile, fmt, ap);
|
|
va_end(ap);
|
|
fprintf(debuglogfile, "\n");
|
|
fflush(debuglogfile);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// module init and cleanup
|
|
|
|
void
|
|
place_init(void)
|
|
{
|
|
placefilearray_init(&placefiles);
|
|
}
|
|
|
|
void
|
|
place_cleanup(void)
|
|
{
|
|
placefilearray_destroyall(&placefiles);
|
|
placefilearray_cleanup(&placefiles);
|
|
}
|