pathspec.con commit convert add_files_to_cache to take struct pathspec (3efe8e4)
   1#include "cache.h"
   2#include "dir.h"
   3#include "pathspec.h"
   4
   5/*
   6 * Finds which of the given pathspecs match items in the index.
   7 *
   8 * For each pathspec, sets the corresponding entry in the seen[] array
   9 * (which should be specs items long, i.e. the same size as pathspec)
  10 * to the nature of the "closest" (i.e. most specific) match found for
  11 * that pathspec in the index, if it was a closer type of match than
  12 * the existing entry.  As an optimization, matching is skipped
  13 * altogether if seen[] already only contains non-zero entries.
  14 *
  15 * If seen[] has not already been written to, it may make sense
  16 * to use find_pathspecs_matching_against_index() instead.
  17 */
  18void add_pathspec_matches_against_index(const char **pathspec,
  19                                        char *seen, int specs)
  20{
  21        int num_unmatched = 0, i;
  22
  23        /*
  24         * Since we are walking the index as if we were walking the directory,
  25         * we have to mark the matched pathspec as seen; otherwise we will
  26         * mistakenly think that the user gave a pathspec that did not match
  27         * anything.
  28         */
  29        for (i = 0; i < specs; i++)
  30                if (!seen[i])
  31                        num_unmatched++;
  32        if (!num_unmatched)
  33                return;
  34        for (i = 0; i < active_nr; i++) {
  35                struct cache_entry *ce = active_cache[i];
  36                match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen);
  37        }
  38}
  39
  40/*
  41 * Finds which of the given pathspecs match items in the index.
  42 *
  43 * This is a one-shot wrapper around add_pathspec_matches_against_index()
  44 * which allocates, populates, and returns a seen[] array indicating the
  45 * nature of the "closest" (i.e. most specific) matches which each of the
  46 * given pathspecs achieves against all items in the index.
  47 */
  48char *find_pathspecs_matching_against_index(const char **pathspec)
  49{
  50        char *seen;
  51        int i;
  52
  53        for (i = 0; pathspec[i];  i++)
  54                ; /* just counting */
  55        seen = xcalloc(i, 1);
  56        add_pathspec_matches_against_index(pathspec, seen, i);
  57        return seen;
  58}
  59
  60/*
  61 * Magic pathspec
  62 *
  63 * Possible future magic semantics include stuff like:
  64 *
  65 *      { PATHSPEC_NOGLOB, '!', "noglob" },
  66 *      { PATHSPEC_ICASE, '\0', "icase" },
  67 *      { PATHSPEC_RECURSIVE, '*', "recursive" },
  68 *      { PATHSPEC_REGEXP, '\0', "regexp" },
  69 *
  70 */
  71
  72static struct pathspec_magic {
  73        unsigned bit;
  74        char mnemonic; /* this cannot be ':'! */
  75        const char *name;
  76} pathspec_magic[] = {
  77        { PATHSPEC_FROMTOP, '/', "top" },
  78};
  79
  80/*
  81 * Take an element of a pathspec and check for magic signatures.
  82 * Append the result to the prefix. Return the magic bitmap.
  83 *
  84 * For now, we only parse the syntax and throw out anything other than
  85 * "top" magic.
  86 *
  87 * NEEDSWORK: This needs to be rewritten when we start migrating
  88 * get_pathspec() users to use the "struct pathspec" interface.  For
  89 * example, a pathspec element may be marked as case-insensitive, but
  90 * the prefix part must always match literally, and a single stupid
  91 * string cannot express such a case.
  92 */
  93static unsigned prefix_pathspec(struct pathspec_item *item,
  94                                unsigned *p_short_magic,
  95                                const char **raw, unsigned flags,
  96                                const char *prefix, int prefixlen,
  97                                const char *elt)
  98{
  99        unsigned magic = 0, short_magic = 0;
 100        const char *copyfrom = elt;
 101        char *match;
 102        int i;
 103
 104        if (elt[0] != ':') {
 105                ; /* nothing to do */
 106        } else if (elt[1] == '(') {
 107                /* longhand */
 108                const char *nextat;
 109                for (copyfrom = elt + 2;
 110                     *copyfrom && *copyfrom != ')';
 111                     copyfrom = nextat) {
 112                        size_t len = strcspn(copyfrom, ",)");
 113                        if (copyfrom[len] == ',')
 114                                nextat = copyfrom + len + 1;
 115                        else
 116                                /* handle ')' and '\0' */
 117                                nextat = copyfrom + len;
 118                        if (!len)
 119                                continue;
 120                        for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)
 121                                if (strlen(pathspec_magic[i].name) == len &&
 122                                    !strncmp(pathspec_magic[i].name, copyfrom, len)) {
 123                                        magic |= pathspec_magic[i].bit;
 124                                        break;
 125                                }
 126                        if (ARRAY_SIZE(pathspec_magic) <= i)
 127                                die(_("Invalid pathspec magic '%.*s' in '%s'"),
 128                                    (int) len, copyfrom, elt);
 129                }
 130                if (*copyfrom != ')')
 131                        die(_("Missing ')' at the end of pathspec magic in '%s'"), elt);
 132                copyfrom++;
 133        } else {
 134                /* shorthand */
 135                for (copyfrom = elt + 1;
 136                     *copyfrom && *copyfrom != ':';
 137                     copyfrom++) {
 138                        char ch = *copyfrom;
 139
 140                        if (!is_pathspec_magic(ch))
 141                                break;
 142                        for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)
 143                                if (pathspec_magic[i].mnemonic == ch) {
 144                                        short_magic |= pathspec_magic[i].bit;
 145                                        break;
 146                                }
 147                        if (ARRAY_SIZE(pathspec_magic) <= i)
 148                                die(_("Unimplemented pathspec magic '%c' in '%s'"),
 149                                    ch, elt);
 150                }
 151                if (*copyfrom == ':')
 152                        copyfrom++;
 153        }
 154
 155        magic |= short_magic;
 156        *p_short_magic = short_magic;
 157
 158        if (magic & PATHSPEC_FROMTOP)
 159                match = xstrdup(copyfrom);
 160        else
 161                match = prefix_path(prefix, prefixlen, copyfrom);
 162        *raw = item->match = match;
 163        /*
 164         * Prefix the pathspec (keep all magic) and assign to
 165         * original. Useful for passing to another command.
 166         */
 167        if (flags & PATHSPEC_PREFIX_ORIGIN) {
 168                struct strbuf sb = STRBUF_INIT;
 169                strbuf_add(&sb, elt, copyfrom - elt);
 170                strbuf_addstr(&sb, match);
 171                item->original = strbuf_detach(&sb, NULL);
 172        } else
 173                item->original = elt;
 174        item->len = strlen(item->match);
 175
 176        if ((flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP) &&
 177            (item->len >= 1 && item->match[item->len - 1] == '/') &&
 178            (i = cache_name_pos(item->match, item->len - 1)) >= 0 &&
 179            S_ISGITLINK(active_cache[i]->ce_mode)) {
 180                item->len--;
 181                match[item->len] = '\0';
 182        }
 183
 184        if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE)
 185                for (i = 0; i < active_nr; i++) {
 186                        struct cache_entry *ce = active_cache[i];
 187                        int ce_len = ce_namelen(ce);
 188
 189                        if (!S_ISGITLINK(ce->ce_mode))
 190                                continue;
 191
 192                        if (item->len <= ce_len || match[ce_len] != '/' ||
 193                            memcmp(ce->name, match, ce_len))
 194                                continue;
 195                        if (item->len == ce_len + 1) {
 196                                /* strip trailing slash */
 197                                item->len--;
 198                                match[item->len] = '\0';
 199                        } else
 200                                die (_("Pathspec '%s' is in submodule '%.*s'"),
 201                                     elt, ce_len, ce->name);
 202                }
 203
 204        if (limit_pathspec_to_literal())
 205                item->nowildcard_len = item->len;
 206        else
 207                item->nowildcard_len = simple_length(item->match);
 208        item->flags = 0;
 209        if (item->nowildcard_len < item->len &&
 210            item->match[item->nowildcard_len] == '*' &&
 211            no_wildcard(item->match + item->nowildcard_len + 1))
 212                item->flags |= PATHSPEC_ONESTAR;
 213        return magic;
 214}
 215
 216static int pathspec_item_cmp(const void *a_, const void *b_)
 217{
 218        struct pathspec_item *a, *b;
 219
 220        a = (struct pathspec_item *)a_;
 221        b = (struct pathspec_item *)b_;
 222        return strcmp(a->match, b->match);
 223}
 224
 225static void NORETURN unsupported_magic(const char *pattern,
 226                                       unsigned magic,
 227                                       unsigned short_magic)
 228{
 229        struct strbuf sb = STRBUF_INIT;
 230        int i, n;
 231        for (n = i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {
 232                const struct pathspec_magic *m = pathspec_magic + i;
 233                if (!(magic & m->bit))
 234                        continue;
 235                if (sb.len)
 236                        strbuf_addstr(&sb, " ");
 237                if (short_magic & m->bit)
 238                        strbuf_addf(&sb, "'%c'", m->mnemonic);
 239                else
 240                        strbuf_addf(&sb, "'%s'", m->name);
 241                n++;
 242        }
 243        /*
 244         * We may want to substitute "this command" with a command
 245         * name. E.g. when add--interactive dies when running
 246         * "checkout -p"
 247         */
 248        die(_("%s: pathspec magic not supported by this command: %s"),
 249            pattern, sb.buf);
 250}
 251
 252/*
 253 * Given command line arguments and a prefix, convert the input to
 254 * pathspec. die() if any magic in magic_mask is used.
 255 */
 256void parse_pathspec(struct pathspec *pathspec,
 257                    unsigned magic_mask, unsigned flags,
 258                    const char *prefix, const char **argv)
 259{
 260        struct pathspec_item *item;
 261        const char *entry = argv ? *argv : NULL;
 262        int i, n, prefixlen;
 263
 264        memset(pathspec, 0, sizeof(*pathspec));
 265
 266        if (flags & PATHSPEC_MAXDEPTH_VALID)
 267                pathspec->magic |= PATHSPEC_MAXDEPTH;
 268
 269        /* No arguments, no prefix -> no pathspec */
 270        if (!entry && !prefix)
 271                return;
 272
 273        if ((flags & PATHSPEC_PREFER_CWD) &&
 274            (flags & PATHSPEC_PREFER_FULL))
 275                die("BUG: PATHSPEC_PREFER_CWD and PATHSPEC_PREFER_FULL are incompatible");
 276
 277        /* No arguments with prefix -> prefix pathspec */
 278        if (!entry) {
 279                static const char *raw[2];
 280
 281                if (flags & PATHSPEC_PREFER_FULL)
 282                        return;
 283
 284                if (!(flags & PATHSPEC_PREFER_CWD))
 285                        die("BUG: PATHSPEC_PREFER_CWD requires arguments");
 286
 287                pathspec->items = item = xmalloc(sizeof(*item));
 288                memset(item, 0, sizeof(*item));
 289                item->match = prefix;
 290                item->original = prefix;
 291                item->nowildcard_len = item->len = strlen(prefix);
 292                raw[0] = prefix;
 293                raw[1] = NULL;
 294                pathspec->nr = 1;
 295                pathspec->raw = raw;
 296                return;
 297        }
 298
 299        n = 0;
 300        while (argv[n])
 301                n++;
 302
 303        pathspec->nr = n;
 304        pathspec->items = item = xmalloc(sizeof(*item) * n);
 305        pathspec->raw = argv;
 306        prefixlen = prefix ? strlen(prefix) : 0;
 307
 308        for (i = 0; i < n; i++) {
 309                unsigned short_magic;
 310                entry = argv[i];
 311
 312                item[i].magic = prefix_pathspec(item + i, &short_magic,
 313                                                argv + i, flags,
 314                                                prefix, prefixlen, entry);
 315                if (item[i].magic & magic_mask)
 316                        unsupported_magic(entry,
 317                                          item[i].magic & magic_mask,
 318                                          short_magic);
 319
 320                if ((flags & PATHSPEC_SYMLINK_LEADING_PATH) &&
 321                    has_symlink_leading_path(item[i].match, item[i].len)) {
 322                        die(_("pathspec '%s' is beyond a symbolic link"), entry);
 323                }
 324
 325                if (item[i].nowildcard_len < item[i].len)
 326                        pathspec->has_wildcard = 1;
 327                pathspec->magic |= item[i].magic;
 328        }
 329
 330
 331        if (pathspec->magic & PATHSPEC_MAXDEPTH) {
 332                if (flags & PATHSPEC_KEEP_ORDER)
 333                        die("BUG: PATHSPEC_MAXDEPTH_VALID and PATHSPEC_KEEP_ORDER are incompatible");
 334                qsort(pathspec->items, pathspec->nr,
 335                      sizeof(struct pathspec_item), pathspec_item_cmp);
 336        }
 337}
 338
 339/*
 340 * N.B. get_pathspec() is deprecated in favor of the "struct pathspec"
 341 * based interface - see pathspec.c:parse_pathspec().
 342 *
 343 * Arguments:
 344 *  - prefix - a path relative to the root of the working tree
 345 *  - pathspec - a list of paths underneath the prefix path
 346 *
 347 * Iterates over pathspec, prepending each path with prefix,
 348 * and return the resulting list.
 349 *
 350 * If pathspec is empty, return a singleton list containing prefix.
 351 *
 352 * If pathspec and prefix are both empty, return an empty list.
 353 *
 354 * This is typically used by built-in commands such as add.c, in order
 355 * to normalize argv arguments provided to the built-in into a list of
 356 * paths to process, all relative to the root of the working tree.
 357 */
 358const char **get_pathspec(const char *prefix, const char **pathspec)
 359{
 360        struct pathspec ps;
 361        parse_pathspec(&ps,
 362                       PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP,
 363                       PATHSPEC_PREFER_CWD,
 364                       prefix, pathspec);
 365        return ps.raw;
 366}
 367
 368void copy_pathspec(struct pathspec *dst, const struct pathspec *src)
 369{
 370        *dst = *src;
 371        dst->items = xmalloc(sizeof(struct pathspec_item) * dst->nr);
 372        memcpy(dst->items, src->items,
 373               sizeof(struct pathspec_item) * dst->nr);
 374}