linux/tools/perf/util/path.c
<<
>>
Prefs
   1/*
   2 * I'm tired of doing "vsnprintf()" etc just to open a
   3 * file, so here's a "return static buffer with printf"
   4 * interface for paths.
   5 *
   6 * It's obviously not thread-safe. Sue me. But it's quite
   7 * useful for doing things like
   8 *
   9 *   f = open(mkpath("%s/%s.perf", base, name), O_RDONLY);
  10 *
  11 * which is what it's designed for.
  12 */
  13#include "cache.h"
  14
  15static char bad_path[] = "/bad-path/";
  16/*
  17 * Two hacks:
  18 */
  19
  20static const char *get_perf_dir(void)
  21{
  22        return ".";
  23}
  24
  25static char *get_pathname(void)
  26{
  27        static char pathname_array[4][PATH_MAX];
  28        static int idx;
  29
  30        return pathname_array[3 & ++idx];
  31}
  32
  33static char *cleanup_path(char *path)
  34{
  35        /* Clean it up */
  36        if (!memcmp(path, "./", 2)) {
  37                path += 2;
  38                while (*path == '/')
  39                        path++;
  40        }
  41        return path;
  42}
  43
  44char *mkpath(const char *fmt, ...)
  45{
  46        va_list args;
  47        unsigned len;
  48        char *pathname = get_pathname();
  49
  50        va_start(args, fmt);
  51        len = vsnprintf(pathname, PATH_MAX, fmt, args);
  52        va_end(args);
  53        if (len >= PATH_MAX)
  54                return bad_path;
  55        return cleanup_path(pathname);
  56}
  57
  58char *perf_path(const char *fmt, ...)
  59{
  60        const char *perf_dir = get_perf_dir();
  61        char *pathname = get_pathname();
  62        va_list args;
  63        unsigned len;
  64
  65        len = strlen(perf_dir);
  66        if (len > PATH_MAX-100)
  67                return bad_path;
  68        memcpy(pathname, perf_dir, len);
  69        if (len && perf_dir[len-1] != '/')
  70                pathname[len++] = '/';
  71        va_start(args, fmt);
  72        len += vsnprintf(pathname + len, PATH_MAX - len, fmt, args);
  73        va_end(args);
  74        if (len >= PATH_MAX)
  75                return bad_path;
  76        return cleanup_path(pathname);
  77}
  78
  79/* strip arbitrary amount of directory separators at end of path */
  80static inline int chomp_trailing_dir_sep(const char *path, int len)
  81{
  82        while (len && is_dir_sep(path[len - 1]))
  83                len--;
  84        return len;
  85}
  86
  87/*
  88 * If path ends with suffix (complete path components), returns the
  89 * part before suffix (sans trailing directory separators).
  90 * Otherwise returns NULL.
  91 */
  92char *strip_path_suffix(const char *path, const char *suffix)
  93{
  94        int path_len = strlen(path), suffix_len = strlen(suffix);
  95
  96        while (suffix_len) {
  97                if (!path_len)
  98                        return NULL;
  99
 100                if (is_dir_sep(path[path_len - 1])) {
 101                        if (!is_dir_sep(suffix[suffix_len - 1]))
 102                                return NULL;
 103                        path_len = chomp_trailing_dir_sep(path, path_len);
 104                        suffix_len = chomp_trailing_dir_sep(suffix, suffix_len);
 105                }
 106                else if (path[--path_len] != suffix[--suffix_len])
 107                        return NULL;
 108        }
 109
 110        if (path_len && !is_dir_sep(path[path_len - 1]))
 111                return NULL;
 112        return strndup(path, chomp_trailing_dir_sep(path, path_len));
 113}
 114