xref: /openbmc/linux/scripts/dtc/srcpos.c (revision dd5b2498)
1 /*
2  * Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
17  *                                                                   USA
18  */
19 
20 #define _GNU_SOURCE
21 
22 #include <stdio.h>
23 
24 #include "dtc.h"
25 #include "srcpos.h"
26 
27 /* A node in our list of directories to search for source/include files */
28 struct search_path {
29 	struct search_path *next;	/* next node in list, NULL for end */
30 	const char *dirname;		/* name of directory to search */
31 };
32 
33 /* This is the list of directories that we search for source files */
34 static struct search_path *search_path_head, **search_path_tail;
35 
36 /* Detect infinite include recursion. */
37 #define MAX_SRCFILE_DEPTH     (100)
38 static int srcfile_depth; /* = 0 */
39 
40 static char *get_dirname(const char *path)
41 {
42 	const char *slash = strrchr(path, '/');
43 
44 	if (slash) {
45 		int len = slash - path;
46 		char *dir = xmalloc(len + 1);
47 
48 		memcpy(dir, path, len);
49 		dir[len] = '\0';
50 		return dir;
51 	}
52 	return NULL;
53 }
54 
55 FILE *depfile; /* = NULL */
56 struct srcfile_state *current_srcfile; /* = NULL */
57 static char *initial_path; /* = NULL */
58 static int initial_pathlen; /* = 0 */
59 static bool initial_cpp = true;
60 
61 static void set_initial_path(char *fname)
62 {
63 	int i, len = strlen(fname);
64 
65 	xasprintf(&initial_path, "%s", fname);
66 	initial_pathlen = 0;
67 	for (i = 0; i != len; i++)
68 		if (initial_path[i] == '/')
69 			initial_pathlen++;
70 }
71 
72 static char *shorten_to_initial_path(char *fname)
73 {
74 	char *p1, *p2, *prevslash1 = NULL;
75 	int slashes = 0;
76 
77 	for (p1 = fname, p2 = initial_path; *p1 && *p2; p1++, p2++) {
78 		if (*p1 != *p2)
79 			break;
80 		if (*p1 == '/') {
81 			prevslash1 = p1;
82 			slashes++;
83 		}
84 	}
85 	p1 = prevslash1 + 1;
86 	if (prevslash1) {
87 		int diff = initial_pathlen - slashes, i, j;
88 		int restlen = strlen(fname) - (p1 - fname);
89 		char *res;
90 
91 		res = xmalloc((3 * diff) + restlen + 1);
92 		for (i = 0, j = 0; i != diff; i++) {
93 			res[j++] = '.';
94 			res[j++] = '.';
95 			res[j++] = '/';
96 		}
97 		strcpy(res + j, p1);
98 		return res;
99 	}
100 	return NULL;
101 }
102 
103 /**
104  * Try to open a file in a given directory.
105  *
106  * If the filename is an absolute path, then dirname is ignored. If it is a
107  * relative path, then we look in that directory for the file.
108  *
109  * @param dirname	Directory to look in, or NULL for none
110  * @param fname		Filename to look for
111  * @param fp		Set to NULL if file did not open
112  * @return allocated filename on success (caller must free), NULL on failure
113  */
114 static char *try_open(const char *dirname, const char *fname, FILE **fp)
115 {
116 	char *fullname;
117 
118 	if (!dirname || fname[0] == '/')
119 		fullname = xstrdup(fname);
120 	else
121 		fullname = join_path(dirname, fname);
122 
123 	*fp = fopen(fullname, "rb");
124 	if (!*fp) {
125 		free(fullname);
126 		fullname = NULL;
127 	}
128 
129 	return fullname;
130 }
131 
132 /**
133  * Open a file for read access
134  *
135  * If it is a relative filename, we search the full search path for it.
136  *
137  * @param fname	Filename to open
138  * @param fp	Returns pointer to opened FILE, or NULL on failure
139  * @return pointer to allocated filename, which caller must free
140  */
141 static char *fopen_any_on_path(const char *fname, FILE **fp)
142 {
143 	const char *cur_dir = NULL;
144 	struct search_path *node;
145 	char *fullname;
146 
147 	/* Try current directory first */
148 	assert(fp);
149 	if (current_srcfile)
150 		cur_dir = current_srcfile->dir;
151 	fullname = try_open(cur_dir, fname, fp);
152 
153 	/* Failing that, try each search path in turn */
154 	for (node = search_path_head; !*fp && node; node = node->next)
155 		fullname = try_open(node->dirname, fname, fp);
156 
157 	return fullname;
158 }
159 
160 FILE *srcfile_relative_open(const char *fname, char **fullnamep)
161 {
162 	FILE *f;
163 	char *fullname;
164 
165 	if (streq(fname, "-")) {
166 		f = stdin;
167 		fullname = xstrdup("<stdin>");
168 	} else {
169 		fullname = fopen_any_on_path(fname, &f);
170 		if (!f)
171 			die("Couldn't open \"%s\": %s\n", fname,
172 			    strerror(errno));
173 	}
174 
175 	if (depfile)
176 		fprintf(depfile, " %s", fullname);
177 
178 	if (fullnamep)
179 		*fullnamep = fullname;
180 	else
181 		free(fullname);
182 
183 	return f;
184 }
185 
186 void srcfile_push(const char *fname)
187 {
188 	struct srcfile_state *srcfile;
189 
190 	if (srcfile_depth++ >= MAX_SRCFILE_DEPTH)
191 		die("Includes nested too deeply");
192 
193 	srcfile = xmalloc(sizeof(*srcfile));
194 
195 	srcfile->f = srcfile_relative_open(fname, &srcfile->name);
196 	srcfile->dir = get_dirname(srcfile->name);
197 	srcfile->prev = current_srcfile;
198 
199 	srcfile->lineno = 1;
200 	srcfile->colno = 1;
201 
202 	current_srcfile = srcfile;
203 
204 	if (srcfile_depth == 1)
205 		set_initial_path(srcfile->name);
206 }
207 
208 bool srcfile_pop(void)
209 {
210 	struct srcfile_state *srcfile = current_srcfile;
211 
212 	assert(srcfile);
213 
214 	current_srcfile = srcfile->prev;
215 
216 	if (fclose(srcfile->f))
217 		die("Error closing \"%s\": %s\n", srcfile->name,
218 		    strerror(errno));
219 
220 	/* FIXME: We allow the srcfile_state structure to leak,
221 	 * because it could still be referenced from a location
222 	 * variable being carried through the parser somewhere.  To
223 	 * fix this we could either allocate all the files from a
224 	 * table, or use a pool allocator. */
225 
226 	return current_srcfile ? true : false;
227 }
228 
229 void srcfile_add_search_path(const char *dirname)
230 {
231 	struct search_path *node;
232 
233 	/* Create the node */
234 	node = xmalloc(sizeof(*node));
235 	node->next = NULL;
236 	node->dirname = xstrdup(dirname);
237 
238 	/* Add to the end of our list */
239 	if (search_path_tail)
240 		*search_path_tail = node;
241 	else
242 		search_path_head = node;
243 	search_path_tail = &node->next;
244 }
245 
246 void srcpos_update(struct srcpos *pos, const char *text, int len)
247 {
248 	int i;
249 
250 	pos->file = current_srcfile;
251 
252 	pos->first_line = current_srcfile->lineno;
253 	pos->first_column = current_srcfile->colno;
254 
255 	for (i = 0; i < len; i++)
256 		if (text[i] == '\n') {
257 			current_srcfile->lineno++;
258 			current_srcfile->colno = 1;
259 		} else {
260 			current_srcfile->colno++;
261 		}
262 
263 	pos->last_line = current_srcfile->lineno;
264 	pos->last_column = current_srcfile->colno;
265 }
266 
267 struct srcpos *
268 srcpos_copy(struct srcpos *pos)
269 {
270 	struct srcpos *pos_new;
271 	struct srcfile_state *srcfile_state;
272 
273 	if (!pos)
274 		return NULL;
275 
276 	pos_new = xmalloc(sizeof(struct srcpos));
277 	assert(pos->next == NULL);
278 	memcpy(pos_new, pos, sizeof(struct srcpos));
279 
280 	/* allocate without free */
281 	srcfile_state = xmalloc(sizeof(struct srcfile_state));
282 	memcpy(srcfile_state, pos->file, sizeof(struct srcfile_state));
283 	pos_new->file = srcfile_state;
284 
285 	return pos_new;
286 }
287 
288 struct srcpos *srcpos_extend(struct srcpos *pos, struct srcpos *newtail)
289 {
290 	struct srcpos *p;
291 
292 	if (!pos)
293 		return newtail;
294 
295 	for (p = pos; p->next != NULL; p = p->next);
296 	p->next = newtail;
297 	return pos;
298 }
299 
300 char *
301 srcpos_string(struct srcpos *pos)
302 {
303 	const char *fname = "<no-file>";
304 	char *pos_str;
305 
306 	if (pos->file && pos->file->name)
307 		fname = pos->file->name;
308 
309 
310 	if (pos->first_line != pos->last_line)
311 		xasprintf(&pos_str, "%s:%d.%d-%d.%d", fname,
312 			  pos->first_line, pos->first_column,
313 			  pos->last_line, pos->last_column);
314 	else if (pos->first_column != pos->last_column)
315 		xasprintf(&pos_str, "%s:%d.%d-%d", fname,
316 			  pos->first_line, pos->first_column,
317 			  pos->last_column);
318 	else
319 		xasprintf(&pos_str, "%s:%d.%d", fname,
320 			  pos->first_line, pos->first_column);
321 
322 	return pos_str;
323 }
324 
325 static char *
326 srcpos_string_comment(struct srcpos *pos, bool first_line, int level)
327 {
328 	char *pos_str, *fname, *first, *rest;
329 	bool fresh_fname = false;
330 
331 	if (!pos) {
332 		if (level > 1) {
333 			xasprintf(&pos_str, "<no-file>:<no-line>");
334 			return pos_str;
335 		} else {
336 			return NULL;
337 		}
338 	}
339 
340 	if (!pos->file)
341 		fname = "<no-file>";
342 	else if (!pos->file->name)
343 		fname = "<no-filename>";
344 	else if (level > 1)
345 		fname = pos->file->name;
346 	else {
347 		fname = shorten_to_initial_path(pos->file->name);
348 		if (fname)
349 			fresh_fname = true;
350 		else
351 			fname = pos->file->name;
352 	}
353 
354 	if (level > 1)
355 		xasprintf(&first, "%s:%d:%d-%d:%d", fname,
356 			  pos->first_line, pos->first_column,
357 			  pos->last_line, pos->last_column);
358 	else
359 		xasprintf(&first, "%s:%d", fname,
360 			  first_line ? pos->first_line : pos->last_line);
361 
362 	if (fresh_fname)
363 		free(fname);
364 
365 	if (pos->next != NULL) {
366 		rest = srcpos_string_comment(pos->next, first_line, level);
367 		xasprintf(&pos_str, "%s, %s", first, rest);
368 		free(first);
369 		free(rest);
370 	} else {
371 		pos_str = first;
372 	}
373 
374 	return pos_str;
375 }
376 
377 char *srcpos_string_first(struct srcpos *pos, int level)
378 {
379 	return srcpos_string_comment(pos, true, level);
380 }
381 
382 char *srcpos_string_last(struct srcpos *pos, int level)
383 {
384 	return srcpos_string_comment(pos, false, level);
385 }
386 
387 void srcpos_verror(struct srcpos *pos, const char *prefix,
388 		   const char *fmt, va_list va)
389 {
390 	char *srcstr;
391 
392 	srcstr = srcpos_string(pos);
393 
394 	fprintf(stderr, "%s: %s ", prefix, srcstr);
395 	vfprintf(stderr, fmt, va);
396 	fprintf(stderr, "\n");
397 
398 	free(srcstr);
399 }
400 
401 void srcpos_error(struct srcpos *pos, const char *prefix,
402 		  const char *fmt, ...)
403 {
404 	va_list va;
405 
406 	va_start(va, fmt);
407 	srcpos_verror(pos, prefix, fmt, va);
408 	va_end(va);
409 }
410 
411 void srcpos_set_line(char *f, int l)
412 {
413 	current_srcfile->name = f;
414 	current_srcfile->lineno = l;
415 
416 	if (initial_cpp) {
417 		initial_cpp = false;
418 		set_initial_path(f);
419 	}
420 }
421