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