home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume35 / makeptch / part01 < prev    next >
Encoding:
Text File  |  1993-02-21  |  22.7 KB  |  809 lines

  1. Newsgroups: comp.sources.misc
  2. From: jv@mh.nl (Johan Vromans)
  3. Subject: v35i074:  makepatch - Generate patch kits, version 1.6, Part01/01
  4. Message-ID: <1993Feb22.033831.14390@sparky.imd.sterling.com>
  5. X-Md4-Signature: 992e1ccc2d6fdaac6a38e7bc7c4aa9c9
  6. Date: Mon, 22 Feb 1993 03:38:31 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: jv@mh.nl (Johan Vromans)
  10. Posting-number: Volume 35, Issue 74
  11. Archive-name: makepatch/part01
  12. Environment: Perl
  13.  
  14. This is makepatch, a program to generate a patch file from two files
  15. or directories.
  16.  
  17. It resembles "diff -c -r -N", but:
  18.  
  19.   - it is always recursive;
  20.   - it handles 'patchlevel.h' first;
  21.   - it supplies 'Index:' and 'Prereq:' lines;
  22.   - it can use 'manifest' files;
  23.   - it generates shell commands to remove files;
  24.   - it can manipulate manifest files.
  25.  
  26. As distributed, it assumes that perl resides in /usr/local/bin. You
  27. have to change the first line of makepatch.pl if your perl is in a
  28. different location.
  29.  
  30. To install: edit the Makefile (if needed) and type 'make install'.
  31.  
  32. Johan Vromans                       jv@mh.nl via internet backbones
  33. Multihouse Automatisering bv               uucp:..!{uunet,sun4nl}!mh.nl!jv
  34. Doesburgweg 7, 2803 PL Gouda, The Netherlands  phone/fax: +31 1820 62911/62500
  35. ------------------------ "Arms are made for hugging" -------------------------
  36. #! /bin/sh
  37. # This is a shell archive.  Remove anything before this line, then feed it
  38. # into a shell via "sh file" or similar.  To overwrite existing files,
  39. # type "sh file -c".
  40. # Contents:  README MANIFEST Makefile makepatch.man makepatch.pl
  41. # Wrapped by kent@sparky on Sat Feb 20 23:29:49 1993
  42. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  43. echo If this archive is complete, you will see the following message:
  44. echo '          "shar: End of archive 1 (of 1)."'
  45. if test -f 'README' -a "${1}" != "-c" ; then 
  46.   echo shar: Will not clobber existing file \"'README'\"
  47. else
  48.   echo shar: Extracting \"'README'\" \(861 characters\)
  49.   sed "s/^X//" >'README' <<'END_OF_FILE'
  50. XThis is makepatch, a program to generate a patch file from two files
  51. Xor directories.
  52. X
  53. XIt resembles "diff -c -r -N", but:
  54. X
  55. X  - it is always recursive;
  56. X  - it handles 'patchlevel.h' first;
  57. X  - it supplies 'Index:' and 'Prereq:' lines;
  58. X  - it can use 'manifest' files;
  59. X  - it generates shell commands to remove files;
  60. X  - it can manipulate manifest files.
  61. X
  62. XAs distributed, it assumes that perl resides in /usr/local/bin. You
  63. Xhave to change the first line of makepatch.pl if your perl is in a
  64. Xdifferent location.
  65. X
  66. XTo install: edit the Makefile (if needed) and type 'make install'.
  67. X
  68. XJohan Vromans                       jv@mh.nl via internet backbones
  69. XMultihouse Automatisering bv               uucp:..!{uunet,sun4nl}!mh.nl!jv
  70. XDoesburgweg 7, 2803 PL Gouda, The Netherlands  phone/fax: +31 1820 62911/62500
  71. X------------------------ "Arms are made for hugging" -------------------------
  72. END_OF_FILE
  73.   if test 861 -ne `wc -c <'README'`; then
  74.     echo shar: \"'README'\" unpacked with wrong size!
  75.   fi
  76.   # end of 'README'
  77. fi
  78. if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  79.   echo shar: Will not clobber existing file \"'MANIFEST'\"
  80. else
  81.   echo shar: Extracting \"'MANIFEST'\" \(171 characters\)
  82.   sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
  83. XMANIFEST for makepatch 1.6
  84. X
  85. XREADME        Short description
  86. XMANIFEST    List of files
  87. XMakefile    Simple Makefile to install it
  88. Xmakepatch.pl    The program
  89. Xmakepatch.man    The manual page
  90. END_OF_FILE
  91.   if test 171 -ne `wc -c <'MANIFEST'`; then
  92.     echo shar: \"'MANIFEST'\" unpacked with wrong size!
  93.   fi
  94.   # end of 'MANIFEST'
  95. fi
  96. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  97.   echo shar: Will not clobber existing file \"'Makefile'\"
  98. else
  99.   echo shar: Extracting \"'Makefile'\" \(649 characters\)
  100.   sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  101. XVERSION    = 1.6
  102. XBINDIR    = /usr/local/bin
  103. XMANEXT    = 1
  104. XMANDIR    = /usr/local/man/man$(MANEXT)
  105. X
  106. XINSTALL_PROGRAM    = install -c -m 0555
  107. XINSTALL_DATA    = install -c -m 0444
  108. X
  109. Xall:
  110. X    @echo "Edit the Makefile and issue"
  111. X    @echo "'make install' to install makepatch"
  112. X
  113. Xinstall:
  114. X    $(INSTALL_PROGRAM) makepatch.pl $(BINDIR)/makepatch
  115. X    $(INSTALL_DATA) makepatch.man $(MANDIR)/makepatch.$(MANEXT)
  116. X
  117. Xdist:
  118. X    ln -s . makepatch-$(VERSION)
  119. X    makepatch -quiet -filelist -prefix makepatch-$(VERSION)/ MANIFEST |\
  120. X        gtar -zcvf makepatch-$(VERSION).tar.Z -T -
  121. X    rm -f makepatch-$(VERSION)
  122. X
  123. Xshar:
  124. X    makepatch -quiet -filelist -nosort MANIFEST |\
  125. X        shar -f -F -S > makepatch-$(VERSION).shar
  126. END_OF_FILE
  127.   if test 649 -ne `wc -c <'Makefile'`; then
  128.     echo shar: \"'Makefile'\" unpacked with wrong size!
  129.   fi
  130.   # end of 'Makefile'
  131. fi
  132. if test -f 'makepatch.man' -a "${1}" != "-c" ; then 
  133.   echo shar: Will not clobber existing file \"'makepatch.man'\"
  134. else
  135.   echo shar: Extracting \"'makepatch.man'\" \(5543 characters\)
  136.   sed "s/^X//" >'makepatch.man' <<'END_OF_FILE'
  137. X.TH MAKEPATCH 1 "93/02/13" "Version 1.6"
  138. X.SH NAME
  139. Xmakepatch \- create patch diffs between two versions of source
  140. X.SH SYNOPSIS
  141. X.B makepatch
  142. X.RI [ options ]
  143. X.I old new
  144. X.PP
  145. X.B makepatch
  146. X\-filelist
  147. X.RI [ options ] 
  148. X.I manifest
  149. X.SH DESCRIPTION
  150. X.I Makepatch
  151. Xgenerates a set of differences between two files or two sets of files
  152. Xmaintained in two different directories and prints the results to
  153. X\fIstdout\fP.
  154. XThis resulting output is suitable for use by the 
  155. X.IR patch (1)
  156. Xprogram to update copies of the target file(s) from the \fIold\fP
  157. Xto the \fInew\fP version.
  158. X.LP
  159. XFeatures of this utility include:
  160. X.in +2n
  161. X.na
  162. X.ti -2n
  163. X\- Recursive descend through sub-directories.
  164. X.ti -2n
  165. X\- Generation of commands to remove obsolete files.
  166. X.ti -2n
  167. X\- Automatic handling of the \fIpatchlevel.h\fP file first.
  168. X.ti -2n
  169. X\- Automatic inclusion of \fIIndex:\fP and \fIPrereq:\fP lines.
  170. X.ti -2n
  171. X\- Ability to utilize specified \fImanifest\fP file(s).
  172. X.ad
  173. X.in -2n
  174. X.SH ARGUMENTS
  175. X.TP 6
  176. X.I old
  177. XThis is the name of either a single file or else a directory which
  178. Xcontains copies of the older version of the target file(s); in
  179. Xother words, copies of the file(s) \fIprior\fP to any modifications.
  180. X.TP 
  181. X.I new
  182. XThis is the name of either a single file or else a directory which
  183. Xcontains copies of the newer version of the target file(s); in
  184. Xother words, copies of the file(s) \fIafter\fP the modifications have
  185. Xbeen made.
  186. XA 
  187. X.IR rm (1)
  188. Xcommand will automatically be generated for every
  189. X\fIold\fP file that no longer has a corresponding \fInew\fP version.
  190. X.SH "MAKEPATCH OPTIONS"
  191. X.TP 6
  192. X\fB\-diff\fP \fIcmd\fP
  193. XIf specified, \fIcmd\fP is the command to be used to generate the
  194. Xdifferences between the two versions of the files.
  195. XIf not specified, this command defaults to "\fBdiff \-c\fP".
  196. X.TP 6
  197. X\fB\-patchlevel\fP \fIpfile\fP
  198. XIf specified, \fIpfile\fP indicates an alternate file that is to be
  199. Xused in lieu of "\fBpatchlevel.h\fP".
  200. X.TP 6
  201. X\fB\-man\fP[\fBifest\fP] \fImfile\fP
  202. XIf specified, \fImfile\fP indicates the name of the manifest file
  203. Xwhich consists of a list of the files contained in both the \fIold\fP
  204. Xand the \fInew\fP directories.
  205. X.TP 6
  206. X\fB\-oldman\fP[\fBifest\fP] \fIomfile\fP
  207. XIf specified, \fIomfile\fP indicates the name of the manifest file
  208. Xwhich consists of a list of the files contained in the \fIold\fP
  209. Xdirectory.
  210. XThis option is designed to be used in conjunction with the
  211. X\%\fB-newmanifest\fP option.
  212. XNote that the \fIold\fP and \fInew\fP directories must still be
  213. Xindicated.
  214. X.TP 6
  215. X\fB\-newman\fP[\fBifest\fP] \fInmfile\fP
  216. XIf specified, \fInmfile\fP indicates the name of the manifest file
  217. Xwhich consists of a list of the files contained in the \fInew\fP
  218. Xdirectory.
  219. XThis option is designed to be used in conjunction with the
  220. X\%\fB-oldmanifest\fP option.
  221. XNote that the \fIold\fP and \fInew\fP directories must still be
  222. Xindicated.
  223. X.SH "FILELIST OPTIONS"
  224. X.TP 6
  225. X.BR \-file [ list ]
  226. XThis option instructs 
  227. X.I makepatch
  228. Xto read a manifest file, and output the list of files included in
  229. Xthis manifest. This option is useful to turn the contents of a
  230. Xmanifest file into a list of files suitable for other programs.
  231. X.TP 6
  232. X\fB\-man\fP[\fBifest\fP] \fImfile\fP
  233. XIf specified, \fImfile\fP indicates the name of the manifest file to
  234. Xbe used. Alternatively, the name of the manifest file may follow the
  235. Xcommand line options.
  236. X.TP 6
  237. X.B \-prefix 
  238. X.I string
  239. XEvery entry in the manifest file is prefixed with
  240. X.I string
  241. Xbefore it is written to 
  242. X.IR stdout .
  243. X.TP 6
  244. X.B \-nosort
  245. XRetain the order of filenames from the manifest file.
  246. X.SH "GENERAL OPTIONS"
  247. X.TP 6
  248. X.B \-verbose
  249. XThis is the default mode which displays information
  250. Xconcerning \fBmakepatch\fP's activity to \fIstderr\fP.
  251. X.TP 6
  252. X.B \-quiet
  253. XThe opposite of \fB-verbose\fP.
  254. XThis instructs \fImakepatch\fP to suppress the display of
  255. Xactivity information.
  256. X.TP 6
  257. X.B \-help
  258. XThis causes a short help message to be displayed, after which the
  259. Xprogram immediately exits.
  260. X.SH "MANIFEST FILES"
  261. XAlthough there is no formal standard for manifest files, the following
  262. Xrules apply:
  263. X.TP 2n
  264. X\-
  265. XIf the second line from the manifest file looks like a separator
  266. Xline (e.g. it is empty, or contains only dashes), it is discarded and
  267. Xso is the first line. 
  268. X.TP 2n
  269. X\-
  270. XEmpty lines and lines that start with a 
  271. X.B #
  272. Xare ignored.
  273. X.TP 2n
  274. X\-
  275. XIf there are multiple space-separated ``words'' on a line, the
  276. Xfirst word is considered to be the filename.
  277. X.SH EXAMPLES
  278. XSuppose you have a directory tree 
  279. X.B emacs\-18.58
  280. Xcontaining the sources for GNU Emacs 18.58, and a directory tree
  281. X.B emacs\-18.59
  282. Xcontaining the sources for GNU Emacs 18.59. The following command will
  283. Xgenerate the patch file needed to transform the 18.58 sources into
  284. X18.59: 
  285. X
  286. X.in +6n
  287. X.na
  288. Xmakepatch emacs-18.58 emacs-18.59 > emacs-18.58-18.59.diff
  289. X.in
  290. X.ad
  291. X
  292. XThis is one way to generate and use manifest files:
  293. X
  294. X.in +6n
  295. X.na
  296. X(cd emacs-18.58; find . -type f -print > MANIFEST)
  297. X.br
  298. X(cd emacs-18.59; find . -type f -print > MANIFEST)
  299. X.br
  300. Xmakepatch \e
  301. X.in +4n
  302. X-oldmanifest emacs-18.58/MANIFEST \e
  303. X.br
  304. X-newmanifest emacs-18.59/MANIFEST \e
  305. X.br
  306. Xemacs-18.58 emacs-18.59 > emacs-18.58-18.59.diff
  307. X.in -10n
  308. X.ad
  309. X
  310. XThe following example transforms the manifest file into a list of
  311. Xfiles suitable for GNU tar. Note the trailing
  312. X.B /
  313. Xin the prefix string:
  314. X
  315. X.na
  316. X.in +6n
  317. Xmakepatch -filelist -prefix emacs-18.59/ emacs-18.59/MANIFEST |
  318. X.in +4n
  319. Xgtar -zcvf emacs-18.59.tar.Z -T -
  320. X.in -10n
  321. X.ad
  322. X
  323. X.SH "SEE ALSO"
  324. X.IR diff (1),
  325. X.IR patch (1),
  326. X.IR  perl (1),
  327. X.IR rm (1).
  328. X.SH AUTHORS
  329. XJohan Vromans (jv@mh.nl).
  330. X.br
  331. XJeffery Small (jeff@cjsa.uucp) donated the base version of this manual
  332. Xpage that inspired me to complete it.
  333. END_OF_FILE
  334.   if test 5543 -ne `wc -c <'makepatch.man'`; then
  335.     echo shar: \"'makepatch.man'\" unpacked with wrong size!
  336.   fi
  337.   # end of 'makepatch.man'
  338. fi
  339. if test -f 'makepatch.pl' -a "${1}" != "-c" ; then 
  340.   echo shar: Will not clobber existing file \"'makepatch.pl'\"
  341. else
  342.   echo shar: Extracting \"'makepatch.pl'\" \(11375 characters\)
  343.   sed "s/^X//" >'makepatch.pl' <<'END_OF_FILE'
  344. X#!/usr/local/bin/perl
  345. X# makepatch.pl -- generate batch of patches.
  346. X# SCCS Status     : @(#)@ makepatch.pl    1.6
  347. X# Author          : Johan Vromans
  348. X# Created On      : Tue Jul  7 20:39:39 1992
  349. X# Last Modified By: Johan Vromans
  350. X# Last Modified On: Sat Feb 13 17:23:06 1993
  351. X# Update Count    : 125
  352. X# Status          : Released to USEnet.
  353. X#
  354. X# Generate a patch from two files or directories.
  355. X#
  356. X# Resembles "diff -c -r -N", but:
  357. X#
  358. X#   - always recursive
  359. X#   - handles 'patchlevel.h' first
  360. X#   - supplies 'Index:' and 'Prereq:' lines
  361. X#   - can use manifest file
  362. X#   - generates shell commands to remove files
  363. X#   - manipulates manifest files
  364. X#
  365. X################################################################
  366. X#
  367. X# Usage:
  368. X# 
  369. X#   makepatch <old-dir> <new-dir
  370. X# 
  371. X#     This will compare all files in <new-dir> against the files in
  372. X#     <old-dir>, and generate a bunch of patches to transform every
  373. X#     file in <old-dir> into the corresponding one in <new-dir>.
  374. X#     Files that appear in <new-dir> but not in <old-dir> are created.
  375. X#     For files that appear in <old-dir> but not in <new-dir>
  376. X#     'rm'-commands are generated at the beginning of the patch.
  377. X# 
  378. X# Using MANIFEST files:
  379. X# 
  380. X#   makepatch -oldmanifest <oldmanifest> -newmanifest <newmanifest> \
  381. X#           <new-dir> <old-dir>
  382. X# 
  383. X#     <oldmanifest> and <newmanifest> list the files in <old-dir>
  384. X#     and <new-dir> that are to be examined.
  385. X#     Only the files that are named will be examined. 
  386. X#     <oldmanifest> should contain the names of the files relative to
  387. X#     <old-dir> and <newmanifest> should contain the names of the files
  388. X#     relative to <new-dir>.
  389. X# 
  390. X#   makepatch -manifest <manifest> <new-dir> <old-dir>
  391. X# 
  392. X#     This is a simplified form of the above example.
  393. X#     <manifest> applies to both <old-dir> and <new-dir>.
  394. X# 
  395. X#   makepatch -filelist [ -prefix xxx ] manifest
  396. X#
  397. X#     The filenames are extracted from the manifest file,
  398. X#     optionally prefixed, sorted and written to standard output.
  399. X#
  400. X# Examples:
  401. X# 
  402. X#   % makepatch -verbose emacs-18.58 emacs-18.59 > emacs-18.58-18.59.diff
  403. X# 
  404. X#   % (cd emacs-18.58; find . -type f -print > MANIFEST)
  405. X#   % (cd emacs-18.59; find . -type f -print > MANIFEST)
  406. X#   % makepatch -verbose \
  407. X#         -oldmanifest emacs-18.58/MANIFEST \
  408. X#         -newmanifest emacs-18.59/MANIFEST \
  409. X#         emacs-18.58 emacs-18.59 > emacs-18.58-18.59.diff
  410. X#
  411. X#   % makepatch -filelist -prefix emacs-18.59/ emacs-18.59/MANIFEST |
  412. X#    gtar -zcvf emacs-18.59.tar.Z -T -
  413. X#
  414. X################################################################
  415. X
  416. X&stdio;
  417. X&options;
  418. X($old, $new) = @ARGV;
  419. X
  420. Xprint STDERR ("This is makepatch.pl version 1.6\n") if $opt_verbose;
  421. X
  422. Xif ( defined $opt_filelist ) {
  423. X    @new = &domanifest (shift (@ARGV));
  424. X    foreach ( @new ) {
  425. X    print STDOUT ($opt_prefix, $_, "\n");
  426. X    }
  427. X    exit (0);
  428. X}
  429. X
  430. X$tmpfile = $ENV{"TMPDIR"} || "/usr/tmp";
  431. X$thepatch = "$tmpfile/mp$$.p";
  432. X$tmpfile .= "/mp$$.t";
  433. Xopen (PATCH, ">$thepatch") || die ("$thepatch: $!\n");
  434. X$patched = $created = 0;
  435. X&doit ($old, $new);
  436. X&wrapup;
  437. Xexit (0);
  438. X
  439. X################ Subroutines ################
  440. X
  441. Xsub doit {
  442. X    local ($old, $new) = @_;
  443. X
  444. X    if ( -f $old && -f $new ) {
  445. X    # Two files.
  446. X    if ( $opt_verbose ) {
  447. X        print STDERR ("Old file = $old.\n",
  448. X              "New file = $new.\n");
  449. X    }
  450. X    &dodiff ("", $old, "", $new);
  451. X    }
  452. X    elsif ( -f $old && -d $new ) {
  453. X    # File and dir -> File and dir/File.
  454. X    $new = ( $new =~ m|^\./?$| ) ? "" : "$new/";
  455. X    if ( $opt_verbose ) {
  456. X        print STDERR ("Old file = $old.\n",
  457. X              "New file = $new$old.\n");
  458. X    }
  459. X    &dodiff ("", $old, $new, $old);
  460. X    }
  461. X    elsif ( -f $new && -d $old ) {
  462. X    $old = ( $old =~ m|^\./?$| ) ? "" : "$old/";
  463. X    if ( $opt_verbose ) {
  464. X        print STDERR ("Old file = $old$new.\n",
  465. X              "New file = $new.\n");
  466. X    }
  467. X    &dodiff ($old, $new, "", $new);
  468. X    }
  469. X    else {
  470. X    # Should be two directories.
  471. X    local (@old, @new);
  472. X    if ( defined $opt_oldmanifest ) {
  473. X        @old = &domanifest ($opt_oldmanifest);
  474. X    }
  475. X    else {
  476. X        @old = &make_filelist ($old);
  477. X    }
  478. X    if ( defined $opt_newmanifest ) {
  479. X        @new = &domanifest ($opt_newmanifest);
  480. X    }
  481. X    else {
  482. X        @new = &make_filelist ($new);
  483. X    }
  484. X
  485. X    $new = ( $new =~ m|^\./?$| ) ? "" : "$new/";
  486. X    $old = ( $old =~ m|^\./?$| ) ? "" : "$old/";
  487. X
  488. X    if ( $opt_verbose ) {
  489. X        local ($old) = $old; chop ($old);
  490. X        local ($new) = $new; chop ($new);
  491. X        print STDERR ("Old dir = $old, file list = ",
  492. X              defined $opt_oldmanifest ? $opt_oldmanifest : "<*>",
  493. X              ", ", 0+@old, " files.\n");
  494. X        print STDERR ("New dir = $new, file list = ",
  495. X              defined $opt_newmanifest ? $opt_newmanifest : "<*>",
  496. X              ", ", 0+@new, " files.\n");
  497. X    }
  498. X    if ( $opt_debug ) {
  499. X        print STDERR ("Old: @old\nNew: @new\n");
  500. X    }
  501. X
  502. X    # Handle patchlevel file first.
  503. X    $opt_patchlevel = (grep (/patchlevel\.h/, @new))[0]
  504. X        unless defined $opt_patchlevel;
  505. X
  506. X    if ( defined $opt_patchlevel && $opt_patchlevel ne "" ) {
  507. X        if ( ! -f "$new$opt_patchlevel" ) {
  508. X        die ("$new$opt_patchlevel: $!\n");
  509. X        }
  510. X        if ( -f "$old$opt_patchlevel" ) {
  511. X        &dodiff ($old, $opt_patchlevel, $new, $opt_patchlevel);
  512. X        }
  513. X        else {
  514. X        $created++;
  515. X        &dodiff ("", "/dev/null", $new, $opt_patchlevel);
  516. X        }
  517. X    }
  518. X    else {
  519. X        undef $opt_patchlevel;
  520. X    }
  521. X
  522. X    # Process the filelists.
  523. X    while ( @old + @new ) {
  524. X
  525. X        $o = shift (@old) unless defined $o;
  526. X        $n = shift (@new) unless defined $n;
  527. X        
  528. X        if ( !defined $o || $o gt $n ) {
  529. X        # New file.
  530. X        if ( defined $opt_patchlevel && $n eq $opt_patchlevel ) {
  531. X            undef $opt_patchlevel;
  532. X        }
  533. X        else {
  534. X            $created++;
  535. X            &dodiff ("", "/dev/null", $new, $n);
  536. X        }
  537. X        undef $n;
  538. X        }
  539. X        elsif ( !defined $n || $o lt $n ) {
  540. X        # Obsolete (removed) file.
  541. X        push (@goners, $o);
  542. X        undef $o;
  543. X        }
  544. X        elsif ( $o eq $n ) {
  545. X        # Same file.
  546. X        if ( defined $opt_patchlevel && $n eq $opt_patchlevel ) {
  547. X            undef $opt_patchlevel;
  548. X        }
  549. X        else {
  550. X            &dodiff ($old, $o, $new, $n);
  551. X        }
  552. X        undef $n;
  553. X        undef $o;
  554. X        }
  555. X    }
  556. X    }
  557. X}
  558. X
  559. Xsub make_filelist {
  560. X    local ($dir, $disp) = @_;
  561. X
  562. X    # Return a list of files, sorted, for this directory.
  563. X    # Recurses.
  564. X
  565. X    local (@ret);
  566. X    local (*DIR);
  567. X    local (@tmp);
  568. X    local ($fname);
  569. X
  570. X    $disp = "" unless defined $disp;
  571. X
  572. X    print STDERR ("+ recurse $dir\n") if $opt_trace;
  573. X    opendir (DIR, $dir) || die ("$dir: $!\n");
  574. X    @tmp = sort (readdir (DIR));
  575. X    closedir (DIR);
  576. X    print STDERR ("Dir $dir: ", 0+@tmp, " entries\n") if $opt_debug;
  577. X
  578. X    @ret = ();
  579. X    foreach $file ( @tmp ) {
  580. X
  581. X    # Skip unwanted files.
  582. X    next if $file =~ /^\.\.?$/; # dot and dotdot
  583. X    next if $file =~ /~$/;    # editor backup files
  584. X
  585. X    # Push on the list.
  586. X    $fname = "$dir/$file";
  587. X    if ( -d $fname ) {
  588. X        # Recurse.
  589. X        push (@ret, &make_filelist ($fname, "$disp$file/"));
  590. X    }
  591. X    elsif ( -f _ ) {
  592. X        push (@ret, $disp . $file);
  593. X    }
  594. X    else {
  595. X        print STDERR ("Ignored $fname: not a file\n");
  596. X    }
  597. X    }
  598. X    @ret;
  599. X}
  600. X
  601. Xsub domanifest {
  602. X    local ($man) = @_;
  603. X    local (*MAN);
  604. X    local (@ret) = ();
  605. X
  606. X    open (MAN, $man) || die ("$man: $!\n");
  607. X    while ( <MAN> ) {
  608. X    if ( $. == 2 && /^[-=_\s]*$/ ) {
  609. X        @ret = ();
  610. X        next;
  611. X    }
  612. X    next if /^#/;
  613. X    next unless /\S/;
  614. X    $_ = $` if /\s/;
  615. X    push (@ret, $_);
  616. X    }
  617. X    close (MAN);
  618. X    @ret = sort @ret unless defined $opt_nosort;
  619. X    @ret;
  620. X}
  621. X
  622. Xsub dodiff {
  623. X    local ($olddir, $old, $newdir, $new) = @_;
  624. X
  625. X    # Produce a patch hunk.
  626. X
  627. X    local ($cmd) = "$opt_diff '$olddir$old' '$newdir$new'";
  628. X    print STDERR ("+ ", $cmd, "\n") if $opt_trace;
  629. X    $result = system ("$cmd > $tmpfile");
  630. X    printf STDERR ("+> result = 0x%x\n", $result) 
  631. X    if $result && $opt_debug;
  632. X
  633. X    return unless $result == 0x100;    # no diffs
  634. X    $patched++;
  635. X
  636. X    # print PATCH ($cmd, "\n");
  637. X    print PATCH ("Index: ", $new, "\n");
  638. X
  639. X    # Try to find a prereq.
  640. X    open (OLD, $olddir . $old);
  641. X    while ( <OLD> ) {
  642. X    next unless /\@\(\#\)/;             # SCCS header
  643. X    next unless $' =~ /\b\d+(\.\d+)*\b/; # e.g. 5.4
  644. X    print PATCH ("Prereq: $&\n");
  645. X    last;
  646. X    }
  647. X    close (OLD);
  648. X
  649. X    # Copy patch.
  650. X    open (TMP, $tmpfile);
  651. X    print PATCH <TMP>;
  652. X    close (TMP);
  653. X}
  654. X
  655. Xsub wrapup {
  656. X    if ( $opt_verbose ) {
  657. X    local ($goners) = scalar (@goners);
  658. X    print STDERR ("Collecting: $patched patch",
  659. X              $patched == 1 ? "" : "es");
  660. X    print STDERR (" ($created new file", 
  661. X              $created == 1 ? "" : "s", ")") if $created;
  662. X    print STDERR (", $goners goner", 
  663. X              $goners == 1 ? "" : "s") if $goners;
  664. X    print STDERR (".\n");
  665. X    }
  666. X    if ( @goners ) {
  667. X    print STDOUT 
  668. X        ("# Please remove the following file",
  669. X         @goners == 1 ? "" : "s", " before applying this patch.\n",
  670. X         "# (You can feed this patch to 'sh' to do so.)\n",
  671. X         "\n");
  672. X    foreach ( @goners ) {
  673. X        print STDOUT ("rm -f ", $_, "\n");
  674. X    }
  675. X    print STDOUT ("exit\n\n");
  676. X    }
  677. X
  678. X    # Copy patch.
  679. X    open (PATCH, $thepatch);
  680. X    print while <PATCH>;
  681. X    close (PATCH);
  682. X
  683. X    # Cleanup.
  684. X    unlink ($tmpfile, $thepatch);
  685. X}
  686. X
  687. Xsub stdio {
  688. X    # Since output to STDERR seems to be character based (and slow),
  689. X    # we connect STDERR to STDOUT if they both point to the terminal.
  690. X    if ( -t STDOUT && -t STDERR ) {
  691. X    close (STDERR);
  692. X    open (STDERR, '>&STDOUT');
  693. X    select (STDERR); $| = 1;
  694. X    select (STDOUT);
  695. X    }
  696. X}
  697. X
  698. Xsub options {
  699. X    local ($opt_manifest);
  700. X    local ($opt_quiet);
  701. X
  702. X    # Defaults...
  703. X    $opt_diff = "diff -c";
  704. X    $opt_verbose = 1;
  705. X
  706. X    # Process options, if any...
  707. X    if ( $ARGV[0] =~ /^-/ ) {
  708. X    require "newgetopt.pl";
  709. X
  710. X    # Aliases.
  711. X    *opt_man = *opt_manifest;
  712. X    *opt_oldman = *opt_oldmanifest;
  713. X    *opt_newman = *opt_newmanifest;
  714. X    *opt_v = *opt_verbose;
  715. X    *opt_list = *opt_filelist;
  716. X
  717. X    if ( ! &NGetOpt ("patchlevel=s", "diff=s", 
  718. X             "manifest=s", "newmanifest=s", "oldmanifest=s",
  719. X             "man=s", "newman=s", "oldman=s",
  720. X             "list", "filelist", "prefix=s", "nosort",
  721. X             "quiet", "verbose", "v", "help", "debug", "trace")
  722. X        || defined $opt_help ) {
  723. X        &usage;
  724. X    }
  725. X    $opt_trace = 1 if defined $opt_debug;
  726. X    $opt_verbose = 0 if defined $opt_quiet;
  727. X    if ( defined $opt_prefix ) {
  728. X        die ("$0: option \"-prefix\" requires \"-filelist\"\n")
  729. X        unless defined $opt_filelist;
  730. X    }
  731. X    if ( defined $opt_nosort ) {
  732. X        die ("$0: option \"-nosort\" requires \"-filelist\"\n")
  733. X        unless defined $opt_filelist;
  734. X    }
  735. X    if ( defined $opt_filelist ) {
  736. X        die ("$0: option \"-filelist\" only uses \"-manifest\"\n")
  737. X        if defined $opt_oldmanifest || defined $opt_newmanifest;
  738. X    }
  739. X    if ( defined $opt_manifest ) {
  740. X        die ("$0: do not use \"-manifest\" with \"-oldmanifest\"".
  741. X         " or \"-newmanifest\"\n")
  742. X        if defined $opt_newmanifest || defined $opt_oldmanifest;
  743. X        $opt_newmanifest = $opt_oldmanifest = $opt_manifest;
  744. X    }
  745. X    }
  746. X
  747. X    # Argument check.
  748. X    if ( defined $opt_filelist ) {
  749. X    if ( defined $opt_manifest ) {
  750. X        &usage if @ARGV;
  751. X        @ARGV = ( $opt_manifest );
  752. X    }
  753. X    else {
  754. X        &usage unless @ARGV == 1;
  755. X    }
  756. X    }
  757. X    else {
  758. X    &usage unless @ARGV == 2;
  759. X    }
  760. X}
  761. X
  762. Xsub usage {
  763. X    print STDERR <<EoU;
  764. XThis is makepatch.pl version 1.6
  765. X
  766. XUsage: $0 [options] old new
  767. XUsage: $0 -filelist [ -prefix XXX ] [ -nosort ] [ -manifest ] file
  768. X
  769. XMakepatch options:
  770. X   -diff cmd        diff command to use, default \"$opt_diff\"
  771. X   -patchlevel file    file to use as patchlevel.h
  772. X   -man[ifest] file    list of files for old and new dir
  773. X   -newman[ifest] file    list of files for new dir
  774. X   -oldman[ifest] file    list of files for old dir
  775. XFilelist options:
  776. X   -[file]list        extract filenames from manifest file
  777. X   -prefix XXX        add a prefix to these filenames
  778. X   -nosort        do not sort manifest entries
  779. XGeneral options:
  780. X   -verbose        verbose output (default)
  781. X   -quiet        no verbose output
  782. X   -help        this message
  783. XEoU
  784. X    exit (1);
  785. X}
  786. END_OF_FILE
  787.   if test 11375 -ne `wc -c <'makepatch.pl'`; then
  788.     echo shar: \"'makepatch.pl'\" unpacked with wrong size!
  789.   fi
  790.   # end of 'makepatch.pl'
  791. fi
  792. echo shar: End of archive 1 \(of 1\).
  793. cp /dev/null ark1isdone
  794. MISSING=""
  795. for I in 1 ; do
  796.     if test ! -f ark${I}isdone ; then
  797.     MISSING="${MISSING} ${I}"
  798.     fi
  799. done
  800. if test "${MISSING}" = "" ; then
  801.     echo You have the archive.
  802.     rm -f ark[1-9]isdone
  803. else
  804.     echo You still must unpack the following archives:
  805.     echo "        " ${MISSING}
  806. fi
  807. exit 0
  808. exit 0 # Just in case...
  809.