root/scripts/dtc/srcpos.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_dirname
  2. set_initial_path
  3. shorten_to_initial_path
  4. try_open
  5. fopen_any_on_path
  6. srcfile_relative_open
  7. srcfile_push
  8. srcfile_pop
  9. srcfile_add_search_path
  10. srcpos_update
  11. srcpos_copy
  12. srcpos_extend
  13. srcpos_string
  14. srcpos_string_comment
  15. srcpos_string_first
  16. srcpos_string_last
  17. srcpos_verror
  18. srcpos_error
  19. srcpos_set_line

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc.
   4  */
   5 
   6 #define _GNU_SOURCE
   7 
   8 #include <stdio.h>
   9 
  10 #include "dtc.h"
  11 #include "srcpos.h"
  12 
  13 /* A node in our list of directories to search for source/include files */
  14 struct search_path {
  15         struct search_path *next;       /* next node in list, NULL for end */
  16         const char *dirname;            /* name of directory to search */
  17 };
  18 
  19 /* This is the list of directories that we search for source files */
  20 static struct search_path *search_path_head, **search_path_tail;
  21 
  22 /* Detect infinite include recursion. */
  23 #define MAX_SRCFILE_DEPTH     (100)
  24 static int srcfile_depth; /* = 0 */
  25 
  26 static char *get_dirname(const char *path)
  27 {
  28         const char *slash = strrchr(path, '/');
  29 
  30         if (slash) {
  31                 int len = slash - path;
  32                 char *dir = xmalloc(len + 1);
  33 
  34                 memcpy(dir, path, len);
  35                 dir[len] = '\0';
  36                 return dir;
  37         }
  38         return NULL;
  39 }
  40 
  41 FILE *depfile; /* = NULL */
  42 struct srcfile_state *current_srcfile; /* = NULL */
  43 static char *initial_path; /* = NULL */
  44 static int initial_pathlen; /* = 0 */
  45 static bool initial_cpp = true;
  46 
  47 static void set_initial_path(char *fname)
  48 {
  49         int i, len = strlen(fname);
  50 
  51         xasprintf(&initial_path, "%s", fname);
  52         initial_pathlen = 0;
  53         for (i = 0; i != len; i++)
  54                 if (initial_path[i] == '/')
  55                         initial_pathlen++;
  56 }
  57 
  58 static char *shorten_to_initial_path(char *fname)
  59 {
  60         char *p1, *p2, *prevslash1 = NULL;
  61         int slashes = 0;
  62 
  63         for (p1 = fname, p2 = initial_path; *p1 && *p2; p1++, p2++) {
  64                 if (*p1 != *p2)
  65                         break;
  66                 if (*p1 == '/') {
  67                         prevslash1 = p1;
  68                         slashes++;
  69                 }
  70         }
  71         p1 = prevslash1 + 1;
  72         if (prevslash1) {
  73                 int diff = initial_pathlen - slashes, i, j;
  74                 int restlen = strlen(fname) - (p1 - fname);
  75                 char *res;
  76 
  77                 res = xmalloc((3 * diff) + restlen + 1);
  78                 for (i = 0, j = 0; i != diff; i++) {
  79                         res[j++] = '.';
  80                         res[j++] = '.';
  81                         res[j++] = '/';
  82                 }
  83                 strcpy(res + j, p1);
  84                 return res;
  85         }
  86         return NULL;
  87 }
  88 
  89 /**
  90  * Try to open a file in a given directory.
  91  *
  92  * If the filename is an absolute path, then dirname is ignored. If it is a
  93  * relative path, then we look in that directory for the file.
  94  *
  95  * @param dirname       Directory to look in, or NULL for none
  96  * @param fname         Filename to look for
  97  * @param fp            Set to NULL if file did not open
  98  * @return allocated filename on success (caller must free), NULL on failure
  99  */
 100 static char *try_open(const char *dirname, const char *fname, FILE **fp)
 101 {
 102         char *fullname;
 103 
 104         if (!dirname || fname[0] == '/')
 105                 fullname = xstrdup(fname);
 106         else
 107                 fullname = join_path(dirname, fname);
 108 
 109         *fp = fopen(fullname, "rb");
 110         if (!*fp) {
 111                 free(fullname);
 112                 fullname = NULL;
 113         }
 114 
 115         return fullname;
 116 }
 117 
 118 /**
 119  * Open a file for read access
 120  *
 121  * If it is a relative filename, we search the full search path for it.
 122  *
 123  * @param fname Filename to open
 124  * @param fp    Returns pointer to opened FILE, or NULL on failure
 125  * @return pointer to allocated filename, which caller must free
 126  */
 127 static char *fopen_any_on_path(const char *fname, FILE **fp)
 128 {
 129         const char *cur_dir = NULL;
 130         struct search_path *node;
 131         char *fullname;
 132 
 133         /* Try current directory first */
 134         assert(fp);
 135         if (current_srcfile)
 136                 cur_dir = current_srcfile->dir;
 137         fullname = try_open(cur_dir, fname, fp);
 138 
 139         /* Failing that, try each search path in turn */
 140         for (node = search_path_head; !*fp && node; node = node->next)
 141                 fullname = try_open(node->dirname, fname, fp);
 142 
 143         return fullname;
 144 }
 145 
 146 FILE *srcfile_relative_open(const char *fname, char **fullnamep)
 147 {
 148         FILE *f;
 149         char *fullname;
 150 
 151         if (streq(fname, "-")) {
 152                 f = stdin;
 153                 fullname = xstrdup("<stdin>");
 154         } else {
 155                 fullname = fopen_any_on_path(fname, &f);
 156                 if (!f)
 157                         die("Couldn't open \"%s\": %s\n", fname,
 158                             strerror(errno));
 159         }
 160 
 161         if (depfile)
 162                 fprintf(depfile, " %s", fullname);
 163 
 164         if (fullnamep)
 165                 *fullnamep = fullname;
 166         else
 167                 free(fullname);
 168 
 169         return f;
 170 }
 171 
 172 void srcfile_push(const char *fname)
 173 {
 174         struct srcfile_state *srcfile;
 175 
 176         if (srcfile_depth++ >= MAX_SRCFILE_DEPTH)
 177                 die("Includes nested too deeply");
 178 
 179         srcfile = xmalloc(sizeof(*srcfile));
 180 
 181         srcfile->f = srcfile_relative_open(fname, &srcfile->name);
 182         srcfile->dir = get_dirname(srcfile->name);
 183         srcfile->prev = current_srcfile;
 184 
 185         srcfile->lineno = 1;
 186         srcfile->colno = 1;
 187 
 188         current_srcfile = srcfile;
 189 
 190         if (srcfile_depth == 1)
 191                 set_initial_path(srcfile->name);
 192 }
 193 
 194 bool srcfile_pop(void)
 195 {
 196         struct srcfile_state *srcfile = current_srcfile;
 197 
 198         assert(srcfile);
 199 
 200         current_srcfile = srcfile->prev;
 201 
 202         if (fclose(srcfile->f))
 203                 die("Error closing \"%s\": %s\n", srcfile->name,
 204                     strerror(errno));
 205 
 206         /* FIXME: We allow the srcfile_state structure to leak,
 207          * because it could still be referenced from a location
 208          * variable being carried through the parser somewhere.  To
 209          * fix this we could either allocate all the files from a
 210          * table, or use a pool allocator. */
 211 
 212         return current_srcfile ? true : false;
 213 }
 214 
 215 void srcfile_add_search_path(const char *dirname)
 216 {
 217         struct search_path *node;
 218 
 219         /* Create the node */
 220         node = xmalloc(sizeof(*node));
 221         node->next = NULL;
 222         node->dirname = xstrdup(dirname);
 223 
 224         /* Add to the end of our list */
 225         if (search_path_tail)
 226                 *search_path_tail = node;
 227         else
 228                 search_path_head = node;
 229         search_path_tail = &node->next;
 230 }
 231 
 232 void srcpos_update(struct srcpos *pos, const char *text, int len)
 233 {
 234         int i;
 235 
 236         pos->file = current_srcfile;
 237 
 238         pos->first_line = current_srcfile->lineno;
 239         pos->first_column = current_srcfile->colno;
 240 
 241         for (i = 0; i < len; i++)
 242                 if (text[i] == '\n') {
 243                         current_srcfile->lineno++;
 244                         current_srcfile->colno = 1;
 245                 } else {
 246                         current_srcfile->colno++;
 247                 }
 248 
 249         pos->last_line = current_srcfile->lineno;
 250         pos->last_column = current_srcfile->colno;
 251 }
 252 
 253 struct srcpos *
 254 srcpos_copy(struct srcpos *pos)
 255 {
 256         struct srcpos *pos_new;
 257         struct srcfile_state *srcfile_state;
 258 
 259         if (!pos)
 260                 return NULL;
 261 
 262         pos_new = xmalloc(sizeof(struct srcpos));
 263         assert(pos->next == NULL);
 264         memcpy(pos_new, pos, sizeof(struct srcpos));
 265 
 266         /* allocate without free */
 267         srcfile_state = xmalloc(sizeof(struct srcfile_state));
 268         memcpy(srcfile_state, pos->file, sizeof(struct srcfile_state));
 269         pos_new->file = srcfile_state;
 270 
 271         return pos_new;
 272 }
 273 
 274 struct srcpos *srcpos_extend(struct srcpos *pos, struct srcpos *newtail)
 275 {
 276         struct srcpos *p;
 277 
 278         if (!pos)
 279                 return newtail;
 280 
 281         for (p = pos; p->next != NULL; p = p->next);
 282         p->next = newtail;
 283         return pos;
 284 }
 285 
 286 char *
 287 srcpos_string(struct srcpos *pos)
 288 {
 289         const char *fname = "<no-file>";
 290         char *pos_str;
 291 
 292         if (pos->file && pos->file->name)
 293                 fname = pos->file->name;
 294 
 295 
 296         if (pos->first_line != pos->last_line)
 297                 xasprintf(&pos_str, "%s:%d.%d-%d.%d", fname,
 298                           pos->first_line, pos->first_column,
 299                           pos->last_line, pos->last_column);
 300         else if (pos->first_column != pos->last_column)
 301                 xasprintf(&pos_str, "%s:%d.%d-%d", fname,
 302                           pos->first_line, pos->first_column,
 303                           pos->last_column);
 304         else
 305                 xasprintf(&pos_str, "%s:%d.%d", fname,
 306                           pos->first_line, pos->first_column);
 307 
 308         return pos_str;
 309 }
 310 
 311 static char *
 312 srcpos_string_comment(struct srcpos *pos, bool first_line, int level)
 313 {
 314         char *pos_str, *fname, *first, *rest;
 315         bool fresh_fname = false;
 316 
 317         if (!pos) {
 318                 if (level > 1) {
 319                         xasprintf(&pos_str, "<no-file>:<no-line>");
 320                         return pos_str;
 321                 } else {
 322                         return NULL;
 323                 }
 324         }
 325 
 326         if (!pos->file)
 327                 fname = "<no-file>";
 328         else if (!pos->file->name)
 329                 fname = "<no-filename>";
 330         else if (level > 1)
 331                 fname = pos->file->name;
 332         else {
 333                 fname = shorten_to_initial_path(pos->file->name);
 334                 if (fname)
 335                         fresh_fname = true;
 336                 else
 337                         fname = pos->file->name;
 338         }
 339 
 340         if (level > 1)
 341                 xasprintf(&first, "%s:%d:%d-%d:%d", fname,
 342                           pos->first_line, pos->first_column,
 343                           pos->last_line, pos->last_column);
 344         else
 345                 xasprintf(&first, "%s:%d", fname,
 346                           first_line ? pos->first_line : pos->last_line);
 347 
 348         if (fresh_fname)
 349                 free(fname);
 350 
 351         if (pos->next != NULL) {
 352                 rest = srcpos_string_comment(pos->next, first_line, level);
 353                 xasprintf(&pos_str, "%s, %s", first, rest);
 354                 free(first);
 355                 free(rest);
 356         } else {
 357                 pos_str = first;
 358         }
 359 
 360         return pos_str;
 361 }
 362 
 363 char *srcpos_string_first(struct srcpos *pos, int level)
 364 {
 365         return srcpos_string_comment(pos, true, level);
 366 }
 367 
 368 char *srcpos_string_last(struct srcpos *pos, int level)
 369 {
 370         return srcpos_string_comment(pos, false, level);
 371 }
 372 
 373 void srcpos_verror(struct srcpos *pos, const char *prefix,
 374                    const char *fmt, va_list va)
 375 {
 376         char *srcstr;
 377 
 378         srcstr = srcpos_string(pos);
 379 
 380         fprintf(stderr, "%s: %s ", prefix, srcstr);
 381         vfprintf(stderr, fmt, va);
 382         fprintf(stderr, "\n");
 383 
 384         free(srcstr);
 385 }
 386 
 387 void srcpos_error(struct srcpos *pos, const char *prefix,
 388                   const char *fmt, ...)
 389 {
 390         va_list va;
 391 
 392         va_start(va, fmt);
 393         srcpos_verror(pos, prefix, fmt, va);
 394         va_end(va);
 395 }
 396 
 397 void srcpos_set_line(char *f, int l)
 398 {
 399         current_srcfile->name = f;
 400         current_srcfile->lineno = l;
 401 
 402         if (initial_cpp) {
 403                 initial_cpp = false;
 404                 set_initial_path(f);
 405         }
 406 }

/* [<][>][^][v][top][bottom][index][help] */