sdiff.c 23 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109
  1. /* SDIFF -- interactive merge front end to diff
  2. Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
  3. This file is part of GNU DIFF.
  4. GNU DIFF is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8. GNU DIFF is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU DIFF; see the file COPYING. If not, write to
  14. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  15. /* GNU SDIFF was written by Thomas Lord. */
  16. #include <sys/cdefs.h>
  17. __FBSDID("$FreeBSD: src/contrib/diff/sdiff.c,v 1.1.1.1.12.1 2002/01/28 01:26:35 nectar Exp $");
  18. #include "system.h"
  19. #include <stdio.h>
  20. #include <signal.h>
  21. #include "getopt.h"
  22. /* Size of chunks read from files which must be parsed into lines. */
  23. #define SDIFF_BUFSIZE ((size_t) 65536)
  24. /* Default name of the diff program */
  25. #ifndef DIFF_PROGRAM
  26. #define DIFF_PROGRAM "/usr/bin/diff"
  27. #endif
  28. /* Users' editor of nonchoice */
  29. #ifndef DEFAULT_EDITOR_PROGRAM
  30. #define DEFAULT_EDITOR_PROGRAM "ed"
  31. #endif
  32. extern char version_string[];
  33. static char const *program_name;
  34. static char const *diffbin = DIFF_PROGRAM;
  35. static char const *edbin = DEFAULT_EDITOR_PROGRAM;
  36. static char const **diffargv;
  37. static char *tmpname;
  38. static int volatile tmpmade;
  39. #if HAVE_FORK
  40. static pid_t volatile diffpid;
  41. #endif
  42. struct line_filter;
  43. static FILE *ck_fopen PARAMS((char const *, char const *));
  44. static RETSIGTYPE catchsig PARAMS((int));
  45. static VOID *xmalloc PARAMS((size_t));
  46. static char const *expand_name PARAMS((char *, int, char const *));
  47. static int edit PARAMS((struct line_filter *, int, struct line_filter *, int, FILE*));
  48. static int interact PARAMS((struct line_filter *, struct line_filter *, struct line_filter *, FILE*));
  49. static int lf_snarf PARAMS((struct line_filter *, char *, size_t));
  50. static int skip_white PARAMS((void));
  51. static size_t ck_fread PARAMS((char *, size_t, FILE *));
  52. static size_t lf_refill PARAMS((struct line_filter *));
  53. static void checksigs PARAMS((void));
  54. static void ck_fclose PARAMS((FILE *));
  55. static void ck_fflush PARAMS((FILE *));
  56. static void ck_fwrite PARAMS((char const *, size_t, FILE *));
  57. static void cleanup PARAMS((void));
  58. static void diffarg PARAMS((char const *));
  59. static void execdiff PARAMS((void));
  60. static void exiterr PARAMS((void));
  61. static void fatal PARAMS((char const *));
  62. static void flush_line PARAMS((void));
  63. static void give_help PARAMS((void));
  64. static void lf_copy PARAMS((struct line_filter *, int, FILE *));
  65. static void lf_init PARAMS((struct line_filter *, FILE *));
  66. static void lf_skip PARAMS((struct line_filter *, int));
  67. static void perror_fatal PARAMS((char const *));
  68. static void trapsigs PARAMS((void));
  69. static void try_help PARAMS((char const *));
  70. static void untrapsig PARAMS((int));
  71. static void usage PARAMS((void));
  72. static int diraccess PARAMS((char const *));
  73. /* Options: */
  74. /* name of output file if -o spec'd */
  75. static char *out_file;
  76. /* do not print common lines if true, set by -s option */
  77. static int suppress_common_flag;
  78. static struct option const longopts[] =
  79. {
  80. {"ignore-blank-lines", 0, 0, 'B'},
  81. {"speed-large-files", 0, 0, 'H'},
  82. {"ignore-matching-lines", 1, 0, 'I'},
  83. {"ignore-all-space", 0, 0, 'W'}, /* swap W and w for historical reasons */
  84. {"text", 0, 0, 'a'},
  85. {"ignore-space-change", 0, 0, 'b'},
  86. {"minimal", 0, 0, 'd'},
  87. {"ignore-case", 0, 0, 'i'},
  88. {"left-column", 0, 0, 'l'},
  89. {"output", 1, 0, 'o'},
  90. {"suppress-common-lines", 0, 0, 's'},
  91. {"expand-tabs", 0, 0, 't'},
  92. {"width", 1, 0, 'w'},
  93. {"version", 0, 0, 'v'},
  94. {"help", 0, 0, 129},
  95. {0, 0, 0, 0}
  96. };
  97. static void
  98. try_help (reason)
  99. char const *reason;
  100. {
  101. if (reason)
  102. fprintf (stderr, "%s: %s\n", program_name, reason);
  103. fprintf (stderr, "%s: Try `%s --help' for more information.\n",
  104. program_name, program_name);
  105. exit (2);
  106. }
  107. static void
  108. usage ()
  109. {
  110. printf ("Usage: %s [OPTIONS]... FILE1 FILE2\n\n", program_name);
  111. printf ("%s", "\
  112. -o FILE --output=FILE Operate interactively, sending output to FILE.\n\n");
  113. printf ("%s", "\
  114. -i --ignore-case Consider upper- and lower-case to be the same.\n\
  115. -W --ignore-all-space Ignore all white space.\n\
  116. -b --ignore-space-change Ignore changes in the amount of white space.\n\
  117. -B --ignore-blank-lines Ignore changes whose lines are all blank.\n\
  118. -I RE --ignore-matching-lines=RE Ignore changes whose lines all match RE.\n\
  119. -a --text Treat all files as text.\n\n");
  120. printf ("%s", "\
  121. -w NUM --width=NUM Output at most NUM (default 130) characters per line.\n\
  122. -l --left-column Output only the left column of common lines.\n\
  123. -s --suppress-common-lines Do not output common lines.\n\n");
  124. printf ("\
  125. -t --expand-tabs Expand tabs to spaces in output.\n\n");
  126. printf ("%s", "\
  127. -d --minimal Try hard to find a smaller set of changes.\n\
  128. -H --speed-large-files Assume large files and many scattered small changes.\n\n");
  129. printf ("%s", "\
  130. -v --version Output version info.\n\
  131. --help Output this help.\n\n\
  132. If FILE1 or FILE2 is `-', read standard input.\n");
  133. }
  134. static void
  135. cleanup ()
  136. {
  137. #if HAVE_FORK
  138. if (0 < diffpid)
  139. kill (diffpid, SIGPIPE);
  140. #endif
  141. if (tmpmade)
  142. unlink (tmpname);
  143. }
  144. static void
  145. exiterr ()
  146. {
  147. cleanup ();
  148. untrapsig (0);
  149. checksigs ();
  150. exit (2);
  151. }
  152. static void
  153. fatal (msg)
  154. char const *msg;
  155. {
  156. fprintf (stderr, "%s: %s\n", program_name, msg);
  157. exiterr ();
  158. }
  159. static void
  160. perror_fatal (msg)
  161. char const *msg;
  162. {
  163. int e = errno;
  164. checksigs ();
  165. fprintf (stderr, "%s: ", program_name);
  166. errno = e;
  167. perror (msg);
  168. exiterr ();
  169. }
  170. /* malloc freely or DIE! */
  171. static VOID *
  172. xmalloc (size)
  173. size_t size;
  174. {
  175. VOID *r = (VOID *) malloc (size);
  176. if (!r)
  177. fatal ("memory exhausted");
  178. return r;
  179. }
  180. static FILE *
  181. ck_fopen (fname, type)
  182. char const *fname, *type;
  183. {
  184. FILE *r = fopen (fname, type);
  185. if (!r)
  186. perror_fatal (fname);
  187. return r;
  188. }
  189. static void
  190. ck_fclose (f)
  191. FILE *f;
  192. {
  193. if (fclose (f))
  194. perror_fatal ("input/output error");
  195. }
  196. static size_t
  197. ck_fread (buf, size, f)
  198. char *buf;
  199. size_t size;
  200. FILE *f;
  201. {
  202. size_t r = fread (buf, sizeof (char), size, f);
  203. if (r == 0 && ferror (f))
  204. perror_fatal ("input error");
  205. return r;
  206. }
  207. static void
  208. ck_fwrite (buf, size, f)
  209. char const *buf;
  210. size_t size;
  211. FILE *f;
  212. {
  213. if (fwrite (buf, sizeof (char), size, f) != size)
  214. perror_fatal ("output error");
  215. }
  216. static void
  217. ck_fflush (f)
  218. FILE *f;
  219. {
  220. if (fflush (f) != 0)
  221. perror_fatal ("output error");
  222. }
  223. static char const *
  224. expand_name (name, is_dir, other_name)
  225. char *name;
  226. int is_dir;
  227. char const *other_name;
  228. {
  229. if (strcmp (name, "-") == 0)
  230. fatal ("cannot interactively merge standard input");
  231. if (!is_dir)
  232. return name;
  233. else
  234. {
  235. /* Yield NAME/BASE, where BASE is OTHER_NAME's basename. */
  236. char const *p = filename_lastdirchar (other_name);
  237. char const *base = p ? p+1 : other_name;
  238. size_t namelen = strlen (name), baselen = strlen (base);
  239. char *r = xmalloc (namelen + baselen + 2);
  240. memcpy (r, name, namelen);
  241. r[namelen] = '/';
  242. memcpy (r + namelen + 1, base, baselen + 1);
  243. return r;
  244. }
  245. }
  246. struct line_filter {
  247. FILE *infile;
  248. char *bufpos;
  249. char *buffer;
  250. char *buflim;
  251. };
  252. static void
  253. lf_init (lf, infile)
  254. struct line_filter *lf;
  255. FILE *infile;
  256. {
  257. lf->infile = infile;
  258. lf->bufpos = lf->buffer = lf->buflim = xmalloc (SDIFF_BUFSIZE + 1);
  259. lf->buflim[0] = '\n';
  260. }
  261. /* Fill an exhausted line_filter buffer from its INFILE */
  262. static size_t
  263. lf_refill (lf)
  264. struct line_filter *lf;
  265. {
  266. size_t s = ck_fread (lf->buffer, SDIFF_BUFSIZE, lf->infile);
  267. lf->bufpos = lf->buffer;
  268. lf->buflim = lf->buffer + s;
  269. lf->buflim[0] = '\n';
  270. checksigs ();
  271. return s;
  272. }
  273. /* Advance LINES on LF's infile, copying lines to OUTFILE */
  274. static void
  275. lf_copy (lf, lines, outfile)
  276. struct line_filter *lf;
  277. int lines;
  278. FILE *outfile;
  279. {
  280. char *start = lf->bufpos;
  281. while (lines)
  282. {
  283. lf->bufpos = (char *) memchr (lf->bufpos, '\n', lf->buflim - lf->bufpos);
  284. if (! lf->bufpos)
  285. {
  286. ck_fwrite (start, lf->buflim - start, outfile);
  287. if (! lf_refill (lf))
  288. return;
  289. start = lf->bufpos;
  290. }
  291. else
  292. {
  293. --lines;
  294. ++lf->bufpos;
  295. }
  296. }
  297. ck_fwrite (start, lf->bufpos - start, outfile);
  298. }
  299. /* Advance LINES on LF's infile without doing output */
  300. static void
  301. lf_skip (lf, lines)
  302. struct line_filter *lf;
  303. int lines;
  304. {
  305. while (lines)
  306. {
  307. lf->bufpos = (char *) memchr (lf->bufpos, '\n', lf->buflim - lf->bufpos);
  308. if (! lf->bufpos)
  309. {
  310. if (! lf_refill (lf))
  311. break;
  312. }
  313. else
  314. {
  315. --lines;
  316. ++lf->bufpos;
  317. }
  318. }
  319. }
  320. /* Snarf a line into a buffer. Return EOF if EOF, 0 if error, 1 if OK. */
  321. static int
  322. lf_snarf (lf, buffer, bufsize)
  323. struct line_filter *lf;
  324. char *buffer;
  325. size_t bufsize;
  326. {
  327. char *start = lf->bufpos;
  328. for (;;)
  329. {
  330. char *next = (char *) memchr (start, '\n', lf->buflim + 1 - start);
  331. size_t s = next - start;
  332. if (bufsize <= s)
  333. return 0;
  334. memcpy (buffer, start, s);
  335. if (next < lf->buflim)
  336. {
  337. buffer[s] = 0;
  338. lf->bufpos = next + 1;
  339. return 1;
  340. }
  341. if (! lf_refill (lf))
  342. return s ? 0 : EOF;
  343. buffer += s;
  344. bufsize -= s;
  345. start = next;
  346. }
  347. }
  348. int
  349. main (argc, argv)
  350. int argc;
  351. char *argv[];
  352. {
  353. int opt;
  354. char *editor;
  355. char *differ;
  356. initialize_main (&argc, &argv);
  357. program_name = argv[0];
  358. editor = getenv ("EDITOR");
  359. if (editor)
  360. edbin = editor;
  361. differ = getenv ("DIFF");
  362. if (differ)
  363. diffbin = differ;
  364. diffarg ("diff");
  365. /* parse command line args */
  366. while ((opt = getopt_long (argc, argv, "abBdHiI:lo:stvw:W", longopts, 0))
  367. != EOF)
  368. {
  369. switch (opt)
  370. {
  371. case 'a':
  372. diffarg ("-a");
  373. break;
  374. case 'b':
  375. diffarg ("-b");
  376. break;
  377. case 'B':
  378. diffarg ("-B");
  379. break;
  380. case 'd':
  381. diffarg ("-d");
  382. break;
  383. case 'H':
  384. diffarg ("-H");
  385. break;
  386. case 'i':
  387. diffarg ("-i");
  388. break;
  389. case 'I':
  390. diffarg ("-I");
  391. diffarg (optarg);
  392. break;
  393. case 'l':
  394. diffarg ("--left-column");
  395. break;
  396. case 'o':
  397. out_file = optarg;
  398. break;
  399. case 's':
  400. suppress_common_flag = 1;
  401. break;
  402. case 't':
  403. diffarg ("-t");
  404. break;
  405. case 'v':
  406. printf ("sdiff - GNU diffutils version %s\n", version_string);
  407. exit (0);
  408. case 'w':
  409. diffarg ("-W");
  410. diffarg (optarg);
  411. break;
  412. case 'W':
  413. diffarg ("-w");
  414. break;
  415. case 129:
  416. usage ();
  417. if (ferror (stdout) || fclose (stdout) != 0)
  418. fatal ("write error");
  419. exit (0);
  420. default:
  421. try_help (0);
  422. }
  423. }
  424. if (argc - optind != 2)
  425. try_help (argc - optind < 2 ? "missing operand" : "extra operand");
  426. if (! out_file)
  427. {
  428. /* easy case: diff does everything for us */
  429. if (suppress_common_flag)
  430. diffarg ("--suppress-common-lines");
  431. diffarg ("-y");
  432. diffarg ("--");
  433. diffarg (argv[optind]);
  434. diffarg (argv[optind + 1]);
  435. diffarg (0);
  436. execdiff ();
  437. }
  438. else
  439. {
  440. FILE *left, *right, *out, *diffout;
  441. int interact_ok;
  442. struct line_filter lfilt;
  443. struct line_filter rfilt;
  444. struct line_filter diff_filt;
  445. int leftdir = diraccess (argv[optind]);
  446. int rightdir = diraccess (argv[optind + 1]);
  447. if (leftdir && rightdir)
  448. fatal ("both files to be compared are directories");
  449. left = ck_fopen (expand_name (argv[optind], leftdir, argv[optind + 1]), "r");
  450. ;
  451. right = ck_fopen (expand_name (argv[optind + 1], rightdir, argv[optind]), "r");
  452. out = ck_fopen (out_file, "w");
  453. diffarg ("--sdiff-merge-assist");
  454. diffarg ("--");
  455. diffarg (argv[optind]);
  456. diffarg (argv[optind + 1]);
  457. diffarg (0);
  458. trapsigs ();
  459. #if ! HAVE_FORK
  460. {
  461. size_t cmdsize = 1;
  462. char *p, *command;
  463. int i;
  464. for (i = 0; diffargv[i]; i++)
  465. cmdsize += 4 * strlen (diffargv[i]) + 3;
  466. command = p = xmalloc (cmdsize);
  467. for (i = 0; diffargv[i]; i++)
  468. {
  469. char const *a = diffargv[i];
  470. SYSTEM_QUOTE_ARG (p, a);
  471. *p++ = ' ';
  472. }
  473. p[-1] = '\0';
  474. diffout = popen (command, "r");
  475. if (!diffout)
  476. perror_fatal (command);
  477. free (command);
  478. }
  479. #else /* HAVE_FORK */
  480. {
  481. int diff_fds[2];
  482. if (pipe (diff_fds) != 0)
  483. perror_fatal ("pipe");
  484. diffpid = fork ();
  485. if (diffpid < 0)
  486. perror_fatal ("fork failed");
  487. if (!diffpid)
  488. {
  489. signal (SIGINT, SIG_IGN); /* in case user interrupts editor */
  490. signal (SIGPIPE, SIG_DFL);
  491. close (diff_fds[0]);
  492. if (diff_fds[1] != STDOUT_FILENO)
  493. {
  494. dup2 (diff_fds[1], STDOUT_FILENO);
  495. close (diff_fds[1]);
  496. }
  497. execdiff ();
  498. }
  499. close (diff_fds[1]);
  500. diffout = fdopen (diff_fds[0], "r");
  501. if (!diffout)
  502. perror_fatal ("fdopen");
  503. }
  504. #endif /* HAVE_FORK */
  505. lf_init (&diff_filt, diffout);
  506. lf_init (&lfilt, left);
  507. lf_init (&rfilt, right);
  508. interact_ok = interact (&diff_filt, &lfilt, &rfilt, out);
  509. ck_fclose (left);
  510. ck_fclose (right);
  511. ck_fclose (out);
  512. {
  513. int wstatus;
  514. #if ! HAVE_FORK
  515. wstatus = pclose (diffout);
  516. #else
  517. ck_fclose (diffout);
  518. while (waitpid (diffpid, &wstatus, 0) < 0)
  519. if (errno == EINTR)
  520. checksigs ();
  521. else
  522. perror_fatal ("wait failed");
  523. diffpid = 0;
  524. #endif
  525. if (tmpmade)
  526. {
  527. unlink (tmpname);
  528. tmpmade = 0;
  529. }
  530. if (! interact_ok)
  531. exiterr ();
  532. if (! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 2))
  533. fatal ("Subsidiary diff failed");
  534. untrapsig (0);
  535. checksigs ();
  536. exit (WEXITSTATUS (wstatus));
  537. }
  538. }
  539. return 0; /* Fool -Wall . . . */
  540. }
  541. static void
  542. diffarg (a)
  543. char const *a;
  544. {
  545. static unsigned diffargs, diffargsmax;
  546. if (diffargs == diffargsmax)
  547. {
  548. if (! diffargsmax)
  549. {
  550. diffargv = (char const **) xmalloc (sizeof (char));
  551. diffargsmax = 8;
  552. }
  553. diffargsmax *= 2;
  554. diffargv = (char const **) realloc (diffargv,
  555. diffargsmax * sizeof (char const *));
  556. if (! diffargv)
  557. fatal ("out of memory");
  558. }
  559. diffargv[diffargs++] = a;
  560. }
  561. static void
  562. execdiff ()
  563. {
  564. execvp (diffbin, (char **) diffargv);
  565. write (STDERR_FILENO, diffbin, strlen (diffbin));
  566. write (STDERR_FILENO, ": not found\n", 12);
  567. _exit (2);
  568. }
  569. /* Signal handling */
  570. #define NUM_SIGS (sizeof (sigs) / sizeof (*sigs))
  571. static int const sigs[] = {
  572. #ifdef SIGHUP
  573. SIGHUP,
  574. #endif
  575. #ifdef SIGQUIT
  576. SIGQUIT,
  577. #endif
  578. #ifdef SIGTERM
  579. SIGTERM,
  580. #endif
  581. #ifdef SIGXCPU
  582. SIGXCPU,
  583. #endif
  584. #ifdef SIGXFSZ
  585. SIGXFSZ,
  586. #endif
  587. SIGINT,
  588. SIGPIPE
  589. };
  590. /* Prefer `sigaction' if it is available, since `signal' can lose signals. */
  591. #if HAVE_SIGACTION
  592. static struct sigaction initial_action[NUM_SIGS];
  593. #define initial_handler(i) (initial_action[i].sa_handler)
  594. #else
  595. static RETSIGTYPE (*initial_action[NUM_SIGS]) ();
  596. #define initial_handler(i) (initial_action[i])
  597. #endif
  598. static int volatile ignore_SIGINT;
  599. static int volatile signal_received;
  600. static int sigs_trapped;
  601. static RETSIGTYPE
  602. catchsig (s)
  603. int s;
  604. {
  605. #if ! HAVE_SIGACTION
  606. signal (s, SIG_IGN);
  607. #endif
  608. if (! (s == SIGINT && ignore_SIGINT))
  609. signal_received = s;
  610. }
  611. static void
  612. trapsigs ()
  613. {
  614. int i;
  615. #if HAVE_SIGACTION
  616. struct sigaction catchaction;
  617. bzero (&catchaction, sizeof (catchaction));
  618. catchaction.sa_handler = catchsig;
  619. #ifdef SA_INTERRUPT
  620. /* Non-Posix BSD-style systems like SunOS 4.1.x need this
  621. so that `read' calls are interrupted properly. */
  622. catchaction.sa_flags = SA_INTERRUPT;
  623. #endif
  624. sigemptyset (&catchaction.sa_mask);
  625. for (i = 0; i < NUM_SIGS; i++)
  626. sigaddset (&catchaction.sa_mask, sigs[i]);
  627. for (i = 0; i < NUM_SIGS; i++)
  628. {
  629. sigaction (sigs[i], 0, &initial_action[i]);
  630. if (initial_handler (i) != SIG_IGN
  631. && sigaction (sigs[i], &catchaction, 0) != 0)
  632. fatal ("signal error");
  633. }
  634. #else /* ! HAVE_SIGACTION */
  635. for (i = 0; i < NUM_SIGS; i++)
  636. {
  637. initial_action[i] = signal (sigs[i], SIG_IGN);
  638. if (initial_handler (i) != SIG_IGN
  639. && signal (sigs[i], catchsig) != SIG_IGN)
  640. fatal ("signal error");
  641. }
  642. #endif /* ! HAVE_SIGACTION */
  643. #if !defined(SIGCHLD) && defined(SIGCLD)
  644. #define SIGCHLD SIGCLD
  645. #endif
  646. #ifdef SIGCHLD
  647. /* System V fork+wait does not work if SIGCHLD is ignored. */
  648. signal (SIGCHLD, SIG_DFL);
  649. #endif
  650. sigs_trapped = 1;
  651. }
  652. /* Untrap signal S, or all trapped signals if S is zero. */
  653. static void
  654. untrapsig (s)
  655. int s;
  656. {
  657. int i;
  658. if (sigs_trapped)
  659. for (i = 0; i < NUM_SIGS; i++)
  660. if ((!s || sigs[i] == s) && initial_handler (i) != SIG_IGN)
  661. #if HAVE_SIGACTION
  662. sigaction (sigs[i], &initial_action[i], 0);
  663. #else
  664. signal (sigs[i], initial_action[i]);
  665. #endif
  666. }
  667. /* Exit if a signal has been received. */
  668. static void
  669. checksigs ()
  670. {
  671. int s = signal_received;
  672. if (s)
  673. {
  674. cleanup ();
  675. /* Yield an exit status indicating that a signal was received. */
  676. untrapsig (s);
  677. kill (getpid (), s);
  678. /* That didn't work, so exit with error status. */
  679. exit (2);
  680. }
  681. }
  682. static void
  683. give_help ()
  684. {
  685. fprintf (stderr,"l:\tuse the left version\n");
  686. fprintf (stderr,"r:\tuse the right version\n");
  687. fprintf (stderr,"e l:\tedit then use the left version\n");
  688. fprintf (stderr,"e r:\tedit then use the right version\n");
  689. fprintf (stderr,"e b:\tedit then use the left and right versions concatenated\n");
  690. fprintf (stderr,"e:\tedit a new version\n");
  691. fprintf (stderr,"s:\tsilently include common lines\n");
  692. fprintf (stderr,"v:\tverbosely include common lines\n");
  693. fprintf (stderr,"q:\tquit\n");
  694. }
  695. static int
  696. skip_white ()
  697. {
  698. int c;
  699. for (;;)
  700. {
  701. c = getchar ();
  702. if (!ISSPACE (c) || c == '\n')
  703. break;
  704. checksigs ();
  705. }
  706. if (ferror (stdin))
  707. perror_fatal ("input error");
  708. return c;
  709. }
  710. static void
  711. flush_line ()
  712. {
  713. int c;
  714. while ((c = getchar ()) != '\n' && c != EOF)
  715. ;
  716. if (ferror (stdin))
  717. perror_fatal ("input error");
  718. }
  719. /* interpret an edit command */
  720. static int
  721. edit (left, lenl, right, lenr, outfile)
  722. struct line_filter *left;
  723. int lenl;
  724. struct line_filter *right;
  725. int lenr;
  726. FILE *outfile;
  727. {
  728. for (;;)
  729. {
  730. int cmd0, cmd1;
  731. int gotcmd = 0;
  732. cmd1 = 0; /* Pacify `gcc -W'. */
  733. while (!gotcmd)
  734. {
  735. if (putchar ('%') != '%')
  736. perror_fatal ("output error");
  737. ck_fflush (stdout);
  738. cmd0 = skip_white ();
  739. switch (cmd0)
  740. {
  741. case 'l': case 'r': case 's': case 'v': case 'q':
  742. if (skip_white () != '\n')
  743. {
  744. give_help ();
  745. flush_line ();
  746. continue;
  747. }
  748. gotcmd = 1;
  749. break;
  750. case 'e':
  751. cmd1 = skip_white ();
  752. switch (cmd1)
  753. {
  754. case 'l': case 'r': case 'b':
  755. if (skip_white () != '\n')
  756. {
  757. give_help ();
  758. flush_line ();
  759. continue;
  760. }
  761. gotcmd = 1;
  762. break;
  763. case '\n':
  764. gotcmd = 1;
  765. break;
  766. default:
  767. give_help ();
  768. flush_line ();
  769. continue;
  770. }
  771. break;
  772. case EOF:
  773. if (feof (stdin))
  774. {
  775. gotcmd = 1;
  776. cmd0 = 'q';
  777. break;
  778. }
  779. /* falls through */
  780. default:
  781. flush_line ();
  782. /* falls through */
  783. case '\n':
  784. give_help ();
  785. continue;
  786. }
  787. }
  788. switch (cmd0)
  789. {
  790. case 'l':
  791. lf_copy (left, lenl, outfile);
  792. lf_skip (right, lenr);
  793. return 1;
  794. case 'r':
  795. lf_copy (right, lenr, outfile);
  796. lf_skip (left, lenl);
  797. return 1;
  798. case 's':
  799. suppress_common_flag = 1;
  800. break;
  801. case 'v':
  802. suppress_common_flag = 0;
  803. break;
  804. case 'q':
  805. return 0;
  806. case 'e':
  807. {
  808. int tfd;
  809. FILE *tmp;
  810. if (tmpmade)
  811. {
  812. unlink (tmpname);
  813. tmpmade = 0;
  814. free (tmpname);
  815. }
  816. asprintf (&tmpname, "%s/sdiff.XXXXXX",
  817. getenv("TMPDIR") ?: P_tmpdir);
  818. if (tmpname == NULL)
  819. perror_fatal ("temporary file name");
  820. tfd = mkstemp(tmpname);
  821. if (tfd == -1)
  822. perror_fatal ("temporary file name");
  823. tmp = fdopen (tfd, "w+");
  824. if (tmp == NULL)
  825. perror_fatal ("temporary file name");
  826. tmpmade = 1;
  827. if (cmd1 == 'l' || cmd1 == 'b')
  828. lf_copy (left, lenl, tmp);
  829. else
  830. lf_skip (left, lenl);
  831. if (cmd1 == 'r' || cmd1 == 'b')
  832. lf_copy (right, lenr, tmp);
  833. else
  834. lf_skip (right, lenr);
  835. ck_fflush (tmp);
  836. {
  837. int wstatus;
  838. #if ! HAVE_FORK
  839. char *command = xmalloc (strlen (edbin) + strlen (tmpname) + 2);
  840. sprintf (command, "%s %s", edbin, tmpname);
  841. wstatus = system (command);
  842. free (command);
  843. #else /* HAVE_FORK */
  844. pid_t pid;
  845. ignore_SIGINT = 1;
  846. checksigs ();
  847. pid = fork ();
  848. if (pid == 0)
  849. {
  850. char const *argv[3];
  851. int i = 0;
  852. argv[i++] = edbin;
  853. argv[i++] = tmpname;
  854. argv[i++] = 0;
  855. execvp (edbin, (char **) argv);
  856. write (STDERR_FILENO, edbin, strlen (edbin));
  857. write (STDERR_FILENO, ": not found\n", 12);
  858. _exit (1);
  859. }
  860. if (pid < 0)
  861. perror_fatal ("fork failed");
  862. while (waitpid (pid, &wstatus, 0) < 0)
  863. if (errno == EINTR)
  864. checksigs ();
  865. else
  866. perror_fatal ("wait failed");
  867. ignore_SIGINT = 0;
  868. #endif /* HAVE_FORK */
  869. if (wstatus != 0)
  870. fatal ("Subsidiary editor failed");
  871. }
  872. if (fseek (tmp, 0L, SEEK_SET) != 0)
  873. perror_fatal ("fseek");
  874. {
  875. /* SDIFF_BUFSIZE is too big for a local var
  876. in some compilers, so we allocate it dynamically. */
  877. char *buf = xmalloc (SDIFF_BUFSIZE);
  878. size_t size;
  879. while ((size = ck_fread (buf, SDIFF_BUFSIZE, tmp)) != 0)
  880. {
  881. checksigs ();
  882. ck_fwrite (buf, size, outfile);
  883. }
  884. ck_fclose (tmp);
  885. free (buf);
  886. }
  887. return 1;
  888. }
  889. default:
  890. give_help ();
  891. break;
  892. }
  893. }
  894. }
  895. /* Alternately reveal bursts of diff output and handle user commands. */
  896. static int
  897. interact (diff, left, right, outfile)
  898. struct line_filter *diff;
  899. struct line_filter *left;
  900. struct line_filter *right;
  901. FILE *outfile;
  902. {
  903. for (;;)
  904. {
  905. char diff_help[256];
  906. int snarfed = lf_snarf (diff, diff_help, sizeof (diff_help));
  907. if (snarfed <= 0)
  908. return snarfed;
  909. checksigs ();
  910. switch (diff_help[0])
  911. {
  912. case ' ':
  913. puts (diff_help + 1);
  914. break;
  915. case 'i':
  916. {
  917. int lenl = atoi (diff_help + 1), lenr, lenmax;
  918. char *p = strchr (diff_help, ',');
  919. if (!p)
  920. fatal (diff_help);
  921. lenr = atoi (p + 1);
  922. lenmax = max (lenl, lenr);
  923. if (suppress_common_flag)
  924. lf_skip (diff, lenmax);
  925. else
  926. lf_copy (diff, lenmax, stdout);
  927. lf_copy (left, lenl, outfile);
  928. lf_skip (right, lenr);
  929. break;
  930. }
  931. case 'c':
  932. {
  933. int lenl = atoi (diff_help + 1), lenr;
  934. char *p = strchr (diff_help, ',');
  935. if (!p)
  936. fatal (diff_help);
  937. lenr = atoi (p + 1);
  938. lf_copy (diff, max (lenl, lenr), stdout);
  939. if (! edit (left, lenl, right, lenr, outfile))
  940. return 0;
  941. break;
  942. }
  943. default:
  944. fatal (diff_help);
  945. break;
  946. }
  947. }
  948. }
  949. /* temporary lossage: this is torn from gnu libc */
  950. /* Return nonzero if DIR is an existing directory. */
  951. static int
  952. diraccess (dir)
  953. char const *dir;
  954. {
  955. struct stat buf;
  956. return stat (dir, &buf) == 0 && S_ISDIR (buf.st_mode);
  957. }