linux/scripts/dtc/srcpos.c
<<
>>
Prefs
   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 */
  14struct 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 */
  20static struct search_path *search_path_head, **search_path_tail;
  21
  22/* Detect infinite include recursion. */
  23#define MAX_SRCFILE_DEPTH     (200)
  24static int srcfile_depth; /* = 0 */
  25
  26static 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
  41FILE *depfile; /* = NULL */
  42struct srcfile_state *current_srcfile; /* = NULL */
  43static char *initial_path; /* = NULL */
  44static int initial_pathlen; /* = 0 */
  45static bool initial_cpp = true;
  46
  47static 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
  58static 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 */
 100static 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 */
 127static 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
 146FILE *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
 172void 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
 194bool 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
 215void 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
 232void 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
 253struct srcpos *
 254srcpos_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
 274struct 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
 286char *
 287srcpos_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
 311static char *
 312srcpos_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
 363char *srcpos_string_first(struct srcpos *pos, int level)
 364{
 365        return srcpos_string_comment(pos, true, level);
 366}
 367
 368char *srcpos_string_last(struct srcpos *pos, int level)
 369{
 370        return srcpos_string_comment(pos, false, level);
 371}
 372
 373void 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
 387void 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
 397void 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}
 407