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 * 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 */ 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 */ 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 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 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 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 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 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 * 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 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 * 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 * 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 365 char *srcpos_string_first(struct srcpos *pos, int level) 366 { 367 return srcpos_string_comment(pos, true, level); 368 } 369 370 char *srcpos_string_last(struct srcpos *pos, int level) 371 { 372 return srcpos_string_comment(pos, false, level); 373 } 374 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 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 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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.