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 37 static char *get_dirname(const char *path) 38 { 39 const char *slash = strrchr(path, '/'); 40 41 if (slash) { 42 int len = slash - path; 43 char *dir = xmalloc(len + 1); 44 45 memcpy(dir, path, len); 46 dir[len] = '\0'; 47 return dir; 48 } 49 return NULL; 50 } 51 52 FILE *depfile; /* = NULL */ 53 struct srcfile_state *current_srcfile; /* = NULL */ 54 55 /* Detect infinite include recursion. */ 56 #define MAX_SRCFILE_DEPTH (100) 57 static int srcfile_depth; /* = 0 */ 58 59 60 /** 61 * Try to open a file in a given directory. 62 * 63 * If the filename is an absolute path, then dirname is ignored. If it is a 64 * relative path, then we look in that directory for the file. 65 * 66 * @param dirname Directory to look in, or NULL for none 67 * @param fname Filename to look for 68 * @param fp Set to NULL if file did not open 69 * @return allocated filename on success (caller must free), NULL on failure 70 */ 71 static char *try_open(const char *dirname, const char *fname, FILE **fp) 72 { 73 char *fullname; 74 75 if (!dirname || fname[0] == '/') 76 fullname = xstrdup(fname); 77 else 78 fullname = join_path(dirname, fname); 79 80 *fp = fopen(fullname, "rb"); 81 if (!*fp) { 82 free(fullname); 83 fullname = NULL; 84 } 85 86 return fullname; 87 } 88 89 /** 90 * Open a file for read access 91 * 92 * If it is a relative filename, we search the full search path for it. 93 * 94 * @param fname Filename to open 95 * @param fp Returns pointer to opened FILE, or NULL on failure 96 * @return pointer to allocated filename, which caller must free 97 */ 98 static char *fopen_any_on_path(const char *fname, FILE **fp) 99 { 100 const char *cur_dir = NULL; 101 struct search_path *node; 102 char *fullname; 103 104 /* Try current directory first */ 105 assert(fp); 106 if (current_srcfile) 107 cur_dir = current_srcfile->dir; 108 fullname = try_open(cur_dir, fname, fp); 109 110 /* Failing that, try each search path in turn */ 111 for (node = search_path_head; !*fp && node; node = node->next) 112 fullname = try_open(node->dirname, fname, fp); 113 114 return fullname; 115 } 116 117 FILE *srcfile_relative_open(const char *fname, char **fullnamep) 118 { 119 FILE *f; 120 char *fullname; 121 122 if (streq(fname, "-")) { 123 f = stdin; 124 fullname = xstrdup("<stdin>"); 125 } else { 126 fullname = fopen_any_on_path(fname, &f); 127 if (!f) 128 die("Couldn't open \"%s\": %s\n", fname, 129 strerror(errno)); 130 } 131 132 if (depfile) 133 fprintf(depfile, " %s", fullname); 134 135 if (fullnamep) 136 *fullnamep = fullname; 137 else 138 free(fullname); 139 140 return f; 141 } 142 143 void srcfile_push(const char *fname) 144 { 145 struct srcfile_state *srcfile; 146 147 if (srcfile_depth++ >= MAX_SRCFILE_DEPTH) 148 die("Includes nested too deeply"); 149 150 srcfile = xmalloc(sizeof(*srcfile)); 151 152 srcfile->f = srcfile_relative_open(fname, &srcfile->name); 153 srcfile->dir = get_dirname(srcfile->name); 154 srcfile->prev = current_srcfile; 155 156 srcfile->lineno = 1; 157 srcfile->colno = 1; 158 159 current_srcfile = srcfile; 160 } 161 162 bool srcfile_pop(void) 163 { 164 struct srcfile_state *srcfile = current_srcfile; 165 166 assert(srcfile); 167 168 current_srcfile = srcfile->prev; 169 170 if (fclose(srcfile->f)) 171 die("Error closing \"%s\": %s\n", srcfile->name, 172 strerror(errno)); 173 174 /* FIXME: We allow the srcfile_state structure to leak, 175 * because it could still be referenced from a location 176 * variable being carried through the parser somewhere. To 177 * fix this we could either allocate all the files from a 178 * table, or use a pool allocator. */ 179 180 return current_srcfile ? true : false; 181 } 182 183 void srcfile_add_search_path(const char *dirname) 184 { 185 struct search_path *node; 186 187 /* Create the node */ 188 node = xmalloc(sizeof(*node)); 189 node->next = NULL; 190 node->dirname = xstrdup(dirname); 191 192 /* Add to the end of our list */ 193 if (search_path_tail) 194 *search_path_tail = node; 195 else 196 search_path_head = node; 197 search_path_tail = &node->next; 198 } 199 200 /* 201 * The empty source position. 202 */ 203 204 struct srcpos srcpos_empty = { 205 .first_line = 0, 206 .first_column = 0, 207 .last_line = 0, 208 .last_column = 0, 209 .file = NULL, 210 }; 211 212 void srcpos_update(struct srcpos *pos, const char *text, int len) 213 { 214 int i; 215 216 pos->file = current_srcfile; 217 218 pos->first_line = current_srcfile->lineno; 219 pos->first_column = current_srcfile->colno; 220 221 for (i = 0; i < len; i++) 222 if (text[i] == '\n') { 223 current_srcfile->lineno++; 224 current_srcfile->colno = 1; 225 } else { 226 current_srcfile->colno++; 227 } 228 229 pos->last_line = current_srcfile->lineno; 230 pos->last_column = current_srcfile->colno; 231 } 232 233 struct srcpos * 234 srcpos_copy(struct srcpos *pos) 235 { 236 struct srcpos *pos_new; 237 238 pos_new = xmalloc(sizeof(struct srcpos)); 239 memcpy(pos_new, pos, sizeof(struct srcpos)); 240 241 return pos_new; 242 } 243 244 char * 245 srcpos_string(struct srcpos *pos) 246 { 247 const char *fname = "<no-file>"; 248 char *pos_str; 249 250 if (pos->file && pos->file->name) 251 fname = pos->file->name; 252 253 254 if (pos->first_line != pos->last_line) 255 xasprintf(&pos_str, "%s:%d.%d-%d.%d", fname, 256 pos->first_line, pos->first_column, 257 pos->last_line, pos->last_column); 258 else if (pos->first_column != pos->last_column) 259 xasprintf(&pos_str, "%s:%d.%d-%d", fname, 260 pos->first_line, pos->first_column, 261 pos->last_column); 262 else 263 xasprintf(&pos_str, "%s:%d.%d", fname, 264 pos->first_line, pos->first_column); 265 266 return pos_str; 267 } 268 269 void srcpos_verror(struct srcpos *pos, const char *prefix, 270 const char *fmt, va_list va) 271 { 272 char *srcstr; 273 274 srcstr = srcpos_string(pos); 275 276 fprintf(stderr, "%s: %s ", prefix, srcstr); 277 vfprintf(stderr, fmt, va); 278 fprintf(stderr, "\n"); 279 280 free(srcstr); 281 } 282 283 void srcpos_error(struct srcpos *pos, const char *prefix, 284 const char *fmt, ...) 285 { 286 va_list va; 287 288 va_start(va, fmt); 289 srcpos_verror(pos, prefix, fmt, va); 290 va_end(va); 291 } 292 293 void srcpos_set_line(char *f, int l) 294 { 295 current_srcfile->name = f; 296 current_srcfile->lineno = l; 297 } 298