THIS IS A TEST INSTANCE ONLY! REPOSITORIES CAN BE DELETED AT ANY TIME!

Git Source Code Mirror - This is a publish-only repository and all pull requests are ignored. Please follow Documentation/SubmittingPatches procedure for any of your improvements.
git
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

332 lines
11KB

  1. #include "cache.h"
  2. #include "config.h"
  3. #include "userdiff.h"
  4. #include "attr.h"
  5. static struct userdiff_driver *drivers;
  6. static int ndrivers;
  7. static int drivers_alloc;
  8. #define PATTERNS(name, pattern, word_regex) \
  9. { name, NULL, -1, { pattern, REG_EXTENDED }, \
  10. word_regex "|[^[:space:]]|[\xc0-\xff][\x80-\xbf]+" }
  11. #define IPATTERN(name, pattern, word_regex) \
  12. { name, NULL, -1, { pattern, REG_EXTENDED | REG_ICASE }, \
  13. word_regex "|[^[:space:]]|[\xc0-\xff][\x80-\xbf]+" }
  14. static struct userdiff_driver builtin_drivers[] = {
  15. IPATTERN("ada",
  16. "!^(.*[ \t])?(is[ \t]+new|renames|is[ \t]+separate)([ \t].*)?$\n"
  17. "!^[ \t]*with[ \t].*$\n"
  18. "^[ \t]*((procedure|function)[ \t]+.*)$\n"
  19. "^[ \t]*((package|protected|task)[ \t]+.*)$",
  20. /* -- */
  21. "[a-zA-Z][a-zA-Z0-9_]*"
  22. "|[-+]?[0-9][0-9#_.aAbBcCdDeEfF]*([eE][+-]?[0-9_]+)?"
  23. "|=>|\\.\\.|\\*\\*|:=|/=|>=|<=|<<|>>|<>"),
  24. PATTERNS("dts",
  25. "!;\n"
  26. "!=\n"
  27. /* lines beginning with a word optionally preceded by '&' or the root */
  28. "^[ \t]*((/[ \t]*\\{|&?[a-zA-Z_]).*)",
  29. /* -- */
  30. /* Property names and math operators */
  31. "[a-zA-Z0-9,._+?#-]+"
  32. "|[-+*/%&^|!~]|>>|<<|&&|\\|\\|"),
  33. IPATTERN("fortran",
  34. "!^([C*]|[ \t]*!)\n"
  35. "!^[ \t]*MODULE[ \t]+PROCEDURE[ \t]\n"
  36. "^[ \t]*((END[ \t]+)?(PROGRAM|MODULE|BLOCK[ \t]+DATA"
  37. "|([^'\" \t]+[ \t]+)*(SUBROUTINE|FUNCTION))[ \t]+[A-Z].*)$",
  38. /* -- */
  39. "[a-zA-Z][a-zA-Z0-9_]*"
  40. "|\\.([Ee][Qq]|[Nn][Ee]|[Gg][TtEe]|[Ll][TtEe]|[Tt][Rr][Uu][Ee]|[Ff][Aa][Ll][Ss][Ee]|[Aa][Nn][Dd]|[Oo][Rr]|[Nn]?[Ee][Qq][Vv]|[Nn][Oo][Tt])\\."
  41. /* numbers and format statements like 2E14.4, or ES12.6, 9X.
  42. * Don't worry about format statements without leading digits since
  43. * they would have been matched above as a variable anyway. */
  44. "|[-+]?[0-9.]+([AaIiDdEeFfLlTtXx][Ss]?[-+]?[0-9.]*)?(_[a-zA-Z0-9][a-zA-Z0-9_]*)?"
  45. "|//|\\*\\*|::|[/<>=]="),
  46. IPATTERN("fountain", "^((\\.[^.]|(int|ext|est|int\\.?/ext|i/e)[. ]).*)$",
  47. "[^ \t-]+"),
  48. PATTERNS("golang",
  49. /* Functions */
  50. "^[ \t]*(func[ \t]*.*(\\{[ \t]*)?)\n"
  51. /* Structs and interfaces */
  52. "^[ \t]*(type[ \t].*(struct|interface)[ \t]*(\\{[ \t]*)?)",
  53. /* -- */
  54. "[a-zA-Z_][a-zA-Z0-9_]*"
  55. "|[-+0-9.eE]+i?|0[xX]?[0-9a-fA-F]+i?"
  56. "|[-+*/<>%&^|=!:]=|--|\\+\\+|<<=?|>>=?|&\\^=?|&&|\\|\\||<-|\\.{3}"),
  57. PATTERNS("html", "^[ \t]*(<[Hh][1-6]([ \t].*)?>.*)$",
  58. "[^<>= \t]+"),
  59. PATTERNS("java",
  60. "!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n"
  61. "^[ \t]*(([A-Za-z_][A-Za-z_0-9]*[ \t]+)+[A-Za-z_][A-Za-z_0-9]*[ \t]*\\([^;]*)$",
  62. /* -- */
  63. "[a-zA-Z_][a-zA-Z0-9_]*"
  64. "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
  65. "|[-+*/<>%&^|=!]="
  66. "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
  67. PATTERNS("matlab",
  68. /*
  69. * Octave pattern is mostly the same as matlab, except that '%%%' and
  70. * '##' can also be used to begin code sections, in addition to '%%'
  71. * that is understood by both.
  72. */
  73. "^[[:space:]]*((classdef|function)[[:space:]].*)$|^(%%%?|##)[[:space:]].*$",
  74. "[a-zA-Z_][a-zA-Z0-9_]*|[-+0-9.e]+|[=~<>]=|\\.[*/\\^']|\\|\\||&&"),
  75. PATTERNS("objc",
  76. /* Negate C statements that can look like functions */
  77. "!^[ \t]*(do|for|if|else|return|switch|while)\n"
  78. /* Objective-C methods */
  79. "^[ \t]*([-+][ \t]*\\([ \t]*[A-Za-z_][A-Za-z_0-9* \t]*\\)[ \t]*[A-Za-z_].*)$\n"
  80. /* C functions */
  81. "^[ \t]*(([A-Za-z_][A-Za-z_0-9]*[ \t]+)+[A-Za-z_][A-Za-z_0-9]*[ \t]*\\([^;]*)$\n"
  82. /* Objective-C class/protocol definitions */
  83. "^(@(implementation|interface|protocol)[ \t].*)$",
  84. /* -- */
  85. "[a-zA-Z_][a-zA-Z0-9_]*"
  86. "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
  87. "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"),
  88. PATTERNS("pascal",
  89. "^(((class[ \t]+)?(procedure|function)|constructor|destructor|interface|"
  90. "implementation|initialization|finalization)[ \t]*.*)$"
  91. "\n"
  92. "^(.*=[ \t]*(class|record).*)$",
  93. /* -- */
  94. "[a-zA-Z_][a-zA-Z0-9_]*"
  95. "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+"
  96. "|<>|<=|>=|:=|\\.\\."),
  97. PATTERNS("perl",
  98. "^package .*\n"
  99. "^sub [[:alnum:]_':]+[ \t]*"
  100. "(\\([^)]*\\)[ \t]*)?" /* prototype */
  101. /*
  102. * Attributes. A regex can't count nested parentheses,
  103. * so just slurp up whatever we see, taking care not
  104. * to accept lines like "sub foo; # defined elsewhere".
  105. *
  106. * An attribute could contain a semicolon, but at that
  107. * point it seems reasonable enough to give up.
  108. */
  109. "(:[^;#]*)?"
  110. "(\\{[ \t]*)?" /* brace can come here or on the next line */
  111. "(#.*)?$\n" /* comment */
  112. "^(BEGIN|END|INIT|CHECK|UNITCHECK|AUTOLOAD|DESTROY)[ \t]*"
  113. "(\\{[ \t]*)?" /* brace can come here or on the next line */
  114. "(#.*)?$\n"
  115. "^=head[0-9] .*", /* POD */
  116. /* -- */
  117. "[[:alpha:]_'][[:alnum:]_']*"
  118. "|0[xb]?[0-9a-fA-F_]*"
  119. /* taking care not to interpret 3..5 as (3.)(.5) */
  120. "|[0-9a-fA-F_]+(\\.[0-9a-fA-F_]+)?([eE][-+]?[0-9_]+)?"
  121. "|=>|-[rwxoRWXOezsfdlpSugkbctTBMAC>]|~~|::"
  122. "|&&=|\\|\\|=|//=|\\*\\*="
  123. "|&&|\\|\\||//|\\+\\+|--|\\*\\*|\\.\\.\\.?"
  124. "|[-+*/%.^&<>=!|]="
  125. "|=~|!~"
  126. "|<<|<>|<=>|>>"),
  127. PATTERNS("php",
  128. "^[\t ]*(((public|protected|private|static)[\t ]+)*function.*)$\n"
  129. "^[\t ]*((((final|abstract)[\t ]+)?class|interface|trait).*)$",
  130. /* -- */
  131. "[a-zA-Z_][a-zA-Z0-9_]*"
  132. "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+"
  133. "|[-+*/<>%&^|=!.]=|--|\\+\\+|<<=?|>>=?|===|&&|\\|\\||::|->"),
  134. PATTERNS("python", "^[ \t]*((class|def)[ \t].*)$",
  135. /* -- */
  136. "[a-zA-Z_][a-zA-Z0-9_]*"
  137. "|[-+0-9.e]+[jJlL]?|0[xX]?[0-9a-fA-F]+[lL]?"
  138. "|[-+*/<>%&^|=!]=|//=?|<<=?|>>=?|\\*\\*=?"),
  139. /* -- */
  140. PATTERNS("ruby", "^[ \t]*((class|module|def)[ \t].*)$",
  141. /* -- */
  142. "(@|@@|\\$)?[a-zA-Z_][a-zA-Z0-9_]*"
  143. "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+|\\?(\\\\C-)?(\\\\M-)?."
  144. "|//=?|[-+*/<>%&^|=!]=|<<=?|>>=?|===|\\.{1,3}|::|[!=]~"),
  145. PATTERNS("rust",
  146. "^[\t ]*((pub(\\([^\\)]+\\))?[\t ]+)?((async|const|unsafe|extern([\t ]+\"[^\"]+\"))[\t ]+)?(struct|enum|union|mod|trait|fn|impl)[< \t]+[^;]*)$",
  147. /* -- */
  148. "[a-zA-Z_][a-zA-Z0-9_]*"
  149. "|[0-9][0-9_a-fA-Fiosuxz]*(\\.([0-9]*[eE][+-]?)?[0-9_fF]*)?"
  150. "|[-+*\\/<>%&^|=!:]=|<<=?|>>=?|&&|\\|\\||->|=>|\\.{2}=|\\.{3}|::"),
  151. PATTERNS("bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$",
  152. "[={}\"]|[^={}\" \t]+"),
  153. PATTERNS("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$",
  154. "\\\\[a-zA-Z@]+|\\\\.|[a-zA-Z0-9\x80-\xff]+"),
  155. PATTERNS("cpp",
  156. /* Jump targets or access declarations */
  157. "!^[ \t]*[A-Za-z_][A-Za-z_0-9]*:[[:space:]]*($|/[/*])\n"
  158. /* functions/methods, variables, and compounds at top level */
  159. "^((::[[:space:]]*)?[A-Za-z_].*)$",
  160. /* -- */
  161. "[a-zA-Z_][a-zA-Z0-9_]*"
  162. "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lLuU]*"
  163. "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->\\*?|\\.\\*"),
  164. PATTERNS("csharp",
  165. /* Keywords */
  166. "!^[ \t]*(do|while|for|if|else|instanceof|new|return|switch|case|throw|catch|using)\n"
  167. /* Methods and constructors */
  168. "^[ \t]*(((static|public|internal|private|protected|new|virtual|sealed|override|unsafe|async)[ \t]+)*[][<>@.~_[:alnum:]]+[ \t]+[<>@._[:alnum:]]+[ \t]*\\(.*\\))[ \t]*$\n"
  169. /* Properties */
  170. "^[ \t]*(((static|public|internal|private|protected|new|virtual|sealed|override|unsafe)[ \t]+)*[][<>@.~_[:alnum:]]+[ \t]+[@._[:alnum:]]+)[ \t]*$\n"
  171. /* Type definitions */
  172. "^[ \t]*(((static|public|internal|private|protected|new|unsafe|sealed|abstract|partial)[ \t]+)*(class|enum|interface|struct)[ \t]+.*)$\n"
  173. /* Namespace */
  174. "^[ \t]*(namespace[ \t]+.*)$",
  175. /* -- */
  176. "[a-zA-Z_][a-zA-Z0-9_]*"
  177. "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
  178. "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"),
  179. IPATTERN("css",
  180. "![:;][[:space:]]*$\n"
  181. "^[_a-z0-9].*$",
  182. /* -- */
  183. /*
  184. * This regex comes from W3C CSS specs. Should theoretically also
  185. * allow ISO 10646 characters U+00A0 and higher,
  186. * but they are not handled in this regex.
  187. */
  188. "-?[_a-zA-Z][-_a-zA-Z0-9]*" /* identifiers */
  189. "|-?[0-9]+|\\#[0-9a-fA-F]+" /* numbers */
  190. ),
  191. { "default", NULL, -1, { NULL, 0 } },
  192. };
  193. #undef PATTERNS
  194. #undef IPATTERN
  195. static struct userdiff_driver driver_true = {
  196. "diff=true",
  197. NULL,
  198. 0,
  199. { NULL, 0 }
  200. };
  201. static struct userdiff_driver driver_false = {
  202. "!diff",
  203. NULL,
  204. 1,
  205. { NULL, 0 }
  206. };
  207. static struct userdiff_driver *userdiff_find_by_namelen(const char *k, int len)
  208. {
  209. int i;
  210. for (i = 0; i < ndrivers; i++) {
  211. struct userdiff_driver *drv = drivers + i;
  212. if (!strncmp(drv->name, k, len) && !drv->name[len])
  213. return drv;
  214. }
  215. for (i = 0; i < ARRAY_SIZE(builtin_drivers); i++) {
  216. struct userdiff_driver *drv = builtin_drivers + i;
  217. if (!strncmp(drv->name, k, len) && !drv->name[len])
  218. return drv;
  219. }
  220. return NULL;
  221. }
  222. static int parse_funcname(struct userdiff_funcname *f, const char *k,
  223. const char *v, int cflags)
  224. {
  225. if (git_config_string(&f->pattern, k, v) < 0)
  226. return -1;
  227. f->cflags = cflags;
  228. return 0;
  229. }
  230. static int parse_tristate(int *b, const char *k, const char *v)
  231. {
  232. if (v && !strcasecmp(v, "auto"))
  233. *b = -1;
  234. else
  235. *b = git_config_bool(k, v);
  236. return 0;
  237. }
  238. static int parse_bool(int *b, const char *k, const char *v)
  239. {
  240. *b = git_config_bool(k, v);
  241. return 0;
  242. }
  243. int userdiff_config(const char *k, const char *v)
  244. {
  245. struct userdiff_driver *drv;
  246. const char *name, *type;
  247. int namelen;
  248. if (parse_config_key(k, "diff", &name, &namelen, &type) || !name)
  249. return 0;
  250. drv = userdiff_find_by_namelen(name, namelen);
  251. if (!drv) {
  252. ALLOC_GROW(drivers, ndrivers+1, drivers_alloc);
  253. drv = &drivers[ndrivers++];
  254. memset(drv, 0, sizeof(*drv));
  255. drv->name = xmemdupz(name, namelen);
  256. drv->binary = -1;
  257. }
  258. if (!strcmp(type, "funcname"))
  259. return parse_funcname(&drv->funcname, k, v, 0);
  260. if (!strcmp(type, "xfuncname"))
  261. return parse_funcname(&drv->funcname, k, v, REG_EXTENDED);
  262. if (!strcmp(type, "binary"))
  263. return parse_tristate(&drv->binary, k, v);
  264. if (!strcmp(type, "command"))
  265. return git_config_string(&drv->external, k, v);
  266. if (!strcmp(type, "textconv"))
  267. return git_config_string(&drv->textconv, k, v);
  268. if (!strcmp(type, "cachetextconv"))
  269. return parse_bool(&drv->textconv_want_cache, k, v);
  270. if (!strcmp(type, "wordregex"))
  271. return git_config_string(&drv->word_regex, k, v);
  272. return 0;
  273. }
  274. struct userdiff_driver *userdiff_find_by_name(const char *name)
  275. {
  276. int len = strlen(name);
  277. return userdiff_find_by_namelen(name, len);
  278. }
  279. struct userdiff_driver *userdiff_find_by_path(struct index_state *istate,
  280. const char *path)
  281. {
  282. static struct attr_check *check;
  283. if (!check)
  284. check = attr_check_initl("diff", NULL);
  285. if (!path)
  286. return NULL;
  287. git_check_attr(istate, path, check);
  288. if (ATTR_TRUE(check->items[0].value))
  289. return &driver_true;
  290. if (ATTR_FALSE(check->items[0].value))
  291. return &driver_false;
  292. if (ATTR_UNSET(check->items[0].value))
  293. return NULL;
  294. return userdiff_find_by_name(check->items[0].value);
  295. }
  296. struct userdiff_driver *userdiff_get_textconv(struct repository *r,
  297. struct userdiff_driver *driver)
  298. {
  299. if (!driver->textconv)
  300. return NULL;
  301. if (driver->textconv_want_cache && !driver->textconv_cache) {
  302. struct notes_cache *c = xmalloc(sizeof(*c));
  303. struct strbuf name = STRBUF_INIT;
  304. strbuf_addf(&name, "textconv/%s", driver->name);
  305. notes_cache_init(r, c, name.buf, driver->textconv);
  306. driver->textconv_cache = c;
  307. strbuf_release(&name);
  308. }
  309. return driver;
  310. }