userdiff.con commit Merge branch 'pc/remove-warn' into maint (21919d3)
   1#include "userdiff.h"
   2#include "cache.h"
   3#include "attr.h"
   4
   5static struct userdiff_driver *drivers;
   6static int ndrivers;
   7static int drivers_alloc;
   8
   9#define PATTERNS(name, pattern, word_regex)                     \
  10        { name, NULL, -1, { pattern, REG_EXTENDED }, word_regex }
  11static struct userdiff_driver builtin_drivers[] = {
  12PATTERNS("html", "^[ \t]*(<[Hh][1-6][ \t].*>.*)$",
  13         "[^<>= \t]+|[^[:space:]]|[\x80-\xff]+"),
  14PATTERNS("java",
  15         "!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n"
  16         "^[ \t]*(([A-Za-z_][A-Za-z_0-9]*[ \t]+)+[A-Za-z_][A-Za-z_0-9]*[ \t]*\\([^;]*)$",
  17         /* -- */
  18         "[a-zA-Z_][a-zA-Z0-9_]*"
  19         "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
  20         "|[-+*/<>%&^|=!]="
  21         "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"
  22         "|[^[:space:]]|[\x80-\xff]+"),
  23PATTERNS("objc",
  24         /* Negate C statements that can look like functions */
  25         "!^[ \t]*(do|for|if|else|return|switch|while)\n"
  26         /* Objective-C methods */
  27         "^[ \t]*([-+][ \t]*\\([ \t]*[A-Za-z_][A-Za-z_0-9* \t]*\\)[ \t]*[A-Za-z_].*)$\n"
  28         /* C functions */
  29         "^[ \t]*(([A-Za-z_][A-Za-z_0-9]*[ \t]+)+[A-Za-z_][A-Za-z_0-9]*[ \t]*\\([^;]*)$\n"
  30         /* Objective-C class/protocol definitions */
  31         "^(@(implementation|interface|protocol)[ \t].*)$",
  32         /* -- */
  33         "[a-zA-Z_][a-zA-Z0-9_]*"
  34         "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
  35         "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"
  36         "|[^[:space:]]|[\x80-\xff]+"),
  37PATTERNS("pascal",
  38         "^((procedure|function|constructor|destructor|interface|"
  39                "implementation|initialization|finalization)[ \t]*.*)$"
  40         "\n"
  41         "^(.*=[ \t]*(class|record).*)$",
  42         /* -- */
  43         "[a-zA-Z_][a-zA-Z0-9_]*"
  44         "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+"
  45         "|<>|<=|>=|:=|\\.\\."
  46         "|[^[:space:]]|[\x80-\xff]+"),
  47PATTERNS("php",
  48         "^[\t ]*(((public|protected|private|static)[\t ]+)*function.*)$\n"
  49         "^[\t ]*(class.*)$",
  50         /* -- */
  51         "[a-zA-Z_][a-zA-Z0-9_]*"
  52         "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+"
  53         "|[-+*/<>%&^|=!.]=|--|\\+\\+|<<=?|>>=?|===|&&|\\|\\||::|->"
  54         "|[^[:space:]]|[\x80-\xff]+"),
  55PATTERNS("python", "^[ \t]*((class|def)[ \t].*)$",
  56         /* -- */
  57         "[a-zA-Z_][a-zA-Z0-9_]*"
  58         "|[-+0-9.e]+[jJlL]?|0[xX]?[0-9a-fA-F]+[lL]?"
  59         "|[-+*/<>%&^|=!]=|//=?|<<=?|>>=?|\\*\\*=?"
  60         "|[^[:space:]|[\x80-\xff]+"),
  61         /* -- */
  62PATTERNS("ruby", "^[ \t]*((class|module|def)[ \t].*)$",
  63         /* -- */
  64         "(@|@@|\\$)?[a-zA-Z_][a-zA-Z0-9_]*"
  65         "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+|\\?(\\\\C-)?(\\\\M-)?."
  66         "|//=?|[-+*/<>%&^|=!]=|<<=?|>>=?|===|\\.{1,3}|::|[!=]~"
  67         "|[^[:space:]|[\x80-\xff]+"),
  68PATTERNS("bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$",
  69         "[={}\"]|[^={}\" \t]+"),
  70PATTERNS("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$",
  71         "\\\\[a-zA-Z@]+|\\\\.|[a-zA-Z0-9\x80-\xff]+|[^[:space:]]"),
  72PATTERNS("cpp",
  73         /* Jump targets or access declarations */
  74         "!^[ \t]*[A-Za-z_][A-Za-z_0-9]*:.*$\n"
  75         /* C/++ functions/methods at top level */
  76         "^([A-Za-z_][A-Za-z_0-9]*([ \t]+[A-Za-z_][A-Za-z_0-9]*([ \t]*::[ \t]*[^[:space:]]+)?){1,}[ \t]*\\([^;]*)$\n"
  77         /* compound type at top level */
  78         "^((struct|class|enum)[^;]*)$",
  79         /* -- */
  80         "[a-zA-Z_][a-zA-Z0-9_]*"
  81         "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
  82         "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"
  83         "|[^[:space:]]|[\x80-\xff]+"),
  84{ "default", NULL, -1, { NULL, 0 } },
  85};
  86#undef PATTERNS
  87
  88static struct userdiff_driver driver_true = {
  89        "diff=true",
  90        NULL,
  91        0,
  92        { NULL, 0 }
  93};
  94
  95static struct userdiff_driver driver_false = {
  96        "!diff",
  97        NULL,
  98        1,
  99        { NULL, 0 }
 100};
 101
 102static struct userdiff_driver *userdiff_find_by_namelen(const char *k, int len)
 103{
 104        int i;
 105        for (i = 0; i < ndrivers; i++) {
 106                struct userdiff_driver *drv = drivers + i;
 107                if (!strncmp(drv->name, k, len) && !drv->name[len])
 108                        return drv;
 109        }
 110        for (i = 0; i < ARRAY_SIZE(builtin_drivers); i++) {
 111                struct userdiff_driver *drv = builtin_drivers + i;
 112                if (!strncmp(drv->name, k, len) && !drv->name[len])
 113                        return drv;
 114        }
 115        return NULL;
 116}
 117
 118static struct userdiff_driver *parse_driver(const char *var,
 119                const char *value, const char *type)
 120{
 121        struct userdiff_driver *drv;
 122        const char *dot;
 123        const char *name;
 124        int namelen;
 125
 126        if (prefixcmp(var, "diff."))
 127                return NULL;
 128        dot = strrchr(var, '.');
 129        if (dot == var + 4)
 130                return NULL;
 131        if (strcmp(type, dot+1))
 132                return NULL;
 133
 134        name = var + 5;
 135        namelen = dot - name;
 136        drv = userdiff_find_by_namelen(name, namelen);
 137        if (!drv) {
 138                ALLOC_GROW(drivers, ndrivers+1, drivers_alloc);
 139                drv = &drivers[ndrivers++];
 140                memset(drv, 0, sizeof(*drv));
 141                drv->name = xmemdupz(name, namelen);
 142                drv->binary = -1;
 143        }
 144        return drv;
 145}
 146
 147static int parse_funcname(struct userdiff_funcname *f, const char *k,
 148                const char *v, int cflags)
 149{
 150        if (git_config_string(&f->pattern, k, v) < 0)
 151                return -1;
 152        f->cflags = cflags;
 153        return 1;
 154}
 155
 156static int parse_string(const char **d, const char *k, const char *v)
 157{
 158        if (git_config_string(d, k, v) < 0)
 159                return -1;
 160        return 1;
 161}
 162
 163static int parse_tristate(int *b, const char *k, const char *v)
 164{
 165        if (v && !strcasecmp(v, "auto"))
 166                *b = -1;
 167        else
 168                *b = git_config_bool(k, v);
 169        return 1;
 170}
 171
 172int userdiff_config(const char *k, const char *v)
 173{
 174        struct userdiff_driver *drv;
 175
 176        if ((drv = parse_driver(k, v, "funcname")))
 177                return parse_funcname(&drv->funcname, k, v, 0);
 178        if ((drv = parse_driver(k, v, "xfuncname")))
 179                return parse_funcname(&drv->funcname, k, v, REG_EXTENDED);
 180        if ((drv = parse_driver(k, v, "binary")))
 181                return parse_tristate(&drv->binary, k, v);
 182        if ((drv = parse_driver(k, v, "command")))
 183                return parse_string(&drv->external, k, v);
 184        if ((drv = parse_driver(k, v, "textconv")))
 185                return parse_string(&drv->textconv, k, v);
 186        if ((drv = parse_driver(k, v, "wordregex")))
 187                return parse_string(&drv->word_regex, k, v);
 188
 189        return 0;
 190}
 191
 192struct userdiff_driver *userdiff_find_by_name(const char *name) {
 193        int len = strlen(name);
 194        return userdiff_find_by_namelen(name, len);
 195}
 196
 197struct userdiff_driver *userdiff_find_by_path(const char *path)
 198{
 199        static struct git_attr *attr;
 200        struct git_attr_check check;
 201
 202        if (!attr)
 203                attr = git_attr("diff");
 204        check.attr = attr;
 205
 206        if (!path)
 207                return NULL;
 208        if (git_checkattr(path, 1, &check))
 209                return NULL;
 210
 211        if (ATTR_TRUE(check.value))
 212                return &driver_true;
 213        if (ATTR_FALSE(check.value))
 214                return &driver_false;
 215        if (ATTR_UNSET(check.value))
 216                return NULL;
 217        return userdiff_find_by_name(check.value);
 218}