diff-new.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821
  1. /* diff - a file comparison program
  2. Copyright (C) 1986 Free Software Foundation
  3. This will be free software eventually, but not until it is finished.
  4. @@ replace with the latest copyright/temms notice from rms when
  5. diff is ready for release.
  6. The basic algorithm is described in: "A File Comparison Program",
  7. Webb Miller and Eugene W. Myers, Software-Practice and Experience,
  8. Volume 15, Number 11, November 1985, pages 1025-1039.
  9. Created. Basic algorithm and functionality in place.
  10. - tower@prep.ai.mit.edu Mon Feb 23 07:44:18 1987
  11. */
  12. /* @@ a double at sign has been used to indicate spots where work is still
  13. needed.
  14. ..!tektronix!videovax!stever has expressed interest in beta-testing
  15. the program via a port to the amiga.
  16. jeffl@wolf.UUCP was looking for a PC/AT-SCO Xenix version. Might be willing
  17. to test and port.
  18. @@ Left to do: Oueries welcome. -len tower <tower@prep.ai.mit.edu>
  19. 1 off bug: "diff{-new,} diff-NEWS*": 12,17c12,12
  20. lint it when it's all done.
  21. Get the multiple exclusive option code to work better. Check the GNU ps to
  22. see how this is done there.
  23. close dirs on file/dir dir/file case (so diff doesn't run out of file
  24. desriptors.
  25. close files on multiple file case.
  26. use stdio if not a file or dir...ie:
  27. handle length problem if stdin is used and it's a pipe/tty.
  28. (believe present code fails for pipe/tty).
  29. flags:
  30. -e finish
  31. -b, -i (note array lookup technique in /u2/emacs/src/etags.c
  32. BSD flags:
  33. -c make # of context lines variable
  34. -l pipe each file thru "pr". for dir only: output other diffs at end.
  35. -r do sub-directories recusively
  36. -Sname (start dir cmp at name)
  37. -Dstring (output cpp format with #ifdef string causing file2)
  38. others?
  39. (losing?) BSD behaviour:
  40. # diff inews inews.old
  41. Binary files inews and inews.old differ
  42. (Should at least, report first difference point as cmp does!)
  43. For compares of more than one (why not one?) include entire file in output
  44. when one file is non-existant (use a special check to prevent all the
  45. grinding). Useful for diff/patch based method of update distribution
  46. (used e.g. in GNU Emacs). Maybe cause this behaviuor by a flag? (or
  47. turn it off with a flag?)
  48. Hack a dir-sort library out of ls, and use it for ls, diff, et.al.
  49. (or just exec ls to get a sorted list of each dir).
  50. N filename args with dir-name as firts or last arg, with error checking
  51. for a dir mid-list or more than one dir with more than two args
  52. chunking program if file(s) is too long (>200K).
  53. load 200K, when get to last complete line, trace chain back to first
  54. gap (same as header break in output), output to there (handle special
  55. case where first gap is beginning of chain). move input after gap to
  56. beginning of buffer, fill buffer to 200K (or EOF),
  57. and loop after resetting file and line number pointers, and
  58. throwing out unused chain (easier to recalculate, than adjust).
  59. line-end-char flag
  60. Date: Fri, 22 Aug 86 19:03:08 EDT
  61. From: rms (Richard M. Stallman)
  62. To: tower
  63. Subject: comments on diff-new
  64. 9. It is important for character codes over \200 octal to work. Perhaps
  65. they will work automatically. If not, changing char to unsigned char
  66. in some places is probably enough to make them work.
  67. 10. diff should be able to handle files that do not end in newlines.
  68. So it should remember, for each file, whether the last line had
  69. a newline at the end. This information can be ignored in doing the
  70. actual comparison, but some output routines must find a way to
  71. indicate this in the output.
  72. 11. It is useful to include character positions as well as line numbers
  73. when describing the position of each difference. Perhaps a new
  74. command line switch should control this feature.
  75. -C (after wc -c ...)
  76. If the entire file is read in at once, the character position is
  77. straightforwardly found from the address of the line's contents.
  78. 12. There should be a command line switch that causes all the lines of
  79. difference to be output with a total of 8 characters of stuff added at
  80. the left. This preserves the alignment of tabs and spaces within the
  81. quoted text.
  82. Use -8 as the flag?
  83. 13. There should be a feature for ignoring all blank lines of input.
  84. Perhaps -b should control this, or perhaps another new switch.
  85. Len: -B ?? how to handle line numbers? a second array for printing them?
  86. 14. There should be a feature to make each set of changes print
  87. (in the **** line) the name of the function they occur in.
  88. Assume that a line with an alphanumeric character in column 0
  89. is a function definition beginning and that the function name
  90. starts there. This feature is present in the ITS file comparison
  91. program and it is very much appreciated.
  92. -F ?? (better one? (see etags switches?)
  93. 15. There should be a switch to ignore changes in case (not count
  94. them as making lines differ). -i
  95. 16. There should be a switch to ignore changes in C comments
  96. (not count them as making lines differ). This cannot work perfectly;
  97. it will be confused by things inside strings that look like comments,
  98. and it may not handle multi-line comments, but it will still be useful.
  99. Len: -E from cc?
  100. */
  101. #include <stdio.h>
  102. #include <strings.h>
  103. #include <sys/file.h>
  104. #include <sys/types.h>
  105. #include <sys/stat.h>
  106. #include <sys/time.h>
  107. #include <ndir.h>
  108. #include <errno.h>
  109. extern int errno;
  110. extern int sys_nerr;
  111. extern char *sys_errlist[];
  112. #define EOS (0)
  113. #define FALSE (0) /* TRUE is any non-zero value */
  114. enum edit_cmd {
  115. INSERT,
  116. DELETE};
  117. /* command line options */
  118. int ws_same_flag = FALSE; /* all strings of contiguous spaces and tabs
  119. are not different */
  120. int print_context_flag = FALSE; /* print out several lines of context before
  121. and after each difference */
  122. int ed_script_flag = FALSE; /* output script that the editor 'ed' can use
  123. to produce file2 from file1 */
  124. int ignore_case_flag = FALSE; /* case differences are ignored */
  125. int print_file_same_flag = FALSE; /* report if files are the same */
  126. int print_english_headers_flag = FALSE; /* difference headers and separators
  127. in ouput are verbose english */
  128. int context_to_show = 3; /* number of lines of context to show before
  129. and after each change when
  130. print_context_flag is set. */
  131. int complex_cmp = 0; /* non-FALSE if not a simple compare
  132. (e.g. ignoring case, or
  133. condensing white space) */
  134. char line_end_char = '\n'; /* character that ends a line */
  135. int exit_status = 0; /* need this for multi-pair comparisions
  136. 0: no differences
  137. 1: differnces found
  138. 2: abnormal termination */
  139. /* edit scripts are stored in linked lists */
  140. struct edit {
  141. struct edit *link; /* previous edit command */
  142. enum edit_cmd op;
  143. int lineA; /* line number in file1 */
  144. int lineB; /* line number in file2 */
  145. };
  146. struct line_def {
  147. char *text;
  148. int length;
  149. } *A, *B; /* alias for inf[0,1].L->line */
  150. struct line_array_def {
  151. struct line_def line[1]; /* The first element of a dynamically sized
  152. array. */
  153. } *Ap, *Bp; /* alias for inf[0,1].L */
  154. /* data on two files being compared */
  155. struct {
  156. int desc; /* file descriptor */
  157. char *name; /* file name */
  158. struct stat stat; /* file status from fstat() */
  159. int argv_dir_p; /* filename argument is a directory */
  160. int maxL; /* number of lines in file */
  161. struct line_array_def *L; /* pointer to array of data on lines of file.
  162. The array never has more than maxL
  163. elements.
  164. It is allocated in diff_2_files(). */
  165. } inf[2];
  166. int maxA, maxB; /* "alias" for inf[0,1].maxL */
  167. static
  168. void
  169. err_msg (text, arg)
  170. char *text, *arg;
  171. {
  172. fprintf (stderr, "diff: %s ", text);
  173. fprintf (stderr, "%s\n", arg);
  174. }
  175. /* use when a system call returns non-zero status. */
  176. static
  177. void
  178. sys_err_msg (text)
  179. char *text;
  180. {
  181. fprintf (stderr, "diff: %s: %s\n", text,
  182. (errno > sys_nerr
  183. ? "No Message in System Table sys_errlist[]"
  184. : sys_errlist[errno]));
  185. }
  186. static
  187. void
  188. fatal (message)
  189. char *message;
  190. {
  191. err_msg (message, "");
  192. exit (2);
  193. }
  194. static
  195. char *
  196. xmalloc (size)
  197. unsigned size;
  198. {
  199. char *malloc();
  200. register char *value = malloc (size);
  201. if ((int) value == 0)
  202. fatal ("virtual memory exhausted");
  203. return value;
  204. }
  205. /* line_cmp - compare two lines of the files */
  206. static
  207. int
  208. line_cmp (s1, s2)
  209. struct line_def *s1, *s2;
  210. {
  211. register char *t1, *t2;
  212. /* @@ need to have this consider line[].length for case where one file has
  213. @@ line_end_char and other does not. */
  214. if ((s1->length != s2->length) && !complex_cmp)
  215. return (1);
  216. t1 = s1->text;
  217. t2 = s2->text;
  218. while (*t1++ == *t2++) {
  219. if ((*t1 == line_end_char) && (*t2 == line_end_char))
  220. return (0);
  221. if (complex_cmp)
  222. abort(); /* ws and ignore_case stuff */
  223. }
  224. return (1);
  225. }
  226. /* print_1_line - print the prefix and text of a single line */
  227. static
  228. void
  229. print_1_line (prefix, line)
  230. char *prefix;
  231. struct line_def *line;
  232. {
  233. printf ("%s", prefix);
  234. fwrite (line->text, sizeof (char), line->length, stdout);
  235. if (line_end_char != '\n')
  236. printf ("\n");
  237. }
  238. char *context_prefix;
  239. int context_start, context_end;
  240. /* print_range - print a range of lines from the proper file.
  241. If context is wanted, print it, using globals variables context_start and
  242. context_end (both of which should have been checked for boundary
  243. conditions). */
  244. print_range (L, start, end, prefix)
  245. struct line_array_def *L;
  246. int start, end; /* origin 1 */
  247. char *prefix;
  248. {
  249. int i;
  250. if (print_context_flag) {
  251. for (i = context_start; i < start; i++)
  252. print_1_line (context_prefix, &(L->line[i-1]));
  253. }
  254. for (i = start; i <= end; i++)
  255. print_1_line (prefix, &(L->line[i-1]));
  256. if (print_context_flag) {
  257. for (i = end + 1; i <= context_end; i++)
  258. print_1_line (context_prefix, &(L->line[i-1]));
  259. }
  260. }
  261. /* print_script - print the edit script */
  262. static
  263. void
  264. print_script (start)
  265. struct edit *start;
  266. {
  267. struct edit *ep, *ap, *bp;
  268. int i, change;
  269. int ins_startA, ins_endA, del_startA, del_endA;
  270. int ins_startB, ins_endB, del_startB, del_endB;
  271. char print_letter, /* letter to use in a header line */
  272. *del_prefix, /* prefix for a deleted line */
  273. *ins_prefix, /* prefix for a inserted line */
  274. *sep_format; /* printf format for a separator line */
  275. if (ed_script_flag)
  276. ep = start;
  277. else {
  278. /* reverse the pointers */
  279. struct edit *behind, *ahead = start;
  280. ep = NULL;
  281. while (ahead != NULL) {
  282. behind = ep;
  283. ep = ahead;
  284. ahead = ahead -> link;
  285. ep->link = behind; /* flip the pointer */
  286. }
  287. }
  288. /* set up non-varying printf formats et. al. */
  289. if (print_english_headers_flag) {
  290. ins_prefix =
  291. del_prefix = " ";
  292. sep_format = "To:\n";
  293. }
  294. else if (print_context_flag) {
  295. context_prefix = " ";
  296. for (i = 0; i <= 1; i++) {
  297. extern char *ctime();
  298. printf ("%s %s\t%s", (i ? "---" : "***"), inf[i].name,
  299. (inf[i].desc == 0 ? "\n" : ctime (&inf[i].stat.st_mtime)));
  300. }
  301. }
  302. else {
  303. ins_prefix = "> ";
  304. del_prefix = "< ";
  305. sep_format = "---\n";
  306. }
  307. /* print the edit commands */
  308. while (ep != NULL) {
  309. if (ep->op == INSERT) {
  310. ins_startA = ep->lineA;
  311. ins_startB = ep->lineB;
  312. bp = ep;
  313. do {
  314. ins_endA = ep->lineA;
  315. ins_endB = ep->lineB;
  316. ep = ep->link;
  317. } while ((ep != NULL) && (ep->op == INSERT) && (ep->lineA == bp->lineA));
  318. if (print_english_headers_flag)
  319. printf ("Inserted after line %d:\n", ins_startA);
  320. else {
  321. if (print_context_flag) {
  322. print_letter = 'i'; /* to setup ins_prefix ... */
  323. change = FALSE; /* ... properly */
  324. context_start = (( (ins_startA + 1 - context_to_show) < 1)
  325. ? 1
  326. : (ins_startA + 1 - context_to_show));
  327. context_end = (((ins_endA + context_to_show) > maxA)
  328. ? maxA
  329. : (ins_endA + context_to_show));
  330. printf ("***************\n*** %d,%d\n", context_start, context_end);
  331. /* just need the context here. */
  332. for (i = context_start; i <= context_end; i++)
  333. print_1_line (context_prefix, &A[i-1]);
  334. }
  335. else {
  336. if (ins_startB != ins_endB)
  337. printf ("%da%d,%d\n", ins_startA, ins_startB, ins_endB);
  338. else
  339. printf ("%da%d\n", ins_startA, ins_startB);
  340. }
  341. }
  342. }
  343. else {
  344. /* DELETE: look for a block of consecutive deleted lines. */
  345. del_startA = ep->lineA;
  346. del_startB = ep->lineB;
  347. do {
  348. del_endA = ep->lineA;
  349. del_endB = ep->lineB;
  350. ap = ep;
  351. ep = ep->link;
  352. } while ((ep != NULL) && (ep->op == DELETE) &&
  353. (ep->lineA == ap->lineA + 1));
  354. bp = ep; /* b points to the command after
  355. the last deletion. */
  356. change =
  357. ((ep != NULL) && (ep->op == INSERT) && (ep->lineA == ap->lineA));
  358. if (change) {
  359. /* count the inserted lines */
  360. ins_startA = ep->lineA;
  361. ins_startB = ep->lineB;
  362. do {
  363. ins_endA = ep->lineA;
  364. ins_endB = ep->lineB;
  365. ep = ep->link;
  366. } while ((ep != NULL)&&(ep->op == INSERT) && (ep->lineA == bp->lineA));
  367. if (print_english_headers_flag)
  368. printf ("Changed ");
  369. else
  370. print_letter = 'c';
  371. }
  372. else {
  373. if (print_english_headers_flag)
  374. printf ("Deleted ");
  375. else
  376. print_letter = 'd';
  377. }
  378. if (print_context_flag) {
  379. context_start = (del_startA - context_to_show);
  380. context_start = ((context_start < 1) ? 1 : context_start);
  381. context_end = (((del_endA + context_to_show) > maxA)
  382. ? maxA
  383. : (del_endA + context_to_show));
  384. printf ("***************\n*** %d,%d\n", context_start, context_end);
  385. del_prefix = (change ? "! " : "- " );
  386. }
  387. else if (del_startA == del_endA) {
  388. if (print_english_headers_flag)
  389. printf ("line %d:\n", del_startA);
  390. else
  391. printf ("%d%c%d\n", del_startA, print_letter,
  392. del_startB + (change ? 1 : 0) );
  393. }
  394. else {
  395. if (print_english_headers_flag)
  396. printf ("lines %d-%d:\n", del_startA, del_endA);
  397. else {
  398. printf ("%d,%d%c%d,%d\n", del_startA, del_endA, print_letter,
  399. del_startB + (change ? 1 : 0), del_endB + (change ? 1 : 0));
  400. }
  401. }
  402. /* Print the deleted lines. */
  403. print_range (Ap, del_startA, del_endA, del_prefix);
  404. if ( !print_context_flag && !change )
  405. continue;
  406. if (!print_context_flag)
  407. printf ("%s", sep_format);
  408. }
  409. /* Print the inserted lines. */
  410. if (print_context_flag) {
  411. if ( !change && !('i' == print_letter)) {
  412. ins_startB = del_startB + 1;
  413. ins_endB = del_endB;
  414. }
  415. context_start = (((ins_startB - context_to_show) < 1)
  416. ? 1
  417. :(ins_startB - context_to_show));
  418. context_end = (((ins_endB + context_to_show) > maxB) /* @@??maxA?? */
  419. ? maxB
  420. : (ins_endB + context_to_show));
  421. printf ("\n--- %d,%d -----\n", context_start, context_end);
  422. ins_prefix = (change ? "! " : (print_letter != 'i' ? " " : "+ "));
  423. }
  424. print_range (Bp, ins_startB, ins_endB, ins_prefix);
  425. }
  426. }
  427. /* make_script - does the diffs and prints out the results.
  428. Requires both files to be open, stat'ed, and input. */
  429. static
  430. void
  431. make_script () /* @@ better interface later? */
  432. {
  433. int max_d = maxA + maxB, /* bound on size of edit script */
  434. origin = maxA + 1, /* origin diagonal */
  435. lower, /* left-most diagonal under consideration */
  436. upper, /* right-most diagonal under consideration */
  437. d, /* current edit distance */
  438. k, /* current diagonal */
  439. row, /* row number */
  440. col; /* column number */
  441. /* for each diagonal, two items are saved: */
  442. int *last_d /* - the row containing the last d; */
  443. = (int *) alloca ((maxA + maxB + 1) * sizeof (int));
  444. struct edit **script /* - corresponding edit script. */
  445. = (struct edit **) alloca ((maxA + maxB + 1) * sizeof (struct edit *));
  446. struct edit *new; /* current instruction in an edit script */
  447. /* Initialize: 0 entries in D indicate identical prefixes. */
  448. for (row = 0;
  449. (row < maxA) && (row < maxB) && (0 == line_cmp (&A[row], &B[row]));
  450. ++row) ;
  451. last_d [origin] = row;
  452. script [origin] = NULL;
  453. lower = (row == maxA) ? origin + 1 : origin - 1;
  454. upper = (row == maxB) ? origin - 1 : origin + 1;
  455. if (lower > upper) { /* The files are identical. */
  456. if (print_file_same_flag)
  457. printf ("No differences encountered. The files are identical.\n");
  458. /* @@ need dir_mode message */
  459. /* exit_status initialized to zero */
  460. return;
  461. }
  462. /* for each value of the edit distance */
  463. for (d = 1; d <= max_d; ++d) {
  464. /* for each relevant diagonal */
  465. for (k = lower; k <= upper; k += 2) {
  466. /* Get space for the edit instruction. */
  467. new = (struct edit *) xmalloc ((unsigned) sizeof (struct edit));
  468. /* Find a d on diagonal k. */
  469. if ((k == origin - d)
  470. || ((k != origin + d) && (last_d[k+1] >= last_d[k-1]))) {
  471. /* Moving down from the last d-1 on diagonal k+1 puts one
  472. farther along diagonal k,
  473. than does moving right from the last d-1 on diagonal k-1. */
  474. row = last_d[k+1] + 1;
  475. new->link = script [k+1];
  476. new->op = DELETE;
  477. }
  478. else {
  479. /* Move right from the last d-1 on diagonal k-1. */
  480. row = last_d[k-1];
  481. new->link = script [k-1];
  482. new->op = INSERT;
  483. }
  484. /* Code common to both DELETE and INSERT. */
  485. new->lineA = row;
  486. new->lineB = col = row + k - origin;
  487. script[k] = new;
  488. /* Slide down the diagonal. */
  489. while ((row < maxA) && (col < maxB) && (0 == line_cmp (&A[row], &B[col]))) {
  490. ++row;
  491. ++col;
  492. }
  493. last_d[k] = row;
  494. if ((row == maxA) && (col == maxB)) {
  495. /* Hit south east corner; have the answer! */
  496. print_script (script[k]);
  497. exit_status = 1;
  498. return;
  499. }
  500. if (row == maxA) /* Hit last row; don't look to the left. */
  501. lower = k + 2;
  502. if (col == maxB) /* Last column; don't look to the right. */
  503. upper = k - 2;
  504. }
  505. --lower;
  506. ++upper;
  507. }
  508. abort(); /* should NEVER get here */
  509. }
  510. /* diff_2_files - requires 2 input files open, and
  511. inf[1,2].desc,name,char initialized. */
  512. static
  513. void
  514. diff_2_files ()
  515. {
  516. int fnum; /* loop iterator */
  517. /* check if the two named files are actually the same physical file. */
  518. if ((inf[0].stat.st_ino == inf[1].stat.st_ino) &&
  519. (inf[0].stat.st_dev == inf[1].stat.st_dev) &&
  520. (print_file_same_flag)) {
  521. printf ("No differences encountered. The files are identical.\n");
  522. /* @@ need dir_mode message */
  523. return;
  524. }
  525. /* Read in file1 and file2, and initialise aliases. */
  526. for (fnum = 0; fnum <= 1; fnum++) {
  527. int lines = 0, /* number of lines in file - origin 1 */
  528. Llength, /* maximum number of lines L can hold */
  529. fsize = inf[fnum].stat.st_size; /* size of file */
  530. char *fbuf = (char *) alloca (fsize + 1),
  531. *i; /* loop iterator */
  532. if (read (inf[fnum].desc, fbuf, fsize) < 0)
  533. sys_err_msg (inf[fnum].name);
  534. Llength = 5; /* @@ change to 1000 fro release */
  535. inf[fnum].L = (struct line_array_def *)
  536. xmalloc ((unsigned) ((unsigned) Llength *
  537. (unsigned) sizeof (struct line_def)));
  538. inf[fnum].L->line[lines++].text = (char *) fbuf;
  539. for (i = fbuf; i <= fbuf + fsize; i++) {
  540. if ((*i == line_end_char) && ((i + 1) < (fbuf + fsize))) {
  541. if (lines >= Llength) {
  542. int oldLlength = Llength;
  543. struct line_array_def *oldL;
  544. oldL = inf[fnum].L;
  545. Llength = ((Llength + 1) * fsize) / (i - fbuf);
  546. /* Assume average line length seen so far is average line length of
  547. whole file, and fudge a little just in case. */
  548. inf[fnum].L = (struct line_array_def *)
  549. xmalloc ((unsigned) ((unsigned) Llength *
  550. (unsigned) sizeof (struct line_def)));
  551. bcopy (oldL, inf[fnum].L, oldLlength * sizeof (struct line_def));
  552. free ((char *) oldL);
  553. }
  554. inf[fnum].L->line[lines - 1].length =
  555. (i + 1) - inf[fnum].L->line[lines - 1].text;
  556. inf[fnum].L->line[lines++].text = (char *) (i + 1);
  557. }
  558. }
  559. inf[fnum].L->line[lines - 1].length =
  560. inf[fnum].L->line[lines - 1].text - inf[fnum].L->line[lines - 2].text;
  561. close (inf[fnum].desc);
  562. inf[fnum].maxL = lines;
  563. }
  564. maxA = inf[0].maxL;
  565. maxB = inf[1].maxL;
  566. Ap = inf[0].L;
  567. Bp = inf[1].L;
  568. A = Ap->line;
  569. B = Bp->line;
  570. make_script ();
  571. free ((char *) Ap); /* free the xmalloc'ed space */
  572. free ((char *) Bp);
  573. }
  574. main (argc, argv)
  575. int argc;
  576. char *argv[];
  577. {
  578. char *ap;
  579. int i;
  580. while (argc > 1 && *(ap = argv[1]) == '-' && *++ap != EOS) {
  581. while (*ap != EOS) {
  582. switch (*ap++) {
  583. case 'b':
  584. ws_same_flag++;
  585. complex_cmp++;
  586. break;
  587. case 'c':
  588. print_context_flag++;
  589. break;
  590. case 'e':
  591. ed_script_flag++;
  592. break;
  593. case 'h':
  594. err_msg ("Warning, useless option. ",
  595. "GNU doesn't do half-hearted jobs.");
  596. break;
  597. case 'i':
  598. ignore_case_flag++;
  599. complex_cmp++;
  600. break;
  601. case 's':
  602. print_file_same_flag++;
  603. break;
  604. case 'v':
  605. print_english_headers_flag++;
  606. break;
  607. default:
  608. { char opt_str[2];
  609. opt_str[0] = ap[-1];
  610. opt_str[1] = EOS;
  611. err_msg ("Warning, bad option:", opt_str);
  612. break;
  613. }
  614. }
  615. }
  616. argc--;
  617. argv++;
  618. }
  619. if (argc != 3)
  620. fatal ("requires two file names. Usage: diff [-options] file1 file2");
  621. /* @@ need more complicated usage string for directory options??
  622. Note three liner at top of BSD documentation, and John Gilmore message
  623. in his public domain tar being used by GNU. */
  624. if (print_context_flag && ed_script_flag) {
  625. /* @@ more flags are incompatible -f, -Dstring*/
  626. err_msg ("Warning, -c and -e are incompatible, -c supressed.\n", "");
  627. print_context_flag = FALSE;
  628. }
  629. argv++;
  630. for (i = 0; i <= 1; i++) {
  631. if (argv[i][0] == '-' && argv[i][1] == EOS) {
  632. inf[i].desc = 0;
  633. inf[i].name = "Standard Input";
  634. }
  635. else {
  636. char *filename = argv[i];
  637. if (0 > (inf[i].desc = open (filename, O_RDONLY, 0)))
  638. sys_err_msg (filename);
  639. else {
  640. extern int stat();
  641. inf[i].name = filename;
  642. if (fstat (inf[i].desc, &inf[i].stat) < 0)
  643. sys_err_msg (inf[i].name);
  644. inf[i].argv_dir_p = (S_IFDIR == (inf[i].stat.st_mode & S_IFDIR));
  645. }
  646. }
  647. }
  648. if ((inf[0].desc < 0) || (inf[1].desc < 0))
  649. fatal ("can not continue");
  650. if (inf[0].argv_dir_p && inf[1].argv_dir_p) {
  651. /* diff all files in both directories */
  652. abort ();
  653. }
  654. else {
  655. if (inf[0].argv_dir_p || inf[1].argv_dir_p) {
  656. int dir_arg = (inf[0].argv_dir_p ? 0 : 1);
  657. int fnm_arg = (inf[0].argv_dir_p ? 1 : 0);
  658. char *filename = (char *) alloca (strlen (argv[dir_arg]) +
  659. strlen (argv[fnm_arg]) + 2);
  660. extern int stat();
  661. strcpy (filename, argv[dir_arg]);
  662. strcat (filename, "/");
  663. strcat (filename, argv[fnm_arg]);
  664. if (0 > (inf[dir_arg].desc = open (filename, O_RDONLY, 0))) {
  665. sys_err_msg (filename);
  666. fatal ("can not continue");
  667. }
  668. else {
  669. inf[dir_arg].name = filename;
  670. if (fstat (inf[dir_arg].desc, &inf[dir_arg].stat) < 0) {
  671. sys_err_msg (inf[dir_arg].name);
  672. fatal ("can not continue");
  673. }
  674. }
  675. }
  676. diff_2_files();
  677. }
  678. exit (exit_status);
  679. }
  680. /*
  681. Local variables:
  682. compile-command: "cc -o diff-new -g diff-new.c"
  683. End:
  684. */