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 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 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 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 * Returns true if the given path is an absolute one. 93 * 94 * On Windows, it either needs to begin with a forward slash or with a drive 95 * letter (e.g. "C:"). 96 * On all other operating systems, it must begin with a forward slash to be 97 * considered an absolute path. 98 */ 99 static bool is_absolute_path(const char *path) 100 { 101 #ifdef WIN32 102 return ( 103 path[0] == '/' || 104 (((path[0] >= 'A' && path[0] <= 'Z') || (path[0] >= 'a' && path[0] <= 'z')) && path[1] == ':') 105 ); 106 #else 107 return (path[0] == '/'); 108 #endif 109 } 110 111 /** 112 * Try to open a file in a given directory. 113 * 114 * If the filename is an absolute path, then dirname is ignored. If it is a 115 * relative path, then we look in that directory for the file. 116 * 117 * @param dirname Directory to look in, or NULL for none 118 * @param fname Filename to look for 119 * @param fp Set to NULL if file did not open 120 * @return allocated filename on success (caller must free), NULL on failure 121 */ 122 static char *try_open(const char *dirname, const char *fname, FILE **fp) 123 { 124 char *fullname; 125 126 if (!dirname || is_absolute_path(fname)) 127 fullname = xstrdup(fname); 128 else 129 fullname = join_path(dirname, fname); 130 131 *fp = fopen(fullname, "rb"); 132 if (!*fp) { 133 free(fullname); 134 fullname = NULL; 135 } 136 137 return fullname; 138 } 139 140 /** 141 * Open a file for read access 142 * 143 * If it is a relative filename, we search the full search path for it. 144 * 145 * @param fname Filename to open 146 * @param fp Returns pointer to opened FILE, or NULL on failure 147 * @return pointer to allocated filename, which caller must free 148 */ 149 static char *fopen_any_on_path(const char *fname, FILE **fp) 150 { 151 const char *cur_dir = NULL; 152 struct search_path *node; 153 char *fullname; 154 155 /* Try current directory first */ 156 assert(fp); 157 if (current_srcfile) 158 cur_dir = current_srcfile->dir; 159 fullname = try_open(cur_dir, fname, fp); 160 161 /* Failing that, try each search path in turn */ 162 for (node = search_path_head; !*fp && node; node = node->next) 163 fullname = try_open(node->dirname, fname, fp); 164 165 return fullname; 166 } 167 168 FILE *srcfile_relative_open(const char *fname, char **fullnamep) 169 { 170 FILE *f; 171 char *fullname; 172 173 if (streq(fname, "-")) { 174 f = stdin; 175 fullname = xstrdup("<stdin>"); 176 } else { 177 fullname = fopen_any_on_path(fname, &f); 178 if (!f) 179 die("Couldn't open \"%s\": %s\n", fname, 180 strerror(errno)); 181 } 182 183 if (depfile) { 184 fputc(' ', depfile); 185 fprint_path_escaped(depfile, fullname); 186 } 187 188 if (fullnamep) 189 *fullnamep = fullname; 190 else 191 free(fullname); 192 193 return f; 194 } 195 196 void srcfile_push(const char *fname) 197 { 198 struct srcfile_state *srcfile; 199 200 if (srcfile_depth++ >= MAX_SRCFILE_DEPTH) 201 die("Includes nested too deeply"); 202 203 srcfile = xmalloc(sizeof(*srcfile)); 204 205 srcfile->f = srcfile_relative_open(fname, &srcfile->name); 206 srcfile->dir = get_dirname(srcfile->name); 207 srcfile->prev = current_srcfile; 208 209 srcfile->lineno = 1; 210 srcfile->colno = 1; 211 212 current_srcfile = srcfile; 213 214 if (srcfile_depth == 1) 215 set_initial_path(srcfile->name); 216 } 217 218 bool srcfile_pop(void) 219 { 220 struct srcfile_state *srcfile = current_srcfile; 221 222 assert(srcfile); 223 224 current_srcfile = srcfile->prev; 225 226 if (fclose(srcfile->f)) 227 die("Error closing \"%s\": %s\n", srcfile->name, 228 strerror(errno)); 229 230 /* FIXME: We allow the srcfile_state structure to leak, 231 * because it could still be referenced from a location 232 * variable being carried through the parser somewhere. To 233 * fix this we could either allocate all the files from a 234 * table, or use a pool allocator. */ 235 236 return current_srcfile ? true : false; 237 } 238 239 void srcfile_add_search_path(const char *dirname) 240 { 241 struct search_path *node; 242 243 /* Create the node */ 244 node = xmalloc(sizeof(*node)); 245 node->next = NULL; 246 node->dirname = xstrdup(dirname); 247 248 /* Add to the end of our list */ 249 if (search_path_tail) 250 *search_path_tail = node; 251 else 252 search_path_head = node; 253 search_path_tail = &node->next; 254 } 255 256 void srcpos_update(struct srcpos *pos, const char *text, int len) 257 { 258 int i; 259 260 pos->file = current_srcfile; 261 262 pos->first_line = current_srcfile->lineno; 263 pos->first_column = current_srcfile->colno; 264 265 for (i = 0; i < len; i++) 266 if (text[i] == '\n') { 267 current_srcfile->lineno++; 268 current_srcfile->colno = 1; 269 } else { 270 current_srcfile->colno++; 271 } 272 273 pos->last_line = current_srcfile->lineno; 274 pos->last_column = current_srcfile->colno; 275 } 276 277 struct srcpos * 278 srcpos_copy(struct srcpos *pos) 279 { 280 struct srcpos *pos_new; 281 struct srcfile_state *srcfile_state; 282 283 if (!pos) 284 return NULL; 285 286 pos_new = xmalloc(sizeof(struct srcpos)); 287 assert(pos->next == NULL); 288 memcpy(pos_new, pos, sizeof(struct srcpos)); 289 290 /* allocate without free */ 291 srcfile_state = xmalloc(sizeof(struct srcfile_state)); 292 memcpy(srcfile_state, pos->file, sizeof(struct srcfile_state)); 293 pos_new->file = srcfile_state; 294 295 return pos_new; 296 } 297 298 struct srcpos *srcpos_extend(struct srcpos *pos, struct srcpos *newtail) 299 { 300 struct srcpos *p; 301 302 if (!pos) 303 return newtail; 304 305 for (p = pos; p->next != NULL; p = p->next); 306 p->next = newtail; 307 return pos; 308 } 309 310 void srcpos_free(struct srcpos *pos) 311 { 312 struct srcpos *p_next; 313 314 while (pos) { 315 p_next = pos->next; 316 free(pos); 317 pos = p_next; 318 } 319 } 320 321 char * 322 srcpos_string(struct srcpos *pos) 323 { 324 const char *fname = "<no-file>"; 325 char *pos_str; 326 327 if (pos->file && pos->file->name) 328 fname = pos->file->name; 329 330 331 if (pos->first_line != pos->last_line) 332 xasprintf(&pos_str, "%s:%d.%d-%d.%d", fname, 333 pos->first_line, pos->first_column, 334 pos->last_line, pos->last_column); 335 else if (pos->first_column != pos->last_column) 336 xasprintf(&pos_str, "%s:%d.%d-%d", fname, 337 pos->first_line, pos->first_column, 338 pos->last_column); 339 else 340 xasprintf(&pos_str, "%s:%d.%d", fname, 341 pos->first_line, pos->first_column); 342 343 return pos_str; 344 } 345 346 static char * 347 srcpos_string_comment(struct srcpos *pos, bool first_line, int level) 348 { 349 char *pos_str, *fresh_fname = NULL, *first, *rest; 350 const char *fname; 351 352 if (!pos) { 353 if (level > 1) { 354 xasprintf(&pos_str, "<no-file>:<no-line>"); 355 return pos_str; 356 } else { 357 return NULL; 358 } 359 } 360 361 if (!pos->file) 362 fname = "<no-file>"; 363 else if (!pos->file->name) 364 fname = "<no-filename>"; 365 else if (level > 1) 366 fname = pos->file->name; 367 else { 368 fresh_fname = shorten_to_initial_path(pos->file->name); 369 if (fresh_fname) 370 fname = fresh_fname; 371 else 372 fname = pos->file->name; 373 } 374 375 if (level > 1) 376 xasprintf(&first, "%s:%d:%d-%d:%d", fname, 377 pos->first_line, pos->first_column, 378 pos->last_line, pos->last_column); 379 else 380 xasprintf(&first, "%s:%d", fname, 381 first_line ? pos->first_line : pos->last_line); 382 383 if (fresh_fname) 384 free(fresh_fname); 385 386 if (pos->next != NULL) { 387 rest = srcpos_string_comment(pos->next, first_line, level); 388 xasprintf(&pos_str, "%s, %s", first, rest); 389 free(first); 390 free(rest); 391 } else { 392 pos_str = first; 393 } 394 395 return pos_str; 396 } 397 398 char *srcpos_string_first(struct srcpos *pos, int level) 399 { 400 return srcpos_string_comment(pos, true, level); 401 } 402 403 char *srcpos_string_last(struct srcpos *pos, int level) 404 { 405 return srcpos_string_comment(pos, false, level); 406 } 407 408 void srcpos_verror(struct srcpos *pos, const char *prefix, 409 const char *fmt, va_list va) 410 { 411 char *srcstr; 412 413 srcstr = srcpos_string(pos); 414 415 fprintf(stderr, "%s: %s ", prefix, srcstr); 416 vfprintf(stderr, fmt, va); 417 fprintf(stderr, "\n"); 418 419 free(srcstr); 420 } 421 422 void srcpos_error(struct srcpos *pos, const char *prefix, 423 const char *fmt, ...) 424 { 425 va_list va; 426 427 va_start(va, fmt); 428 srcpos_verror(pos, prefix, fmt, va); 429 va_end(va); 430 } 431 432 void srcpos_set_line(char *f, int l) 433 { 434 current_srcfile->name = f; 435 current_srcfile->lineno = l; 436 437 if (initial_cpp) { 438 initial_cpp = false; 439 set_initial_path(f); 440 } 441 } 442