├── .gitignore ├── quickfix-ruby ├── .gitignore ├── ext │ └── quickfix │ │ └── extconf.rb └── quickfix.gemspec ├── quickfix-python ├── .gitignore ├── MANIFEST.in ├── test_std_shared_ptr.cpp ├── test_std_tr1_shared_ptr.cpp └── setup.py ├── setup-macports.sh ├── setup-ubuntu.sh ├── package.sh ├── package.bat ├── package-python.sh ├── package-ruby.sh └── git2cl /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.gz 3 | *.zip 4 | /quickfix -------------------------------------------------------------------------------- /quickfix-ruby/.gitignore: -------------------------------------------------------------------------------- 1 | *.h 2 | *.hpp 3 | *.cpp 4 | *.gem 5 | lib 6 | test 7 | LICENSE -------------------------------------------------------------------------------- /quickfix-python/.gitignore: -------------------------------------------------------------------------------- 1 | C++ 2 | spec 3 | dist 4 | LICENSE 5 | MANIFEST 6 | quickfix*.py 7 | test_* -------------------------------------------------------------------------------- /quickfix-python/MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include C++ *.h *.hpp *.cc 2 | include test*.cpp 3 | include LICENSE 4 | include spec/*.xml -------------------------------------------------------------------------------- /setup-macports.sh: -------------------------------------------------------------------------------- 1 | port install doxygen 2 | port install graphviz 3 | port install autoconf 4 | port install libtool 5 | 6 | -------------------------------------------------------------------------------- /quickfix-python/test_std_shared_ptr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char** argv) 4 | { 5 | std::shared_ptr o; 6 | } 7 | -------------------------------------------------------------------------------- /quickfix-python/test_std_tr1_shared_ptr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char** argv) 4 | { 5 | std::tr1::shared_ptr o; 6 | } 7 | -------------------------------------------------------------------------------- /setup-ubuntu.sh: -------------------------------------------------------------------------------- 1 | apt-get install git 2 | apt-get install doxygen 3 | apt-get install graphviz 4 | apt-get install autoconf 5 | apt-get install libtool 6 | apt-get install g++ 7 | apt-get install ruby 8 | apt-get install ruby-dev 9 | apt-get install python 10 | apt-get install python-dev 11 | -------------------------------------------------------------------------------- /quickfix-ruby/ext/quickfix/extconf.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf' 2 | dir_config("quickfix", ["."], ".") 3 | CONFIG["CC"] = ENV['CXX'] 4 | CONFIG["CXXFLAGS"] = '-std=c++0x' 5 | CONFIG["LIBS"] += ENV['LIBS'] if ENV['LIBS'] != nil 6 | 7 | if( ENV['CXX'] != nil ) 8 | CONFIG["LDSHARED"].gsub!("gcc", ENV['CXX']) 9 | CONFIG["LDSHARED"].gsub!("cc", ENV['CXX']) 10 | end 11 | 12 | create_makefile("quickfix") 13 | -------------------------------------------------------------------------------- /package.sh: -------------------------------------------------------------------------------- 1 | QF_VERSION=$1 2 | 3 | rm -rf quickfix 4 | 5 | git clone --depth 1 https://github.com/quickfix/quickfix.git 6 | rm -rf quickfix/.git 7 | 8 | pushd quickfix/doc 9 | ./document.sh 10 | popd 11 | 12 | pushd quickfix 13 | ../git2cl > ChangeLog 14 | ./bootstrap 15 | popd 16 | 17 | rm -f quickfix-$QF_VERSION.tar.gz 18 | 19 | tar czvf quickfix-$QF_VERSION.tar.gz quickfix 20 | 21 | pushd quickfix 22 | ./configure --with-python2 --with-python3 --with-ruby && make && make check 23 | popd 24 | -------------------------------------------------------------------------------- /quickfix-ruby/quickfix.gemspec: -------------------------------------------------------------------------------- 1 | Gem::Specification.new do |s| 2 | s.name = 'quickfix_ruby' 3 | s.version = '1.15.1' 4 | s.date = '2018-04-15' 5 | s.summary = "QuickFIX" 6 | s.description = "FIX (Financial Information eXchange) protocol implementation" 7 | s.authors = ["Oren Miller"] 8 | s.email = 'oren@quickfixengine.org' 9 | s.files = Dir.glob("lib/*.rb") + Dir.glob("ext/quickfix/*.*") + Dir.glob("ext/quickfix/double-conversion/*.*") + Dir.glob("spec/FIX*.xml") + Dir.glob("test/*") + Dir.glob("Rakefile") 10 | s.extensions = %w[ext/quickfix/extconf.rb] 11 | s.homepage = 12 | 'http://www.quickfixengine.org' 13 | s.licenses = 'Apache Style' 14 | s.rdoc_options = ['--exclude=ext'] 15 | end 16 | -------------------------------------------------------------------------------- /package.bat: -------------------------------------------------------------------------------- 1 | if "%1" == "" goto USAGE 2 | if "%2" == "" goto USAGE 3 | 4 | set VS_VERSION=%1 5 | set QF_VERSION=%2 6 | 7 | rmdir /s/q quickfix 8 | 9 | git clone --depth 1 https://github.com/quickfix/quickfix.git 10 | rmdir /s/q quickfix\.git 11 | 12 | pushd quickfix\doc 13 | call document.bat 14 | popd 15 | 16 | del /Q quickfix.zip 17 | 7z a -tzip -xr!?git\* quickfix-%QF_VERSION%.zip quickfix 18 | 19 | pushd quickfix 20 | call build_vs%VS_VERSION%.bat 21 | popd 22 | 23 | pushd quickfix\test 24 | call runut.bat release 11111 25 | call runat.bat release 11111 26 | popd 27 | 28 | 7z a -tzip -xr!?git\* quickfix-bin-vs%VS_VERSION%-%QF_VERSION%.zip quickfix/include quickfix/lib/quickfix.lib quickfix/spec/FIX*.xml quickfix/doc/html 29 | 30 | goto END 31 | 32 | :USAGE 33 | echo build.bat [vs version] [qf version] 34 | 35 | :END -------------------------------------------------------------------------------- /package-python.sh: -------------------------------------------------------------------------------- 1 | rm -rf quickfix-python/C++ 2 | rm -rf quickfix-python/spec 3 | rm -rf quickfix-python/quickfix*.py 4 | rm -rf quickfix-python/doc 5 | rm -rf quickfix-python/LICENSE 6 | 7 | mkdir quickfix-python/C++ 8 | mkdir quickfix-python/spec 9 | 10 | cp quickfix/LICENSE quickfix-python 11 | 12 | cp quickfix/src/python3/*.py quickfix-python 13 | cp quickfix/src/C++/*.h quickfix-python/C++ 14 | cp quickfix/src/C++/*.hpp quickfix-python/C++ 15 | cp quickfix/src/C++/*.cpp quickfix-python/C++ 16 | cp -R quickfix/src/C++/double-conversion quickfix-python/C++ 17 | cp quickfix/src/python3/QuickfixPython.cpp quickfix-python/C++ 18 | cp quickfix/src/python3/QuickfixPython.h quickfix-python/C++ 19 | 20 | cp quickfix/spec/FIX*.xml quickfix-python/spec 21 | 22 | touch quickfix-python/C++/config.h 23 | touch quickfix-python/C++/config_windows.h 24 | rm -f quickfix-python/C++/stdafx.* 25 | 26 | pushd quickfix-python 27 | python setup.py sdist 28 | PYTHONWARNINGS="ignore" twine upload --repository-url https://test.pypi.org/legacy/ dist/* 29 | -------------------------------------------------------------------------------- /package-ruby.sh: -------------------------------------------------------------------------------- 1 | rm -rf quickfix-ruby/lib 2 | rm -rf quickfix-ruby/ext/quickfix/*.h 3 | rm -rf quickfix-ruby/ext/quickfix/*.hpp 4 | rm -rf quickfix-ruby/ext/quickfix/*.cpp 5 | rm -rf quickfix-ruby/test 6 | rm -rf quickfix-ruby/spec 7 | 8 | mkdir -p quickfix-ruby/lib 9 | mkdir -p quickfix-ruby/ext/quickfix 10 | mkdir -p quickfix-ruby/ext/quickfix/double-conversion 11 | mkdir -p quickfix-ruby/test 12 | mkdir -p quickfix-ruby/spec 13 | 14 | cp quickfix/LICENSE quickfix-ruby/ 15 | 16 | cp quickfix/src/ruby/quickfix*.rb quickfix-ruby/lib 17 | cp quickfix/src/C++/*.h quickfix-ruby/ext/quickfix 18 | cp quickfix/src/C++/*.hpp quickfix-ruby/ext/quickfix 19 | cp quickfix/src/C++/*.cpp quickfix-ruby/ext/quickfix 20 | cp quickfix/src/C++/double-conversion/* quickfix-ruby/ext/quickfix/double-conversion 21 | cp quickfix/src/ruby/QuickfixRuby.cpp quickfix-ruby/ext/quickfix 22 | cp quickfix/src/ruby/QuickfixRuby.h quickfix-ruby/ext/quickfix 23 | cp quickfix/src/ruby/test/*TestCase.rb quickfix-ruby/test 24 | 25 | cp quickfix/spec/FIX*.xml quickfix-ruby/spec 26 | 27 | touch quickfix-ruby/ext/quickfix/config.h 28 | touch quickfix-ruby/ext/quickfix/config_windows.h 29 | rm -f quickfix-ruby/ext/quickfix/stdafx.* 30 | 31 | pushd quickfix-ruby/test 32 | for file in * ; 33 | do 34 | mv "$file" "test_$file" 35 | done 36 | popd 37 | 38 | pushd quickfix-ruby 39 | 40 | gem build quickfix.gemspec 41 | -------------------------------------------------------------------------------- /quickfix-python/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | from distutils.core import Extension 3 | from distutils.command.install import install 4 | from distutils.command.build import build 5 | from distutils.command.build_ext import build_ext 6 | from distutils.sysconfig import get_config_vars 7 | 8 | import subprocess 9 | import shutil 10 | import glob 11 | import os 12 | import sys 13 | 14 | class build_ext_subclass( build_ext ): 15 | def build_extensions(self): 16 | self.compiler.define_macro("PYTHON_MAJOR_VERSION", sys.version_info[0]) 17 | print("Testing for std::tr1::shared_ptr...") 18 | try: 19 | self.compiler.compile(['test_std_tr1_shared_ptr.cpp']) 20 | self.compiler.define_macro("HAVE_STD_TR1_SHARED_PTR") 21 | print("...found") 22 | except: 23 | print(" ...not found") 24 | 25 | print("Testing for std::shared_ptr...") 26 | try: 27 | self.compiler.compile(['test_std_shared_ptr.cpp'], extra_preargs=['-std=c++0x']), 28 | self.compiler.define_macro("HAVE_STD_SHARED_PTR") 29 | print("...found") 30 | except: 31 | print("...not found") 32 | 33 | print("Testing for std::unique_ptr...") 34 | try: 35 | self.compiler.compile(['test_std_unique_ptr.cpp'], extra_preargs=['-std=c++0x']), 36 | self.compiler.define_macro("HAVE_STD_UNIQUE_PTR") 37 | print("...found") 38 | except: 39 | print("...not found") 40 | 41 | build_ext.build_extensions(self) 42 | 43 | # Remove the "-Wstrict-prototypes" compiler option, which isn't valid for C++. 44 | import distutils.sysconfig 45 | cfg_vars = distutils.sysconfig.get_config_vars() 46 | for key, value in cfg_vars.items(): 47 | if type(value) == str: 48 | cfg_vars[key] = value.replace("-Wstrict-prototypes", "") 49 | 50 | long_description='' 51 | with open('LICENSE') as file: 52 | license = file.read(); 53 | 54 | setup(name='quickfix', 55 | version='1.15.1', 56 | py_modules=['quickfix', 'quickfixt11', 'quickfix40', 'quickfix41', 'quickfix42', 'quickfix43', 'quickfix44', 'quickfix50', 'quickfix50sp1', 'quickfix50sp2'], 57 | data_files=[('share/quickfix', glob.glob('spec/FIX*.xml'))], 58 | author='Oren Miller', 59 | author_email='oren@quickfixengine.org', 60 | maintainer='Oren Miller', 61 | maintainer_email='oren@quickfixengine.org', 62 | description="FIX (Financial Information eXchange) protocol implementation", 63 | url='http://www.quickfixengine.org', 64 | download_url='http://www.quickfixengine.org', 65 | license=license, 66 | include_dirs=['C++'], 67 | cmdclass = {'build_ext': build_ext_subclass }, 68 | ext_modules=[Extension('_quickfix', glob.glob('C++/*.cpp'), extra_compile_args=['-std=c++0x', '-Wno-deprecated', '-Wno-unused-variable', '-Wno-deprecated-declarations', '-Wno-maybe-uninitialized'])], 69 | ) 70 | -------------------------------------------------------------------------------- /git2cl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Copyright (C) 2007, 2008 Simon Josefsson 4 | # Copyright (C) 2007 Luis Mondesi 5 | # * calls git directly. To use it just: 6 | # cd ~/Project/my_git_repo; git2cl > ChangeLog 7 | # * implements strptime() 8 | # * fixes bugs in $comment parsing 9 | # - copy input before we remove leading spaces 10 | # - skip "merge branch" statements as they don't 11 | # have information about files (i.e. we never 12 | # go into $state 2) 13 | # - behaves like a pipe/filter if input is given from the CLI 14 | # else it calls git log by itself 15 | # 16 | # The functions mywrap, last_line_len, wrap_log_entry are derived from 17 | # the cvs2cl tool, see : 18 | # Copyright (C) 2001,2002,2003,2004 Martyn J. Pearce 19 | # Copyright (C) 1999 Karl Fogel 20 | # 21 | # git2cl is free software; you can redistribute it and/or modify it 22 | # under the terms of the GNU General Public License as published by 23 | # the Free Software Foundation; either version 2, or (at your option) 24 | # any later version. 25 | # 26 | # git2cl is distributed in the hope that it will be useful, but 27 | # WITHOUT ANY WARRANTY; without even the implied warranty of 28 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 29 | # General Public License for more details. 30 | # 31 | # You should have received a copy of the GNU General Public License 32 | # along with git2cl; see the file COPYING. If not, write to the Free 33 | # Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 34 | # 02110-1301 USA. 35 | 36 | =head1 NAME 37 | 38 | git2cl - tool to convert git logs to GNU ChangeLog 39 | 40 | =head1 SYNOPSIS 41 | 42 | git2cl > ChangeLog 43 | 44 | If you don't want git2cl to invoke git log internally, you can use it 45 | as a pipe. 46 | It needs a git log generated with --pretty --numstat and --summary. 47 | You can use it as follows: 48 | 49 | git log --pretty --numstat --summary | git2cl > ChangeLog 50 | 51 | =head1 DESCRIPTION 52 | 53 | This is a quick'n'dirty tool to convert git logs to GNU ChangeLog 54 | format. 55 | 56 | The tool invokes `git log` internally unless you pipe a log to it. 57 | Thus, typically you would use it as follows: 58 | 59 | =head1 SEE ALSO 60 | 61 | Output format specification: 62 | 63 | 64 | =head1 AUTHORS 65 | 66 | git2cl is developed by Simon Josefsson 67 | and Luis Mondesi 68 | 69 | =cut 70 | 71 | use strict; 72 | use POSIX qw(strftime); 73 | use Text::Wrap qw(wrap); 74 | use FileHandle; 75 | 76 | use constant EMPTY_LOG_MESSAGE => '*** empty log message ***'; 77 | 78 | # this is a helper hash for stptime. 79 | # Assumes you are calling 'git log ...' with LC_ALL=C 80 | my %month = ( 81 | 'Jan'=>0, 82 | 'Feb'=>1, 83 | 'Mar'=>2, 84 | 'Apr'=>3, 85 | 'May'=>4, 86 | 'Jun'=>5, 87 | 'Jul'=>6, 88 | 'Aug'=>7, 89 | 'Sep'=>8, 90 | 'Oct'=>9, 91 | 'Nov'=>10, 92 | 'Dec'=>11, 93 | ); 94 | 95 | my $fh = new FileHandle; 96 | 97 | sub key_ready 98 | { 99 | my ($rin, $nfd); 100 | vec($rin, fileno(STDIN), 1) = 1; 101 | return $nfd = select($rin, undef, undef, 0); 102 | } 103 | 104 | sub strptime { 105 | my $str = shift; 106 | return undef if not defined $str; 107 | 108 | # we are parsing this format 109 | # Fri Oct 26 00:42:56 2007 -0400 110 | # to these fields 111 | # sec, min, hour, mday, mon, year, wday = -1, yday = -1, isdst = -1 112 | # Luis Mondesi 113 | my @date; 114 | if ($str =~ /([[:alpha:]]{3})\s+([[:alpha:]]{3})\s+([[:digit:]]{1,2})\s+([[:digit:]]{1,2}):([[:digit:]]{1,2}):([[:digit:]]{1,2})\s+([[:digit:]]{4})/){ 115 | push(@date,$6,$5,$4,$3,$month{$2},($7 - 1900),-1,-1,-1); 116 | } else { 117 | die ("Cannot parse date '$str'\n'"); 118 | } 119 | return @date; 120 | } 121 | 122 | sub mywrap { 123 | my ($indent1, $indent2, @text) = @_; 124 | # If incoming text looks preformatted, don't get clever 125 | my $text = Text::Wrap::wrap($indent1, $indent2, @text); 126 | if ( grep /^\s+/m, @text ) { 127 | return $text; 128 | } 129 | my @lines = split /\n/, $text; 130 | $indent2 =~ s!^((?: {8})+)!"\t" x (length($1)/8)!e; 131 | $lines[0] =~ s/^$indent1\s+/$indent1/; 132 | s/^$indent2\s+/$indent2/ 133 | for @lines[1..$#lines]; 134 | my $newtext = join "\n", @lines; 135 | $newtext .= "\n" 136 | if substr($text, -1) eq "\n"; 137 | return $newtext; 138 | } 139 | 140 | sub last_line_len { 141 | my $files_list = shift; 142 | my @lines = split (/\n/, $files_list); 143 | my $last_line = pop (@lines); 144 | return length ($last_line); 145 | } 146 | 147 | # A custom wrap function, sensitive to some common constructs used in 148 | # log entries. 149 | sub wrap_log_entry { 150 | my $text = shift; # The text to wrap. 151 | my $left_pad_str = shift; # String to pad with on the left. 152 | 153 | # These do NOT take left_pad_str into account: 154 | my $length_remaining = shift; # Amount left on current line. 155 | my $max_line_length = shift; # Amount left for a blank line. 156 | 157 | my $wrapped_text = ''; # The accumulating wrapped entry. 158 | my $user_indent = ''; # Inherited user_indent from prev line. 159 | 160 | my $first_time = 1; # First iteration of the loop? 161 | my $suppress_line_start_match = 0; # Set to disable line start checks. 162 | 163 | my @lines = split (/\n/, $text); 164 | while (@lines) # Don't use `foreach' here, it won't work. 165 | { 166 | my $this_line = shift (@lines); 167 | chomp $this_line; 168 | 169 | if ($this_line =~ /^(\s+)/) { 170 | $user_indent = $1; 171 | } 172 | else { 173 | $user_indent = ''; 174 | } 175 | 176 | # If it matches any of the line-start regexps, print a newline now... 177 | if ($suppress_line_start_match) 178 | { 179 | $suppress_line_start_match = 0; 180 | } 181 | elsif (($this_line =~ /^(\s*)\*\s+[a-zA-Z0-9]/) 182 | || ($this_line =~ /^(\s*)\* [a-zA-Z0-9_\.\/\+-]+/) 183 | || ($this_line =~ /^(\s*)\([a-zA-Z0-9_\.\/\+-]+(\)|,\s*)/) 184 | || ($this_line =~ /^(\s+)(\S+)/) 185 | || ($this_line =~ /^(\s*)- +/) 186 | || ($this_line =~ /^()\s*$/) 187 | || ($this_line =~ /^(\s*)\*\) +/) 188 | || ($this_line =~ /^(\s*)[a-zA-Z0-9](\)|\.|\:) +/)) 189 | { 190 | $length_remaining = $max_line_length - (length ($user_indent)); 191 | } 192 | 193 | # Now that any user_indent has been preserved, strip off leading 194 | # whitespace, so up-folding has no ugly side-effects. 195 | $this_line =~ s/^\s*//; 196 | 197 | # Accumulate the line, and adjust parameters for next line. 198 | my $this_len = length ($this_line); 199 | if ($this_len == 0) 200 | { 201 | # Blank lines should cancel any user_indent level. 202 | $user_indent = ''; 203 | $length_remaining = $max_line_length; 204 | } 205 | elsif ($this_len >= $length_remaining) # Line too long, try breaking it. 206 | { 207 | # Walk backwards from the end. At first acceptable spot, break 208 | # a new line. 209 | my $idx = $length_remaining - 1; 210 | if ($idx < 0) { $idx = 0 }; 211 | while ($idx > 0) 212 | { 213 | if (substr ($this_line, $idx, 1) =~ /\s/) 214 | { 215 | my $line_now = substr ($this_line, 0, $idx); 216 | my $next_line = substr ($this_line, $idx); 217 | $this_line = $line_now; 218 | 219 | # Clean whitespace off the end. 220 | chomp $this_line; 221 | 222 | # The current line is ready to be printed. 223 | $this_line .= "\n${left_pad_str}"; 224 | 225 | # Make sure the next line is allowed full room. 226 | $length_remaining = $max_line_length - (length ($user_indent)); 227 | 228 | # Strip next_line, but then preserve any user_indent. 229 | $next_line =~ s/^\s*//; 230 | 231 | # Sneak a peek at the user_indent of the upcoming line, so 232 | # $next_line (which will now precede it) can inherit that 233 | # indent level. Otherwise, use whatever user_indent level 234 | # we currently have, which might be none. 235 | my $next_next_line = shift (@lines); 236 | if ((defined ($next_next_line)) && ($next_next_line =~ /^(\s+)/)) { 237 | $next_line = $1 . $next_line if (defined ($1)); 238 | # $length_remaining = $max_line_length - (length ($1)); 239 | $next_next_line =~ s/^\s*//; 240 | } 241 | else { 242 | $next_line = $user_indent . $next_line; 243 | } 244 | if (defined ($next_next_line)) { 245 | unshift (@lines, $next_next_line); 246 | } 247 | unshift (@lines, $next_line); 248 | 249 | # Our new next line might, coincidentally, begin with one of 250 | # the line-start regexps, so we temporarily turn off 251 | # sensitivity to that until we're past the line. 252 | $suppress_line_start_match = 1; 253 | 254 | last; 255 | } 256 | else 257 | { 258 | $idx--; 259 | } 260 | } 261 | 262 | if ($idx == 0) 263 | { 264 | # We bottomed out because the line is longer than the 265 | # available space. But that could be because the space is 266 | # small, or because the line is longer than even the maximum 267 | # possible space. Handle both cases below. 268 | 269 | if ($length_remaining == ($max_line_length - (length ($user_indent)))) 270 | { 271 | # The line is simply too long -- there is no hope of ever 272 | # breaking it nicely, so just insert it verbatim, with 273 | # appropriate padding. 274 | $this_line = "\n${left_pad_str}${this_line}"; 275 | } 276 | else 277 | { 278 | # Can't break it here, but may be able to on the next round... 279 | unshift (@lines, $this_line); 280 | $length_remaining = $max_line_length - (length ($user_indent)); 281 | $this_line = "\n${left_pad_str}"; 282 | } 283 | } 284 | } 285 | else # $this_len < $length_remaining, so tack on what we can. 286 | { 287 | # Leave a note for the next iteration. 288 | $length_remaining = $length_remaining - $this_len; 289 | 290 | if ($this_line =~ /\.$/) 291 | { 292 | $this_line .= " "; 293 | $length_remaining -= 2; 294 | } 295 | else # not a sentence end 296 | { 297 | $this_line .= " "; 298 | $length_remaining -= 1; 299 | } 300 | } 301 | 302 | # Unconditionally indicate that loop has run at least once. 303 | $first_time = 0; 304 | 305 | $wrapped_text .= "${user_indent}${this_line}"; 306 | } 307 | 308 | # One last bit of padding. 309 | $wrapped_text .= "\n"; 310 | 311 | return $wrapped_text; 312 | } 313 | 314 | # main 315 | 316 | my @date; 317 | my $author; 318 | my @files; 319 | my $comment; 320 | 321 | my $state; # 0-header 1-comment 2-files 322 | my $done = 0; 323 | 324 | $state = 0; 325 | 326 | # if reading from STDIN, we assume that we are 327 | # getting git log as input 328 | if (key_ready()) 329 | { 330 | 331 | #my $dummyfh; # don't care about writing 332 | #($fh,$dummyfh) = FileHandle::pipe; 333 | $fh->fdopen(*STDIN, 'r'); 334 | } 335 | else 336 | { 337 | $fh->open("LC_ALL=C git log --pretty --numstat --summary|") 338 | or die("Cannot execute git log...$!\n"); 339 | } 340 | 341 | while (my $_l = <$fh>) { 342 | #print STDERR "debug ($state, " . (@date ? (strftime "%Y-%m-%d", @date) : "") . "): `$_'\n"; 343 | if ($state == 0) { 344 | if ($_l =~ m,^Author: (.*),) { 345 | $author = $1; 346 | } 347 | if ($_l =~ m,^Date: (.*),) { 348 | @date = strptime($1); 349 | } 350 | $state = 1 if ($_l =~ m,^$, and $author and (@date+0>0)); 351 | } elsif ($state == 1) { 352 | # * modifying our input text is a bad choice 353 | # let's make a copy of it first, then we remove spaces 354 | # * if we meet a "merge branch" statement, we need to start 355 | # over and find a real entry 356 | # Luis Mondesi 357 | my $_s = $_l; 358 | $_s =~ s/^ //g; 359 | if ($_s =~ m/^Merge branch/) 360 | { 361 | $state=0; 362 | next; 363 | } 364 | $comment = $comment . $_s; 365 | $state = 2 if ($_l =~ m,^$,); 366 | } elsif ($state == 2) { 367 | if ($_l =~ m,^([0-9]+)\t([0-9]+)\t(.*)$,) { 368 | push @files, $3; 369 | } 370 | $done = 1 if ($_l =~ m,^$,); 371 | } 372 | 373 | if ($done) { 374 | print (strftime "%Y-%m-%d $author\n\n", @date); 375 | 376 | my $files = join (", ", @files); 377 | $files = mywrap ("\t", "\t", "* $files"), ": "; 378 | 379 | if (index($comment, EMPTY_LOG_MESSAGE) > -1 ) { 380 | $comment = "[no log message]\n"; 381 | } 382 | 383 | my $files_last_line_len = 0; 384 | $files_last_line_len = last_line_len($files) + 1; 385 | my $msg = wrap_log_entry($comment, "\t", 69-$files_last_line_len, 69); 386 | 387 | $msg =~ s/[ \t]+\n/\n/g; 388 | 389 | print "$files: $msg\n"; 390 | 391 | @date = (); 392 | $author = ""; 393 | @files = (); 394 | $comment = ""; 395 | 396 | $state = 0; 397 | $done = 0; 398 | } 399 | } 400 | 401 | if (@date + 0) 402 | { 403 | print (strftime "%Y-%m-%d $author\n\n", @date); 404 | my $msg = wrap_log_entry($comment, "\t", 69, 69); 405 | $msg =~ s/[ \t]+\n/\n/g; 406 | print "\t* $msg\n"; 407 | } 408 | --------------------------------------------------------------------------------