PageRenderTime 39ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/cgit-0.9.0.2/git/diff-no-index.c

#
C | 274 lines | 213 code | 36 blank | 25 comment | 79 complexity | 90ed63a86ddbc4ff561ec38f5dccc849 MD5 | raw file
Possible License(s): GPL-2.0, BSD-2-Clause
  1. /*
  2. * "diff --no-index" support
  3. * Copyright (c) 2007 by Johannes Schindelin
  4. * Copyright (c) 2008 by Junio C Hamano
  5. */
  6. #include "cache.h"
  7. #include "color.h"
  8. #include "commit.h"
  9. #include "blob.h"
  10. #include "tag.h"
  11. #include "diff.h"
  12. #include "diffcore.h"
  13. #include "revision.h"
  14. #include "log-tree.h"
  15. #include "builtin.h"
  16. #include "string-list.h"
  17. static int read_directory(const char *path, struct string_list *list)
  18. {
  19. DIR *dir;
  20. struct dirent *e;
  21. if (!(dir = opendir(path)))
  22. return error("Could not open directory %s", path);
  23. while ((e = readdir(dir)))
  24. if (strcmp(".", e->d_name) && strcmp("..", e->d_name))
  25. string_list_insert(list, e->d_name);
  26. closedir(dir);
  27. return 0;
  28. }
  29. static int get_mode(const char *path, int *mode)
  30. {
  31. struct stat st;
  32. if (!path || !strcmp(path, "/dev/null"))
  33. *mode = 0;
  34. #ifdef _WIN32
  35. else if (!strcasecmp(path, "nul"))
  36. *mode = 0;
  37. #endif
  38. else if (!strcmp(path, "-"))
  39. *mode = create_ce_mode(0666);
  40. else if (lstat(path, &st))
  41. return error("Could not access '%s'", path);
  42. else
  43. *mode = st.st_mode;
  44. return 0;
  45. }
  46. static int queue_diff(struct diff_options *o,
  47. const char *name1, const char *name2)
  48. {
  49. int mode1 = 0, mode2 = 0;
  50. if (get_mode(name1, &mode1) || get_mode(name2, &mode2))
  51. return -1;
  52. if (mode1 && mode2 && S_ISDIR(mode1) != S_ISDIR(mode2))
  53. return error("file/directory conflict: %s, %s", name1, name2);
  54. if (S_ISDIR(mode1) || S_ISDIR(mode2)) {
  55. char buffer1[PATH_MAX], buffer2[PATH_MAX];
  56. struct string_list p1 = STRING_LIST_INIT_DUP;
  57. struct string_list p2 = STRING_LIST_INIT_DUP;
  58. int len1 = 0, len2 = 0, i1, i2, ret = 0;
  59. if (name1 && read_directory(name1, &p1))
  60. return -1;
  61. if (name2 && read_directory(name2, &p2)) {
  62. string_list_clear(&p1, 0);
  63. return -1;
  64. }
  65. if (name1) {
  66. len1 = strlen(name1);
  67. if (len1 > 0 && name1[len1 - 1] == '/')
  68. len1--;
  69. memcpy(buffer1, name1, len1);
  70. buffer1[len1++] = '/';
  71. }
  72. if (name2) {
  73. len2 = strlen(name2);
  74. if (len2 > 0 && name2[len2 - 1] == '/')
  75. len2--;
  76. memcpy(buffer2, name2, len2);
  77. buffer2[len2++] = '/';
  78. }
  79. for (i1 = i2 = 0; !ret && (i1 < p1.nr || i2 < p2.nr); ) {
  80. const char *n1, *n2;
  81. int comp;
  82. if (i1 == p1.nr)
  83. comp = 1;
  84. else if (i2 == p2.nr)
  85. comp = -1;
  86. else
  87. comp = strcmp(p1.items[i1].string,
  88. p2.items[i2].string);
  89. if (comp > 0)
  90. n1 = NULL;
  91. else {
  92. n1 = buffer1;
  93. strncpy(buffer1 + len1, p1.items[i1++].string,
  94. PATH_MAX - len1);
  95. }
  96. if (comp < 0)
  97. n2 = NULL;
  98. else {
  99. n2 = buffer2;
  100. strncpy(buffer2 + len2, p2.items[i2++].string,
  101. PATH_MAX - len2);
  102. }
  103. ret = queue_diff(o, n1, n2);
  104. }
  105. string_list_clear(&p1, 0);
  106. string_list_clear(&p2, 0);
  107. return ret;
  108. } else {
  109. struct diff_filespec *d1, *d2;
  110. if (DIFF_OPT_TST(o, REVERSE_DIFF)) {
  111. unsigned tmp;
  112. const char *tmp_c;
  113. tmp = mode1; mode1 = mode2; mode2 = tmp;
  114. tmp_c = name1; name1 = name2; name2 = tmp_c;
  115. }
  116. if (!name1)
  117. name1 = "/dev/null";
  118. if (!name2)
  119. name2 = "/dev/null";
  120. d1 = alloc_filespec(name1);
  121. d2 = alloc_filespec(name2);
  122. fill_filespec(d1, null_sha1, mode1);
  123. fill_filespec(d2, null_sha1, mode2);
  124. diff_queue(&diff_queued_diff, d1, d2);
  125. return 0;
  126. }
  127. }
  128. static int path_outside_repo(const char *path)
  129. {
  130. const char *work_tree;
  131. size_t len;
  132. if (!is_absolute_path(path))
  133. return 0;
  134. work_tree = get_git_work_tree();
  135. if (!work_tree)
  136. return 1;
  137. len = strlen(work_tree);
  138. if (strncmp(path, work_tree, len) ||
  139. (path[len] != '\0' && path[len] != '/'))
  140. return 1;
  141. return 0;
  142. }
  143. void diff_no_index(struct rev_info *revs,
  144. int argc, const char **argv,
  145. int nongit, const char *prefix)
  146. {
  147. int i;
  148. int no_index = 0;
  149. unsigned options = 0;
  150. /* Were we asked to do --no-index explicitly? */
  151. for (i = 1; i < argc; i++) {
  152. if (!strcmp(argv[i], "--")) {
  153. i++;
  154. break;
  155. }
  156. if (!strcmp(argv[i], "--no-index"))
  157. no_index = 1;
  158. if (argv[i][0] != '-')
  159. break;
  160. }
  161. if (!no_index && !nongit) {
  162. /*
  163. * Inside a git repository, without --no-index. Only
  164. * when a path outside the repository is given,
  165. * e.g. "git diff /var/tmp/[12]", or "git diff
  166. * Makefile /var/tmp/Makefile", allow it to be used as
  167. * a colourful "diff" replacement.
  168. */
  169. if ((argc != i + 2) ||
  170. (!path_outside_repo(argv[i]) &&
  171. !path_outside_repo(argv[i+1])))
  172. return;
  173. }
  174. if (argc != i + 2)
  175. usagef("git diff %s <path> <path>",
  176. no_index ? "--no-index" : "[--no-index]");
  177. diff_setup(&revs->diffopt);
  178. for (i = 1; i < argc - 2; ) {
  179. int j;
  180. if (!strcmp(argv[i], "--no-index"))
  181. i++;
  182. else if (!strcmp(argv[i], "-q")) {
  183. options |= DIFF_SILENT_ON_REMOVED;
  184. i++;
  185. }
  186. else if (!strcmp(argv[i], "--"))
  187. i++;
  188. else {
  189. j = diff_opt_parse(&revs->diffopt, argv + i, argc - i);
  190. if (!j)
  191. die("invalid diff option/value: %s", argv[i]);
  192. i += j;
  193. }
  194. }
  195. /*
  196. * If the user asked for our exit code then don't start a
  197. * pager or we would end up reporting its exit code instead.
  198. */
  199. if (!DIFF_OPT_TST(&revs->diffopt, EXIT_WITH_STATUS))
  200. setup_pager();
  201. if (prefix) {
  202. int len = strlen(prefix);
  203. revs->diffopt.paths = xcalloc(2, sizeof(char *));
  204. for (i = 0; i < 2; i++) {
  205. const char *p = argv[argc - 2 + i];
  206. /*
  207. * stdin should be spelled as '-'; if you have
  208. * path that is '-', spell it as ./-.
  209. */
  210. p = (strcmp(p, "-")
  211. ? xstrdup(prefix_filename(prefix, len, p))
  212. : p);
  213. revs->diffopt.paths[i] = p;
  214. }
  215. }
  216. else
  217. revs->diffopt.paths = argv + argc - 2;
  218. revs->diffopt.nr_paths = 2;
  219. revs->diffopt.skip_stat_unmatch = 1;
  220. if (!revs->diffopt.output_format)
  221. revs->diffopt.output_format = DIFF_FORMAT_PATCH;
  222. DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
  223. DIFF_OPT_SET(&revs->diffopt, NO_INDEX);
  224. revs->max_count = -2;
  225. if (diff_setup_done(&revs->diffopt) < 0)
  226. die("diff_setup_done failed");
  227. if (queue_diff(&revs->diffopt, revs->diffopt.paths[0],
  228. revs->diffopt.paths[1]))
  229. exit(1);
  230. diff_set_mnemonic_prefix(&revs->diffopt, "1/", "2/");
  231. diffcore_std(&revs->diffopt);
  232. diff_flush(&revs->diffopt);
  233. /*
  234. * The return code for --no-index imitates diff(1):
  235. * 0 = no changes, 1 = changes, else error
  236. */
  237. exit(revs->diffopt.found_changes);
  238. }