main.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include "diff.h"
  5. #define DIRECTORY(s) ((s)->qid.type&QTDIR)
  6. #define REGULAR_FILE(s) ((s)->type == 'M' && !DIRECTORY(s))
  7. Biobuf stdout;
  8. static char *tmp[] = {"/tmp/diff1XXXXXXXXXXX", "/tmp/diff2XXXXXXXXXXX"};
  9. static int whichtmp;
  10. static char *progname;
  11. static char usage[] = "diff [-abcefmnrw] file1 ... file2\n";
  12. static void
  13. rmtmpfiles(void)
  14. {
  15. while (whichtmp > 0) {
  16. whichtmp--;
  17. remove(tmp[whichtmp]);
  18. }
  19. }
  20. void
  21. done(int status)
  22. {
  23. rmtmpfiles();
  24. switch(status)
  25. {
  26. case 0:
  27. exits("");
  28. case 1:
  29. exits("some");
  30. default:
  31. exits("error");
  32. }
  33. /*NOTREACHED*/
  34. }
  35. void
  36. panic(int status, char *fmt, ...)
  37. {
  38. va_list arg;
  39. Bflush(&stdout);
  40. fprint(2, "%s: ", progname);
  41. va_start(arg, fmt);
  42. vfprint(2, fmt, arg);
  43. va_end(arg);
  44. if (status)
  45. done(status);
  46. /*NOTREACHED*/
  47. }
  48. static int
  49. catch(void *a, char *msg)
  50. {
  51. USED(a);
  52. panic(2, msg);
  53. return 1;
  54. }
  55. int
  56. mkpathname(char *pathname, char *path, char *name)
  57. {
  58. if (strlen(path) + strlen(name) > MAXPATHLEN) {
  59. panic(0, "pathname %s/%s too long\n", path, name);
  60. return 1;
  61. }
  62. sprint(pathname, "%s/%s", path, name);
  63. return 0;
  64. }
  65. static char *
  66. mktmpfile(int input, Dir **sb)
  67. {
  68. int fd, i;
  69. char *p;
  70. char buf[8192];
  71. atnotify(catch, 1);
  72. p = mktemp(tmp[whichtmp++]);
  73. fd = create(p, OWRITE, 0600);
  74. if (fd < 0) {
  75. panic(mflag ? 0: 2, "cannot create %s: %r\n", p);
  76. return 0;
  77. }
  78. while ((i = read(input, buf, sizeof(buf))) > 0) {
  79. if ((i = write(fd, buf, i)) < 0)
  80. break;
  81. }
  82. *sb = dirfstat(fd);
  83. close(fd);
  84. if (i < 0) {
  85. panic(mflag ? 0: 2, "cannot read/write %s: %r\n", p);
  86. return 0;
  87. }
  88. return p;
  89. }
  90. static char *
  91. statfile(char *file, Dir **sb)
  92. {
  93. Dir *dir;
  94. int input;
  95. dir = dirstat(file);
  96. if(dir == nil) {
  97. if (strcmp(file, "-") || (dir = dirfstat(0)) == nil) {
  98. panic(mflag ? 0: 2, "cannot stat %s: %r\n", file);
  99. return 0;
  100. }
  101. free(dir);
  102. return mktmpfile(0, sb);
  103. }
  104. else if (!REGULAR_FILE(dir) && !DIRECTORY(dir)) {
  105. free(dir);
  106. if ((input = open(file, OREAD)) == -1) {
  107. panic(mflag ? 0: 2, "cannot open %s: %r\n", file);
  108. return 0;
  109. }
  110. file = mktmpfile(input, sb);
  111. close(input);
  112. }
  113. else
  114. *sb = dir;
  115. return file;
  116. }
  117. void
  118. diff(char *f, char *t, int level)
  119. {
  120. char *fp, *tp, *p, fb[MAXPATHLEN+1], tb[MAXPATHLEN+1];
  121. Dir *fsb, *tsb;
  122. if ((fp = statfile(f, &fsb)) == 0)
  123. goto Return;
  124. if ((tp = statfile(t, &tsb)) == 0){
  125. free(fsb);
  126. goto Return;
  127. }
  128. if (DIRECTORY(fsb) && DIRECTORY(tsb)) {
  129. if (rflag || level == 0)
  130. diffdir(fp, tp, level);
  131. else
  132. Bprint(&stdout, "Common subdirectories: %s and %s\n",
  133. fp, tp);
  134. }
  135. else if (REGULAR_FILE(fsb) && REGULAR_FILE(tsb))
  136. diffreg(fp, tp);
  137. else {
  138. if (REGULAR_FILE(fsb)) {
  139. if ((p = utfrrune(f, '/')) == 0)
  140. p = f;
  141. else
  142. p++;
  143. if (mkpathname(tb, tp, p) == 0)
  144. diffreg(fp, tb);
  145. }
  146. else {
  147. if ((p = utfrrune(t, '/')) == 0)
  148. p = t;
  149. else
  150. p++;
  151. if (mkpathname(fb, fp, p) == 0)
  152. diffreg(fb, tp);
  153. }
  154. }
  155. free(fsb);
  156. free(tsb);
  157. Return:
  158. rmtmpfiles();
  159. }
  160. void
  161. main(int argc, char *argv[])
  162. {
  163. char *p;
  164. int i;
  165. Dir *fsb, *tsb;
  166. Binit(&stdout, 1, OWRITE);
  167. progname = *argv;
  168. while (--argc && (*++argv)[0] == '-' && (*argv)[1]) {
  169. for (p = *argv+1; *p; p++) {
  170. switch (*p) {
  171. case 'e':
  172. case 'f':
  173. case 'n':
  174. case 'c':
  175. case 'a':
  176. mode = *p;
  177. break;
  178. case 'w':
  179. bflag = 2;
  180. break;
  181. case 'b':
  182. bflag = 1;
  183. break;
  184. case 'r':
  185. rflag = 1;
  186. break;
  187. case 'm':
  188. mflag = 1;
  189. break;
  190. case 'h':
  191. default:
  192. progname = "Usage";
  193. panic(2, usage);
  194. }
  195. }
  196. }
  197. if (argc < 2)
  198. panic(2, usage, progname);
  199. if ((tsb = dirstat(argv[argc-1])) == nil)
  200. panic(2, "can't stat %s\n", argv[argc-1]);
  201. if (argc > 2) {
  202. if (!DIRECTORY(tsb))
  203. panic(2, usage, progname);
  204. mflag = 1;
  205. }
  206. else {
  207. if ((fsb = dirstat(argv[0])) == nil)
  208. panic(2, "can't stat %s\n", argv[0]);
  209. if (DIRECTORY(fsb) && DIRECTORY(tsb))
  210. mflag = 1;
  211. free(fsb);
  212. }
  213. free(tsb);
  214. for (i = 0; i < argc-1; i++)
  215. diff(argv[i], argv[argc-1], 0);
  216. done(anychange);
  217. /*NOTREACHED*/
  218. }
  219. static char noroom[] = "out of memory - try diff -h\n";
  220. void *
  221. emalloc(unsigned n)
  222. {
  223. register void *p;
  224. if ((p = malloc(n)) == 0)
  225. panic(2, noroom);
  226. return p;
  227. }
  228. void *
  229. erealloc(void *p, unsigned n)
  230. {
  231. register void *rp;
  232. if ((rp = realloc(p, n)) == 0)
  233. panic(2, noroom);
  234. return rp;
  235. }