srcpos.c 9.3 KB

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