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