0001
0002
0003
0004
0005
0006 #define _GNU_SOURCE
0007
0008 #include <stdio.h>
0009
0010 #include "dtc.h"
0011 #include "srcpos.h"
0012
0013
0014 struct search_path {
0015 struct search_path *next;
0016 const char *dirname;
0017 };
0018
0019
0020 static struct search_path *search_path_head, **search_path_tail;
0021
0022
0023 #define MAX_SRCFILE_DEPTH (200)
0024 static int srcfile_depth;
0025
0026 static char *get_dirname(const char *path)
0027 {
0028 const char *slash = strrchr(path, '/');
0029
0030 if (slash) {
0031 int len = slash - path;
0032 char *dir = xmalloc(len + 1);
0033
0034 memcpy(dir, path, len);
0035 dir[len] = '\0';
0036 return dir;
0037 }
0038 return NULL;
0039 }
0040
0041 FILE *depfile;
0042 struct srcfile_state *current_srcfile;
0043 static char *initial_path;
0044 static int initial_pathlen;
0045 static bool initial_cpp = true;
0046
0047 static void set_initial_path(char *fname)
0048 {
0049 int i, len = strlen(fname);
0050
0051 xasprintf(&initial_path, "%s", fname);
0052 initial_pathlen = 0;
0053 for (i = 0; i != len; i++)
0054 if (initial_path[i] == '/')
0055 initial_pathlen++;
0056 }
0057
0058 static char *shorten_to_initial_path(char *fname)
0059 {
0060 char *p1, *p2, *prevslash1 = NULL;
0061 int slashes = 0;
0062
0063 for (p1 = fname, p2 = initial_path; *p1 && *p2; p1++, p2++) {
0064 if (*p1 != *p2)
0065 break;
0066 if (*p1 == '/') {
0067 prevslash1 = p1;
0068 slashes++;
0069 }
0070 }
0071 p1 = prevslash1 + 1;
0072 if (prevslash1) {
0073 int diff = initial_pathlen - slashes, i, j;
0074 int restlen = strlen(fname) - (p1 - fname);
0075 char *res;
0076
0077 res = xmalloc((3 * diff) + restlen + 1);
0078 for (i = 0, j = 0; i != diff; i++) {
0079 res[j++] = '.';
0080 res[j++] = '.';
0081 res[j++] = '/';
0082 }
0083 strcpy(res + j, p1);
0084 return res;
0085 }
0086 return NULL;
0087 }
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100 static char *try_open(const char *dirname, const char *fname, FILE **fp)
0101 {
0102 char *fullname;
0103
0104 if (!dirname || fname[0] == '/')
0105 fullname = xstrdup(fname);
0106 else
0107 fullname = join_path(dirname, fname);
0108
0109 *fp = fopen(fullname, "rb");
0110 if (!*fp) {
0111 free(fullname);
0112 fullname = NULL;
0113 }
0114
0115 return fullname;
0116 }
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127 static char *fopen_any_on_path(const char *fname, FILE **fp)
0128 {
0129 const char *cur_dir = NULL;
0130 struct search_path *node;
0131 char *fullname;
0132
0133
0134 assert(fp);
0135 if (current_srcfile)
0136 cur_dir = current_srcfile->dir;
0137 fullname = try_open(cur_dir, fname, fp);
0138
0139
0140 for (node = search_path_head; !*fp && node; node = node->next)
0141 fullname = try_open(node->dirname, fname, fp);
0142
0143 return fullname;
0144 }
0145
0146 FILE *srcfile_relative_open(const char *fname, char **fullnamep)
0147 {
0148 FILE *f;
0149 char *fullname;
0150
0151 if (streq(fname, "-")) {
0152 f = stdin;
0153 fullname = xstrdup("<stdin>");
0154 } else {
0155 fullname = fopen_any_on_path(fname, &f);
0156 if (!f)
0157 die("Couldn't open \"%s\": %s\n", fname,
0158 strerror(errno));
0159 }
0160
0161 if (depfile)
0162 fprintf(depfile, " %s", fullname);
0163
0164 if (fullnamep)
0165 *fullnamep = fullname;
0166 else
0167 free(fullname);
0168
0169 return f;
0170 }
0171
0172 void srcfile_push(const char *fname)
0173 {
0174 struct srcfile_state *srcfile;
0175
0176 if (srcfile_depth++ >= MAX_SRCFILE_DEPTH)
0177 die("Includes nested too deeply");
0178
0179 srcfile = xmalloc(sizeof(*srcfile));
0180
0181 srcfile->f = srcfile_relative_open(fname, &srcfile->name);
0182 srcfile->dir = get_dirname(srcfile->name);
0183 srcfile->prev = current_srcfile;
0184
0185 srcfile->lineno = 1;
0186 srcfile->colno = 1;
0187
0188 current_srcfile = srcfile;
0189
0190 if (srcfile_depth == 1)
0191 set_initial_path(srcfile->name);
0192 }
0193
0194 bool srcfile_pop(void)
0195 {
0196 struct srcfile_state *srcfile = current_srcfile;
0197
0198 assert(srcfile);
0199
0200 current_srcfile = srcfile->prev;
0201
0202 if (fclose(srcfile->f))
0203 die("Error closing \"%s\": %s\n", srcfile->name,
0204 strerror(errno));
0205
0206
0207
0208
0209
0210
0211
0212 return current_srcfile ? true : false;
0213 }
0214
0215 void srcfile_add_search_path(const char *dirname)
0216 {
0217 struct search_path *node;
0218
0219
0220 node = xmalloc(sizeof(*node));
0221 node->next = NULL;
0222 node->dirname = xstrdup(dirname);
0223
0224
0225 if (search_path_tail)
0226 *search_path_tail = node;
0227 else
0228 search_path_head = node;
0229 search_path_tail = &node->next;
0230 }
0231
0232 void srcpos_update(struct srcpos *pos, const char *text, int len)
0233 {
0234 int i;
0235
0236 pos->file = current_srcfile;
0237
0238 pos->first_line = current_srcfile->lineno;
0239 pos->first_column = current_srcfile->colno;
0240
0241 for (i = 0; i < len; i++)
0242 if (text[i] == '\n') {
0243 current_srcfile->lineno++;
0244 current_srcfile->colno = 1;
0245 } else {
0246 current_srcfile->colno++;
0247 }
0248
0249 pos->last_line = current_srcfile->lineno;
0250 pos->last_column = current_srcfile->colno;
0251 }
0252
0253 struct srcpos *
0254 srcpos_copy(struct srcpos *pos)
0255 {
0256 struct srcpos *pos_new;
0257 struct srcfile_state *srcfile_state;
0258
0259 if (!pos)
0260 return NULL;
0261
0262 pos_new = xmalloc(sizeof(struct srcpos));
0263 assert(pos->next == NULL);
0264 memcpy(pos_new, pos, sizeof(struct srcpos));
0265
0266
0267 srcfile_state = xmalloc(sizeof(struct srcfile_state));
0268 memcpy(srcfile_state, pos->file, sizeof(struct srcfile_state));
0269 pos_new->file = srcfile_state;
0270
0271 return pos_new;
0272 }
0273
0274 struct srcpos *srcpos_extend(struct srcpos *pos, struct srcpos *newtail)
0275 {
0276 struct srcpos *p;
0277
0278 if (!pos)
0279 return newtail;
0280
0281 for (p = pos; p->next != NULL; p = p->next);
0282 p->next = newtail;
0283 return pos;
0284 }
0285
0286 char *
0287 srcpos_string(struct srcpos *pos)
0288 {
0289 const char *fname = "<no-file>";
0290 char *pos_str;
0291
0292 if (pos->file && pos->file->name)
0293 fname = pos->file->name;
0294
0295
0296 if (pos->first_line != pos->last_line)
0297 xasprintf(&pos_str, "%s:%d.%d-%d.%d", fname,
0298 pos->first_line, pos->first_column,
0299 pos->last_line, pos->last_column);
0300 else if (pos->first_column != pos->last_column)
0301 xasprintf(&pos_str, "%s:%d.%d-%d", fname,
0302 pos->first_line, pos->first_column,
0303 pos->last_column);
0304 else
0305 xasprintf(&pos_str, "%s:%d.%d", fname,
0306 pos->first_line, pos->first_column);
0307
0308 return pos_str;
0309 }
0310
0311 static char *
0312 srcpos_string_comment(struct srcpos *pos, bool first_line, int level)
0313 {
0314 char *pos_str, *fname, *first, *rest;
0315 bool fresh_fname = false;
0316
0317 if (!pos) {
0318 if (level > 1) {
0319 xasprintf(&pos_str, "<no-file>:<no-line>");
0320 return pos_str;
0321 } else {
0322 return NULL;
0323 }
0324 }
0325
0326 if (!pos->file)
0327 fname = "<no-file>";
0328 else if (!pos->file->name)
0329 fname = "<no-filename>";
0330 else if (level > 1)
0331 fname = pos->file->name;
0332 else {
0333 fname = shorten_to_initial_path(pos->file->name);
0334 if (fname)
0335 fresh_fname = true;
0336 else
0337 fname = pos->file->name;
0338 }
0339
0340 if (level > 1)
0341 xasprintf(&first, "%s:%d:%d-%d:%d", fname,
0342 pos->first_line, pos->first_column,
0343 pos->last_line, pos->last_column);
0344 else
0345 xasprintf(&first, "%s:%d", fname,
0346 first_line ? pos->first_line : pos->last_line);
0347
0348 if (fresh_fname)
0349 free(fname);
0350
0351 if (pos->next != NULL) {
0352 rest = srcpos_string_comment(pos->next, first_line, level);
0353 xasprintf(&pos_str, "%s, %s", first, rest);
0354 free(first);
0355 free(rest);
0356 } else {
0357 pos_str = first;
0358 }
0359
0360 return pos_str;
0361 }
0362
0363 char *srcpos_string_first(struct srcpos *pos, int level)
0364 {
0365 return srcpos_string_comment(pos, true, level);
0366 }
0367
0368 char *srcpos_string_last(struct srcpos *pos, int level)
0369 {
0370 return srcpos_string_comment(pos, false, level);
0371 }
0372
0373 void srcpos_verror(struct srcpos *pos, const char *prefix,
0374 const char *fmt, va_list va)
0375 {
0376 char *srcstr;
0377
0378 srcstr = srcpos_string(pos);
0379
0380 fprintf(stderr, "%s: %s ", prefix, srcstr);
0381 vfprintf(stderr, fmt, va);
0382 fprintf(stderr, "\n");
0383
0384 free(srcstr);
0385 }
0386
0387 void srcpos_error(struct srcpos *pos, const char *prefix,
0388 const char *fmt, ...)
0389 {
0390 va_list va;
0391
0392 va_start(va, fmt);
0393 srcpos_verror(pos, prefix, fmt, va);
0394 va_end(va);
0395 }
0396
0397 void srcpos_set_line(char *f, int l)
0398 {
0399 current_srcfile->name = f;
0400 current_srcfile->lineno = l;
0401
0402 if (initial_cpp) {
0403 initial_cpp = false;
0404 set_initial_path(f);
0405 }
0406 }