1204431Sraj/*
2204431Sraj * Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc.
3204431Sraj *
4204431Sraj * This program is free software; you can redistribute it and/or
5204431Sraj * modify it under the terms of the GNU General Public License as
6204431Sraj * published by the Free Software Foundation; either version 2 of the
7204431Sraj * License, or (at your option) any later version.
8204431Sraj *
9204431Sraj *  This program is distributed in the hope that it will be useful,
10204431Sraj *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11204431Sraj *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12204431Sraj *  General Public License for more details.
13204431Sraj *
14204431Sraj *  You should have received a copy of the GNU General Public License
15204431Sraj *  along with this program; if not, write to the Free Software
16204431Sraj *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
17204431Sraj *                                                                   USA
18204431Sraj */
19204431Sraj
20204433Sraj#define _GNU_SOURCE
21204433Sraj
22204433Sraj#include <stdio.h>
23204433Sraj
24204431Sraj#include "dtc.h"
25204431Sraj#include "srcpos.h"
26204431Sraj
27238742Simp/* A node in our list of directories to search for source/include files */
28238742Simpstruct search_path {
29238742Simp	struct search_path *next;	/* next node in list, NULL for end */
30238742Simp	const char *dirname;		/* name of directory to search */
31238742Simp};
32204433Sraj
33238742Simp/* This is the list of directories that we search for source files */
34238742Simpstatic struct search_path *search_path_head, **search_path_tail;
35204431Sraj
36204433Sraj
37318102Sgonzostatic char *get_dirname(const char *path)
38238742Simp{
39238742Simp	const char *slash = strrchr(path, '/');
40204433Sraj
41238742Simp	if (slash) {
42238742Simp		int len = slash - path;
43238742Simp		char *dir = xmalloc(len + 1);
44204433Sraj
45238742Simp		memcpy(dir, path, len);
46238742Simp		dir[len] = '\0';
47238742Simp		return dir;
48238742Simp	}
49238742Simp	return NULL;
50238742Simp}
51204433Sraj
52238742SimpFILE *depfile; /* = NULL */
53238742Simpstruct srcfile_state *current_srcfile; /* = NULL */
54238742Simp
55238742Simp/* Detect infinite include recursion. */
56238742Simp#define MAX_SRCFILE_DEPTH     (100)
57238742Simpstatic int srcfile_depth; /* = 0 */
58238742Simp
59238742Simp
60238742Simp/**
61238742Simp * Try to open a file in a given directory.
62238742Simp *
63238742Simp * If the filename is an absolute path, then dirname is ignored. If it is a
64238742Simp * relative path, then we look in that directory for the file.
65238742Simp *
66238742Simp * @param dirname	Directory to look in, or NULL for none
67238742Simp * @param fname		Filename to look for
68238742Simp * @param fp		Set to NULL if file did not open
69238742Simp * @return allocated filename on success (caller must free), NULL on failure
70238742Simp */
71238742Simpstatic char *try_open(const char *dirname, const char *fname, FILE **fp)
72204431Sraj{
73204431Sraj	char *fullname;
74204431Sraj
75238742Simp	if (!dirname || fname[0] == '/')
76204433Sraj		fullname = xstrdup(fname);
77238742Simp	else
78238742Simp		fullname = join_path(dirname, fname);
79204431Sraj
80318102Sgonzo	*fp = fopen(fullname, "rb");
81238742Simp	if (!*fp) {
82204431Sraj		free(fullname);
83238742Simp		fullname = NULL;
84204431Sraj	}
85204431Sraj
86238742Simp	return fullname;
87204431Sraj}
88204431Sraj
89238742Simp/**
90238742Simp * Open a file for read access
91238742Simp *
92238742Simp * If it is a relative filename, we search the full search path for it.
93238742Simp *
94238742Simp * @param fname	Filename to open
95238742Simp * @param fp	Returns pointer to opened FILE, or NULL on failure
96238742Simp * @return pointer to allocated filename, which caller must free
97238742Simp */
98238742Simpstatic char *fopen_any_on_path(const char *fname, FILE **fp)
99204431Sraj{
100238742Simp	const char *cur_dir = NULL;
101238742Simp	struct search_path *node;
102238742Simp	char *fullname;
103204431Sraj
104238742Simp	/* Try current directory first */
105238742Simp	assert(fp);
106238742Simp	if (current_srcfile)
107238742Simp		cur_dir = current_srcfile->dir;
108238742Simp	fullname = try_open(cur_dir, fname, fp);
109204431Sraj
110238742Simp	/* Failing that, try each search path in turn */
111238742Simp	for (node = search_path_head; !*fp && node; node = node->next)
112238742Simp		fullname = try_open(node->dirname, fname, fp);
113204431Sraj
114238742Simp	return fullname;
115238742Simp}
116204431Sraj
117238742SimpFILE *srcfile_relative_open(const char *fname, char **fullnamep)
118238742Simp{
119238742Simp	FILE *f;
120238742Simp	char *fullname;
121204431Sraj
122204431Sraj	if (streq(fname, "-")) {
123238742Simp		f = stdin;
124238742Simp		fullname = xstrdup("<stdin>");
125238742Simp	} else {
126238742Simp		fullname = fopen_any_on_path(fname, &f);
127238742Simp		if (!f)
128238742Simp			die("Couldn't open \"%s\": %s\n", fname,
129238742Simp			    strerror(errno));
130204431Sraj	}
131204431Sraj
132238742Simp	if (depfile)
133238742Simp		fprintf(depfile, " %s", fullname);
134204431Sraj
135238742Simp	if (fullnamep)
136238742Simp		*fullnamep = fullname;
137238742Simp	else
138238742Simp		free(fullname);
139204431Sraj
140238742Simp	return f;
141238742Simp}
142204431Sraj
143238742Simpvoid srcfile_push(const char *fname)
144238742Simp{
145238742Simp	struct srcfile_state *srcfile;
146204431Sraj
147238742Simp	if (srcfile_depth++ >= MAX_SRCFILE_DEPTH)
148238742Simp		die("Includes nested too deeply");
149204431Sraj
150238742Simp	srcfile = xmalloc(sizeof(*srcfile));
151204431Sraj
152238742Simp	srcfile->f = srcfile_relative_open(fname, &srcfile->name);
153318102Sgonzo	srcfile->dir = get_dirname(srcfile->name);
154238742Simp	srcfile->prev = current_srcfile;
155238742Simp
156238742Simp	srcfile->lineno = 1;
157238742Simp	srcfile->colno = 1;
158238742Simp
159238742Simp	current_srcfile = srcfile;
160204431Sraj}
161204431Sraj
162261215Simpbool srcfile_pop(void)
163238742Simp{
164238742Simp	struct srcfile_state *srcfile = current_srcfile;
165204433Sraj
166238742Simp	assert(srcfile);
167238742Simp
168238742Simp	current_srcfile = srcfile->prev;
169238742Simp
170238742Simp	if (fclose(srcfile->f))
171238742Simp		die("Error closing \"%s\": %s\n", srcfile->name,
172238742Simp		    strerror(errno));
173238742Simp
174238742Simp	/* FIXME: We allow the srcfile_state structure to leak,
175238742Simp	 * because it could still be referenced from a location
176238742Simp	 * variable being carried through the parser somewhere.  To
177238742Simp	 * fix this we could either allocate all the files from a
178238742Simp	 * table, or use a pool allocator. */
179238742Simp
180261215Simp	return current_srcfile ? true : false;
181238742Simp}
182238742Simp
183238742Simpvoid srcfile_add_search_path(const char *dirname)
184204431Sraj{
185238742Simp	struct search_path *node;
186238742Simp
187238742Simp	/* Create the node */
188238742Simp	node = xmalloc(sizeof(*node));
189238742Simp	node->next = NULL;
190238742Simp	node->dirname = xstrdup(dirname);
191238742Simp
192238742Simp	/* Add to the end of our list */
193238742Simp	if (search_path_tail)
194238742Simp		*search_path_tail = node;
195238742Simp	else
196238742Simp		search_path_head = node;
197238742Simp	search_path_tail = &node->next;
198204433Sraj}
199204431Sraj
200238742Simp/*
201238742Simp * The empty source position.
202238742Simp */
203204433Sraj
204238742Simpstruct srcpos srcpos_empty = {
205238742Simp	.first_line = 0,
206238742Simp	.first_column = 0,
207238742Simp	.last_line = 0,
208238742Simp	.last_column = 0,
209238742Simp	.file = NULL,
210238742Simp};
211238742Simp
212238742Simp#define TAB_SIZE      8
213238742Simp
214238742Simpvoid srcpos_update(struct srcpos *pos, const char *text, int len)
215204433Sraj{
216238742Simp	int i;
217204433Sraj
218238742Simp	pos->file = current_srcfile;
219204433Sraj
220238742Simp	pos->first_line = current_srcfile->lineno;
221238742Simp	pos->first_column = current_srcfile->colno;
222238742Simp
223238742Simp	for (i = 0; i < len; i++)
224238742Simp		if (text[i] == '\n') {
225238742Simp			current_srcfile->lineno++;
226238742Simp			current_srcfile->colno = 1;
227238742Simp		} else if (text[i] == '\t') {
228238742Simp			current_srcfile->colno =
229238742Simp				ALIGN(current_srcfile->colno, TAB_SIZE);
230238742Simp		} else {
231238742Simp			current_srcfile->colno++;
232238742Simp		}
233238742Simp
234238742Simp	pos->last_line = current_srcfile->lineno;
235238742Simp	pos->last_column = current_srcfile->colno;
236238742Simp}
237238742Simp
238238742Simpstruct srcpos *
239238742Simpsrcpos_copy(struct srcpos *pos)
240238742Simp{
241238742Simp	struct srcpos *pos_new;
242238742Simp
243238742Simp	pos_new = xmalloc(sizeof(struct srcpos));
244238742Simp	memcpy(pos_new, pos, sizeof(struct srcpos));
245238742Simp
246204433Sraj	return pos_new;
247204431Sraj}
248204433Sraj
249204433Srajchar *
250238742Simpsrcpos_string(struct srcpos *pos)
251204433Sraj{
252238742Simp	const char *fname = "<no-file>";
253204433Sraj	char *pos_str;
254204433Sraj
255318102Sgonzo	if (pos->file && pos->file->name)
256204433Sraj		fname = pos->file->name;
257204433Sraj
258204433Sraj
259238742Simp	if (pos->first_line != pos->last_line)
260318102Sgonzo		xasprintf(&pos_str, "%s:%d.%d-%d.%d", fname,
261318102Sgonzo			  pos->first_line, pos->first_column,
262318102Sgonzo			  pos->last_line, pos->last_column);
263238742Simp	else if (pos->first_column != pos->last_column)
264318102Sgonzo		xasprintf(&pos_str, "%s:%d.%d-%d", fname,
265318102Sgonzo			  pos->first_line, pos->first_column,
266318102Sgonzo			  pos->last_column);
267238742Simp	else
268318102Sgonzo		xasprintf(&pos_str, "%s:%d.%d", fname,
269318102Sgonzo			  pos->first_line, pos->first_column);
270204433Sraj
271204433Sraj	return pos_str;
272204433Sraj}
273204433Sraj
274261215Simpvoid srcpos_verror(struct srcpos *pos, const char *prefix,
275261215Simp		   const char *fmt, va_list va)
276238742Simp{
277261215Simp	char *srcstr;
278204433Sraj
279261215Simp	srcstr = srcpos_string(pos);
280238742Simp
281261215Simp	fprintf(stderr, "%s: %s ", prefix, srcstr);
282261215Simp	vfprintf(stderr, fmt, va);
283261215Simp	fprintf(stderr, "\n");
284261215Simp
285261215Simp	free(srcstr);
286238742Simp}
287238742Simp
288261215Simpvoid srcpos_error(struct srcpos *pos, const char *prefix,
289261215Simp		  const char *fmt, ...)
290204433Sraj{
291204433Sraj	va_list va;
292238742Simp
293204433Sraj	va_start(va, fmt);
294261215Simp	srcpos_verror(pos, prefix, fmt, va);
295204433Sraj	va_end(va);
296204433Sraj}
297204433Sraj
298261215Simpvoid srcpos_set_line(char *f, int l)
299204433Sraj{
300261215Simp	current_srcfile->name = f;
301261215Simp	current_srcfile->lineno = l;
302204433Sraj}
303