1 /* $NetBSD: srcpos.c,v 1.3 2017/06/08 16:00:40 skrll Exp $ */ 2 3 /* 4 * Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc. 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of the 9 * License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 19 * USA 20 */ 21 22 #define _GNU_SOURCE 23 24 #include <stdio.h> 25 26 #include "dtc.h" 27 #include "srcpos.h" 28 29 /* A node in our list of directories to search for source/include files */ 30 struct search_path { 31 struct search_path *next; /* next node in list, NULL for end */ 32 const char *dirname; /* name of directory to search */ 33 }; 34 35 /* This is the list of directories that we search for source files */ 36 static struct search_path *search_path_head, **search_path_tail; 37 38 39 static char *get_dirname(const char *path) 40 { 41 const char *slash = strrchr(path, '/'); 42 43 if (slash) { 44 int len = slash - path; 45 char *dir = xmalloc(len + 1); 46 47 memcpy(dir, path, len); 48 dir[len] = '\0'; 49 return dir; 50 } 51 return NULL; 52 } 53 54 FILE *depfile; /* = NULL */ 55 struct srcfile_state *current_srcfile; /* = NULL */ 56 57 /* Detect infinite include recursion. */ 58 #define MAX_SRCFILE_DEPTH (100) 59 static int srcfile_depth; /* = 0 */ 60 61 62 /** 63 * Try to open a file in a given directory. 64 * 65 * If the filename is an absolute path, then dirname is ignored. If it is a 66 * relative path, then we look in that directory for the file. 67 * 68 * @param dirname Directory to look in, or NULL for none 69 * @param fname Filename to look for 70 * @param fp Set to NULL if file did not open 71 * @return allocated filename on success (caller must free), NULL on failure 72 */ 73 static char *try_open(const char *dirname, const char *fname, FILE **fp) 74 { 75 char *fullname; 76 77 if (!dirname || fname[0] == '/') 78 fullname = xstrdup(fname); 79 else 80 fullname = join_path(dirname, fname); 81 82 *fp = fopen(fullname, "rb"); 83 if (!*fp) { 84 free(fullname); 85 fullname = NULL; 86 } 87 88 return fullname; 89 } 90 91 /** 92 * Open a file for read access 93 * 94 * If it is a relative filename, we search the full search path for it. 95 * 96 * @param fname Filename to open 97 * @param fp Returns pointer to opened FILE, or NULL on failure 98 * @return pointer to allocated filename, which caller must free 99 */ 100 static char *fopen_any_on_path(const char *fname, FILE **fp) 101 { 102 const char *cur_dir = NULL; 103 struct search_path *node; 104 char *fullname; 105 106 /* Try current directory first */ 107 assert(fp); 108 if (current_srcfile) 109 cur_dir = current_srcfile->dir; 110 fullname = try_open(cur_dir, fname, fp); 111 112 /* Failing that, try each search path in turn */ 113 for (node = search_path_head; !*fp && node; node = node->next) 114 fullname = try_open(node->dirname, fname, fp); 115 116 return fullname; 117 } 118 119 FILE *srcfile_relative_open(const char *fname, char **fullnamep) 120 { 121 FILE *f; 122 char *fullname; 123 124 if (streq(fname, "-")) { 125 f = stdin; 126 fullname = xstrdup("<stdin>"); 127 } else { 128 fullname = fopen_any_on_path(fname, &f); 129 if (!f) 130 die("Couldn't open \"%s\": %s\n", fname, 131 strerror(errno)); 132 } 133 134 if (depfile) 135 fprintf(depfile, " %s", fullname); 136 137 if (fullnamep) 138 *fullnamep = fullname; 139 else 140 free(fullname); 141 142 return f; 143 } 144 145 void srcfile_push(const char *fname) 146 { 147 struct srcfile_state *srcfile; 148 149 if (srcfile_depth++ >= MAX_SRCFILE_DEPTH) 150 die("Includes nested too deeply"); 151 152 srcfile = xmalloc(sizeof(*srcfile)); 153 154 srcfile->f = srcfile_relative_open(fname, &srcfile->name); 155 srcfile->dir = get_dirname(srcfile->name); 156 srcfile->prev = current_srcfile; 157 158 srcfile->lineno = 1; 159 srcfile->colno = 1; 160 161 current_srcfile = srcfile; 162 } 163 164 bool srcfile_pop(void) 165 { 166 struct srcfile_state *srcfile = current_srcfile; 167 168 assert(srcfile); 169 170 current_srcfile = srcfile->prev; 171 172 if (fclose(srcfile->f)) 173 die("Error closing \"%s\": %s\n", srcfile->name, 174 strerror(errno)); 175 176 /* FIXME: We allow the srcfile_state structure to leak, 177 * because it could still be referenced from a location 178 * variable being carried through the parser somewhere. To 179 * fix this we could either allocate all the files from a 180 * table, or use a pool allocator. */ 181 182 return current_srcfile ? true : false; 183 } 184 185 void srcfile_add_search_path(const char *dirname) 186 { 187 struct search_path *node; 188 189 /* Create the node */ 190 node = xmalloc(sizeof(*node)); 191 node->next = NULL; 192 node->dirname = xstrdup(dirname); 193 194 /* Add to the end of our list */ 195 if (search_path_tail) 196 *search_path_tail = node; 197 else 198 search_path_head = node; 199 search_path_tail = &node->next; 200 } 201 202 /* 203 * The empty source position. 204 */ 205 206 struct srcpos srcpos_empty = { 207 .first_line = 0, 208 .first_column = 0, 209 .last_line = 0, 210 .last_column = 0, 211 .file = NULL, 212 }; 213 214 #define TAB_SIZE 8 215 216 void srcpos_update(struct srcpos *pos, const char *text, int len) 217 { 218 int i; 219 220 pos->file = current_srcfile; 221 222 pos->first_line = current_srcfile->lineno; 223 pos->first_column = current_srcfile->colno; 224 225 for (i = 0; i < len; i++) 226 if (text[i] == '\n') { 227 current_srcfile->lineno++; 228 current_srcfile->colno = 1; 229 } else if (text[i] == '\t') { 230 current_srcfile->colno = 231 FDTALIGN2(current_srcfile->colno, TAB_SIZE); 232 } else { 233 current_srcfile->colno++; 234 } 235 236 pos->last_line = current_srcfile->lineno; 237 pos->last_column = current_srcfile->colno; 238 } 239 240 struct srcpos * 241 srcpos_copy(struct srcpos *pos) 242 { 243 struct srcpos *pos_new; 244 245 pos_new = xmalloc(sizeof(struct srcpos)); 246 memcpy(pos_new, pos, sizeof(struct srcpos)); 247 248 return pos_new; 249 } 250 251 char * 252 srcpos_string(struct srcpos *pos) 253 { 254 const char *fname = "<no-file>"; 255 char *pos_str; 256 257 if (pos->file && pos->file->name) 258 fname = pos->file->name; 259 260 261 if (pos->first_line != pos->last_line) 262 xasprintf(&pos_str, "%s:%d.%d-%d.%d", fname, 263 pos->first_line, pos->first_column, 264 pos->last_line, pos->last_column); 265 else if (pos->first_column != pos->last_column) 266 xasprintf(&pos_str, "%s:%d.%d-%d", fname, 267 pos->first_line, pos->first_column, 268 pos->last_column); 269 else 270 xasprintf(&pos_str, "%s:%d.%d", fname, 271 pos->first_line, pos->first_column); 272 273 return pos_str; 274 } 275 276 void srcpos_verror(struct srcpos *pos, const char *prefix, 277 const char *fmt, va_list va) 278 { 279 char *srcstr; 280 281 srcstr = srcpos_string(pos); 282 283 fprintf(stderr, "%s: %s ", prefix, srcstr); 284 vfprintf(stderr, fmt, va); 285 fprintf(stderr, "\n"); 286 287 free(srcstr); 288 } 289 290 void srcpos_error(struct srcpos *pos, const char *prefix, 291 const char *fmt, ...) 292 { 293 va_list va; 294 295 va_start(va, fmt); 296 srcpos_verror(pos, prefix, fmt, va); 297 va_end(va); 298 } 299 300 void srcpos_set_line(char *f, int l) 301 { 302 current_srcfile->name = f; 303 current_srcfile->lineno = l; 304 } 305