4ab68aca566a8c440239889f76a916772f8f6122
   1#include "cache.h"
   2#include "string-list.h"
   3
   4/*
   5 * A "string_list_each_func_t" function that normalizes an entry from
   6 * GIT_CEILING_DIRECTORIES.  If the path is unusable for some reason,
   7 * die with an explanation.
   8 */
   9static int normalize_ceiling_entry(struct string_list_item *item, void *unused)
  10{
  11        const char *ceil = item->string;
  12        int len = strlen(ceil);
  13        char buf[PATH_MAX+1];
  14
  15        if (len == 0)
  16                die("Empty path is not supported");
  17        if (len > PATH_MAX)
  18                die("Path \"%s\" is too long", ceil);
  19        if (!is_absolute_path(ceil))
  20                die("Path \"%s\" is not absolute", ceil);
  21        if (normalize_path_copy(buf, ceil) < 0)
  22                die("Path \"%s\" could not be normalized", ceil);
  23        len = strlen(buf);
  24        free(item->string);
  25        item->string = xstrdup(buf);
  26        return 1;
  27}
  28
  29static void normalize_argv_string(const char **var, const char *input)
  30{
  31        if (!strcmp(input, "<null>"))
  32                *var = NULL;
  33        else if (!strcmp(input, "<empty>"))
  34                *var = "";
  35        else
  36                *var = input;
  37
  38        if (*var && (**var == '<' || **var == '('))
  39                die("Bad value: %s\n", input);
  40}
  41
  42struct test_data {
  43        const char *from;  /* input:  transform from this ... */
  44        const char *to;    /* output: ... to this.            */
  45};
  46
  47static int test_function(struct test_data *data, char *(*func)(char *input),
  48        const char *funcname)
  49{
  50        int failed = 0, i;
  51        char buffer[1024];
  52        char *to;
  53
  54        for (i = 0; data[i].to; i++) {
  55                if (!data[i].from)
  56                        to = func(NULL);
  57                else {
  58                        strcpy(buffer, data[i].from);
  59                        to = func(buffer);
  60                }
  61                if (strcmp(to, data[i].to)) {
  62                        error("FAIL: %s(%s) => '%s' != '%s'\n",
  63                                funcname, data[i].from, to, data[i].to);
  64                        failed = 1;
  65                }
  66        }
  67        return failed;
  68}
  69
  70static struct test_data basename_data[] = {
  71        /* --- POSIX type paths --- */
  72        { NULL,              "."    },
  73        { "",                "."    },
  74        { ".",               "."    },
  75        { "..",              ".."   },
  76        { "/",               "/"    },
  77#if defined(__CYGWIN__) && !defined(NO_LIBGEN_H)
  78        { "//",              "//"   },
  79        { "///",             "//"   },
  80        { "////",            "//"   },
  81#else
  82        { "//",              "/"    },
  83        { "///",             "/"    },
  84        { "////",            "/"    },
  85#endif
  86        { "usr",             "usr"  },
  87        { "/usr",            "usr"  },
  88        { "/usr/",           "usr"  },
  89        { "/usr//",          "usr"  },
  90        { "/usr/lib",        "lib"  },
  91        { "usr/lib",         "lib"  },
  92        { "usr/lib///",      "lib"  },
  93
  94#if defined(__MINGW32__) || defined(_MSC_VER)
  95
  96        /* --- win32 type paths --- */
  97        { "\\usr",           "usr"  },
  98        { "\\usr\\",         "usr"  },
  99        { "\\usr\\\\",       "usr"  },
 100        { "\\usr\\lib",      "lib"  },
 101        { "usr\\lib",        "lib"  },
 102        { "usr\\lib\\\\\\",  "lib"  },
 103        { "C:/usr",          "usr"  },
 104        { "C:/usr",          "usr"  },
 105        { "C:/usr/",         "usr"  },
 106        { "C:/usr//",        "usr"  },
 107        { "C:/usr/lib",      "lib"  },
 108        { "C:usr/lib",       "lib"  },
 109        { "C:usr/lib///",    "lib"  },
 110        { "C:",              "."    },
 111        { "C:a",             "a"    },
 112        { "C:/",             "/"    },
 113        { "C:///",           "/"    },
 114#if defined(NO_LIBGEN_H)
 115        { "\\",              "\\"   },
 116        { "\\\\",            "\\"   },
 117        { "\\\\\\",          "\\"   },
 118#else
 119
 120        /* win32 platform variations: */
 121#if defined(__MINGW32__)
 122        { "\\",              "/"    },
 123        { "\\\\",            "/"    },
 124        { "\\\\\\",          "/"    },
 125#endif
 126
 127#if defined(_MSC_VER)
 128        { "\\",              "\\"   },
 129        { "\\\\",            "\\"   },
 130        { "\\\\\\",          "\\"   },
 131#endif
 132
 133#endif
 134#endif
 135        { NULL,              NULL   }
 136};
 137
 138static struct test_data dirname_data[] = {
 139        /* --- POSIX type paths --- */
 140        { NULL,              "."      },
 141        { "",                "."      },
 142        { ".",               "."      },
 143        { "..",              "."      },
 144        { "/",               "/"      },
 145        { "//",              "//"     },
 146#if defined(__CYGWIN__) && !defined(NO_LIBGEN_H)
 147        { "///",             "//"     },
 148        { "////",            "//"     },
 149#else
 150        { "///",             "/"      },
 151        { "////",            "/"      },
 152#endif
 153        { "usr",             "."      },
 154        { "/usr",            "/"      },
 155        { "/usr/",           "/"      },
 156        { "/usr//",          "/"      },
 157        { "/usr/lib",        "/usr"   },
 158        { "usr/lib",         "usr"    },
 159        { "usr/lib///",      "usr"    },
 160
 161#if defined(__MINGW32__) || defined(_MSC_VER)
 162
 163        /* --- win32 type paths --- */
 164        { "\\",              "\\"     },
 165        { "\\\\",            "\\\\"   },
 166        { "\\usr",           "\\"     },
 167        { "\\usr\\",         "\\"     },
 168        { "\\usr\\\\",       "\\"     },
 169        { "\\usr\\lib",      "\\usr"  },
 170        { "usr\\lib",        "usr"    },
 171        { "usr\\lib\\\\\\",  "usr"    },
 172        { "C:a",             "C:."    },
 173        { "C:/",             "C:/"    },
 174        { "C:///",           "C:/"    },
 175        { "C:/usr",          "C:/"    },
 176        { "C:/usr/",         "C:/"    },
 177        { "C:/usr//",        "C:/"    },
 178        { "C:/usr/lib",      "C:/usr" },
 179        { "C:usr/lib",       "C:usr"  },
 180        { "C:usr/lib///",    "C:usr"  },
 181        { "\\\\\\",          "\\"     },
 182        { "\\\\\\\\",        "\\"     },
 183#if defined(NO_LIBGEN_H)
 184        { "C:",              "C:."    },
 185#else
 186
 187        /* win32 platform variations: */
 188#if defined(__MINGW32__)
 189        /* the following is clearly wrong ... */
 190        { "C:",              "."      },
 191#endif
 192
 193#if defined(_MSC_VER)
 194        { "C:",              "C:."    },
 195#endif
 196
 197#endif
 198#endif
 199        { NULL,              NULL     }
 200};
 201
 202int main(int argc, char **argv)
 203{
 204        if (argc == 3 && !strcmp(argv[1], "normalize_path_copy")) {
 205                char *buf = xmalloc(PATH_MAX + 1);
 206                int rv = normalize_path_copy(buf, argv[2]);
 207                if (rv)
 208                        buf = "++failed++";
 209                puts(buf);
 210                return 0;
 211        }
 212
 213        if (argc >= 2 && !strcmp(argv[1], "real_path")) {
 214                while (argc > 2) {
 215                        puts(real_path(argv[2]));
 216                        argc--;
 217                        argv++;
 218                }
 219                return 0;
 220        }
 221
 222        if (argc >= 2 && !strcmp(argv[1], "absolute_path")) {
 223                while (argc > 2) {
 224                        puts(absolute_path(argv[2]));
 225                        argc--;
 226                        argv++;
 227                }
 228                return 0;
 229        }
 230
 231        if (argc == 4 && !strcmp(argv[1], "longest_ancestor_length")) {
 232                int len;
 233                struct string_list ceiling_dirs = STRING_LIST_INIT_DUP;
 234                char *path = xstrdup(argv[2]);
 235
 236                /*
 237                 * We have to normalize the arguments because under
 238                 * Windows, bash mangles arguments that look like
 239                 * absolute POSIX paths or colon-separate lists of
 240                 * absolute POSIX paths into DOS paths (e.g.,
 241                 * "/foo:/foo/bar" might be converted to
 242                 * "D:\Src\msysgit\foo;D:\Src\msysgit\foo\bar"),
 243                 * whereas longest_ancestor_length() requires paths
 244                 * that use forward slashes.
 245                 */
 246                if (normalize_path_copy(path, path))
 247                        die("Path \"%s\" could not be normalized", argv[2]);
 248                string_list_split(&ceiling_dirs, argv[3], PATH_SEP, -1);
 249                filter_string_list(&ceiling_dirs, 0,
 250                                   normalize_ceiling_entry, NULL);
 251                len = longest_ancestor_length(path, &ceiling_dirs);
 252                string_list_clear(&ceiling_dirs, 0);
 253                free(path);
 254                printf("%d\n", len);
 255                return 0;
 256        }
 257
 258        if (argc >= 4 && !strcmp(argv[1], "prefix_path")) {
 259                char *prefix = argv[2];
 260                int prefix_len = strlen(prefix);
 261                int nongit_ok;
 262                setup_git_directory_gently(&nongit_ok);
 263                while (argc > 3) {
 264                        puts(prefix_path(prefix, prefix_len, argv[3]));
 265                        argc--;
 266                        argv++;
 267                }
 268                return 0;
 269        }
 270
 271        if (argc == 4 && !strcmp(argv[1], "strip_path_suffix")) {
 272                char *prefix = strip_path_suffix(argv[2], argv[3]);
 273                printf("%s\n", prefix ? prefix : "(null)");
 274                return 0;
 275        }
 276
 277        if (argc == 3 && !strcmp(argv[1], "print_path")) {
 278                puts(argv[2]);
 279                return 0;
 280        }
 281
 282        if (argc == 4 && !strcmp(argv[1], "relative_path")) {
 283                struct strbuf sb = STRBUF_INIT;
 284                const char *in, *prefix, *rel;
 285                normalize_argv_string(&in, argv[2]);
 286                normalize_argv_string(&prefix, argv[3]);
 287                rel = relative_path(in, prefix, &sb);
 288                if (!rel)
 289                        puts("(null)");
 290                else
 291                        puts(strlen(rel) > 0 ? rel : "(empty)");
 292                strbuf_release(&sb);
 293                return 0;
 294        }
 295
 296        if (argc == 2 && !strcmp(argv[1], "basename"))
 297                return test_function(basename_data, basename, argv[1]);
 298
 299        if (argc == 2 && !strcmp(argv[1], "dirname"))
 300                return test_function(dirname_data, dirname, argv[1]);
 301
 302        fprintf(stderr, "%s: unknown function name: %s\n", argv[0],
 303                argv[1] ? argv[1] : "(there was none)");
 304        return 1;
 305}