Commit | Line | Data |
---|---|---|
a4da2e3e DG |
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 | ||
658f29a5 JB |
20 | #define _GNU_SOURCE |
21 | ||
22 | #include <stdio.h> | |
23 | ||
a4da2e3e DG |
24 | #include "dtc.h" |
25 | #include "srcpos.h" | |
26 | ||
a4da2e3e | 27 | |
658f29a5 JB |
28 | static char *dirname(const char *path) |
29 | { | |
30 | const char *slash = strrchr(path, '/'); | |
31 | ||
32 | if (slash) { | |
33 | int len = slash - path; | |
34 | char *dir = xmalloc(len + 1); | |
35 | ||
36 | memcpy(dir, path, len); | |
37 | dir[len] = '\0'; | |
38 | return dir; | |
39 | } | |
40 | return NULL; | |
41 | } | |
42 | ||
136ec204 | 43 | FILE *depfile; /* = NULL */ |
658f29a5 | 44 | struct srcfile_state *current_srcfile; /* = NULL */ |
a4da2e3e | 45 | |
658f29a5 JB |
46 | /* Detect infinite include recursion. */ |
47 | #define MAX_SRCFILE_DEPTH (100) | |
48 | static int srcfile_depth; /* = 0 */ | |
49 | ||
50 | FILE *srcfile_relative_open(const char *fname, char **fullnamep) | |
a4da2e3e | 51 | { |
658f29a5 | 52 | FILE *f; |
ed95d745 | 53 | char *fullname; |
a4da2e3e | 54 | |
658f29a5 JB |
55 | if (streq(fname, "-")) { |
56 | f = stdin; | |
57 | fullname = xstrdup("<stdin>"); | |
ed95d745 | 58 | } else { |
658f29a5 JB |
59 | if (!current_srcfile || !current_srcfile->dir |
60 | || (fname[0] == '/')) | |
61 | fullname = xstrdup(fname); | |
62 | else | |
63 | fullname = join_path(current_srcfile->dir, fname); | |
64 | ||
65 | f = fopen(fullname, "r"); | |
66 | if (!f) | |
67 | die("Couldn't open \"%s\": %s\n", fname, | |
68 | strerror(errno)); | |
ed95d745 | 69 | } |
a4da2e3e | 70 | |
136ec204 SW |
71 | if (depfile) |
72 | fprintf(depfile, " %s", fullname); | |
73 | ||
658f29a5 JB |
74 | if (fullnamep) |
75 | *fullnamep = fullname; | |
76 | else | |
ed95d745 | 77 | free(fullname); |
a4da2e3e | 78 | |
658f29a5 | 79 | return f; |
a4da2e3e DG |
80 | } |
81 | ||
658f29a5 JB |
82 | void srcfile_push(const char *fname) |
83 | { | |
84 | struct srcfile_state *srcfile; | |
85 | ||
86 | if (srcfile_depth++ >= MAX_SRCFILE_DEPTH) | |
87 | die("Includes nested too deeply"); | |
88 | ||
89 | srcfile = xmalloc(sizeof(*srcfile)); | |
90 | ||
91 | srcfile->f = srcfile_relative_open(fname, &srcfile->name); | |
92 | srcfile->dir = dirname(srcfile->name); | |
93 | srcfile->prev = current_srcfile; | |
94 | ||
95 | srcfile->lineno = 1; | |
96 | srcfile->colno = 1; | |
97 | ||
98 | current_srcfile = srcfile; | |
99 | } | |
a4da2e3e | 100 | |
658f29a5 | 101 | int srcfile_pop(void) |
ed95d745 | 102 | { |
658f29a5 | 103 | struct srcfile_state *srcfile = current_srcfile; |
a4da2e3e | 104 | |
658f29a5 | 105 | assert(srcfile); |
a4da2e3e | 106 | |
658f29a5 | 107 | current_srcfile = srcfile->prev; |
a4da2e3e | 108 | |
658f29a5 JB |
109 | if (fclose(srcfile->f)) |
110 | die("Error closing \"%s\": %s\n", srcfile->name, | |
111 | strerror(errno)); | |
ed95d745 | 112 | |
658f29a5 JB |
113 | /* FIXME: We allow the srcfile_state structure to leak, |
114 | * because it could still be referenced from a location | |
115 | * variable being carried through the parser somewhere. To | |
116 | * fix this we could either allocate all the files from a | |
117 | * table, or use a pool allocator. */ | |
a4da2e3e | 118 | |
658f29a5 JB |
119 | return current_srcfile ? 1 : 0; |
120 | } | |
a4da2e3e | 121 | |
658f29a5 JB |
122 | /* |
123 | * The empty source position. | |
124 | */ | |
ed95d745 | 125 | |
658f29a5 JB |
126 | struct srcpos srcpos_empty = { |
127 | .first_line = 0, | |
128 | .first_column = 0, | |
129 | .last_line = 0, | |
130 | .last_column = 0, | |
131 | .file = NULL, | |
132 | }; | |
a4da2e3e | 133 | |
658f29a5 | 134 | #define TAB_SIZE 8 |
a4da2e3e | 135 | |
658f29a5 JB |
136 | void srcpos_update(struct srcpos *pos, const char *text, int len) |
137 | { | |
138 | int i; | |
139 | ||
140 | pos->file = current_srcfile; | |
141 | ||
142 | pos->first_line = current_srcfile->lineno; | |
143 | pos->first_column = current_srcfile->colno; | |
144 | ||
145 | for (i = 0; i < len; i++) | |
146 | if (text[i] == '\n') { | |
147 | current_srcfile->lineno++; | |
148 | current_srcfile->colno = 1; | |
149 | } else if (text[i] == '\t') { | |
150 | current_srcfile->colno = | |
151 | ALIGN(current_srcfile->colno, TAB_SIZE); | |
152 | } else { | |
153 | current_srcfile->colno++; | |
154 | } | |
155 | ||
156 | pos->last_line = current_srcfile->lineno; | |
157 | pos->last_column = current_srcfile->colno; | |
158 | } | |
ed95d745 | 159 | |
658f29a5 JB |
160 | struct srcpos * |
161 | srcpos_copy(struct srcpos *pos) | |
162 | { | |
163 | struct srcpos *pos_new; | |
ed95d745 | 164 | |
658f29a5 JB |
165 | pos_new = xmalloc(sizeof(struct srcpos)); |
166 | memcpy(pos_new, pos, sizeof(struct srcpos)); | |
167 | ||
168 | return pos_new; | |
169 | } | |
170 | ||
171 | ||
172 | ||
173 | void | |
174 | srcpos_dump(struct srcpos *pos) | |
175 | { | |
176 | printf("file : \"%s\"\n", | |
177 | pos->file ? (char *) pos->file : "<no file>"); | |
178 | printf("first_line : %d\n", pos->first_line); | |
179 | printf("first_column: %d\n", pos->first_column); | |
180 | printf("last_line : %d\n", pos->last_line); | |
181 | printf("last_column : %d\n", pos->last_column); | |
182 | printf("file : %s\n", pos->file->name); | |
183 | } | |
a4da2e3e | 184 | |
658f29a5 JB |
185 | |
186 | char * | |
187 | srcpos_string(struct srcpos *pos) | |
188 | { | |
189 | const char *fname = "<no-file>"; | |
190 | char *pos_str; | |
191 | int rc; | |
192 | ||
193 | if (pos) | |
194 | fname = pos->file->name; | |
195 | ||
196 | ||
197 | if (pos->first_line != pos->last_line) | |
198 | rc = asprintf(&pos_str, "%s:%d.%d-%d.%d", fname, | |
199 | pos->first_line, pos->first_column, | |
200 | pos->last_line, pos->last_column); | |
201 | else if (pos->first_column != pos->last_column) | |
202 | rc = asprintf(&pos_str, "%s:%d.%d-%d", fname, | |
203 | pos->first_line, pos->first_column, | |
204 | pos->last_column); | |
205 | else | |
206 | rc = asprintf(&pos_str, "%s:%d.%d", fname, | |
207 | pos->first_line, pos->first_column); | |
208 | ||
209 | if (rc == -1) | |
210 | die("Couldn't allocate in srcpos string"); | |
211 | ||
212 | return pos_str; | |
213 | } | |
214 | ||
215 | void | |
216 | srcpos_verror(struct srcpos *pos, char const *fmt, va_list va) | |
217 | { | |
218 | const char *srcstr; | |
219 | ||
220 | srcstr = srcpos_string(pos); | |
221 | ||
222 | fprintf(stdout, "Error: %s ", srcstr); | |
223 | vfprintf(stdout, fmt, va); | |
224 | fprintf(stdout, "\n"); | |
a4da2e3e DG |
225 | } |
226 | ||
658f29a5 JB |
227 | void |
228 | srcpos_error(struct srcpos *pos, char const *fmt, ...) | |
a4da2e3e | 229 | { |
658f29a5 JB |
230 | va_list va; |
231 | ||
232 | va_start(va, fmt); | |
233 | srcpos_verror(pos, fmt, va); | |
234 | va_end(va); | |
235 | } | |
236 | ||
237 | ||
238 | void | |
239 | srcpos_warn(struct srcpos *pos, char const *fmt, ...) | |
240 | { | |
241 | const char *srcstr; | |
242 | va_list va; | |
243 | va_start(va, fmt); | |
244 | ||
245 | srcstr = srcpos_string(pos); | |
246 | ||
247 | fprintf(stderr, "Warning: %s ", srcstr); | |
248 | vfprintf(stderr, fmt, va); | |
249 | fprintf(stderr, "\n"); | |
ed95d745 | 250 | |
658f29a5 | 251 | va_end(va); |
a4da2e3e | 252 | } |