home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume39 / makeptch / part01 < prev    next >
Encoding:
Text File  |  1993-09-12  |  22.8 KB  |  823 lines

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