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