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 #define TAB_SIZE 8 213 214 void srcpos_update(struct srcpos *pos, const char *text, int len) 215 { 216 int i; 217 218 pos->file = current_srcfile; 219 220 pos->first_line = current_srcfile->lineno; 221 pos->first_column = current_srcfile->colno; 222 223 for (i = 0; i < len; i++) 224 if (text[i] == '\n') { 225 current_srcfile->lineno++; 226 current_srcfile->colno = 1; 227 } else if (text[i] == '\t') { 228 current_srcfile->colno = 229 ALIGN(current_srcfile->colno, TAB_SIZE); 230 } else { 231 current_srcfile->colno++; 232 } 233 234 pos->last_line = current_srcfile->lineno; 235 pos->last_column = current_srcfile->colno; 236 } 237 238 struct srcpos * 239 srcpos_copy(struct srcpos *pos) 240 { 241 struct srcpos *pos_new; 242 243 pos_new = xmalloc(sizeof(struct srcpos)); 244 memcpy(pos_new, pos, sizeof(struct srcpos)); 245 246 return pos_new; 247 } 248 249 250 251 void 252 srcpos_dump(struct srcpos *pos) 253 { 254 printf("file : \"%s\"\n", 255 pos->file ? (char *) pos->file : "<no file>"); 256 printf("first_line : %d\n", pos->first_line); 257 printf("first_column: %d\n", pos->first_column); 258 printf("last_line : %d\n", pos->last_line); 259 printf("last_column : %d\n", pos->last_column); 260 printf("file : %s\n", pos->file->name); 261 } 262 263 264 char * 265 srcpos_string(struct srcpos *pos) 266 { 267 const char *fname = "<no-file>"; 268 char *pos_str; 269 int rc; 270 271 if (pos) 272 fname = pos->file->name; 273 274 275 if (pos->first_line != pos->last_line) 276 rc = asprintf(&pos_str, "%s:%d.%d-%d.%d", fname, 277 pos->first_line, pos->first_column, 278 pos->last_line, pos->last_column); 279 else if (pos->first_column != pos->last_column) 280 rc = asprintf(&pos_str, "%s:%d.%d-%d", fname, 281 pos->first_line, pos->first_column, 282 pos->last_column); 283 else 284 rc = asprintf(&pos_str, "%s:%d.%d", fname, 285 pos->first_line, pos->first_column); 286 287 if (rc == -1) 288 die("Couldn't allocate in srcpos string"); 289 290 return pos_str; 291 } 292 293 void srcpos_verror(struct srcpos *pos, const char *prefix, 294 const char *fmt, va_list va) 295 { 296 char *srcstr; 297 298 srcstr = srcpos_string(pos); 299 300 fprintf(stderr, "%s: %s ", prefix, srcstr); 301 vfprintf(stderr, fmt, va); 302 fprintf(stderr, "\n"); 303 304 free(srcstr); 305 } 306 307 void srcpos_error(struct srcpos *pos, const char *prefix, 308 const char *fmt, ...) 309 { 310 va_list va; 311 312 va_start(va, fmt); 313 srcpos_verror(pos, prefix, fmt, va); 314 va_end(va); 315 } 316 317 void srcpos_set_line(char *f, int l) 318 { 319 current_srcfile->name = f; 320 current_srcfile->lineno = l; 321 } 322