Fixed line number handling for escaped end of lines inside strings.
[wine] / tools / genpatch
1 #!/usr/bin/perl
2 #
3 # genpatch - A utility that generates patches for submission to
4 # wine-patches@winehq.org
5 #
6 # Copyright Steven Elliott <elliotsl@mindspring.com>
7 #
8 # This library is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Lesser General Public
10 # License as published by the Free Software Foundation; either
11 # version 2.1 of the License, or (at your option) any later version.
12 #
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 # Lesser General Public License for more details.
17 #
18 # You should have received a copy of the GNU Lesser General Public
19 # License along with this library; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21 #
22
23 =head1 NAME
24
25 genpatch - A utility that generates patches for submission to
26 wine-patches@winehq.org
27
28 =head1 SYNOPSIS
29
30 genpatch [B<-v>] [B<-n> patch_name] [B<-f> patch_file]
31          [B<-c> change_log] [B<-m> modified_files]
32          [B<-a> added_files]
33
34 =head1 DESCRIPTION
35
36 The genpatch utility generated patches for submission to
37 wine-patches@winehq by acting as a wrapper to "cvs diff".  The "B<-v>"
38 switch specifies that verbose output should be generated.  The "B<-n>"
39 switch overrides the patch name ("Name" field) which defaults to a
40 numeric UTC date.  The "B<-f>" switch overrides the filename of the patch
41 which defaults to "patches/<patch_name>.diff".  The "B<-c>" switch
42 specifies the CVS change log entry ("ChangeLog" field) which can be
43 seen when "cvs log" is invoked.  The "B<-m>" ("ModifiedFiles" field) and
44 "B<-a>" ("AddedFiles" field) switches override the set of files that
45 would normally be included by the "cvs diff".  Normally "cvs diff"
46 includes all files modified relative to the deltas indicated by the
47 "CVS/Entries" file and ignores all newly added files.  The "B<-m>" switch
48 specifies a whitespace separated list of files that were modified.
49 The "B<-a>" switch specifies a whitespace separated list of files that
50 were added.
51
52 =head1 EXAMPLE
53
54 genpatch B<-n> NLSFix B<-c> "various fixes for NLS support" \
55     B<-m> ole/ole2nls.c B<-a> ole/ole3nls.c
56
57 The above generates a patch named "NLSFix" in "patches/NLSFix.diff"
58 that includes a modification to "ole/ole2nls.c" and a newly added
59 "ole/ole3nls.c".
60
61 =cut
62
63 use strict;
64
65 use Getopt::Std;
66 use File::Basename;
67 use POSIX qw(strftime);
68
69 my $gen_date;       # date the patch was generated
70 my %options;        # command line options
71 my @modified_files; # optional list of files that were modified
72 my @added_files;    # added files as an array
73 my $added_file;     # added file being considered
74 my $cvs_line;       # line of output from CVS
75 my $mod_files_str;  # string that describes the modified files
76
77 # Default the patch name to the UTC time.  Use a more descriptive date for the
78 # patch generation date.
79 $options{n} = strftime "%Y%m%d%H%M", gmtime;
80 $gen_date = strftime "%Y/%m/%d %H:%M:%S UTC", gmtime;
81
82 unless(getopts("vn:f:c:m:a:p:", \%options))
83 {
84     print STDERR "Usage: $0 [-v] [-n patch_name] [-f patch_file] " .
85         "[-c change_log] [-m modified_files] [-a added_files] [-p path_to_patches]\n";
86     exit 1;
87 }
88
89 $options{p} = "patches" unless(exists $options{p});
90 $options{f} = "$options{p}/$options{n}.diff" unless(exists $options{f});
91 $options{p} = dirname $options{f};
92 @added_files = split ' ', $options{a};
93 @modified_files = split ' ', $options{m};
94 $options{c} =~ s/\\n/\n\t/g;
95
96 if(-d $options{p})
97 {
98     if(-e $options{f})
99     {
100         print STDERR "$options{f} already exists.  Aborting.\n";
101         exit 1;
102     }
103 }
104 else
105 {
106     mkdir $options{p}, (0777 & ~umask) or
107         die "Unable to mkdir $options{p}: $!";
108 }
109
110 $mod_files_str = exists($options{m}) ? $options{m} : "<see cvs diff>";
111 print "Generating $options{f}.\n" if($options{v});
112 open OPT_F, ">$options{f}" or die "Unable to open $options{f} for write: $!";
113 print OPT_F <<EOF;
114 Name: $options{n}
115 ChangeLog: $options{c}
116 GenDate: $gen_date
117 ModifiedFiles: $mod_files_str
118 AddedFiles: $options{a}
119 EOF
120
121 print "Invoking cvs diff.\n" if($options{v});
122 open CVS_IN, "cvs diff -u @modified_files|" or die "Unable to invoke cvs: $!";
123 while($cvs_line = <CVS_IN>)
124 {
125     chomp $cvs_line;
126     if($cvs_line =~ /^\? (.*)/)
127     {
128         push @added_files, $1 unless(exists $options{a});
129     }
130     else
131     {
132         print OPT_F <CVS_IN>;
133     }
134 }
135 close CVS_IN;
136
137 foreach $added_file (@added_files)
138 {
139     print "Adding $added_file as a new file.\n" if($options{v});
140     open DIFF_IN, "diff -u /dev/null $added_file|" or die "Unable to " .
141         "invoke diff: $!";
142     print OPT_F <DIFF_IN>;
143     close DIFF_IN;
144 }
145
146 close OPT_F;