srcpos.c 7.5 KB
Newer Older
D
David Gibson 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 * Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 *                                                                   USA
 */

20 21 22 23
#define _GNU_SOURCE

#include <stdio.h>

D
David Gibson 已提交
24 25 26
#include "dtc.h"
#include "srcpos.h"

S
Stephen Warren 已提交
27 28 29 30 31 32 33 34 35
/* A node in our list of directories to search for source/include files */
struct search_path {
	struct search_path *next;	/* next node in list, NULL for end */
	const char *dirname;		/* name of directory to search */
};

/* This is the list of directories that we search for source files */
static struct search_path *search_path_head, **search_path_tail;

D
David Gibson 已提交
36

37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
static char *dirname(const char *path)
{
	const char *slash = strrchr(path, '/');

	if (slash) {
		int len = slash - path;
		char *dir = xmalloc(len + 1);

		memcpy(dir, path, len);
		dir[len] = '\0';
		return dir;
	}
	return NULL;
}

52
FILE *depfile; /* = NULL */
53
struct srcfile_state *current_srcfile; /* = NULL */
D
David Gibson 已提交
54

55 56 57 58
/* Detect infinite include recursion. */
#define MAX_SRCFILE_DEPTH     (100)
static int srcfile_depth; /* = 0 */

S
Stephen Warren 已提交
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116

/**
 * Try to open a file in a given directory.
 *
 * If the filename is an absolute path, then dirname is ignored. If it is a
 * relative path, then we look in that directory for the file.
 *
 * @param dirname	Directory to look in, or NULL for none
 * @param fname		Filename to look for
 * @param fp		Set to NULL if file did not open
 * @return allocated filename on success (caller must free), NULL on failure
 */
static char *try_open(const char *dirname, const char *fname, FILE **fp)
{
	char *fullname;

	if (!dirname || fname[0] == '/')
		fullname = xstrdup(fname);
	else
		fullname = join_path(dirname, fname);

	*fp = fopen(fullname, "r");
	if (!*fp) {
		free(fullname);
		fullname = NULL;
	}

	return fullname;
}

/**
 * Open a file for read access
 *
 * If it is a relative filename, we search the full search path for it.
 *
 * @param fname	Filename to open
 * @param fp	Returns pointer to opened FILE, or NULL on failure
 * @return pointer to allocated filename, which caller must free
 */
static char *fopen_any_on_path(const char *fname, FILE **fp)
{
	const char *cur_dir = NULL;
	struct search_path *node;
	char *fullname;

	/* Try current directory first */
	assert(fp);
	if (current_srcfile)
		cur_dir = current_srcfile->dir;
	fullname = try_open(cur_dir, fname, fp);

	/* Failing that, try each search path in turn */
	for (node = search_path_head; !*fp && node; node = node->next)
		fullname = try_open(node->dirname, fname, fp);

	return fullname;
}

117
FILE *srcfile_relative_open(const char *fname, char **fullnamep)
D
David Gibson 已提交
118
{
119
	FILE *f;
120
	char *fullname;
D
David Gibson 已提交
121

122 123 124
	if (streq(fname, "-")) {
		f = stdin;
		fullname = xstrdup("<stdin>");
125
	} else {
S
Stephen Warren 已提交
126
		fullname = fopen_any_on_path(fname, &f);
127 128 129
		if (!f)
			die("Couldn't open \"%s\": %s\n", fname,
			    strerror(errno));
130
	}
D
David Gibson 已提交
131

132 133 134
	if (depfile)
		fprintf(depfile, " %s", fullname);

135 136 137
	if (fullnamep)
		*fullnamep = fullname;
	else
138
		free(fullname);
D
David Gibson 已提交
139

140
	return f;
D
David Gibson 已提交
141 142
}

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
void srcfile_push(const char *fname)
{
	struct srcfile_state *srcfile;

	if (srcfile_depth++ >= MAX_SRCFILE_DEPTH)
		die("Includes nested too deeply");

	srcfile = xmalloc(sizeof(*srcfile));

	srcfile->f = srcfile_relative_open(fname, &srcfile->name);
	srcfile->dir = dirname(srcfile->name);
	srcfile->prev = current_srcfile;

	srcfile->lineno = 1;
	srcfile->colno = 1;

	current_srcfile = srcfile;
}
D
David Gibson 已提交
161

162
int srcfile_pop(void)
163
{
164
	struct srcfile_state *srcfile = current_srcfile;
D
David Gibson 已提交
165

166
	assert(srcfile);
D
David Gibson 已提交
167

168
	current_srcfile = srcfile->prev;
D
David Gibson 已提交
169

170 171 172
	if (fclose(srcfile->f))
		die("Error closing \"%s\": %s\n", srcfile->name,
		    strerror(errno));
173

174 175 176 177 178
	/* FIXME: We allow the srcfile_state structure to leak,
	 * because it could still be referenced from a location
	 * variable being carried through the parser somewhere.  To
	 * fix this we could either allocate all the files from a
	 * table, or use a pool allocator. */
D
David Gibson 已提交
179

180 181
	return current_srcfile ? 1 : 0;
}
D
David Gibson 已提交
182

S
Stephen Warren 已提交
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
void srcfile_add_search_path(const char *dirname)
{
	struct search_path *node;

	/* Create the node */
	node = xmalloc(sizeof(*node));
	node->next = NULL;
	node->dirname = xstrdup(dirname);

	/* Add to the end of our list */
	if (search_path_tail)
		*search_path_tail = node;
	else
		search_path_head = node;
	search_path_tail = &node->next;
}

200 201 202
/*
 * The empty source position.
 */
203

204 205 206 207 208 209 210
struct srcpos srcpos_empty = {
	.first_line = 0,
	.first_column = 0,
	.last_line = 0,
	.last_column = 0,
	.file = NULL,
};
D
David Gibson 已提交
211

212
#define TAB_SIZE      8
D
David Gibson 已提交
213

214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
void srcpos_update(struct srcpos *pos, const char *text, int len)
{
	int i;

	pos->file = current_srcfile;

	pos->first_line = current_srcfile->lineno;
	pos->first_column = current_srcfile->colno;

	for (i = 0; i < len; i++)
		if (text[i] == '\n') {
			current_srcfile->lineno++;
			current_srcfile->colno = 1;
		} else if (text[i] == '\t') {
			current_srcfile->colno =
				ALIGN(current_srcfile->colno, TAB_SIZE);
		} else {
			current_srcfile->colno++;
		}

	pos->last_line = current_srcfile->lineno;
	pos->last_column = current_srcfile->colno;
}
237

238 239 240 241
struct srcpos *
srcpos_copy(struct srcpos *pos)
{
	struct srcpos *pos_new;
242

243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
	pos_new = xmalloc(sizeof(struct srcpos));
	memcpy(pos_new, pos, sizeof(struct srcpos));

	return pos_new;
}



void
srcpos_dump(struct srcpos *pos)
{
	printf("file        : \"%s\"\n",
	       pos->file ? (char *) pos->file : "<no file>");
	printf("first_line  : %d\n", pos->first_line);
	printf("first_column: %d\n", pos->first_column);
	printf("last_line   : %d\n", pos->last_line);
	printf("last_column : %d\n", pos->last_column);
	printf("file        : %s\n", pos->file->name);
}
D
David Gibson 已提交
262

263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302

char *
srcpos_string(struct srcpos *pos)
{
	const char *fname = "<no-file>";
	char *pos_str;
	int rc;

	if (pos)
		fname = pos->file->name;


	if (pos->first_line != pos->last_line)
		rc = asprintf(&pos_str, "%s:%d.%d-%d.%d", fname,
			      pos->first_line, pos->first_column,
			      pos->last_line, pos->last_column);
	else if (pos->first_column != pos->last_column)
		rc = asprintf(&pos_str, "%s:%d.%d-%d", fname,
			      pos->first_line, pos->first_column,
			      pos->last_column);
	else
		rc = asprintf(&pos_str, "%s:%d.%d", fname,
			      pos->first_line, pos->first_column);

	if (rc == -1)
		die("Couldn't allocate in srcpos string");

	return pos_str;
}

void
srcpos_verror(struct srcpos *pos, char const *fmt, va_list va)
{
       const char *srcstr;

       srcstr = srcpos_string(pos);

       fprintf(stdout, "Error: %s ", srcstr);
       vfprintf(stdout, fmt, va);
       fprintf(stdout, "\n");
D
David Gibson 已提交
303 304
}

305 306
void
srcpos_error(struct srcpos *pos, char const *fmt, ...)
D
David Gibson 已提交
307
{
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
	va_list va;

	va_start(va, fmt);
	srcpos_verror(pos, fmt, va);
	va_end(va);
}


void
srcpos_warn(struct srcpos *pos, char const *fmt, ...)
{
	const char *srcstr;
	va_list va;
	va_start(va, fmt);

	srcstr = srcpos_string(pos);

	fprintf(stderr, "Warning: %s ", srcstr);
	vfprintf(stderr, fmt, va);
	fprintf(stderr, "\n");
328

329
	va_end(va);
D
David Gibson 已提交
330
}
S
Stephen Warren 已提交
331 332 333 334 335 336

void srcpos_set_line(char *f, int l)
{
	current_srcfile->name = f;
	current_srcfile->lineno = l;
}