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