Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc.
0004  */
0005 
0006 #define _GNU_SOURCE
0007 
0008 #include <stdio.h>
0009 
0010 #include "dtc.h"
0011 #include "srcpos.h"
0012 
0013 /* A node in our list of directories to search for source/include files */
0014 struct search_path {
0015     struct search_path *next;   /* next node in list, NULL for end */
0016     const char *dirname;        /* name of directory to search */
0017 };
0018 
0019 /* This is the list of directories that we search for source files */
0020 static struct search_path *search_path_head, **search_path_tail;
0021 
0022 /* Detect infinite include recursion. */
0023 #define MAX_SRCFILE_DEPTH     (200)
0024 static int srcfile_depth; /* = 0 */
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; /* = NULL */
0042 struct srcfile_state *current_srcfile; /* = NULL */
0043 static char *initial_path; /* = NULL */
0044 static int initial_pathlen; /* = 0 */
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  * Try to open a file in a given directory.
0091  *
0092  * If the filename is an absolute path, then dirname is ignored. If it is a
0093  * relative path, then we look in that directory for the file.
0094  *
0095  * @param dirname   Directory to look in, or NULL for none
0096  * @param fname     Filename to look for
0097  * @param fp        Set to NULL if file did not open
0098  * @return allocated filename on success (caller must free), NULL on failure
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  * Open a file for read access
0120  *
0121  * If it is a relative filename, we search the full search path for it.
0122  *
0123  * @param fname Filename to open
0124  * @param fp    Returns pointer to opened FILE, or NULL on failure
0125  * @return pointer to allocated filename, which caller must free
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     /* Try current directory first */
0134     assert(fp);
0135     if (current_srcfile)
0136         cur_dir = current_srcfile->dir;
0137     fullname = try_open(cur_dir, fname, fp);
0138 
0139     /* Failing that, try each search path in turn */
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     /* FIXME: We allow the srcfile_state structure to leak,
0207      * because it could still be referenced from a location
0208      * variable being carried through the parser somewhere.  To
0209      * fix this we could either allocate all the files from a
0210      * table, or use a pool allocator. */
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     /* Create the node */
0220     node = xmalloc(sizeof(*node));
0221     node->next = NULL;
0222     node->dirname = xstrdup(dirname);
0223 
0224     /* Add to the end of our list */
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     /* allocate without free */
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 }